[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.
This commit is contained in:
Sukchan Lee
2024-12-26 14:36:00 +09:00
parent 2ce9f2b27e
commit 33960bbb66
4 changed files with 185 additions and 6 deletions

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 by Sukchan Lee <acetcom@gmail.com>
* Copyright (C) 2019-2024 by Sukchan Lee <acetcom@gmail.com>
*
* 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