Add EMM/GMM handler in exception state [#569]

This commit is contained in:
Sukchan Lee 2020-09-22 13:27:58 -04:00
parent 6dace84232
commit 62d95be036
6 changed files with 246 additions and 52 deletions

View File

@ -742,26 +742,6 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e)
ngap_send_ran_ue_context_release_command(amf_ue->ran_ue,
NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release,
NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0);
/*
* Pull #569 : State should be initialized again.
*
* However, we cannot initialize the state in all cases.
*
* In TS24.501 Ch 5.5.1.3.8 Abnormal cases on the network side
*
* d) REGISTRATION REQUEST with 5GS registration type IE set to
* "mobility registration updating" or "periodic registration updating"
* received after the REGISTRATION ACCEPT message has been sent and
* before the REGISTRATION COMPLETE message is received.
*
* Since, we have to do this special case, it is desirable
* to handle it directly inside the state(gmm-sm.c).
*/
#if 0
amf_ue_fsm_fini(amf_ue);
amf_ue_fsm_init(amf_ue);
#endif
}
amf_ue_associate_ran_ue(amf_ue, ran_ue);
}

View File

@ -1011,13 +1011,25 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e)
void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
{
int rv, xact_count = 0;
amf_ue_t *amf_ue = NULL;
amf_sess_t *sess = NULL;
ran_ue_t *ran_ue = NULL;
ogs_nas_5gs_message_t *nas_message = NULL;
ogs_nas_security_header_type_t h;
ogs_assert(e);
amf_sm_debug(e);
amf_ue = e->amf_ue;
ogs_assert(amf_ue);
if (e->sess) {
sess = e->sess;
amf_ue = sess->amf_ue;
ogs_assert(amf_ue);
} else {
amf_ue = e->amf_ue;
ogs_assert(amf_ue);
}
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
@ -1033,8 +1045,70 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e)
break;
case OGS_FSM_EXIT_SIG:
break;
default:
ogs_error("GMM exception occurred [%s]", amf_event_get_name(e));
case AMF_EVT_5GMM_MESSAGE:
nas_message = e->nas.message;
ogs_assert(nas_message);
ran_ue = amf_ue->ran_ue;
ogs_assert(ran_ue);
h.type = e->nas.type;
amf_ue->nas.ngapProcedureCode = e->ngap.code;
xact_count = amf_sess_xact_count(amf_ue);
switch (nas_message->gmm.h.message_type) {
case OGS_NAS_5GS_REGISTRATION_REQUEST:
rv = gmm_handle_registration_request(
amf_ue, &nas_message->gmm.registration_request);
if (rv != OGS_OK) {
ogs_error("gmm_handle_registration_request() failed");
OGS_FSM_TRAN(s, gmm_state_exception);
break;
}
if (!AMF_UE_HAVE_SUCI(amf_ue)) {
CLEAR_AMF_UE_TIMER(amf_ue->t3570);
nas_5gs_send_identity_request(amf_ue);
break;
}
if (h.integrity_protected && SECURITY_CONTEXT_IS_VALID(amf_ue)) {
rv = gmm_handle_registration_update(
amf_ue, &nas_message->gmm.registration_request);
if (rv != OGS_OK) {
ogs_error("gmm_handle_registration_update() failed");
OGS_FSM_TRAN(s, gmm_state_exception);
break;
}
if (amf_sess_xact_count(amf_ue) == xact_count)
nas_5gs_send_registration_accept(amf_ue);
OGS_FSM_TRAN(s, &gmm_state_registered);
} else {
amf_sbi_send_release_all_sessions(
amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE);
if (amf_sess_xact_count(amf_ue) == xact_count) {
amf_ue_sbi_discover_and_send(
OpenAPI_nf_type_AUSF, amf_ue, NULL,
amf_nausf_auth_build_authenticate);
}
OGS_FSM_TRAN(s, &gmm_state_authentication);
}
break;
default:
ogs_error("Unknown message [%d]", nas_message->gmm.h.message_type);
}
break;
default:
ogs_error("Unknown event[%s]", amf_event_get_name(e));
}
}

View File

@ -434,26 +434,6 @@ void ngap_handle_initial_ue_message(amf_gnb_t *gnb, ogs_ngap_message_t *message)
ngap_send_ran_ue_context_release_command(amf_ue->ran_ue,
NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release,
NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0);
/*
* Pull #569 : State should be initialized again.
*
* However, we cannot initialize the state in all cases.
*
* In TS24.501 Ch 5.5.1.3.8 Abnormal cases on the network side
*
* d) REGISTRATION REQUEST with 5GS registration type IE set to
* "mobility registration updating" or "periodic registration updating"
* received after the REGISTRATION ACCEPT message has been sent and
* before the REGISTRATION COMPLETE message is received.
*
* Since, we have to do this special case, it is desirable
* to handle it directly inside the state(gmm-sm.c).
*/
#if 0
amf_ue_fsm_fini(amf_ue);
amf_ue_fsm_init(amf_ue);
#endif
}
amf_ue_associate_ran_ue(amf_ue, ran_ue);
}

View File

@ -105,9 +105,10 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e)
switch (e->id) {
case OGS_FSM_ENTRY_SIG:
return;
break;
case OGS_FSM_EXIT_SIG:
return;
break;
case MME_EVT_EMM_MESSAGE:
message = e->nas_message;
ogs_assert(message);
@ -590,7 +591,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
if (rv != OGS_OK) {
ogs_error("emm_handle_attach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
return;
break;
}
mme_s6a_send_air(mme_ue, NULL);
@ -610,7 +611,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e)
if (rv != OGS_OK) {
ogs_error("emm_handle_detach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
return;
break;
}
mme_send_delete_session_or_detach(mme_ue);
@ -681,7 +682,7 @@ void emm_state_security_mode(ogs_fsm_t *s, mme_event_t *e)
nas_eps_send_service_reject(mme_ue,
EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED);
OGS_FSM_TRAN(s, &emm_state_exception);
return;
break;
}
switch (message->emm.h.message_type) {
@ -864,7 +865,7 @@ void emm_state_initial_context_setup(ogs_fsm_t *s, mme_event_t *e)
if (rv != OGS_OK) {
ogs_error("emm_handle_attach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
return;
break;
}
mme_gtp_send_delete_all_sessions(mme_ue);
@ -884,7 +885,7 @@ void emm_state_initial_context_setup(ogs_fsm_t *s, mme_event_t *e)
if (rv != OGS_OK) {
ogs_error("emm_handle_detach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
return;
break;
}
mme_send_delete_session_or_detach(mme_ue);
@ -916,7 +917,12 @@ void emm_state_initial_context_setup(ogs_fsm_t *s, mme_event_t *e)
void emm_state_exception(ogs_fsm_t *s, mme_event_t *e)
{
int rv;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
ogs_nas_eps_message_t *message = NULL;
ogs_nas_security_header_type_t h;
ogs_assert(e);
mme_sm_debug(e);
@ -931,8 +937,61 @@ void emm_state_exception(ogs_fsm_t *s, mme_event_t *e)
break;
case OGS_FSM_EXIT_SIG:
break;
case MME_EVT_EMM_MESSAGE:
message = e->nas_message;
ogs_assert(message);
enb_ue = mme_ue->enb_ue;
ogs_assert(enb_ue);
h.type = e->nas_type;
switch (message->emm.h.message_type) {
case OGS_NAS_EPS_ATTACH_REQUEST:
ogs_debug("[EMM] Attach request[%s]", mme_ue->imsi_bcd);
rv = emm_handle_attach_request(
mme_ue, &message->emm.attach_request, e->pkbuf);
if (rv != OGS_OK) {
ogs_error("emm_handle_attach_request() failed");
OGS_FSM_TRAN(s, emm_state_exception);
break;
}
if (!MME_UE_HAVE_IMSI(mme_ue)) {
CLEAR_MME_UE_TIMER(mme_ue->t3470);
nas_eps_send_identity_request(mme_ue);
break;
}
if (h.integrity_protected && SECURITY_CONTEXT_IS_VALID(mme_ue)) {
rv = nas_eps_send_emm_to_esm(mme_ue,
&mme_ue->pdn_connectivity_request);
if (rv != OGS_OK) {
ogs_error("nas_eps_send_emm_to_esm() failed");
nas_eps_send_attach_reject(mme_ue,
EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED,
ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
OGS_FSM_TRAN(s, &emm_state_exception);
} else {
OGS_FSM_TRAN(s, &emm_state_initial_context_setup);
}
} else {
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue)) {
mme_gtp_send_delete_all_sessions(mme_ue);
} else {
mme_s6a_send_air(mme_ue, NULL);
}
OGS_FSM_TRAN(s, &emm_state_authentication);
}
break;
default:
ogs_warn("Unknown message[%d]", message->emm.h.message_type);
}
break;
default:
ogs_error("Unknown event[%s]", mme_event_get_name(e));
break;
}
}

View File

@ -416,6 +416,63 @@ static void test1_func(abts_case *tc, void *data)
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Attach Request - No Integrity */
sess->pdn_connectivity_param.eit = 1;
sess->pdn_connectivity_param.pco = 1;
esmbuf = testesm_build_pdn_connectivity_request(sess);
ABTS_PTR_NOTNULL(tc, esmbuf);
memset(&test_ue->attach_request_param,
0, sizeof(test_ue->attach_request_param));
test_ue->attach_request_param.ms_network_feature_support = 1;
emmbuf = testemm_build_attach_request(test_ue, esmbuf);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_initial_ue_message(
test_ue, emmbuf, S1AP_RRC_Establishment_Cause_mo_Signalling, false);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive OLD UE Context Release Command */
enb_ue_s1ap_id = test_ue->enb_ue_s1ap_id;
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send OLD UE Context Release Complete */
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
test_ue->enb_ue_s1ap_id = enb_ue_s1ap_id;
/* Receive Authentication request */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send Authentication failure - MAC failure */
emmbuf = testemm_build_authentication_failure(
test_ue, EMM_CAUSE_MAC_FAILURE, 0);
ABTS_PTR_NOTNULL(tc, emmbuf);
sendbuf = test_s1ap_build_uplink_nas_transport(test_ue, emmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testenb_s1ap_send(s1ap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication reject */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Receive UE Context Release Command */
recvbuf = testenb_s1ap_read(s1ap);
ABTS_PTR_NOTNULL(tc, recvbuf);
tests1ap_recv(test_ue, recvbuf);
/* Send UE Context Release Complete */
sendbuf = test_s1ap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);

View File

@ -213,6 +213,50 @@ static void test1_func(abts_case *tc, void *data)
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send Registration request */
test_ue->registration_request_param.gmm_capability = 1;
gmmbuf = testgmm_build_registration_request(test_ue, NULL);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, false);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* OLD Receive UE context release command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send OLD UE Context Release Complete */
sendbuf = testngap_build_ue_context_release_complete(test_ue);
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_ue, recvbuf);
/* Send Authentication failure - MAC failure */
gmmbuf = testgmm_build_authentication_failure(
test_ue, OGS_5GMM_CAUSE_MAC_FAILURE, 0);
ABTS_PTR_NOTNULL(tc, gmmbuf);
sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf);
ABTS_PTR_NOTNULL(tc, sendbuf);
rv = testgnb_ngap_send(ngap, sendbuf);
ABTS_INT_EQUAL(tc, OGS_OK, rv);
/* Receive Authentication reject */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Receive UE context release command */
recvbuf = testgnb_ngap_read(ngap);
ABTS_PTR_NOTNULL(tc, recvbuf);
testngap_recv(test_ue, recvbuf);
/* Send UE context release complete */
sendbuf = testngap_build_ue_context_release_complete(test_ue);
ABTS_PTR_NOTNULL(tc, sendbuf);