[MME/AMF] Prevent UE context corruption on identity mismatch

An Attach or Registration Request can arrive on an S1/NG connection
already associated with another subscriber. The request was dispatched
through that association without checking its mobile identity.

The subsequent identity update could relabel the associated UE context
and migrate another subscriber's sessions into it. This either aborted
the MME/AMF when the target already owned sessions or silently assigned
the existing sessions to the wrong subscriber.

Re-resolve the identity before dispatch. If it differs from a registered
context or a context with sessions, release the access connection and
drop the request so the UE can retry on a newly resolved context.

Keep the existing migration behaviour for unfinished procedures without
sessions, and add regression tests for the affected MME and AMF paths.

Issues: #4739
This commit is contained in:
Sukchan Lee 2026-08-11 15:48:33 +09:00
parent ee143cec9b
commit a0e22eba31
12 changed files with 3073 additions and 5 deletions

View file

@ -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(&registering_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) {

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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!");

View file

@ -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) {

View file

@ -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},
};

1801
tests/attach/identity-test.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -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',

View file

@ -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},
};

991
tests/slice/identity-test.c Normal file
View file

@ -0,0 +1,991 @@
/*
* Copyright (C) 2019,2020 by Sukchan Lee <acetcom@gmail.com>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#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;
}

View file

@ -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',