diff --git a/lib/sbi/custom/patch_item.c b/lib/sbi/custom/patch_item.c index 533b55bf0..a502b338e 100644 --- a/lib/sbi/custom/patch_item.c +++ b/lib/sbi/custom/patch_item.c @@ -76,7 +76,7 @@ cJSON *OpenAPI_patch_item_convertToJSON(OpenAPI_patch_item_t *patch_item) } } else if (OpenAPI_IsBool(patch_item->value)) { if (cJSON_AddBoolToObject( - item, "value", OpenAPI_IsTrue(patch_item->value))) { + item, "value", OpenAPI_IsTrue(patch_item->value)) == NULL) { ogs_error("OpenAPI_patch_item_convertToJSON() failed [value]"); goto end; } diff --git a/lib/sbi/message.c b/lib/sbi/message.c index 306058af5..e67c8c94f 100644 --- a/lib/sbi/message.c +++ b/lib/sbi/message.c @@ -100,6 +100,9 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message) if (message->Amf3GppAccessRegistration) OpenAPI_amf3_gpp_access_registration_free( message->Amf3GppAccessRegistration); + if (message->Amf3GppAccessRegistrationModification) + OpenAPI_amf3_gpp_access_registration_modification_free( + message->Amf3GppAccessRegistrationModification); if (message->AccessAndMobilitySubscriptionData) OpenAPI_access_and_mobility_subscription_data_free( message->AccessAndMobilitySubscriptionData); @@ -760,6 +763,10 @@ static char *build_json(ogs_sbi_message_t *message) item = OpenAPI_amf3_gpp_access_registration_convertToJSON( message->Amf3GppAccessRegistration); ogs_assert(item); + } else if (message->Amf3GppAccessRegistrationModification) { + item = OpenAPI_amf3_gpp_access_registration_modification_convertToJSON( + message->Amf3GppAccessRegistrationModification); + ogs_assert(item); } else if (message->AccessAndMobilitySubscriptionData) { item = OpenAPI_access_and_mobility_subscription_data_convertToJSON( message->AccessAndMobilitySubscriptionData); @@ -1098,13 +1105,30 @@ static int parse_json(ogs_sbi_message_t *message, CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) SWITCH(message->h.resource.component[2]) CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) - message->Amf3GppAccessRegistration = - OpenAPI_amf3_gpp_access_registration_parseFromJSON( - item); - if (!message->Amf3GppAccessRegistration) { - rv = OGS_ERROR; - ogs_error("JSON parse error"); - } + + SWITCH(message->h.method) + CASE(OGS_SBI_HTTP_METHOD_PUT) + message->Amf3GppAccessRegistration = + OpenAPI_amf3_gpp_access_registration_parseFromJSON( + item); + if (!message->Amf3GppAccessRegistration) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + break; + CASE(OGS_SBI_HTTP_METHOD_PATCH) + message->Amf3GppAccessRegistrationModification = + OpenAPI_amf3_gpp_access_registration_modification_parseFromJSON( + item); + if (!message->Amf3GppAccessRegistrationModification) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + break; + DEFAULT + rv = OGS_ERROR; + ogs_error("Unknown method [%s]", message->h.method); + END break; DEFAULT rv = OGS_ERROR; diff --git a/lib/sbi/message.h b/lib/sbi/message.h index e3b3f0c9e..ee3b7eaf6 100644 --- a/lib/sbi/message.h +++ b/lib/sbi/message.h @@ -373,6 +373,8 @@ typedef struct ogs_sbi_message_s { OpenAPI_confirmation_data_response_t *ConfirmationDataResponse; OpenAPI_auth_event_t *AuthEvent; OpenAPI_amf3_gpp_access_registration_t *Amf3GppAccessRegistration; + OpenAPI_amf3_gpp_access_registration_modification_t + *Amf3GppAccessRegistrationModification; OpenAPI_access_and_mobility_subscription_data_t *AccessAndMobilitySubscriptionData; OpenAPI_smf_selection_subscription_data_t *SmfSelectionSubscriptionData; diff --git a/lib/sbi/ogs-sbi.h b/lib/sbi/ogs-sbi.h index 454df7d16..c0400a30e 100644 --- a/lib/sbi/ogs-sbi.h +++ b/lib/sbi/ogs-sbi.h @@ -42,6 +42,7 @@ #include "model/confirmation_data_response.h" #include "model/auth_event.h" #include "model/amf3_gpp_access_registration.h" +#include "model/amf3_gpp_access_registration_modification.h" #include "model/access_and_mobility_subscription_data.h" #include "model/smf_selection_subscription_data.h" #include "model/ue_context_in_smf_data.h" diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index 9145f9798..95cf86da5 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -450,6 +450,39 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) END break; + CASE(OGS_SBI_SERVICE_NAME_NUDM_UECM) + SWITCH(sbi_message->h.resource.component[1]) + CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) + SWITCH(sbi_message->h.resource.component[2]) + CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) + SWITCH(sbi_message->h.method) + CASE(OGS_SBI_HTTP_METHOD_PATCH) + + ogs_assert(true == + amf_ue_sbi_discover_and_send( + OpenAPI_nf_type_PCF, amf_ue, + NULL, amf_npcf_am_policy_control_build_delete)); + + break; + + DEFAULT + ogs_error("Unknown method [%s]", sbi_message->h.method); + ogs_assert_if_reached(); + END + break; + DEFAULT + ogs_error("Invalid resource name [%s]", + sbi_message->h.resource.component[2]); + ogs_assert_if_reached(); + END + break; + + DEFAULT + ogs_error("Invalid resource name [%s]", + sbi_message->h.resource.component[1]); + ogs_assert_if_reached(); + END + break; DEFAULT ogs_error("Invalid service name [%s]", sbi_message->h.service.name); ogs_assert_if_reached(); diff --git a/src/amf/nsmf-handler.c b/src/amf/nsmf-handler.c index 2953c4b46..7d47ccf77 100644 --- a/src/amf/nsmf-handler.c +++ b/src/amf/nsmf-handler.c @@ -886,8 +886,8 @@ int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state) ogs_assert(true == amf_ue_sbi_discover_and_send( - OpenAPI_nf_type_PCF, amf_ue, - NULL, amf_npcf_am_policy_control_build_delete)); + OpenAPI_nf_type_UDM, amf_ue, + NULL, amf_nudm_uecm_build_registration_delete)); } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered)) { /* diff --git a/src/amf/nudm-build.c b/src/amf/nudm-build.c index 37c897286..11adc3ad4 100644 --- a/src/amf/nudm-build.c +++ b/src/amf/nudm-build.c @@ -74,6 +74,48 @@ ogs_sbi_request_t *amf_nudm_uecm_build_registration( return request; } +ogs_sbi_request_t *amf_nudm_uecm_build_registration_delete( + amf_ue_t *amf_ue, void *data) +{ + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + OpenAPI_amf3_gpp_access_registration_modification_t + Amf3GppAccessRegistrationModification; + + ogs_assert(amf_ue); + ogs_assert(amf_ue->supi); + + memset(&message, 0, sizeof(message)); + message.h.method = (char *)OGS_SBI_HTTP_METHOD_PATCH; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDM_UECM; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = amf_ue->supi; + message.h.resource.component[1] = + (char *)OGS_SBI_RESOURCE_NAME_REGISTRATIONS; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS; + + memset(&Amf3GppAccessRegistrationModification, 0, + sizeof(Amf3GppAccessRegistrationModification)); + + Amf3GppAccessRegistrationModification.guami = + ogs_sbi_build_guami(amf_ue->guami); + Amf3GppAccessRegistrationModification.is_purge_flag = true; + Amf3GppAccessRegistrationModification.purge_flag = 1; + + message.Amf3GppAccessRegistrationModification = + &Amf3GppAccessRegistrationModification; + + request = ogs_sbi_build_request(&message); + ogs_assert(request); + + if (Amf3GppAccessRegistrationModification.guami) + ogs_sbi_free_guami(Amf3GppAccessRegistrationModification.guami); + + return request; +} + ogs_sbi_request_t *amf_nudm_sdm_build_get(amf_ue_t *amf_ue, void *data) { ogs_sbi_message_t message; diff --git a/src/amf/nudm-build.h b/src/amf/nudm-build.h index 8ccd7405e..a3c10968b 100644 --- a/src/amf/nudm-build.h +++ b/src/amf/nudm-build.h @@ -28,6 +28,8 @@ extern "C" { ogs_sbi_request_t *amf_nudm_uecm_build_registration( amf_ue_t *amf_ue, void *data); +ogs_sbi_request_t *amf_nudm_uecm_build_registration_delete( + amf_ue_t *amf_ue, void *data); ogs_sbi_request_t *amf_nudm_sdm_build_get(amf_ue_t *amf_ue, void *data); #ifdef __cplusplus diff --git a/src/udm/nudm-handler.c b/src/udm/nudm-handler.c index 572fe3a03..2a0b8cb1e 100644 --- a/src/udm/nudm-handler.c +++ b/src/udm/nudm-handler.c @@ -336,6 +336,113 @@ bool udm_nudm_uecm_handle_registration( return true; } +bool udm_nudm_uecm_handle_registration_update( + udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) +{ + OpenAPI_amf3_gpp_access_registration_modification_t + *Amf3GppAccessRegistrationModification = NULL; + OpenAPI_guami_t *Guami = NULL; + ogs_guami_t recv_guami; + OpenAPI_list_t *PatchItemList = NULL; + OpenAPI_patch_item_t item; + + ogs_assert(udm_ue); + ogs_assert(stream); + ogs_assert(message); + + Amf3GppAccessRegistrationModification = message->Amf3GppAccessRegistrationModification; + if (!Amf3GppAccessRegistrationModification) { + ogs_error("[%s] No Amf3GppAccessRegistrationModification", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No Amf3GppAccessRegistrationModification", udm_ue->supi)); + return false; + } + + Guami = Amf3GppAccessRegistrationModification->guami; + if (!Guami) { + ogs_error("[%s] No Guami", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No Guami", udm_ue->supi)); + return false; + } + + if (!Guami->amf_id) { + ogs_error("[%s] No Guami.AmfId", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No Guami.AmfId", udm_ue->supi)); + return false; + } + + if (!Guami->plmn_id) { + ogs_error("[%s] No PlmnId", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No PlmnId", udm_ue->supi)); + return false; + } + + if (!Guami->plmn_id->mnc) { + ogs_error("[%s] No PlmnId.Mnc", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No PlmnId.Mnc", udm_ue->supi)); + return false; + } + + if (!Guami->plmn_id->mcc) { + ogs_error("[%s] No PlmnId.Mcc", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + message, "No PlmnId.Mcc", udm_ue->supi)); + return false; + } + + /* TS 29.503: 5.3.2.4.2 AMF deregistration for 3GPP access + * 2a. The UDM shall check whether the received GUAMI matches the stored + * GUAMI. If so, the UDM shall set the PurgeFlag. The UDM responds with + * "204 No Content". + * 2b. Otherwise the UDM responds with "403 Forbidden". */ + ogs_sbi_parse_guami(&recv_guami, Guami); + if (memcmp(&recv_guami, &udm_ue->guami, sizeof(recv_guami)) != 0) { + ogs_error("[%s] Guami mismatch", udm_ue->supi); + ogs_assert(true == + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, + message, "Guami mismatch", udm_ue->supi)); + } + + + if (Amf3GppAccessRegistrationModification->is_purge_flag) { + udm_ue->amf_3gpp_access_registration->is_purge_flag = + Amf3GppAccessRegistrationModification->is_purge_flag; + udm_ue->amf_3gpp_access_registration->purge_flag = + Amf3GppAccessRegistrationModification->purge_flag; + } + + PatchItemList = OpenAPI_list_create(); + ogs_assert(PatchItemList); + + + if (Amf3GppAccessRegistrationModification->is_purge_flag) { + memset(&item, 0, sizeof(item)); + item.op = OpenAPI_patch_operation_replace; + item.path = (char *)"PurgeFlag"; + item.value = OpenAPI_any_type_create_bool( + Amf3GppAccessRegistrationModification->purge_flag); + ogs_assert(item.value); + + OpenAPI_list_add(PatchItemList, &item); + } + + ogs_assert(true == + udm_sbi_discover_and_send(OpenAPI_nf_type_UDR, udm_ue, stream, + PatchItemList, udm_nudr_dr_build_patch_amf_context)); + + return true; +} + bool udm_nudm_sdm_handle_subscription_provisioned( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { diff --git a/src/udm/nudm-handler.h b/src/udm/nudm-handler.h index c7a447e2e..c651f1b8e 100644 --- a/src/udm/nudm-handler.h +++ b/src/udm/nudm-handler.h @@ -33,6 +33,8 @@ bool udm_nudm_ueau_handle_result_confirmation_inform( bool udm_nudm_uecm_handle_registration( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); +bool udm_nudm_uecm_handle_registration_update( + udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message); bool udm_nudm_sdm_handle_subscription_provisioned( udm_ue_t *udm_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); diff --git a/src/udm/nudr-build.c b/src/udm/nudr-build.c index ee5b1ca9f..809aaa1c7 100644 --- a/src/udm/nudr-build.c +++ b/src/udm/nudr-build.c @@ -149,6 +149,50 @@ ogs_sbi_request_t *udm_nudr_dr_build_update_amf_context( return request; } +ogs_sbi_request_t *udm_nudr_dr_build_patch_amf_context( + udm_ue_t *udm_ue, void *data) +{ + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + OpenAPI_patch_item_t *pitem = NULL; + OpenAPI_lnode_t *node = NULL; + + OpenAPI_list_t *PatchItemList = (OpenAPI_list_t *)data; + + ogs_assert(udm_ue); + ogs_assert(PatchItemList); + + memset(&message, 0, sizeof(message)); + message.http.content_type = (char *)OGS_SBI_CONTENT_PATCH_TYPE; + message.h.method = (char *)OGS_SBI_HTTP_METHOD_PATCH; + message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NUDR_DR; + message.h.api.version = (char *)OGS_SBI_API_V1; + message.h.resource.component[0] = + (char *)OGS_SBI_RESOURCE_NAME_SUBSCRIPTION_DATA; + message.h.resource.component[1] = (char *)udm_ue->supi; + message.h.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_CONTEXT_DATA; + message.h.resource.component[3] = + (char *)OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS; + + message.PatchItemList = PatchItemList; + + request = ogs_sbi_build_request(&message); + ogs_assert(request); + + if (PatchItemList) { + OpenAPI_list_for_each(PatchItemList, node) { + pitem = node->data; + if (pitem) + OpenAPI_any_type_free(pitem->value); + } + OpenAPI_list_free(PatchItemList); + } + + return request; +} + ogs_sbi_request_t *udm_nudr_dr_build_query_subscription_provisioned( udm_ue_t *udm_ue, void *data) { diff --git a/src/udm/nudr-build.h b/src/udm/nudr-build.h index 7859c826b..a3b73f376 100644 --- a/src/udm/nudr-build.h +++ b/src/udm/nudr-build.h @@ -34,6 +34,8 @@ ogs_sbi_request_t *udm_nudr_dr_build_update_authentication_status( udm_ue_t *udm_ue, void *data); ogs_sbi_request_t *udm_nudr_dr_build_update_amf_context( udm_ue_t *udm_ue, void *data); +ogs_sbi_request_t *udm_nudr_dr_build_patch_amf_context( + udm_ue_t *udm_ue, void *data); #ifdef __cplusplus } diff --git a/src/udm/nudr-handler.c b/src/udm/nudr-handler.c index a7c9ea57b..14ec9008c 100644 --- a/src/udm/nudr-handler.c +++ b/src/udm/nudr-handler.c @@ -406,6 +406,34 @@ bool udm_nudr_dr_handle_subscription_context( return false; } + SWITCH(recvmsg->h.method) + CASE(OGS_SBI_HTTP_METHOD_PATCH) + SWITCH(recvmsg->h.resource.component[3]) + CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) + memset(&sendmsg, 0, sizeof(sendmsg)); + + response = ogs_sbi_build_response( + &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + return true; + + DEFAULT + strerror = ogs_msprintf("[%s] Invalid resource name [%s]", + udm_ue->supi, recvmsg->h.resource.component[3]); + ogs_assert(strerror); + + ogs_error("%s", strerror); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, strerror, NULL)); + ogs_free(strerror); + return false; + END + END + + SWITCH(recvmsg->h.resource.component[3]) CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) Amf3GppAccessRegistration = udm_ue->amf_3gpp_access_registration; diff --git a/src/udm/ue-sm.c b/src/udm/ue-sm.c index 7439875b0..3fcf2fe08 100644 --- a/src/udm/ue-sm.c +++ b/src/udm/ue-sm.c @@ -101,6 +101,21 @@ void udm_ue_state_operational(ogs_fsm_t *s, udm_event_t *e) udm_nudm_uecm_handle_registration(udm_ue, stream, message); break; + DEFAULT + ogs_error("[%s] Invalid resource name [%s]", + udm_ue->suci, message->h.resource.component[1]); + ogs_assert(true == + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, + "Invalid HTTP method", message->h.method)); + END + break; + CASE(OGS_SBI_HTTP_METHOD_PATCH) + SWITCH(message->h.resource.component[1]) + CASE(OGS_SBI_RESOURCE_NAME_REGISTRATIONS) + udm_nudm_uecm_handle_registration_update(udm_ue, stream, message); + break; + DEFAULT ogs_error("[%s] Invalid resource name [%s]", udm_ue->suci, message->h.resource.component[1]); diff --git a/src/udr/nudr-handler.c b/src/udr/nudr-handler.c index 684e51689..09a73d8de 100644 --- a/src/udr/nudr-handler.c +++ b/src/udr/nudr-handler.c @@ -303,6 +303,30 @@ bool udr_nudr_dr_handle_subscription_context( return true; + CASE(OGS_SBI_HTTP_METHOD_PATCH) + OpenAPI_list_t *PatchItemList; + + PatchItemList = recvmsg->PatchItemList; + if (!PatchItemList) { + ogs_error("[%s] No PatchItemList", supi); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No PatchItemList", supi)); + return false; + } + + /* TODO: parse PatchItemList */ + + memset(&sendmsg, 0, sizeof(sendmsg)); + + response = ogs_sbi_build_response( + &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); + ogs_assert(response); + ogs_assert(true == ogs_sbi_server_send_response(stream, response)); + + return true; + DEFAULT ogs_error("Invalid HTTP method [%s]", recvmsg->h.method); ogs_assert(true ==