Files
open5gs/tests/common/emm-build.c
Sukchan Lee fd897f35a3 MME: handle EPS Bearer Context Status mismatch when active_flag=0 (#4112)
When the UE sends a Tracking Area Update (TAU) Request with active_flag=0,
the MME previously sent TAU Accept without verifying the EPS Bearer Context
Status (EBCS). This caused stale bearer sessions to remain in the MME even
if the UE had already released them.

According to 3GPP TS 24.301 §5.5.3.2, the MME should release any bearer
not reported in the UE’s EBCS when active_flag=0. This patch introduces
mme_send_delete_session_or_tau_accept(), which compares the UE’s EBCS bitmask
with the MME session list and deletes any missing default bearer session
before sending TAU Accept.

If no mismatch is found, TAU Accept is sent immediately. The Delete Session
response triggers TAU Accept when deletions are required. This ensures that
the TAU Accept message reflects the UE’s current bearer context accurately.

Also includes:
 - Added OGS_GTP_DELETE_SEND_TAU_ACCEPT handling in mme-s11-handler.c
 - Simplified EBCS structure (uint16_t value) for bitmask comparison
 - Updated TAU-related tests with realistic EBI bitmasks (0x20, 0x60)

This change aligns TAU handling with 3GPP 24.301 and prevents bearer
mismatch issues between UE and EPC during TAU.
2025-10-16 21:46:38 +09:00

901 lines
36 KiB
C

/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of OpenEPS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "test-common.h"
ogs_pkbuf_t *testemm_build_attach_request(
test_ue_t *test_ue, ogs_pkbuf_t *esmbuf,
bool integrity_protected, bool ciphered)
{
int i;
uint16_t psimask = 0;
ogs_pkbuf_t *pkbuf = NULL;
ogs_nas_eps_message_t message;
ogs_nas_eps_attach_request_t *attach_request = &message.emm.attach_request;
ogs_nas_eps_attach_type_t *eps_attach_type =
&attach_request->eps_attach_type;
ogs_nas_eps_mobile_identity_t *eps_mobile_identity =
&attach_request->eps_mobile_identity;
ogs_nas_ue_network_capability_t *ue_network_capability =
&attach_request->ue_network_capability;
ogs_nas_esm_message_container_t *esm_message_container =
&attach_request->esm_message_container;
ogs_nas_tracking_area_identity_t *last_visited_registered_tai =
&attach_request->last_visited_registered_tai;
ogs_nas_drx_parameter_t *drx_parameter = &attach_request->drx_parameter;
ogs_nas_ms_network_capability_t *ms_network_capability =
&attach_request->ms_network_capability;
ogs_nas_location_area_identification_t *old_location_area_identification =
&attach_request->old_location_area_identification;
ogs_nas_tmsi_status_t *tmsi_status = &attach_request->tmsi_status;
ogs_nas_mobile_station_classmark_2_t *mobile_station_classmark_2 =
&attach_request->mobile_station_classmark_2;
ogs_nas_mobile_station_classmark_3_t *mobile_station_classmark_3 =
&attach_request->mobile_station_classmark_3;
ogs_nas_supported_codec_list_t *supported_codecs =
&attach_request->supported_codecs;
ogs_nas_additional_update_type_t *additional_update_type =
&attach_request->additional_update_type;
ogs_nas_voice_domain_preference_and_ue_usage_setting_t
*voice_domain_preference_and_ue_usage_setting =
&attach_request->voice_domain_preference_and_ue_usage_setting;
ogs_nas_guti_type_t *old_guti_type = &attach_request->old_guti_type;
ogs_nas_ms_network_feature_support_t *ms_network_feature_support =
&attach_request->ms_network_feature_support;
ogs_nas_network_resource_identifier_container_t *tmsi_based_nri_container =
&attach_request->tmsi_based_nri_container;
ogs_nas_ue_additional_security_capability_t
*ue_additional_security_capability =
&attach_request->ue_additional_security_capability;
uint8_t classmark_3[11] = "\x60\x14\x04\xef\x65\x23\x3b\x88\x78\xd2\x90";
ogs_assert(test_ue);
ogs_assert(esmbuf);
memset(&message, 0, sizeof(message));
if (integrity_protected) {
if (ciphered)
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
else
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
}
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_ATTACH_REQUEST;
esm_message_container->length = esmbuf->len;
esm_message_container->buffer = esmbuf->data;
memcpy(eps_attach_type, &test_ue->nas.data, sizeof(*eps_attach_type));
if (test_ue->attach_request_param.guti) {
eps_mobile_identity->length =
sizeof(ogs_nas_eps_mobile_identity_guti_t);
eps_mobile_identity->guti.odd_even = OGS_NAS_MOBILE_IDENTITY_EVEN;
eps_mobile_identity->guti.type = OGS_NAS_EPS_MOBILE_IDENTITY_GUTI;
eps_mobile_identity->guti.nas_plmn_id =
test_ue->nas_eps_guti.nas_plmn_id;
eps_mobile_identity->guti.mme_gid = test_ue->nas_eps_guti.mme_gid;
eps_mobile_identity->guti.mme_code = test_ue->nas_eps_guti.mme_code;
eps_mobile_identity->guti.m_tmsi = test_ue->nas_eps_guti.m_tmsi;
} else {
eps_mobile_identity->length =
sizeof(ogs_nas_mobile_identity_imsi_t);
memcpy(&eps_mobile_identity->imsi,
&test_ue->mobile_identity_imsi, eps_mobile_identity->length);
}
ue_network_capability->length = 7;
ue_network_capability->eea = 0xf0;
ue_network_capability->eia = 0xf0;
ue_network_capability->uea = 0xc0;
ue_network_capability->uia = 0x40;
ue_network_capability->notification_procedure = 1;
ue_network_capability->dual_connectivity_with_nr = 1;
if (test_ue->attach_request_param.last_visited_registered_tai) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT;
ogs_nas_from_plmn_id(&last_visited_registered_tai->nas_plmn_id,
&test_ue->e_tai.plmn_id);
last_visited_registered_tai->tac = test_ue->e_tai.tac;
}
if (test_ue->attach_request_param.drx_parameter) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_DRX_PARAMETER_PRESENT;
drx_parameter->split_pg_cycle_code = 32;
}
if (test_ue->attach_request_param.ms_network_capability) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT;
ms_network_capability->length = 3;
ms_network_capability->gea1 = 1;
ms_network_capability->sm_capabilities_via_dedicated_channels = 1;
ms_network_capability->sm_capabilities_via_gprs_channels = 1;
ms_network_capability->ss_screening_indicator = 1;
ms_network_capability->revision_level_indicator = 1;
ms_network_capability->pfc_feature_mode = 1;
ms_network_capability->extended_gea = 0x30;
ms_network_capability->emm_combined_procedures_capability = 1;
ms_network_capability->isr_support = 1;
ms_network_capability->epc_capability = 1;
}
if (test_ue->attach_request_param.location_area_identication) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT;
ogs_nas_from_plmn_id(&old_location_area_identification->nas_plmn_id,
&test_ue->e_tai.plmn_id);
old_location_area_identification->lac = 1;
}
if (test_ue->attach_request_param.tmsi_status) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_TMSI_STATUS_PRESENT;
}
if (test_ue->attach_request_param.mobile_station_classmark_2) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT;
mobile_station_classmark_2->length = 3;
mobile_station_classmark_2->revision_level = 2;
mobile_station_classmark_2->es_ind = 1;
mobile_station_classmark_2->a5_1 = 1;
mobile_station_classmark_2->rf_power_capability = 7;
mobile_station_classmark_2->ps_capa = 1;
mobile_station_classmark_2->ss_screen_indicator = 1;
mobile_station_classmark_2->sm_capabi = 1;
mobile_station_classmark_2->cm3 = 1;
mobile_station_classmark_2->lcsva_cap = 1;
mobile_station_classmark_2->cmsp = 1;
mobile_station_classmark_2->a5_3 = 1;
}
if (test_ue->attach_request_param.mobile_station_classmark_3) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT;
mobile_station_classmark_3->length = 11;
memcpy(mobile_station_classmark_3->buffer,
classmark_3, mobile_station_classmark_3->length);
}
if (test_ue->attach_request_param.supported_codecs) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_SUPPORTED_CODECS_PRESENT;
supported_codecs->length = 8;
supported_codecs->item[0].system_identification = 0x04;
supported_codecs->item[0].length_of_bitmap = 2;
supported_codecs->item[0].codec_bitmap = htobe16(0x6004);
supported_codecs->item[1].system_identification = 0;
supported_codecs->item[1].length_of_bitmap = 2;
supported_codecs->item[1].codec_bitmap = htobe16(0x1f02);
}
if (test_ue->attach_request_param.additional_update_type) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT;
additional_update_type->additional_update_type_value = 1;
}
if (test_ue->attach_request_param.ue_usage_setting) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_VOICE_DOMAIN_PREFERENCE_AND_UE_USAGE_SETTING_PRESENT;
voice_domain_preference_and_ue_usage_setting->length = 1;
voice_domain_preference_and_ue_usage_setting->ue_usage_setting = 1;
voice_domain_preference_and_ue_usage_setting->
voice_domain_preference_for_e_utran = 1;
}
if (test_ue->attach_request_param.old_guti_type) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT;
}
if (test_ue->attach_request_param.ms_network_feature_support) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_MS_NETWORK_FEATURE_SUPPORT_PRESENT;
ms_network_feature_support->extended_periodic_timers = 1;
}
if (test_ue->attach_request_param.nri_container) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_TMSI_BASED_NRI_CONTAINER_PRESENT;
tmsi_based_nri_container->length = 2;
tmsi_based_nri_container->nri_container_value1 = 0x8d;
tmsi_based_nri_container->nri_container_value2 = 0x3;
}
if (test_ue->attach_request_param.ue_additional_security_capability) {
attach_request->presencemask |=
OGS_NAS_EPS_ATTACH_REQUEST_UE_ADDITIONAL_SECURITY_CAPABILITY_PRESENT;
ue_additional_security_capability->length = 4;
ue_additional_security_capability->nea = 0xf0;
ue_additional_security_capability->nia = 0xf0;
}
if (integrity_protected)
pkbuf = test_nas_eps_security_encode(test_ue, &message);
else
pkbuf = ogs_nas_eps_plain_encode(&message);
ogs_pkbuf_free(esmbuf);
return pkbuf;
}
ogs_pkbuf_t *testemm_build_identity_response(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_identity_response_t *identity_response =
&message.emm.identity_response;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.emm.h.protocol_discriminator =
OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_IDENTITY_RESPONSE;
identity_response->mobile_identity.length =
sizeof(ogs_nas_mobile_identity_imsi_t);
memcpy(&identity_response->mobile_identity.imsi,
&test_ue->mobile_identity_imsi,
identity_response->mobile_identity.length);
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_authentication_response(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_authentication_response_t *authentication_response =
&message.emm.authentication_response;
ogs_nas_authentication_response_parameter_t
*authentication_response_parameter =
&authentication_response->authentication_response_parameter;
uint8_t ik[OGS_KEY_LEN];
uint8_t ck[OGS_KEY_LEN];
uint8_t ak[OGS_AK_LEN];
uint8_t sqn[OGS_SQN_LEN];
uint8_t res[OGS_MAX_RES_LEN];
ogs_nas_plmn_id_t nas_plmn_id;
uint8_t kasme[32];
int i;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_AUTHENTICATION_RESPONSE;
ogs_hex_from_string(
test_ue->k_string, test_ue->k, sizeof(test_ue->k));
ogs_hex_from_string(
test_ue->opc_string, test_ue->opc, sizeof(test_ue->opc));
milenage_f2345(test_ue->opc, test_ue->k, test_ue->rand,
res, ck, ik, ak, NULL);
for (i = 0; i < 6; i++)
sqn[i] = test_ue->autn[i] ^ ak[i];
ogs_nas_from_plmn_id(&nas_plmn_id, &test_ue->e_tai.plmn_id);
ogs_auc_kasme(ck, ik, &nas_plmn_id, sqn, ak, test_ue->kasme);
authentication_response_parameter->length = 8;
memcpy(authentication_response_parameter->res, res, 8);
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_authentication_failure(
test_ue_t *test_ue, ogs_nas_emm_cause_t emm_cause, uint64_t sqn_ms)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_authentication_failure_t *authentication_failure =
&message.emm.authentication_failure;
ogs_nas_authentication_failure_parameter_t
*authentication_failure_parameter =
&authentication_failure->authentication_failure_parameter;
uint8_t ak[OGS_AK_LEN];
#if 0
uint8_t sqn_ms[OGS_SQN_LEN] = "\x00\x00\x11\x22\x33\x44";
uint8_t sqn_ms[OGS_SQN_LEN] = "\x00\x00\x00\x00\x1f\x60"; /* Issues 482 */
#endif
uint8_t sqn[OGS_SQN_LEN];
uint8_t mac_s[OGS_MAC_S_LEN];
uint8_t amf[2] = { 0, 0 };
uint8_t auts[OGS_AUTS_LEN];
int i = 0;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_AUTHENTICATION_FAILURE;
authentication_failure->emm_cause = emm_cause;
if (emm_cause == OGS_NAS_EMM_CAUSE_SYNCH_FAILURE) {
authentication_failure->presencemask |=
OGS_NAS_EPS_AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT;
ogs_hex_from_string(
test_ue->k_string, test_ue->k, sizeof(test_ue->k));
ogs_hex_from_string(
test_ue->opc_string, test_ue->opc, sizeof(test_ue->opc));
milenage_f2345(test_ue->opc, test_ue->k, test_ue->rand,
NULL, NULL, NULL, NULL, ak);
ogs_uint64_to_buffer(sqn_ms, 6, sqn);
milenage_f1(test_ue->opc, test_ue->k, test_ue->rand,
sqn, amf, NULL, auts + OGS_SQN_LEN);
for (i = 0; i < OGS_SQN_LEN; i++)
auts[i] = sqn[i] ^ ak[i];
authentication_failure_parameter->length = OGS_AUTS_LEN;
memcpy(authentication_failure_parameter->auts, auts,
authentication_failure_parameter->length);
}
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_security_mode_complete(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_security_mode_complete_t *security_mode_complete =
&message.emm.security_mode_complete;
ogs_nas_mobile_identity_t *imeisv = &security_mode_complete->imeisv;
ogs_nas_mobile_identity_imeisv_t mobile_identity_imeisv;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHTERD_WITH_NEW_INTEGRITY_CONTEXT;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_SECURITY_MODE_COMPLETE;
if (test_ue->mobile_identity_imeisv_presence) {
security_mode_complete->presencemask |=
OGS_NAS_EPS_SECURITY_MODE_COMPLETE_IMEISV_PRESENT;
memset(&mobile_identity_imeisv, 0, sizeof(mobile_identity_imeisv));
imeisv->length = sizeof(test_ue->mobile_identity_imeisv);
memcpy(&imeisv->imeisv,
&test_ue->mobile_identity_imeisv, imeisv->length);
imeisv->imeisv.type = OGS_NAS_MOBILE_IDENTITY_IMEISV;
}
return test_nas_eps_security_encode(test_ue, &message);
}
ogs_pkbuf_t *testemm_build_attach_complete(
test_ue_t *test_ue, ogs_pkbuf_t *esmbuf)
{
ogs_pkbuf_t *pkbuf = NULL;
ogs_nas_eps_message_t message;
ogs_nas_eps_attach_complete_t *attach_complete =
&message.emm.attach_complete;
ogs_nas_esm_message_container_t *esm_message_container =
&attach_complete->esm_message_container;
ogs_assert(test_ue);
ogs_assert(esmbuf);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_ATTACH_COMPLETE;
esm_message_container->length = esmbuf->len;
esm_message_container->buffer = esmbuf->data;
pkbuf = test_nas_eps_security_encode(test_ue, &message);
ogs_pkbuf_free(esmbuf);
return pkbuf;
}
ogs_pkbuf_t *testemm_build_tau_complete(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_TRACKING_AREA_UPDATE_COMPLETE;
return test_nas_eps_security_encode(test_ue, &message);
}
ogs_pkbuf_t *testemm_build_detach_request(
test_ue_t *test_ue, bool switch_off,
bool integrity_protected, bool ciphered)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_detach_request_from_ue_t *detach_request =
&message.emm.detach_request_from_ue;
ogs_nas_detach_type_t *detach_type = &detach_request->detach_type;
ogs_nas_eps_mobile_identity_t *eps_mobile_identity =
&detach_request->eps_mobile_identity;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
if (integrity_protected) {
if (ciphered)
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
else
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
}
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_DETACH_REQUEST;
detach_type->nas_key_set_identifier = test_ue->nas.ksi;
detach_type->switch_off = switch_off;
detach_type->value = OGS_NAS_DETACH_TYPE_FROM_UE_EPS_DETACH;
if (test_ue->nas_eps_guti.m_tmsi) {
eps_mobile_identity->length =
sizeof(ogs_nas_eps_mobile_identity_guti_t);
eps_mobile_identity->guti.odd_even = OGS_NAS_MOBILE_IDENTITY_EVEN;
eps_mobile_identity->guti.type = OGS_NAS_EPS_MOBILE_IDENTITY_GUTI;
eps_mobile_identity->guti.nas_plmn_id =
test_ue->nas_eps_guti.nas_plmn_id;
eps_mobile_identity->guti.mme_gid = test_ue->nas_eps_guti.mme_gid;
eps_mobile_identity->guti.mme_code = test_ue->nas_eps_guti.mme_code;
eps_mobile_identity->guti.m_tmsi = test_ue->nas_eps_guti.m_tmsi;
} else {
eps_mobile_identity->length =
sizeof(ogs_nas_mobile_identity_imsi_t);
memcpy(&eps_mobile_identity->imsi,
&test_ue->mobile_identity_imsi, eps_mobile_identity->length);
}
if (integrity_protected)
return test_nas_eps_security_encode(test_ue, &message);
else
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_service_request(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_service_request_t *service_request =
&message.emm.service_request;
ogs_pkbuf_t *pkbuf = NULL;
ogs_pkbuf_t *new = NULL;
uint8_t mac[4];
ogs_nas_ksi_and_sequence_number_t *ksi_and_sequence_number =
&service_request->ksi_and_sequence_number;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.emm.h.security_header_type =
OGS_NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
ksi_and_sequence_number->sequence_number = test_ue->ul_count;
pkbuf = ogs_nas_eps_plain_encode(&message);
ogs_assert(pkbuf);
new = ogs_pkbuf_copy(pkbuf);
ogs_assert(new);
ogs_pkbuf_trim(new, 2);
/* To prevent error message in ogs_nas_mac_calculate() */
if (test_ue->selected_int_algorithm == OGS_NAS_SECURITY_ALGORITHMS_EIA0)
test_ue->selected_int_algorithm = OGS_NAS_SECURITY_ALGORITHMS_128_EIA1;
ogs_nas_mac_calculate(test_ue->selected_int_algorithm,
test_ue->knas_int, test_ue->ul_count, 0, 0, new, mac);
test_ue->ul_count = (test_ue->ul_count + 1) & 0xffffff; /* Use 24bit */
memcpy(pkbuf->data + 2, mac + 2, 2);
ogs_pkbuf_free(new);
return pkbuf;
}
ogs_pkbuf_t *testemm_build_tau_request(
test_ue_t *test_ue, bool active_flag, uint8_t update_type,
bool integrity_protected, bool ciphered)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_tracking_area_update_request_t *tau_request =
&message.emm.tracking_area_update_request;
ogs_nas_eps_update_type_t *eps_update_type = &tau_request->eps_update_type;
ogs_nas_eps_mobile_identity_t *old_guti = &tau_request->old_guti;
ogs_nas_ue_network_capability_t *ue_network_capability =
&tau_request->ue_network_capability;
ogs_nas_tracking_area_identity_t *last_visited_registered_tai =
&tau_request->last_visited_registered_tai;
ogs_nas_drx_parameter_t *drx_parameter = &tau_request->drx_parameter;
ogs_nas_eps_bearer_context_status_t *eps_bearer_context_status =
&tau_request->eps_bearer_context_status;
ogs_nas_ms_network_capability_t *ms_network_capability =
&tau_request->ms_network_capability;
ogs_nas_location_area_identification_t *old_location_area_identification =
&tau_request->old_location_area_identification;
ogs_nas_tmsi_status_t *tmsi_status = &tau_request->tmsi_status;
ogs_nas_mobile_station_classmark_2_t *mobile_station_classmark_2 =
&tau_request->mobile_station_classmark_2;
ogs_nas_mobile_station_classmark_3_t *mobile_station_classmark_3 =
&tau_request->mobile_station_classmark_3;
ogs_nas_supported_codec_list_t *supported_codecs =
&tau_request->supported_codecs;
ogs_nas_additional_update_type_t *additional_update_type =
&tau_request->additional_update_type;
ogs_nas_voice_domain_preference_and_ue_usage_setting_t
*voice_domain_preference_and_ue_usage_setting =
&tau_request->voice_domain_preference_and_ue_usage_setting;
ogs_nas_guti_type_t *old_guti_type = &tau_request->old_guti_type;
ogs_nas_ms_network_feature_support_t *ms_network_feature_support =
&tau_request->ms_network_feature_support;
ogs_nas_network_resource_identifier_container_t *tmsi_based_nri_container =
&tau_request->tmsi_based_nri_container;
ogs_nas_ue_additional_security_capability_t
*ue_additional_security_capability =
&tau_request->ue_additional_security_capability;
uint8_t classmark_3[11] = "\x60\x14\x04\xef\x65\x23\x3b\x88\x78\xd2\x90";
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
if (integrity_protected) {
if (ciphered) {
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
} else {
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED;
}
}
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST;
eps_update_type->nas_key_set_identifier = test_ue->nas.ksi;
eps_update_type->active_flag = active_flag;
eps_update_type->value = update_type;
old_guti->length = sizeof(ogs_nas_eps_mobile_identity_guti_t);
old_guti->guti.odd_even = OGS_NAS_MOBILE_IDENTITY_EVEN;
old_guti->guti.type = OGS_NAS_EPS_MOBILE_IDENTITY_GUTI;
old_guti->guti.nas_plmn_id = test_ue->nas_eps_guti.nas_plmn_id;
old_guti->guti.mme_gid = test_ue->nas_eps_guti.mme_gid;
old_guti->guti.mme_code = test_ue->nas_eps_guti.mme_code;
old_guti->guti.m_tmsi = test_ue->nas_eps_guti.m_tmsi;
if (test_ue->tau_request_param.ue_network_capability) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT;
ue_network_capability->length = 7;
ue_network_capability->eea = 0xf0;
ue_network_capability->eia = 0xf0;
ue_network_capability->uea = 0xc0;
ue_network_capability->uia = 0x40;
ue_network_capability->notification_procedure = 1;
ue_network_capability->dual_connectivity_with_nr = 1;
}
if (test_ue->tau_request_param.last_visited_registered_tai) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT;
ogs_nas_from_plmn_id(&last_visited_registered_tai->nas_plmn_id,
&test_ue->e_tai.plmn_id);
last_visited_registered_tai->tac = test_ue->e_tai.tac;
}
if (test_ue->tau_request_param.drx_parameter) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_PRESENT;
drx_parameter->split_pg_cycle_code = 32;
}
if (test_ue->tau_request_param.eps_bearer_context_status) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT;
eps_bearer_context_status->length = 2;
eps_bearer_context_status->value =
test_ue->tau_request_param.eps_bearer_context_status;
}
if (test_ue->tau_request_param.ms_network_capability) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT;
ms_network_capability->length = 3;
ms_network_capability->gea1 = 1;
ms_network_capability->sm_capabilities_via_dedicated_channels = 1;
ms_network_capability->sm_capabilities_via_gprs_channels = 1;
ms_network_capability->ss_screening_indicator = 1;
ms_network_capability->revision_level_indicator = 1;
ms_network_capability->pfc_feature_mode = 1;
ms_network_capability->extended_gea = 0x30;
ms_network_capability->emm_combined_procedures_capability = 1;
ms_network_capability->isr_support = 1;
ms_network_capability->epc_capability = 1;
}
if (test_ue->tau_request_param.location_area_identication) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT;
ogs_nas_from_plmn_id(&old_location_area_identification->nas_plmn_id,
&test_ue->e_tai.plmn_id);
old_location_area_identification->lac = 1;
}
if (test_ue->tau_request_param.tmsi_status) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_PRESENT;
}
if (test_ue->tau_request_param.mobile_station_classmark_2) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT;
mobile_station_classmark_2->length = 3;
mobile_station_classmark_2->revision_level = 2;
mobile_station_classmark_2->es_ind = 1;
mobile_station_classmark_2->a5_1 = 1;
mobile_station_classmark_2->rf_power_capability = 7;
mobile_station_classmark_2->ps_capa = 1;
mobile_station_classmark_2->ss_screen_indicator = 1;
mobile_station_classmark_2->sm_capabi = 1;
mobile_station_classmark_2->cm3 = 1;
mobile_station_classmark_2->lcsva_cap = 1;
mobile_station_classmark_2->cmsp = 1;
mobile_station_classmark_2->a5_3 = 1;
}
if (test_ue->tau_request_param.mobile_station_classmark_3) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT;
mobile_station_classmark_3->length = 11;
memcpy(mobile_station_classmark_3->buffer,
classmark_3, mobile_station_classmark_3->length);
}
if (test_ue->tau_request_param.supported_codecs) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_PRESENT;
supported_codecs->length = 8;
supported_codecs->item[0].system_identification = 0x04;
supported_codecs->item[0].length_of_bitmap = 2;
supported_codecs->item[0].codec_bitmap = htobe16(0x6004);
supported_codecs->item[1].system_identification = 0;
supported_codecs->item[1].length_of_bitmap = 2;
supported_codecs->item[1].codec_bitmap = htobe16(0x1f02);
}
if (test_ue->tau_request_param.additional_update_type) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT;
additional_update_type->additional_update_type_value = 1;
}
if (test_ue->tau_request_param.ue_usage_setting) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_VOICE_DOMAIN_PREFERENCE_AND_UE_USAGE_SETTING_PRESENT;
voice_domain_preference_and_ue_usage_setting->length = 1;
voice_domain_preference_and_ue_usage_setting->ue_usage_setting = 1;
voice_domain_preference_and_ue_usage_setting->
voice_domain_preference_for_e_utran = 1;
}
if (test_ue->tau_request_param.old_guti_type) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_PRESENT;
}
if (test_ue->tau_request_param.ms_network_feature_support) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_FEATURE_SUPPORT_PRESENT;
ms_network_feature_support->extended_periodic_timers = 1;
}
if (test_ue->tau_request_param.nri_container) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_TMSI_BASED_NRI_CONTAINER_PRESENT;
tmsi_based_nri_container->length = 2;
tmsi_based_nri_container->nri_container_value1 = 0x8d;
tmsi_based_nri_container->nri_container_value2 = 0x3;
}
if (test_ue->tau_request_param.ue_additional_security_capability) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_UE_ADDITIONAL_SECURITY_CAPABILITY_PRESENT;
ue_additional_security_capability->length = 4;
ue_additional_security_capability->nea = 0xf0;
ue_additional_security_capability->nia = 0xf0;
}
if (test_ue->tau_request_param.device_properties) {
tau_request->presencemask |=
OGS_NAS_EPS_TRACKING_AREA_UPDATE_REQUEST_DEVICE_PROPERTIES_PRESENT;
}
if (integrity_protected)
return test_nas_eps_security_encode(test_ue, &message);
else
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_emm_status(
test_ue_t *test_ue, ogs_nas_emm_cause_t emm_cause)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_emm_status_t *emm_status = &message.emm.emm_status;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_EMM_STATUS;
emm_status->emm_cause = emm_cause;
return test_nas_eps_security_encode(test_ue, &message);
}
ogs_pkbuf_t *testemm_build_extended_service_request(
test_ue_t *test_ue, uint8_t type,
bool integrity_protected, bool ciphered)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_extended_service_request_t *extended_service_request =
&message.emm.extended_service_request;
ogs_nas_service_type_t *service_type =
&extended_service_request->service_type;
ogs_nas_mobile_identity_t *mobile_identity =
&extended_service_request->m_tmsi;
ogs_nas_csfb_response_t *csfb_response =
&extended_service_request->csfb_response;
ogs_nas_eps_bearer_context_status_t *eps_bearer_context_status =
&extended_service_request->eps_bearer_context_status;
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
if (integrity_protected) {
if (ciphered)
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
else
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
}
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_EXTENDED_SERVICE_REQUEST;
service_type->value = type;
mobile_identity->length = 5;
mobile_identity->tmsi.type = OGS_NAS_MOBILE_IDENTITY_TMSI;
mobile_identity->tmsi.tmsi = test_ue->nas_eps_guti.m_tmsi;
if (test_ue->extended_service_request_param.csfb_response) {
extended_service_request->presencemask |=
OGS_NAS_EPS_EXTENDED_SERVICE_REQUEST_CSFB_RESPONSE_PRESENT;
csfb_response->response =
test_ue->extended_service_request_param.csfb.response;
}
if (test_ue->extended_service_request_param.eps_bearer_context_status) {
test_sess_t *sess = NULL;
test_bearer_t *bearer = NULL;
extended_service_request->presencemask |= OGS_NAS_EPS_EXTENDED_SERVICE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT;
eps_bearer_context_status->length = 2;
ogs_list_for_each(&test_ue->sess_list, sess) {
ogs_list_for_each(&sess->bearer_list, bearer) {
if (bearer->ebi == 5) eps_bearer_context_status->ebi5 = 1;
else if (bearer->ebi == 6) eps_bearer_context_status->ebi6 = 1;
else if (bearer->ebi == 7) eps_bearer_context_status->ebi7 = 1;
}
}
}
if (integrity_protected)
return test_nas_eps_security_encode(test_ue, &message);
else
return ogs_nas_eps_plain_encode(&message);
}
ogs_pkbuf_t *testemm_build_uplink_nas_transport(test_ue_t *test_ue)
{
ogs_nas_eps_message_t message;
ogs_nas_eps_uplink_nas_transport_t *uplink_nas_transport =
&message.emm.uplink_nas_transport;
ogs_nas_eps_message_container_t *nas_message_container =
&uplink_nas_transport->nas_message_container;
char hexbuf[OGS_HUGE_LEN];
const char *payload =
"390167000300"
"0581005155f55d11 030c914477680205 490000055ad2e2b1 252d467ff6de6c47"
"efd568375b303613 166fb51c6d160cc2 8ab462b006a3d98a 31da90060b0673c5"
"9c512684158bb119 2c88b3058b37e1ad 081bca84c1582d07 93ede4bddc6d2693"
"e566371b";
ogs_assert(test_ue);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_UPLINK_NAS_TRANSPORT;
ogs_hex_from_string(payload, hexbuf, sizeof(hexbuf));
nas_message_container->length = 106;
memcpy(nas_message_container->buffer,
hexbuf, nas_message_container->length);
return test_nas_eps_security_encode(test_ue, &message);
}