From bb4a8f34d4a73d83d9baa4d7b7a4053b12aac066 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 14 May 2022 02:43:01 +0900 Subject: [PATCH] [AMF] Fix the bug NGResetAck (#1525) --- src/amf/ngap-handler.c | 87 +++++++++++++++++- src/amf/ngap-handler.h | 2 + src/amf/ngap-sm.c | 3 + tests/registration/reset-test.c | 151 ++++++++++++++++++++++++++++++++ 4 files changed, 242 insertions(+), 1 deletion(-) diff --git a/src/amf/ngap-handler.c b/src/amf/ngap-handler.c index 057b5059b..d6350acfa 100644 --- a/src/amf/ngap-handler.c +++ b/src/amf/ngap-handler.c @@ -3831,7 +3831,8 @@ void ngap_handle_ng_reset( amf_gnb_t *gnb, ogs_ngap_message_t *message) { char buf[OGS_ADDRSTRLEN]; - int i; + int i, old_xact_count = 0, new_xact_count = 0; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; NGAP_NGReset_t *NGReset = NULL; @@ -3996,10 +3997,16 @@ void ngap_handle_ng_reset( amf_ue = ran_ue->amf_ue; ogs_assert(amf_ue); + old_xact_count = amf_sess_xact_count(amf_ue); + amf_sbi_send_deactivate_all_sessions( amf_ue, AMF_REMOVE_S1_CONTEXT_BY_RESET_PARTIAL, NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_failure_in_radio_interface_procedure); + + new_xact_count = amf_sess_xact_count(amf_ue); + + if (old_xact_count == new_xact_count) ran_ue_remove(ran_ue); } ogs_list_for_each(&gnb->ran_ue_list, iter) { @@ -4025,3 +4032,81 @@ void ngap_handle_ng_reset( break; } } + +void ngap_handle_error_indication(amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + int i; + char buf[OGS_ADDRSTRLEN]; + uint64_t amf_ue_ngap_id; + + ran_ue_t *ran_ue = NULL; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_ErrorIndication_t *ErrorIndication = NULL; + + NGAP_ErrorIndicationIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_Cause_t *Cause = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + ErrorIndication = &initiatingMessage->value.choice.ErrorIndication; + ogs_assert(ErrorIndication); + + ogs_warn("ErrorIndication"); + + for (i = 0; i < ErrorIndication->protocolIEs.list.count; i++) { + ie = ErrorIndication->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_Cause: + Cause = &ie->value.choice.Cause; + break; + default: + break; + } + } + + ogs_warn(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (AMF_UE_NGAP_ID) { + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_warn("Invalid AMF_UE_NGAP_ID"); + } + + ran_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!ran_ue) + ogs_warn("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + else + ogs_warn(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id); + + } else if (RAN_UE_NGAP_ID) { + ran_ue = ran_ue_find_by_ran_ue_ngap_id(gnb, *RAN_UE_NGAP_ID); + if (!ran_ue) + ogs_warn("No RAN UE Context : RAN_UE_NGAP_ID[%d]", + (int)*RAN_UE_NGAP_ID); + else + ogs_warn(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id); + } + + if (Cause) { + ogs_warn(" Cause[Group:%d Cause:%d]", + Cause->present, (int)Cause->choice.radioNetwork); + } +} diff --git a/src/amf/ngap-handler.h b/src/amf/ngap-handler.h index b7ea83f04..5cacc66e6 100644 --- a/src/amf/ngap-handler.h +++ b/src/amf/ngap-handler.h @@ -81,6 +81,8 @@ void ngap_handle_ran_configuration_update( void ngap_handle_ng_reset( amf_gnb_t *gnb, ogs_ngap_message_t *message); +void ngap_handle_error_indication( + amf_gnb_t *gnb, ogs_ngap_message_t *message); #ifdef __cplusplus } diff --git a/src/amf/ngap-sm.c b/src/amf/ngap-sm.c index b86b441a7..86ccf66a0 100644 --- a/src/amf/ngap-sm.c +++ b/src/amf/ngap-sm.c @@ -119,6 +119,9 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e) case NGAP_ProcedureCode_id_NGReset: ngap_handle_ng_reset(gnb, pdu); break; + case NGAP_ProcedureCode_id_ErrorIndication: + ngap_handle_error_indication(gnb, pdu); + break; default: ogs_error("Not implemented(choice:%d, proc:%d)", pdu->present, (int)initiatingMessage->procedureCode); diff --git a/tests/registration/reset-test.c b/tests/registration/reset-test.c index 0770f93c7..16d92c70f 100644 --- a/tests/registration/reset-test.c +++ b/tests/registration/reset-test.c @@ -593,12 +593,163 @@ static void test2_func(abts_case *tc, void *data) test_ue_remove(test_ue); } +static void test3_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_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + bson_t *doc = 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_NAS_5GS_NULL_SCHEME; + mobile_identity_suci.home_network_pki_value = 0; + mobile_identity_suci.scheme_output[0] = 0; + mobile_identity_suci.scheme_output[1] = 0; + mobile_identity_suci.scheme_output[2] = 0x20; + mobile_identity_suci.scheme_output[3] = 0x31; + mobile_identity_suci.scheme_output[4] = 0x90; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue); + + test_ue->nr_cgi.cell_id = 0x40001; + + test_ue->nas.registration.tsc = 0; + test_ue->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue->nas.registration.follow_on_request = 1; + test_ue->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* gNB connects to AMF */ + ngap = testngap_client(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, 23); + 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_ue, recvbuf); + +#if 0 /* To reject UE registration */ + /********** Insert Subscriber in Database */ + doc = test_db_new_simple(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); +#endif + + /* Send Registration request */ + gmmbuf = testgmm_build_registration_request(test_ue, NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue->registration_request_param.gmm_capability = 1; + test_ue->registration_request_param.s1_ue_network_capability = 1; + test_ue->registration_request_param.requested_nssai = 1; + test_ue->registration_request_param.last_visited_registered_tai = 1; + test_ue->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue, NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Registration reject */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send ErrorIndication */ + sendbuf = ogs_ngap_build_error_indication( + &test_ue->ran_ue_ngap_id, &test_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, 0); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send NGReset */ + NGAP_UE_associatedLogicalNG_connectionList_t *partOfNG_Interface = NULL; + partOfNG_Interface = CALLOC(1, sizeof(*partOfNG_Interface)); + ogs_assert(partOfNG_Interface); + + ogs_ngap_build_part_of_ng_interface( + partOfNG_Interface, + &test_ue->ran_ue_ngap_id, &test_ue->amf_ue_ngap_id); + + sendbuf = ogs_ngap_build_ng_reset( + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_release_due_to_ngran_generated_reason, + partOfNG_Interface); + + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NGResetAcknowledge */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + ogs_msleep(300); + +#if 0 /* To reject UE registration */ + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); +#endif + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + abts_suite *test_reset(abts_suite *suite) { suite = ADD_SUITE(suite) abts_run_test(suite, test1_func, NULL); abts_run_test(suite, test2_func, NULL); + abts_run_test(suite, test3_func, NULL); return suite; }