diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index 899d04c12..2ff02482d 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -209,11 +209,10 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) stream, &sbi_message); break; - /* TODO */ -#if 0 CASE(OGS_SBI_RESOURCE_NAME_DEREG_NOTIFY) + amf_namf_callback_handle_dereg_notify(stream, &sbi_message); break; -#endif + CASE(OGS_SBI_RESOURCE_NAME_AM_POLICY_NOTIFY) ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); break; diff --git a/src/amf/context.h b/src/amf/context.h index 16fdb38f8..c5426f2ff 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -408,6 +408,9 @@ struct amf_ue_s { long cause; } handover; + /* Network Initiated De-Registration */ + bool network_initiated_de_reg; + ogs_list_t sess_list; }; diff --git a/src/amf/gmm-build.c b/src/amf/gmm-build.c index 5ec36ca3c..f57fd96c9 100644 --- a/src/amf/gmm-build.c +++ b/src/amf/gmm-build.c @@ -276,6 +276,35 @@ ogs_pkbuf_t *gmm_build_de_registration_accept(amf_ue_t *amf_ue) return nas_5gs_security_encode(amf_ue, &message); } +ogs_pkbuf_t *gmm_build_de_registration_request(amf_ue_t *amf_ue) +{ + ogs_nas_5gs_message_t message; + ogs_nas_5gs_deregistration_request_to_ue_t *dereg_req = + &message.gmm.deregistration_request_to_ue; + + ogs_assert(amf_ue); + + memset(&message, 0, sizeof(message)); + message.h.security_header_type = + OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED; + message.h.extended_protocol_discriminator = + OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM; + + message.gmm.h.extended_protocol_discriminator = + OGS_NAS_EXTENDED_PROTOCOL_DISCRIMINATOR_5GMM; + message.gmm.h.message_type = OGS_NAS_5GS_DEREGISTRATION_REQUEST_TO_UE; + + dereg_req->de_registration_type.switch_off = 1; + dereg_req->de_registration_type.re_registration_required = 0; + dereg_req->de_registration_type.access_type = OGS_ACCESS_TYPE_3GPP; + + dereg_req->presencemask |= + OGS_NAS_5GS_DEREGISTRATION_REQUEST_TO_UE_5GMM_CAUSE_PRESENT; + dereg_req->gmm_cause = OGS_5GMM_CAUSE_5GS_SERVICES_NOT_ALLOWED; + + return nas_5gs_security_encode(amf_ue, &message); +} + ogs_pkbuf_t *gmm_build_identity_request(amf_ue_t *amf_ue) { ogs_nas_5gs_message_t message; diff --git a/src/amf/gmm-build.h b/src/amf/gmm-build.h index dba3034b0..d5185fcf6 100644 --- a/src/amf/gmm-build.h +++ b/src/amf/gmm-build.h @@ -34,6 +34,7 @@ ogs_pkbuf_t *gmm_build_service_reject( amf_ue_t *amf_ue, ogs_nas_5gmm_cause_t gmm_cause); ogs_pkbuf_t *gmm_build_de_registration_accept(amf_ue_t *amf_ue); +ogs_pkbuf_t *gmm_build_de_registration_request(amf_ue_t *amf_ue); ogs_pkbuf_t *gmm_build_identity_request(amf_ue_t *amf_ue); ogs_pkbuf_t *gmm_build_security_mode_command(amf_ue_t *amf_ue); diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index 93ee9234a..20ab49284 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -286,6 +286,21 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) OGS_FSM_TRAN(s, &gmm_state_de_registered); break; + case OGS_NAS_5GS_DEREGISTRATION_ACCEPT_TO_UE: + ogs_info("[%s] Deregistration accept", amf_ue->supi); + CLEAR_AMF_UE_TIMER(amf_ue->t3522); + + /* De-associate NG with NAS/EMM */ + ran_ue_deassociate(amf_ue->ran_ue); + + ogs_assert(OGS_OK == + ngap_send_ran_ue_context_release_command(amf_ue->ran_ue, + NGAP_Cause_PR_misc, NGAP_CauseMisc_om_intervention, + NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0)); + + OGS_FSM_TRAN(s, &gmm_state_de_registered); + break; + case OGS_NAS_5GS_CONFIGURATION_UPDATE_COMPLETE: ogs_debug("[%s] Configuration update complete", amf_ue->supi); @@ -414,6 +429,20 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) } break; + case AMF_TIMER_T3522: + if (amf_ue->t3522.retry_count >= + amf_timer_cfg(AMF_TIMER_T3522)->max_count) { + ogs_warn("Retransmission of Deregistration-Request failed. " + "Stop retransmission"); + CLEAR_AMF_UE_TIMER(amf_ue->t3522); + OGS_FSM_TRAN(&amf_ue->t3522, &gmm_state_exception); + } else { + amf_ue->t3522.retry_count++; + ogs_assert(OGS_OK == + nas_5gs_send_de_registration_request(amf_ue)); + } + break; + default: ogs_error("Unknown timer[%s:%d]", amf_timer_get_name(e->timer_id), e->timer_id); @@ -432,8 +461,10 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) CASE(OGS_SBI_RESOURCE_NAME_POLICIES) SWITCH(sbi_message->h.method) CASE(OGS_SBI_HTTP_METHOD_DELETE) - ogs_assert(OGS_OK == - nas_5gs_send_de_registration_accept(amf_ue)); + + if (!amf_ue->network_initiated_de_reg) + ogs_assert(OGS_OK == + nas_5gs_send_de_registration_accept(amf_ue)); PCF_AM_POLICY_CLEAR(amf_ue); break; diff --git a/src/amf/namf-handler.c b/src/amf/namf-handler.c index 08ae9afe6..8ed4cea30 100644 --- a/src/amf/namf-handler.c +++ b/src/amf/namf-handler.c @@ -508,3 +508,92 @@ cleanup: return OGS_OK; } + +int amf_namf_callback_handle_dereg_notify( + ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) +{ + int status = OGS_SBI_HTTP_STATUS_NO_CONTENT; + + amf_ue_t *amf_ue = NULL; + + ogs_sbi_message_t sendmsg; + ogs_sbi_response_t *response = NULL; + + OpenAPI_deregistration_data_t *DeregistrationData; + + ogs_assert(stream); + ogs_assert(recvmsg); + + if (!recvmsg->h.resource.component[0]) { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + ogs_error("No SUPI"); + goto cleanup; + } + + amf_ue = amf_ue_find_by_supi(recvmsg->h.resource.component[0]); + if (!amf_ue) { + status = OGS_SBI_HTTP_STATUS_NOT_FOUND; + ogs_error("Cannot find SUPI [%s]", recvmsg->h.resource.component[0]); + goto cleanup; + } + + DeregistrationData = recvmsg->DeregistrationData; + if (!DeregistrationData) { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + ogs_error("[%s] No DeregistrationData", amf_ue->supi); + goto cleanup; + } + + if (DeregistrationData->access_type != OpenAPI_access_type_3GPP_ACCESS) + { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + ogs_error("[%s] Deregistration access type not 3GPP", amf_ue->supi); + goto cleanup; + } + + ogs_info("Deregistration notify reason: %s:%s:%s", + amf_ue->supi, + OpenAPI_deregistration_reason_ToString(DeregistrationData->dereg_reason), + OpenAPI_access_type_ToString(DeregistrationData->access_type)); + + /* + * TODO: do not start deregistration if UE has emergency sessions + * 4.2.2.3.3 + * If the UE has established PDU Session associated with emergency service, the AMF shall not initiate + * Deregistration procedure. In this case, the AMF performs network requested PDU Session Release for any PDU + * session associated with non-emergency service as described in clause 4.3.4. + */ + + + if (CM_CONNECTED(amf_ue)) + { + amf_ue->network_initiated_de_reg = true; + + ogs_assert(OGS_OK == + nas_5gs_send_de_registration_request(amf_ue)); + + amf_sbi_send_release_all_sessions( + amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + + if (ogs_list_count(&amf_ue->sess_list) == 0) + ogs_assert(true == + amf_ue_sbi_discover_and_send( + OpenAPI_nf_type_PCF, amf_ue, + NULL, amf_npcf_am_policy_control_build_delete)); + + OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_de_registered); + } + else if (CM_IDLE(amf_ue)) { + /* TODO: need to page UE */ + /*ngap_send_paging(amf_ue);*/ + } + +cleanup: + memset(&sendmsg, 0, sizeof(sendmsg)); + + response = ogs_sbi_build_response(&sendmsg, status); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + return OGS_OK; +} diff --git a/src/amf/namf-handler.h b/src/amf/namf-handler.h index 11e152991..d529377dd 100644 --- a/src/amf/namf-handler.h +++ b/src/amf/namf-handler.h @@ -30,6 +30,8 @@ int amf_namf_comm_handle_n1_n2_message_transfer( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); int amf_namf_callback_handle_sm_context_status( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); +int amf_namf_callback_handle_dereg_notify( + ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); #ifdef __cplusplus } diff --git a/src/amf/nas-path.c b/src/amf/nas-path.c index d7a287090..4de6c61d7 100644 --- a/src/amf/nas-path.c +++ b/src/amf/nas-path.c @@ -276,6 +276,38 @@ int nas_5gs_send_de_registration_accept(amf_ue_t *amf_ue) return rv; } +int nas_5gs_send_de_registration_request(amf_ue_t *amf_ue) +{ + int rv; + + ran_ue_t *ran_ue = NULL; + ogs_pkbuf_t *gmmbuf = NULL; + + ogs_assert(amf_ue); + ran_ue = ran_ue_cycle(amf_ue->ran_ue); + ogs_expect_or_return_val(ran_ue, OGS_ERROR); + + ogs_debug("[%s] De-registration request", amf_ue->supi); + + if (amf_ue->t3522.pkbuf) { + gmmbuf = amf_ue->t3522.pkbuf; + ogs_expect_or_return_val(gmmbuf, OGS_ERROR); + } else { + gmmbuf = gmm_build_de_registration_request(amf_ue); + ogs_expect_or_return_val(gmmbuf, OGS_ERROR); + } + + amf_ue->t3522.pkbuf = ogs_pkbuf_copy(gmmbuf); + ogs_expect_or_return_val(amf_ue->t3522.pkbuf, OGS_ERROR); + ogs_timer_start(amf_ue->t3522.timer, + amf_timer_cfg(AMF_TIMER_T3522)->duration); + + rv = nas_5gs_send_to_downlink_nas_transport(amf_ue, gmmbuf); + ogs_expect_or_return_val(rv == OGS_OK, OGS_ERROR); + + return rv; +} + int nas_5gs_send_identity_request(amf_ue_t *amf_ue) { int rv; diff --git a/src/amf/nas-path.h b/src/amf/nas-path.h index 27f50efd0..40944a07c 100644 --- a/src/amf/nas-path.h +++ b/src/amf/nas-path.h @@ -41,6 +41,7 @@ int nas_5gs_send_service_reject( amf_ue_t *amf_ue, ogs_nas_5gmm_cause_t gmm_cause); int nas_5gs_send_de_registration_accept(amf_ue_t *amf_ue); +int nas_5gs_send_de_registration_request(amf_ue_t *amf_ue); int nas_5gs_send_identity_request(amf_ue_t *amf_ue);