diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index 0d01ba858..95354362f 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -971,6 +971,121 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) } amf_ue = amf_ue_find_by_id(ran_ue->amf_ue_id); + + /* + * REGISTRATION REQUEST on an NG context that already belongs to + * someone else. The 5GS counterpart of the same defect in the + * MME, see mme-sm.c. + * + * InitialUEMessage(5G-S-TMSI of A) -> ran_ue bound to A + * Registration Request(SUCI of B) on the same connection + * -> dispatched to A's context, not to B's + * + * The identity in the message is never looked at, so + * amf_ue_set_suci() re-labels A's context as B and + * amf_ue_release_old_context() moves B's sessions into it. If A + * still owns sessions, that hits + * + * ogs_assert(ogs_list_empty(&amf_ue->sess_list)); + * + * and the AMF aborts. If B is unknown to the AMF there is no + * abort - A's sessions silently become B's instead. + * + * Any UE can get here; a stale 5G-GUTI is enough. + * + * So re-resolve the identity, and if it names someone else: + * + * registered, or owns a session -> release, drop the message + * otherwise -> leave it, nothing to lose + * + * Release is the same teardown a RAN-initiated UE Context + * Release Request gets: deactivate the sessions towards the SMF, + * then release the NG context. Handing the NG context over + * instead would leave A's user plane on a connection that now + * serves B. + * + * A UE Context Transfer can leave a context with a SUPI and no + * SUCI, so either index counts as an identity. + */ + if (amf_ue && + (AMF_UE_HAVE_SUCI(amf_ue) || AMF_UE_HAVE_SUPI(amf_ue)) && + nas_message.gmm.h.message_type == + OGS_NAS_5GS_REGISTRATION_REQUEST) { + amf_ue_t *registering_ue = amf_ue_find_by_message(&nas_message); + + if (registering_ue != amf_ue && + (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered) || + ogs_list_count(&amf_ue->sess_list))) { + int old_xact_count = 0, new_xact_count = 0; + + ogs_warn("Registration Request identity does not match " + "the associated NG context"); + ogs_warn(" Associated SUCI[%s] SUPI[%s] ue_id[%d] " + "sessions[%d]", + amf_ue->suci ? amf_ue->suci : "Unknown", + amf_ue->supi ? amf_ue->supi : "Unknown", + amf_ue->id, ogs_list_count(&amf_ue->sess_list)); + if (registering_ue) + ogs_warn(" Requested SUCI[%s] SUPI[%s] ue_id[%d] " + "sessions[%d]", + registering_ue->suci ? + registering_ue->suci : "Unknown", + registering_ue->supi ? + registering_ue->supi : "Unknown", + registering_ue->id, + ogs_list_count(®istering_ue->sess_list)); + else + ogs_warn(" Requested identity has no AMF-UE " + "context yet"); + ogs_warn(" RAN_UE_NGAP_ID[%lld] AMF_UE_NGAP_ID[%lld]", + (long long)ran_ue->ran_ue_ngap_id, + (long long)ran_ue->amf_ue_ngap_id); + + /* Same teardown as a RAN-initiated release request */ + CLEAR_AMF_UE_ALL_TIMERS(amf_ue); + + old_xact_count = amf_sess_xact_count(amf_ue); + + ran_ue->deactivation.group = NGAP_Cause_PR_nas; + ran_ue->deactivation.cause = NGAP_CauseNas_normal_release; + + amf_sbi_send_deactivate_all_sessions( + ran_ue, amf_ue, AMF_UPDATE_SM_CONTEXT_DEACTIVATED, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); + + new_xact_count = amf_sess_xact_count(amf_ue); + + if (old_xact_count == new_xact_count) { + /* + * Nothing was sent to the SMF, so release from here. + * Which action depends on what we are keeping: + * + * registered -> NG_REMOVE_AND_UNLINK + * de-associates the RAN-UE and runs + * the mobile reachable timer, which + * is what ages the context out + * otherwise -> NG_CONTEXT_REMOVE, as in + * ngap_handle_initial_context_setup_ + * failure(); the mobile reachable + * timer is only handled in the + * de-registered and registered + * states, so starting it here would + * fire into a state that ignores it + */ + r = ngap_send_ran_ue_context_release_command(ran_ue, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, + OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered) ? + NGAP_UE_CTX_REL_NG_REMOVE_AND_UNLINK : + NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + } + + ogs_pkbuf_free(pkbuf); + break; + } + } + if (!amf_ue) { amf_ue = amf_ue_find_by_message(&nas_message); if (!amf_ue) { diff --git a/src/mme/emm-handler.c b/src/mme/emm-handler.c index ed72d507f..996d59026 100644 --- a/src/mme/emm-handler.c +++ b/src/mme/emm-handler.c @@ -271,7 +271,7 @@ int emm_handle_attach_request(enb_ue_t *enb_ue, mme_ue_t *mme_ue, ogs_nas_eps_imsi_to_bcd( &eps_mobile_identity->imsi, eps_mobile_identity->length, imsi_bcd); - mme_ue_set_imsi(mme_ue, imsi_bcd); + mme_ue_set_imsi(mme_ue, imsi_bcd, MME_UE_IMSI_FROM_ATTACH_REQUEST); ogs_info(" IMSI[%s]", imsi_bcd); @@ -508,7 +508,7 @@ int emm_handle_identity_response( ogs_nas_eps_imsi_to_bcd( &mobile_identity->imsi, mobile_identity->length, imsi_bcd); - mme_ue_set_imsi(mme_ue, imsi_bcd); + mme_ue_set_imsi(mme_ue, imsi_bcd, MME_UE_IMSI_FROM_IDENTITY_RESPONSE); if (mme_ue->imsi_len != OGS_MAX_IMSI_LEN) { ogs_error("Invalid IMSI LEN[%d]", mme_ue->imsi_len); diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 71b7c1686..9dfc7812f 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -4322,15 +4322,60 @@ mme_ue_t *mme_ue_find_by_message(const ogs_nas_eps_message_t *message) return mme_ue; } -int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd) +static const char *mme_ue_imsi_source_name(mme_ue_imsi_source_e source) +{ + switch (source) { + case MME_UE_IMSI_FROM_ATTACH_REQUEST: + return "ATTACH_REQUEST"; + case MME_UE_IMSI_FROM_IDENTITY_RESPONSE: + return "IDENTITY_RESPONSE"; + case MME_UE_IMSI_FROM_SGSN_CONTEXT_RESPONSE: + return "SGSN_CONTEXT_RESPONSE"; + } + return "UNKNOWN"; +} + +static const char *mme_ue_emm_state_name(mme_ue_t *mme_ue) +{ + ogs_assert(mme_ue); + + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_de_registered)) + return "DE_REGISTERED"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_authentication)) + return "AUTHENTICATION"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_security_mode)) + return "SECURITY_MODE"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup)) + return "INITIAL_CONTEXT_SETUP"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_registered)) + return "REGISTERED"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_ue_context_will_remove)) + return "UE_CONTEXT_WILL_REMOVE"; + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_exception)) + return "EXCEPTION"; + + return "OTHER"; +} + +int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd, + mme_ue_imsi_source_e source) { mme_ue_t *old_mme_ue = NULL; mme_sess_t *old_sess = NULL; mme_bearer_t *old_bearer = NULL; sgw_ue_t *sgw_ue = NULL, *old_sgw_ue = NULL; uint16_t target_bitmap_before = 0; + bool target_had_imsi = false; + char target_imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; ogs_assert(mme_ue && imsi_bcd); + /* + * Remember who this context was before the overwrite below - by the + * time the migration logs, mme_ue->imsi_bcd is already the new IMSI. + */ + target_had_imsi = MME_UE_HAVE_IMSI(mme_ue) ? true : false; + ogs_cpystrn(target_imsi_bcd, mme_ue->imsi_bcd, OGS_MAX_IMSI_BCD_LEN+1); + /* * Issues: #4357 * @@ -4360,6 +4405,39 @@ int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd) if (ogs_pool_index(&mme_ue_pool, mme_ue) != ogs_pool_index(&mme_ue_pool, old_mme_ue)) { ogs_warn("[%s] OLD UE Context Release", mme_ue->imsi_bcd); + + /* + * Who reached the OLD UE context migration? + * + * ATTACH_REQUEST identity is in the message + * IDENTITY_RESPONSE identity arrives mid-procedure + * SGSN_CONTEXT_RESPONSE identity arrives mid-procedure + * + * The migration hands session, bearer, EBI and SGW-S11-TEID + * ownership from one context to another. Replacing it means + * keeping the context that owns the identity and moving the + * S1 association instead, so first we need to know which + * callers actually get here, and in what state. + */ + ogs_warn("[MIGRATION-TRACK] source[%s] " + "target_ue_id[%d] target_imsi[%s] target_state[%s] " + "target_sessions[%d] target_bitmap[0x%04x]", + mme_ue_imsi_source_name(source), + mme_ue->id, + target_had_imsi ? target_imsi_bcd : "Unknown", + mme_ue_emm_state_name(mme_ue), + ogs_list_count(&mme_ue->sess_list), + mme_ue->ebi_bitmap); + ogs_warn("[MIGRATION-TRACK] " + "old_ue_id[%d] old_imsi[%s] old_state[%s] " + "old_sessions[%d] old_bitmap[0x%04x] " + "old_ecm_connected[%d]", + old_mme_ue->id, + old_mme_ue->imsi_bcd, + mme_ue_emm_state_name(old_mme_ue), + ogs_list_count(&old_mme_ue->sess_list), + old_mme_ue->ebi_bitmap, + ECM_CONNECTED(old_mme_ue) ? 1 : 0); if (ECM_CONNECTED(old_mme_ue)) { enb_ue_t *enb_ue = enb_ue_find_by_id(old_mme_ue->enb_ue_id); enb_ue_t *enb_ue_holding = NULL; diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index b95f4b484..c2d5a04b7 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -1234,7 +1234,17 @@ mme_ue_t *mme_ue_find_by_s11_local_teid(uint32_t teid); mme_ue_t *mme_ue_find_by_gn_local_teid(uint32_t teid); mme_ue_t *mme_ue_find_by_message(const ogs_nas_eps_message_t *message); -int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd); + +/* Which procedure supplied the IMSI - logged at the OLD UE context + * migration, so we can tell which callers actually reach it. */ +typedef enum { + MME_UE_IMSI_FROM_ATTACH_REQUEST = 0, + MME_UE_IMSI_FROM_IDENTITY_RESPONSE, + MME_UE_IMSI_FROM_SGSN_CONTEXT_RESPONSE, +} mme_ue_imsi_source_e; + +int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd, + mme_ue_imsi_source_e source); bool mme_ue_have_indirect_tunnel(mme_ue_t *mme_ue); void mme_ue_clear_indirect_tunnel(mme_ue_t *mme_ue); diff --git a/src/mme/mme-gn-handler.c b/src/mme/mme-gn-handler.c index 95146eeb6..5ff7f3dce 100644 --- a/src/mme/mme-gn-handler.c +++ b/src/mme/mme-gn-handler.c @@ -365,7 +365,8 @@ int mme_gn_handle_sgsn_context_response( ogs_buffer_to_bcd(resp->imsi.data, resp->imsi.len, imsi_bcd); ogs_info(" IMSI[%s]", imsi_bcd); - mme_ue_set_imsi(mme_ue, imsi_bcd); + mme_ue_set_imsi(mme_ue, imsi_bcd, + MME_UE_IMSI_FROM_SGSN_CONTEXT_RESPONSE); if (!resp->tunnel_endpoint_identifier_control_plane.presence) { ogs_error("[Gn] Rx SGSN Context Response with no Tunnel Endpoint Identifier Control Plane!"); diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index 3eaaf4a91..e391410f5 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -264,6 +264,72 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) } mme_ue = mme_ue_find_by_id(enb_ue->mme_ue_id); + + /* + * ATTACH REQUEST on an S1 context that already belongs to + * someone else. + * + * InitialUEMessage(S-TMSI of IMSI-A) -> enb_ue bound to A + * NAS MAC failed -> Service Reject #9 -> binding kept + * Attach Request(IMSI-B) on the same connection + * -> dispatched to A's context, not to B's + * + * The identity in the message is never looked at, so + * mme_ue_set_imsi() re-labels A's context as B and moves B's + * sessions into it. If A still owns sessions, Phase-2 hits + * + * ogs_assert(ogs_list_empty(&mme_ue->sess_list)); + * + * and the MME aborts. If B is unknown to the MME there is no + * abort - A's sessions silently become B's instead. + * + * Any UE can get here; a stale GUTI is enough. + * + * So re-resolve the identity, and if it names someone else: + * + * registered, or owns a session -> release, drop the Attach + * otherwise -> leave it, nothing to lose + * + * Release means Release Access Bearers followed by S1 release, + * so A's user plane is gone before the UE retries on a fresh S1 + * context. Handing the S1 context over instead would leave A's + * bearers pointing at a connection that now serves B. + */ + if (mme_ue && MME_UE_HAVE_IMSI(mme_ue) && + nas_message.emm.h.message_type == OGS_NAS_EPS_ATTACH_REQUEST) { + mme_ue_t *attaching_ue = mme_ue_find_by_message(&nas_message); + + if (attaching_ue != mme_ue && + (OGS_FSM_CHECK(&mme_ue->sm, emm_state_registered) || + ogs_list_count(&mme_ue->sess_list))) { + ogs_warn("Attach Request identity does not match " + "the associated S1 context"); + ogs_warn(" Associated IMSI[%s] ue_id[%d] sessions[%d] " + "bitmap[0x%04x]", + mme_ue->imsi_bcd, mme_ue->id, + ogs_list_count(&mme_ue->sess_list), + mme_ue->ebi_bitmap); + if (attaching_ue) + ogs_warn(" Requested IMSI[%s] ue_id[%d] " + "sessions[%d] bitmap[0x%04x]", + attaching_ue->imsi_bcd, attaching_ue->id, + ogs_list_count(&attaching_ue->sess_list), + attaching_ue->ebi_bitmap); + else + ogs_warn(" Requested identity has no MME-UE " + "context yet"); + ogs_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]", + enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id); + + enb_ue->relcause.group = S1AP_Cause_PR_nas; + enb_ue->relcause.cause = S1AP_CauseNas_normal_release; + mme_send_release_access_bearer_or_ue_context_release(enb_ue); + + ogs_pkbuf_free(pkbuf); + return; + } + } + if (!mme_ue) { mme_ue = mme_ue_find_by_message(&nas_message); if (!mme_ue) { diff --git a/tests/attach/abts-main.c b/tests/attach/abts-main.c index 6a99e30f9..ac2921491 100644 --- a/tests/attach/abts-main.c +++ b/tests/attach/abts-main.c @@ -29,6 +29,7 @@ abts_suite *test_ue_context(abts_suite *suite); abts_suite *test_reset(abts_suite *suite); abts_suite *test_issues(abts_suite *suite); abts_suite *test_crash(abts_suite *suite); +abts_suite *test_identity(abts_suite *suite); const struct testlist { abts_suite *(*func)(abts_suite *suite); @@ -43,6 +44,7 @@ const struct testlist { {test_reset}, {test_issues}, {test_crash}, + {test_identity}, {NULL}, }; diff --git a/tests/attach/identity-test.c b/tests/attach/identity-test.c new file mode 100644 index 000000000..6ac13e985 --- /dev/null +++ b/tests/attach/identity-test.c @@ -0,0 +1,1801 @@ +/* + * Copyright (C) 2023 by Sukchan Lee + * + * This file is part of Open5GS. + * + * 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 . + */ + +#include "test-common.h" + +/* + * Attach naming another subscriber, on a registered context. + * + * UE-2 attach, then go idle -> context kept, session kept + * UE-1 attach, stay connected -> owns the S1 context + * Attach Request(IMSI of UE-2) sent with the S1AP IDs of UE-1 + * + * Before: mme_ue_set_imsi() moves UE-2's session into UE-1's context + * -> ogs_assert(ogs_list_empty(&mme_ue->sess_list)) -> abort + * After: access bearers released, S1 released, Attach dropped, and + * UE-1 keeps its own session + * + * In the field the S1 context was mis-associated by a stale GUTI, but + * that only explains how UE-1's context ended up on this connection. + * Any Attach naming someone else is enough. + */ +static void attach_identity_mismatch_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 owns the S1 context that the ATTACH REQUEST arrives on */ + test_ue_t *test_ue1 = NULL; + test_sess_t *sess1 = NULL; + test_bearer_t *bearer1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is the subscriber named by that ATTACH REQUEST */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + test_bearer_t *bearer2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000000030"); + ogs_assert(test_ue1); + + test_ue1->e_cgi.cell_id = 0x1079baf0; + test_ue1->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue1->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue1->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess1 = test_sess_add_by_apn( + test_ue1, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess1); + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000000031"); + ogs_assert(test_ue2); + + test_ue2->e_cgi.cell_id = 0x1079baf0; + test_ue2->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess2 = test_sess_add_by_apn( + test_ue2, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess2); + + /* Both UEs are served by the same eNB, so keep the eNB-UE-S1AP-ID + * ranges apart */ + test_ue2->enb_ue_s1ap_id = 100; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + + /* UE-2: attach, then go idle - context and session stay */ + /* Send Attach Request */ + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.eit = 1; + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + test_ue2->attach_request_param.drx_parameter = 1; + test_ue2->attach_request_param.ms_network_capability = 1; + test_ue2->attach_request_param.tmsi_status = 1; + test_ue2->attach_request_param.mobile_station_classmark_2 = 1; + test_ue2->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue2->initial_ue_param, 0, sizeof(test_ue2->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue2, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + test_ue2->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send ESM Information Response */ + sess2->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess2); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue2->nr_cgi.cell_id = 0x1234502; + bearer2 = test_bearer_find_by_ue_ebi(test_ue2, 5); + ogs_assert(bearer2); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer2, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + /* Send UEContextReleaseRequest - UE-2 goes idle */ + sendbuf = test_s1ap_build_ue_context_release_request(test_ue2, + S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1 attaches and stays connected with an active default bearer */ + /* Send Attach Request */ + memset(&sess1->pdn_connectivity_param, + 0, sizeof(sess1->pdn_connectivity_param)); + sess1->pdn_connectivity_param.eit = 1; + sess1->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess1, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue1->attach_request_param, + 0, sizeof(test_ue1->attach_request_param)); + test_ue1->attach_request_param.drx_parameter = 1; + test_ue1->attach_request_param.ms_network_capability = 1; + test_ue1->attach_request_param.tmsi_status = 1; + test_ue1->attach_request_param.mobile_station_classmark_2 = 1; + test_ue1->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue1, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue1->initial_ue_param, 0, sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + test_ue1->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send ESM Information Response */ + sess1->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess1); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue1->nr_cgi.cell_id = 0x1234502; + bearer1 = test_bearer_find_by_ue_ebi(test_ue1, 5); + ogs_assert(bearer1); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer1, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Attach for UE-2, delivered with the S1AP IDs of UE-1 */ + sess2->pti = 1; + + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Expect the release, not a reply to the Attach. + * Without the fix the MME is already gone by now. + */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_UEContextRelease, + test_ue1->s1ap_procedure_code); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Did UE-1 survive with its session? + * + * The MME answers a Service Request with an + * InitialContextSetupRequest only while the context still has a + * session with active EPS bearers. A re-labelled or emptied UE-1 + * gets a Service Reject in a downlinkNASTransport instead. + */ + emmbuf = testemm_build_service_request(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + memset(&test_ue1->initial_ue_param, 0, + sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, S1AP_RRC_Establishment_Cause_mo_Data, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_InitialContextSetup, + test_ue1->s1ap_procedure_code); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Detach Request for UE-1 */ + emmbuf = testemm_build_detach_request(test_ue1, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Detach Request for UE-2 on a new S1 context */ + emmbuf = testemm_build_detach_request(test_ue2, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + memset(&test_ue2->initial_ue_param, 0, + sizeof(test_ue2->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue2, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + test_gtpu_close(gtpu); + + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} + +/* + * Attach naming a subscriber the MME has never seen. + * + * UE-2 provisioned, never attached -> no MME-UE context + * UE-1 attach, stay connected -> owns the S1 context + * Attach Request(IMSI of UE-2) sent with the S1AP IDs of UE-1 + * + * mme_ue_find_by_message() finds nothing, so there is no migration and + * no abort. Instead UE-1's context is quietly re-labelled as UE-2 and + * its session goes with it - which is why a fix that only acts when the + * identity resolves to another context is not enough. + * + * The Service Request at the end is what catches it. + */ +static void attach_unknown_identity_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 owns the S1 context that the ATTACH REQUEST arrives on */ + test_ue_t *test_ue1 = NULL; + test_sess_t *sess1 = NULL; + test_bearer_t *bearer1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is provisioned but has never attached */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000000032"); + ogs_assert(test_ue1); + + test_ue1->e_cgi.cell_id = 0x1079baf0; + test_ue1->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue1->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue1->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess1 = test_sess_add_by_apn( + test_ue1, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess1); + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000000033"); + ogs_assert(test_ue2); + + test_ue2->e_cgi.cell_id = 0x1079baf0; + test_ue2->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess2 = test_sess_add_by_apn( + test_ue2, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess2); + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + + /* UE-1 attaches and stays connected with an active default bearer */ + /* Send Attach Request */ + memset(&sess1->pdn_connectivity_param, + 0, sizeof(sess1->pdn_connectivity_param)); + sess1->pdn_connectivity_param.eit = 1; + sess1->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess1, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue1->attach_request_param, + 0, sizeof(test_ue1->attach_request_param)); + test_ue1->attach_request_param.drx_parameter = 1; + test_ue1->attach_request_param.ms_network_capability = 1; + test_ue1->attach_request_param.tmsi_status = 1; + test_ue1->attach_request_param.mobile_station_classmark_2 = 1; + test_ue1->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue1, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue1->initial_ue_param, 0, sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + test_ue1->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send ESM Information Response */ + sess1->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess1); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue1->nr_cgi.cell_id = 0x1234502; + bearer1 = test_bearer_find_by_ue_ebi(test_ue1, 5); + ogs_assert(bearer1); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer1, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Attach for UE-2, delivered with the S1AP IDs of UE-1 */ + sess2->pti = 1; + + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Expect the release, not a reply to the Attach. + * Without the fix the MME is already gone by now. + */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_UEContextRelease, + test_ue1->s1ap_procedure_code); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Did UE-1 survive with its session? + * + * The MME answers a Service Request with an + * InitialContextSetupRequest only while the context still has a + * session with active EPS bearers. A re-labelled or emptied UE-1 + * gets a Service Reject in a downlinkNASTransport instead. + */ + emmbuf = testemm_build_service_request(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + memset(&test_ue1->initial_ue_param, 0, + sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, S1AP_RRC_Establishment_Cause_mo_Data, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_InitialContextSetup, + test_ue1->s1ap_procedure_code); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Detach Request for UE-1 */ + emmbuf = testemm_build_detach_request(test_ue1, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + test_gtpu_close(gtpu); + + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} + +/* + * Attach naming another subscriber, on a context with nothing to lose. + * + * UE-2 attach, then go idle -> context kept, session kept + * UE-1 attach, stop at the Authentication Request + * -> has an IMSI, not registered, no session yet + * Attach Request(IMSI of UE-2) sent with the S1AP IDs of UE-1 + * + * Nothing is released here. The context is re-used for UE-2 and UE-2's + * old context is migrated into it, exactly as before the fix - there is + * no idle state for such a context to fall back to, so releasing it + * would leave it behind with no timer to age it out. + * + * The two subscribers use different K, so an authentication vector + * taken from the wrong context cannot pass unnoticed. + */ +static void attach_during_authentication_func( + abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 starts an attach and never finishes it */ + test_ue_t *test_ue1 = NULL; + test_sess_t *sess1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is attached and idle, so its context exists with a session */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + test_bearer_t *bearer2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000000034"); + ogs_assert(test_ue1); + + test_ue1->e_cgi.cell_id = 0x1079baf0; + test_ue1->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + /* + * Use a different K from UE-2, so that an authentication vector + * taken from the wrong context cannot pass unnoticed. + */ + test_ue1->k_string = "8baf473f2f8fd09487cccbd7097c6862"; + test_ue1->opc_string = "8e27b6af0e692e750f32667a3b14605d"; + + sess1 = test_sess_add_by_apn( + test_ue1, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess1); + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000000035"); + ogs_assert(test_ue2); + + test_ue2->e_cgi.cell_id = 0x1079baf0; + test_ue2->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess2 = test_sess_add_by_apn( + test_ue2, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess2); + + /* Both UEs are served by the same eNB, so keep the eNB-UE-S1AP-ID + * ranges apart */ + test_ue2->enb_ue_s1ap_id = 100; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + /* Send Attach Request */ + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.eit = 1; + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + test_ue2->attach_request_param.drx_parameter = 1; + test_ue2->attach_request_param.ms_network_capability = 1; + test_ue2->attach_request_param.tmsi_status = 1; + test_ue2->attach_request_param.mobile_station_classmark_2 = 1; + test_ue2->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue2->initial_ue_param, 0, sizeof(test_ue2->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue2, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + test_ue2->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send ESM Information Response */ + sess2->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess2); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue2->nr_cgi.cell_id = 0x1234502; + bearer2 = test_bearer_find_by_ue_ebi(test_ue2, 5); + ogs_assert(bearer2); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer2, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + /* Send UEContextReleaseRequest - UE-2 goes idle */ + sendbuf = test_s1ap_build_ue_context_release_request(test_ue2, + S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1: attach only as far as the Authentication Request */ + + /* Send Attach Request */ + memset(&sess1->pdn_connectivity_param, + 0, sizeof(sess1->pdn_connectivity_param)); + sess1->pdn_connectivity_param.eit = 1; + sess1->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess1, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue1->attach_request_param, + 0, sizeof(test_ue1->attach_request_param)); + test_ue1->attach_request_param.drx_parameter = 1; + test_ue1->attach_request_param.ms_network_capability = 1; + test_ue1->attach_request_param.tmsi_status = 1; + test_ue1->attach_request_param.mobile_station_classmark_2 = 1; + test_ue1->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue1, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue1->initial_ue_param, 0, sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request - and do not answer it */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + OGS_NAS_EPS_AUTHENTICATION_REQUEST, + test_ue1->emm_message_type); + + /* Send ATTACH REQUEST for UE-2 on the S1 context of UE-1 */ + sess2->pti = 1; + + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* The S1 context now carries UE-2 */ + test_ue2->enb_ue_s1ap_id = test_ue1->enb_ue_s1ap_id; + test_ue2->mme_ue_s1ap_id = test_ue1->mme_ue_s1ap_id; + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_downlinkNASTransport, + test_ue2->s1ap_procedure_code); + ABTS_INT_EQUAL(tc, + OGS_NAS_EPS_AUTHENTICATION_REQUEST, + test_ue2->emm_message_type); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + test_ue2->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send ESM Information Response */ + sess2->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess2); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + bearer2 = test_bearer_find_by_ue_ebi(test_ue2, 5); + ogs_assert(bearer2); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer2, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Detach Request for UE-2 */ + emmbuf = testemm_build_detach_request(test_ue2, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + test_gtpu_close(gtpu); + + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} + +/* + * Attach naming another subscriber, on a half-finished attach. + * + * UE-2 attach, then go idle -> context kept, session kept + * UE-1 attach, stop before ATTACH COMPLETE + * -> not registered, but the session already exists + * Attach Request(IMSI of UE-2) sent with the S1AP IDs of UE-1 + * + * This context cannot be re-labelled - moving UE-2's session into it is + * what breaks Phase-2 of mme_ue_set_imsi() - so it is released like any + * other. UE-1 then attaches again to show that what the MME kept does + * not get in the way, and UE-2 is detached to show it was untouched. + */ +static void attach_during_session_setup_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *s1ap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *emmbuf; + ogs_pkbuf_t *esmbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 stops before ATTACH COMPLETE */ + test_ue_t *test_ue1 = NULL; + test_sess_t *sess1 = NULL; + test_bearer_t *bearer1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is attached and idle, so its context has a session */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + test_bearer_t *bearer2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000000036"); + ogs_assert(test_ue1); + + test_ue1->e_cgi.cell_id = 0x1079baf0; + test_ue1->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue1->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue1->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess1 = test_sess_add_by_apn( + test_ue1, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess1); + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000000037"); + ogs_assert(test_ue2); + + test_ue2->e_cgi.cell_id = 0x1079baf0; + test_ue2->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + sess2 = test_sess_add_by_apn( + test_ue2, "internet", OGS_GTP2_RAT_TYPE_EUTRAN); + ogs_assert(sess2); + + /* Both UEs are served by the same eNB, so keep the eNB-UE-S1AP-ID + * ranges apart */ + test_ue2->enb_ue_s1ap_id = 100; + + /* eNB connects to MME */ + s1ap = tests1ap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, s1ap); + + /* eNB connects to SGW */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send S1-Setup Reqeust */ + sendbuf = test_s1ap_build_s1_setup_request( + S1AP_ENB_ID_PR_macroENB_ID, 0x54f64); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive S1-Setup Response */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(NULL, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + /* Send Attach Request */ + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.eit = 1; + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + test_ue2->attach_request_param.drx_parameter = 1; + test_ue2->attach_request_param.ms_network_capability = 1; + test_ue2->attach_request_param.tmsi_status = 1; + test_ue2->attach_request_param.mobile_station_classmark_2 = 1; + test_ue2->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue2->initial_ue_param, 0, sizeof(test_ue2->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue2, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + test_ue2->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send ESM Information Response */ + sess2->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess2); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue2->nr_cgi.cell_id = 0x1234502; + bearer2 = test_bearer_find_by_ue_ebi(test_ue2, 5); + ogs_assert(bearer2); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer2, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue2, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue2, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + /* Send UEContextReleaseRequest - UE-2 goes idle */ + sendbuf = test_s1ap_build_ue_context_release_request(test_ue2, + S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_user_inactivity); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1 attaches but never sends ATTACH COMPLETE */ + /* Send Attach Request */ + memset(&sess1->pdn_connectivity_param, + 0, sizeof(sess1->pdn_connectivity_param)); + sess1->pdn_connectivity_param.eit = 1; + sess1->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess1, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue1->attach_request_param, + 0, sizeof(test_ue1->attach_request_param)); + test_ue1->attach_request_param.drx_parameter = 1; + test_ue1->attach_request_param.ms_network_capability = 1; + test_ue1->attach_request_param.tmsi_status = 1; + test_ue1->attach_request_param.mobile_station_classmark_2 = 1; + test_ue1->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue1, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue1->initial_ue_param, 0, sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + test_ue1->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send ESM Information Response */ + sess1->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess1); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Stop here: the session exists, the attach does not finish */ + + + /* Attach for UE-2, delivered with the S1AP IDs of UE-1 */ + sess2->pti = 1; + + memset(&sess2->pdn_connectivity_param, + 0, sizeof(sess2->pdn_connectivity_param)); + sess2->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess2, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue2->attach_request_param, + 0, sizeof(test_ue2->attach_request_param)); + emmbuf = testemm_build_attach_request(test_ue2, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Expect the release, not a reply to the Attach. + * Without the fix the MME is already gone by now. + */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + S1AP_ProcedureCode_id_UEContextRelease, + test_ue1->s1ap_procedure_code); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * UE-1 attaches again on a new S1 context. + * + * The MME keeps UE-1's context across the release above, the same + * way it keeps one when an E-RAB setup failure ends an attach. What + * matters is that the leftover does not block the next attach. + */ + sess1->pti = 1; + /* Send Attach Request */ + memset(&sess1->pdn_connectivity_param, + 0, sizeof(sess1->pdn_connectivity_param)); + sess1->pdn_connectivity_param.eit = 1; + sess1->pdn_connectivity_param.request_type = + OGS_NAS_EPS_REQUEST_TYPE_INITIAL; + esmbuf = testesm_build_pdn_connectivity_request( + sess1, false, OGS_NAS_EPS_PDN_TYPE_IPV4V6); + ABTS_PTR_NOTNULL(tc, esmbuf); + + memset(&test_ue1->attach_request_param, + 0, sizeof(test_ue1->attach_request_param)); + test_ue1->attach_request_param.drx_parameter = 1; + test_ue1->attach_request_param.ms_network_capability = 1; + test_ue1->attach_request_param.tmsi_status = 1; + test_ue1->attach_request_param.mobile_station_classmark_2 = 1; + test_ue1->attach_request_param.ue_usage_setting = 1; + emmbuf = testemm_build_attach_request(test_ue1, esmbuf, false, false); + ABTS_PTR_NOTNULL(tc, emmbuf); + + memset(&test_ue1->initial_ue_param, 0, sizeof(test_ue1->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue1, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + emmbuf = testemm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + test_ue1->mobile_identity_imeisv_presence = true; + emmbuf = testemm_build_security_mode_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive ESM Information Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send ESM Information Response */ + sess1->esm_information_param.epco = 1; + esmbuf = testesm_build_esm_information_response(sess1); + ABTS_PTR_NOTNULL(tc, esmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial Context Setup Request + + * Attach Accept + + * Activate Default Bearer Context Request */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Capability Info Indication */ + sendbuf = tests1ap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial Context Setup Response */ + sendbuf = test_s1ap_build_initial_context_setup_response(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Attach Complete + Activate default EPS bearer cotext accept */ + test_ue1->nr_cgi.cell_id = 0x1234502; + bearer1 = test_bearer_find_by_ue_ebi(test_ue1, 5); + ogs_assert(bearer1); + esmbuf = testesm_build_activate_default_eps_bearer_context_accept( + bearer1, false); + ABTS_PTR_NOTNULL(tc, esmbuf); + emmbuf = testemm_build_attach_complete(test_ue1, esmbuf); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive EMM information */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send Detach Request for UE-1 */ + emmbuf = testemm_build_detach_request(test_ue1, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + sendbuf = test_s1ap_build_uplink_nas_transport(test_ue1, emmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue1, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-2 was not touched by any of this */ + + /* Send Detach Request for UE-2 on a new S1 context */ + emmbuf = testemm_build_detach_request(test_ue2, 1, true, true); + ABTS_PTR_NOTNULL(tc, emmbuf); + memset(&test_ue2->initial_ue_param, 0, + sizeof(test_ue2->initial_ue_param)); + sendbuf = test_s1ap_build_initial_ue_message( + test_ue2, emmbuf, + S1AP_RRC_Establishment_Cause_mo_Signalling, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE Context Release Command */ + recvbuf = testenb_s1ap_read(s1ap); + ABTS_PTR_NOTNULL(tc, recvbuf); + tests1ap_recv(test_ue2, recvbuf); + + /* Send UE Context Release Complete */ + sendbuf = test_s1ap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testenb_s1ap_send(s1ap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* eNB disonncect from MME */ + testenb_s1ap_close(s1ap); + + /* eNB disonncect from SGW */ + test_gtpu_close(gtpu); + + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} + +abts_suite *test_identity(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, attach_identity_mismatch_func, NULL); + abts_run_test(suite, attach_unknown_identity_func, NULL); + abts_run_test(suite, attach_during_authentication_func, NULL); + abts_run_test(suite, attach_during_session_setup_func, NULL); + + return suite; +} diff --git a/tests/attach/meson.build b/tests/attach/meson.build index 99adbac03..f8746394f 100644 --- a/tests/attach/meson.build +++ b/tests/attach/meson.build @@ -27,6 +27,7 @@ testapp_attach_sources = files(''' ue-context-test.c issues-test.c crash-test.c + identity-test.c '''.split()) testapp_attach_exe = executable('attach', diff --git a/tests/slice/abts-main.c b/tests/slice/abts-main.c index 5865dac02..8f9d1d215 100644 --- a/tests/slice/abts-main.c +++ b/tests/slice/abts-main.c @@ -22,6 +22,7 @@ abts_suite *test_same_dnn(abts_suite *suite); abts_suite *test_different_dnn(abts_suite *suite); abts_suite *test_paging(abts_suite *suite); +abts_suite *test_identity(abts_suite *suite); const struct testlist { abts_suite *(*func)(abts_suite *suite); @@ -29,6 +30,7 @@ const struct testlist { {test_same_dnn}, {test_different_dnn}, {test_paging}, + {test_identity}, {NULL}, }; diff --git a/tests/slice/identity-test.c b/tests/slice/identity-test.c new file mode 100644 index 000000000..fadf5e016 --- /dev/null +++ b/tests/slice/identity-test.c @@ -0,0 +1,991 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * 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 . + */ + +#include "test-common.h" + +/* + * Registration naming another subscriber, on a registered context. + * + * UE-2 register, PDU session, go idle -> context kept, session kept + * UE-1 register, PDU session, stay connected -> owns the NG context + * Registration Request(SUCI of UE-2) sent with the NGAP IDs of UE-1 + * + * Before: amf_ue_release_old_context() moves UE-2's session into UE-1's + * context -> ogs_assert(ogs_list_empty(&amf_ue->sess_list)) + * After: sessions deactivated, NG released, message dropped, and UE-1 + * keeps its own session + * + * This is the 5GS counterpart of the Attach case in + * tests/attach/identity-test.c. + */ +static void registration_identity_mismatch_func( + abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 owns the NG context that the REGISTRATION REQUEST arrives on */ + test_ue_t *test_ue1 = NULL; + test_sess_t *sess1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is the subscriber named by that REGISTRATION REQUEST */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000203195"); + ogs_assert(test_ue1); + + test_ue1->nr_cgi.cell_id = 0x40001; + + test_ue1->nas.registration.tsc = 0; + test_ue1->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.registration.follow_on_request = 1; + test_ue1->nas.registration.value = + OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue1->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue1->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000203196"); + ogs_assert(test_ue2); + + test_ue2->nr_cgi.cell_id = 0x40001; + + test_ue2->nas.registration.tsc = 0; + test_ue2->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.registration.follow_on_request = 1; + test_ue2->nas.registration.value = + OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* gNB connects to AMF */ + ngap = testngap_client(1, AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + /* UE-2: register, then go idle - context and session stay */ + /* Send Registration request */ + test_ue2->registration_request_param.guti = 1; + gmmbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue2->registration_request_param.gmm_capability = 1; + test_ue2->registration_request_param.s1_ue_network_capability = 1; + test_ue2->registration_request_param.requested_nssai = 1; + test_ue2->registration_request_param.last_visited_registered_tai = 1; + test_ue2->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue2, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_response(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue2, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue2->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue2, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send PDU session establishment request */ + sess2 = test_sess_add_by_dnn_and_psi(test_ue2, "internet", 5); + ogs_assert(sess2); + + sess2->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess2->ul_nas_transport_param.dnn = 1; + sess2->ul_nas_transport_param.s_nssai = 0; + + sess2->pdu_session_establishment_param.ssc_mode = 1; + sess2->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess2); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess2, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue2->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue2, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue2->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1 registers and stays connected with an active PDU session */ + /* Send Registration request */ + test_ue1->registration_request_param.guti = 1; + gmmbuf = testgmm_build_registration_request(test_ue1, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue1->registration_request_param.gmm_capability = 1; + test_ue1->registration_request_param.s1_ue_network_capability = 1; + test_ue1->registration_request_param.requested_nssai = 1; + test_ue1->registration_request_param.last_visited_registered_tai = 1; + test_ue1->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue1, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue1, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_response(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue1, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue1->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue1, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send PDU session establishment request */ + sess1 = test_sess_add_by_dnn_and_psi(test_ue1, "internet", 5); + ogs_assert(sess1); + + sess1->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess1->ul_nas_transport_param.dnn = 1; + sess1->ul_nas_transport_param.s_nssai = 0; + + sess1->pdu_session_establishment_param.ssc_mode = 1; + sess1->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess1); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess1, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue1->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Registration for UE-2, delivered with the NGAP IDs of UE-1 */ + memset(&test_ue2->registration_request_param, 0, + sizeof(test_ue2->registration_request_param)); + gmmbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Expect the release, not a reply to the Registration Request. + * Without the fix the AMF is already gone by now. + */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue1->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Did UE-1 survive with its session? + * + * The AMF answers a Service Request with an + * InitialContextSetupRequest only while the context still has its + * PDU session; otherwise it sends a Service Reject. + */ + /* + * Send InitialUEMessage + + * Service request + * - PDU Session Status + */ + test_ue1->service_request_param.pdu_session_status = 1; + test_ue1->service_request_param.psimask.pdu_session_status = + 1 << sess1->psi; + nasbuf = testgmm_build_service_request( + test_ue1, OGS_NAS_SERVICE_TYPE_SIGNALLING, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue1->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue1, OGS_NAS_SERVICE_TYPE_SIGNALLING, nasbuf, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue1, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue1->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x2000, test_ue1->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue1->pdu_session_reactivation_result); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue1, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue1, 1, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue1->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue2, 1, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_initial_ue_message(test_ue2, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, true, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue2->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* gNB disonncect from UPF */ + test_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} +/* + * Same, on a registered context with no PDU session. + * + * Nothing has to be deactivated towards the SMF, so no SBI transaction + * is started and the release is sent straight from the dispatch. That + * is the branch that picks its own release action, and UE-1 is + * registered, so it must be de-associated with the mobile reachable + * timer started rather than having its RAN-UE removed underneath it. + */ +static void registration_identity_mismatch_no_session_func( + abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + + /* UE-1 owns the NG context that the REGISTRATION REQUEST arrives on */ + test_ue_t *test_ue1 = NULL; + bson_t *doc1 = NULL; + + /* UE-2 is the subscriber named by that REGISTRATION REQUEST */ + test_ue_t *test_ue2 = NULL; + test_sess_t *sess2 = NULL; + bson_t *doc2 = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_PROTECTION_SCHEME_NULL; + mobile_identity_suci.home_network_pki_value = 0; + + test_ue1 = test_ue_add_by_suci(&mobile_identity_suci, "0000203197"); + ogs_assert(test_ue1); + + test_ue1->nr_cgi.cell_id = 0x40001; + + test_ue1->nas.registration.tsc = 0; + test_ue1->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue1->nas.registration.follow_on_request = 1; + test_ue1->nas.registration.value = + OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue1->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue1->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + test_ue2 = test_ue_add_by_suci(&mobile_identity_suci, "0000203198"); + ogs_assert(test_ue2); + + test_ue2->nr_cgi.cell_id = 0x40001; + + test_ue2->nas.registration.tsc = 0; + test_ue2->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue2->nas.registration.follow_on_request = 1; + test_ue2->nas.registration.value = + OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue2->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue2->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* gNB connects to AMF */ + ngap = testngap_client(1, AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /********** Insert Subscriber in Database */ + doc1 = test_db_new_simple(test_ue1); + ABTS_PTR_NOTNULL(tc, doc1); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue1, doc1)); + + doc2 = test_db_new_simple(test_ue2); + ABTS_PTR_NOTNULL(tc, doc2); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue2, doc2)); + + /* UE-2: register, then go idle - the requested identity exists */ + /* Send Registration request */ + test_ue2->registration_request_param.guti = 1; + gmmbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue2->registration_request_param.gmm_capability = 1; + test_ue2->registration_request_param.s1_ue_network_capability = 1; + test_ue2->registration_request_param.requested_nssai = 1; + test_ue2->registration_request_param.last_visited_registered_tai = 1; + test_ue2->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue2, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_response(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue2, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue2->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue2, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + + /* Send PDU session establishment request */ + sess2 = test_sess_add_by_dnn_and_psi(test_ue2, "internet", 5); + ogs_assert(sess2); + + sess2->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess2->ul_nas_transport_param.dnn = 1; + sess2->ul_nas_transport_param.s_nssai = 0; + + sess2->pdu_session_establishment_param.ssc_mode = 1; + sess2->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess2); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess2, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue2, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue2->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue2, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue2->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1 registers but never establishes a PDU session */ + /* Send Registration request */ + test_ue1->registration_request_param.guti = 1; + gmmbuf = testgmm_build_registration_request(test_ue1, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue1->registration_request_param.gmm_capability = 1; + test_ue1->registration_request_param.s1_ue_network_capability = 1; + test_ue1->registration_request_param.requested_nssai = 1; + test_ue1->registration_request_param.last_visited_registered_tai = 1; + test_ue1->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue1, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue1, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_response(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue1, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue1->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue1, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + + /* Registration for UE-2, delivered with the NGAP IDs of UE-1 */ + memset(&test_ue2->registration_request_param, 0, + sizeof(test_ue2->registration_request_param)); + gmmbuf = testgmm_build_registration_request(test_ue2, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_uplink_nas_transport(test_ue1, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Expect the release, not a reply to the Registration Request. + * Without the fix the AMF is already gone by now. + */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue1->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* UE-1 is still registered and can be de-registered from idle */ + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue1, 1, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_initial_ue_message(test_ue1, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, true, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue1, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue1->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue1); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue2, 1, true, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_initial_ue_message(test_ue2, gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, true, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue2, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue2->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue2); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue2)); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue1)); + + /* gNB disonncect from UPF */ + test_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue2); + test_ue_remove(test_ue1); +} + +abts_suite *test_identity(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, registration_identity_mismatch_func, NULL); + abts_run_test(suite, + registration_identity_mismatch_no_session_func, NULL); + + return suite; +} diff --git a/tests/slice/meson.build b/tests/slice/meson.build index 3aee0f058..5eca52910 100644 --- a/tests/slice/meson.build +++ b/tests/slice/meson.build @@ -20,6 +20,7 @@ test5gc_slice_sources = files(''' same-dnn-test.c different-dnn-test.c paging-test.c + identity-test.c '''.split()) test5gc_slice_exe = executable('slice',