From 33960bbb66b4ea2b5d36c2302e34cf2818deedea Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Thu, 26 Dec 2024 14:36:00 +0900 Subject: [PATCH] [NRF] Implemented PLMN list update handling in nrf_nnrf_handle_nf_update (#3566) - Added functionality to parse and validate the plmnList JSON array during a PATCH request. - Updated the nf_instance structure with new PLMN data from the request. - Ensured robust error handling for invalid PLMN entries and excessive PLMN counts. - Responded with appropriate HTTP status codes for success and error scenarios. --- lib/sbi/conv.c | 29 ++++++++ lib/sbi/conv.h | 2 + lib/sbi/message.h | 1 + src/nrf/nnrf-handler.c | 159 +++++++++++++++++++++++++++++++++++++++-- 4 files changed, 185 insertions(+), 6 deletions(-) diff --git a/lib/sbi/conv.c b/lib/sbi/conv.c index acbcbf7e5..8e133a4dd 100644 --- a/lib/sbi/conv.c +++ b/lib/sbi/conv.c @@ -1205,6 +1205,35 @@ void ogs_sbi_free_plmn_list(OpenAPI_list_t *PlmnList) OpenAPI_list_free(PlmnList); } +/** + * Compares an ogs_plmn_id_t structure with an OpenAPI_plmn_id_t structure. + * + * @param plmn_list The PLMN-ID in ogs_plmn_id_t format. + * @param PlmnList The PLMN-ID in OpenAPI_plmn_id_t format. + * @return true if the PLMN-IDs are equal; otherwise, false. + */ +bool ogs_sbi_compare_plmn_list( + ogs_plmn_id_t *plmn_id, OpenAPI_plmn_id_t *PlmnId) +{ + ogs_plmn_id_t temp_plmn_id; + + ogs_assert(plmn_id); + ogs_assert(PlmnId); + ogs_assert(PlmnId->mcc); + ogs_assert(PlmnId->mnc); + + /* Convert OpenAPI_plmn_id_t to ogs_plmn_id_t */ + ogs_sbi_parse_plmn_id(&temp_plmn_id, PlmnId); + + /* Compare MCC and MNC values */ + if (ogs_plmn_id_mcc(plmn_id) == ogs_plmn_id_mcc(&temp_plmn_id) && + ogs_plmn_id_mnc(plmn_id) == ogs_plmn_id_mnc(&temp_plmn_id)) { + return true; + } + + return false; +} + OpenAPI_plmn_id_nid_t *ogs_sbi_build_plmn_id_nid(ogs_plmn_id_t *plmn_id) { OpenAPI_plmn_id_nid_t *PlmnIdNid = NULL; diff --git a/lib/sbi/conv.h b/lib/sbi/conv.h index dc01e3069..6a7d055f7 100644 --- a/lib/sbi/conv.h +++ b/lib/sbi/conv.h @@ -98,6 +98,8 @@ OpenAPI_list_t *ogs_sbi_build_plmn_list( int ogs_sbi_parse_plmn_list( ogs_plmn_id_t *plmn_list, OpenAPI_list_t *PlmnList); void ogs_sbi_free_plmn_list(OpenAPI_list_t *PlmnList); +bool ogs_sbi_compare_plmn_list( + ogs_plmn_id_t *plmn_id, OpenAPI_plmn_id_t *PlmnId); OpenAPI_plmn_id_nid_t *ogs_sbi_build_plmn_id_nid(ogs_plmn_id_t *plmn_id); bool ogs_sbi_parse_plmn_id_nid( diff --git a/lib/sbi/message.h b/lib/sbi/message.h index c41d01e8a..e303862e6 100644 --- a/lib/sbi/message.h +++ b/lib/sbi/message.h @@ -150,6 +150,7 @@ extern "C" { #define OGS_SBI_PATCH_PATH_NF_STATUS "/nfStatus" #define OGS_SBI_PATCH_PATH_LOAD "/load" +#define OGS_SBI_PATCH_PATH_PLMN_LIST "/plmnList" #define OGS_SBI_PATCH_PATH_VALIDITY_TIME "/validityTime" diff --git a/src/nrf/nnrf-handler.c b/src/nrf/nnrf-handler.c index c77e18781..d82a5040d 100644 --- a/src/nrf/nnrf-handler.c +++ b/src/nrf/nnrf-handler.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019-2023 by Sukchan Lee + * Copyright (C) 2019-2024 by Sukchan Lee * * This file is part of Open5GS. * @@ -25,6 +25,15 @@ static int discover_handler( static void handle_nf_discover_search_result( OpenAPI_search_result_t *SearchResult); +/** + * Handles NF registration in NRF. Validates the PLMN-ID against configured + * serving PLMN-IDs and registers the NF instance if valid. + * + * @param nf_instance The NF instance being registered. + * @param stream The SBI stream for communication. + * @param recvmsg The received SBI message. + * @return true if registration is successful; otherwise, false. + */ bool nrf_nnrf_handle_nf_register(ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { @@ -33,6 +42,10 @@ bool nrf_nnrf_handle_nf_register(ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_profile_t *NFProfile = NULL; + OpenAPI_lnode_t *node = NULL; + bool plmn_valid = false; + int i; + ogs_assert(nf_instance); ogs_assert(stream); ogs_assert(recvmsg); @@ -73,6 +86,41 @@ bool nrf_nnrf_handle_nf_register(ogs_sbi_nf_instance_t *nf_instance, return false; } + /* Validate the PLMN-ID against configured serving PLMN-IDs */ + if (NFProfile->plmn_list) { + /* Set PLMN status to invalid */ + plmn_valid = false; + + if (ogs_local_conf()->num_of_serving_plmn_id > 0 && NFProfile->plmn_list) { + OpenAPI_list_for_each(NFProfile->plmn_list, node) { + OpenAPI_plmn_id_t *PlmnId = node->data; + if (PlmnId == NULL) { + continue; + } + for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { + if (ogs_sbi_compare_plmn_list( + &ogs_local_conf()->serving_plmn_id[i], + PlmnId) == true) { + plmn_valid = true; + break; + } + } + if (plmn_valid) { + break; + } + } + } + + /* Reject the registration if PLMN-ID is invalid */ + if (!plmn_valid) { + ogs_error("PLMN-ID in NFProfile is not allowed"); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, + "PLMN-ID not allowed", NULL, NULL)); + return false; + } + } + ogs_nnrf_nfm_handle_nf_profile(nf_instance, NFProfile); ogs_sbi_client_associate(nf_instance); @@ -146,7 +194,6 @@ bool nrf_nnrf_handle_nf_register(ogs_sbi_nf_instance_t *nf_instance, if (ogs_local_conf()->num_of_serving_plmn_id && NFProfile->plmn_list == NULL) { OpenAPI_list_t *PlmnIdList = NULL; - int i; PlmnIdList = OpenAPI_list_create(); ogs_assert(PlmnIdList); @@ -208,6 +255,10 @@ bool nrf_nnrf_handle_nf_update(ogs_sbi_nf_instance_t *nf_instance, ogs_assert(stream); ogs_assert(recvmsg); + cJSON *plmn_array = NULL, *plmn_item = NULL; + bool plmn_valid = false; + int i; + SWITCH(recvmsg->h.method) CASE(OGS_SBI_HTTP_METHOD_PUT) return nrf_nnrf_handle_nf_register( @@ -224,14 +275,14 @@ bool nrf_nnrf_handle_nf_update(ogs_sbi_nf_instance_t *nf_instance, return false; } + /* Iterate through the PatchItemList */ OpenAPI_list_for_each(PatchItemList, node) { OpenAPI_patch_item_t *patch_item = node->data; if (!patch_item) { ogs_error("No PatchItem"); - ogs_assert(true == - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, - recvmsg, "No PatchItem", NULL, NULL)); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, + "No PatchItem", NULL, NULL)); return false; } @@ -246,6 +297,102 @@ bool nrf_nnrf_handle_nf_update(ogs_sbi_nf_instance_t *nf_instance, break; CASE(OGS_SBI_PATCH_PATH_LOAD) break; + CASE(OGS_SBI_PATCH_PATH_PLMN_LIST) + /* Ensure the value is not null and is a valid JSON array */ + if (patch_item->value && patch_item->value->json) { + /* Set PLMN status to invalid */ + plmn_valid = false; + + plmn_array = patch_item->value->json; + if (!cJSON_IsArray(plmn_array)) { + ogs_error("Value for /plmnList is not a JSON array"); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, + "Invalid value for /plmnList", NULL, NULL)); + return false; + } + + /* Clear existing PLMN data in nf_instance */ + memset(nf_instance->plmn_id, 0, + sizeof(nf_instance->plmn_id)); + nf_instance->num_of_plmn_id = 0; + + /* Iterate through the JSON array of PLMN IDs */ + cJSON_ArrayForEach(plmn_item, plmn_array) { + OpenAPI_plmn_id_t plmn_id; + memset(&plmn_id, 0, sizeof(plmn_id)); + + if (nf_instance->num_of_plmn_id >= + OGS_ARRAY_SIZE(nf_instance->plmn_id)) { + ogs_error("Exceeded maximum number of PLMN IDs"); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, + "Too many PLMN IDs", NULL, NULL)); + return false; + } + + /* Parse the PLMN item */ + plmn_id.mcc = cJSON_GetObjectItem(plmn_item, "mcc") + ? cJSON_GetStringValue( + cJSON_GetObjectItem( + plmn_item, "mcc")) + : NULL; + plmn_id.mnc = cJSON_GetObjectItem(plmn_item, "mnc") + ? cJSON_GetStringValue( + cJSON_GetObjectItem( + plmn_item, "mnc")) + : NULL; + + if (!plmn_id.mcc || !plmn_id.mnc) { + ogs_error( + "Invalid PLMN item in /plmnList update"); + ogs_assert(true == + ogs_sbi_server_send_error( + stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, + "Invalid PLMN item", NULL, + NULL)); + return false; + } + + /* + * Convert OpenAPI_plmn_id_t to ogs_plmn_id_t + * and store in nf_instance + */ + ogs_sbi_parse_plmn_id( + &nf_instance-> + plmn_id[nf_instance->num_of_plmn_id], + &plmn_id); + nf_instance->num_of_plmn_id++; + + /* Compare with the serving PLMN list */ + for (i = 0; + i < ogs_local_conf()->num_of_serving_plmn_id; + i++) { + if (ogs_sbi_compare_plmn_list( + &ogs_local_conf()->serving_plmn_id[i], + &plmn_id) == true) { + plmn_valid = true; + break; + } + } + if (plmn_valid) { + break; + } + } + + /* Reject the update if PLMN-ID is invalid */ + if (!plmn_valid) { + ogs_error("PLMN-ID in NFProfile update is not allowed"); + ogs_assert(true == ogs_sbi_server_send_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, + "PLMN-ID not allowed", NULL, NULL)); + return false; + } + } + break; DEFAULT ogs_error("Unknown PatchItem.Path [%s]", patch_item->path); END