[AMF] Handle namf-callback DeregNotify message from UDM

UDM may send a Deregistration Notification to AMF, to deregister
specific UE from the network - Network-Initiated Deregistration.
Deregistration procedure includes sending Deregistration Request to UE,
starting a timer T3522, releasing PDU sessions from SMF, releasing PCF
policies from PCF, and waiting for Deregistration Accept from UE.

Not yet implemented is:
- to prevent deregistration of UE in case it has any emergency sessions,
- page UE when UE is in IDLE mode.
This commit is contained in:
Bostjan Meglic 2022-06-21 11:55:37 +00:00 committed by Sukchan Lee
parent 0633774972
commit aa3cded11a
9 changed files with 192 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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