From 3b043b082a76f3bee33c3aa94cc0b2483f99383d Mon Sep 17 00:00:00 2001 From: mitmitmitm Date: Wed, 23 Nov 2022 12:45:34 +0100 Subject: [PATCH] [AMF] Handle am-data/ratRestrictions change notification When such a notification arrives from UDM, delete the corresponding SDM subscription from the UDM and deregister the UE if it becomes RAT restricted. --- src/amf/context.c | 21 ++++ src/amf/context.h | 2 + src/amf/gmm-handler.c | 5 + src/amf/namf-handler.c | 217 +++++++++++++++++++++++++++++++---------- src/amf/nudm-handler.c | 14 +++ 5 files changed, 207 insertions(+), 52 deletions(-) diff --git a/src/amf/context.c b/src/amf/context.c index 064a3cb8a..e931dc955 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -1325,6 +1325,8 @@ amf_ue_t *amf_ue_add(ran_ue_t *ran_ue) OGS_SBI_FEATURES_SET(amf_ue->am_policy_control_features, OGS_SBI_NPCF_AM_POLICY_CONTROL_UE_AMBR_AUTHORIZATION); + amf_ue->rat_restrictions = OpenAPI_list_create(); + ogs_list_init(&amf_ue->sess_list); /* Initialization */ @@ -1362,6 +1364,8 @@ void amf_ue_remove(amf_ue_t *amf_ue) /* Clear 5GSM Message */ AMF_UE_CLEAR_5GSM_MESSAGE(amf_ue); + OpenAPI_list_free(amf_ue->rat_restrictions); + /* Remove all session context */ amf_sess_remove_all(amf_ue); @@ -2519,3 +2523,20 @@ bool amf_update_allowed_nssai(amf_ue_t *amf_ue) return true; } + +bool amf_ue_is_rat_restricted(amf_ue_t *amf_ue) +{ + OpenAPI_lnode_t *node = NULL; + OpenAPI_rat_type_e rat; + + ogs_assert(amf_ue); + + rat = amf_ue_rat_type(amf_ue); + + OpenAPI_list_for_each(amf_ue->rat_restrictions, node) { + if (node->data == (void *)rat) { + return true; + } + } + return false; +} diff --git a/src/amf/context.h b/src/amf/context.h index b29ea9a28..a87fed43e 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -337,6 +337,7 @@ struct amf_ue_s { /* SubscribedInfo */ ogs_bitrate_t ue_ambr; int num_of_slice; + OpenAPI_list_t *rat_restrictions; ogs_slice_data_t slice[OGS_MAX_NUM_OF_SLICE]; uint64_t am_policy_control_features; /* SBI Features */ @@ -777,6 +778,7 @@ uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue); void amf_clear_subscribed_info(amf_ue_t *amf_ue); bool amf_update_allowed_nssai(amf_ue_t *amf_ue); +bool amf_ue_is_rat_restricted(amf_ue_t *amf_ue); #ifdef __cplusplus } diff --git a/src/amf/gmm-handler.c b/src/amf/gmm-handler.c index a263180f7..ce857c977 100644 --- a/src/amf/gmm-handler.c +++ b/src/amf/gmm-handler.c @@ -273,6 +273,11 @@ ogs_nas_5gmm_cause_t gmm_handle_registration_request(amf_ue_t *amf_ue, return OGS_5GMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; } + if (amf_ue_is_rat_restricted(amf_ue)) { + ogs_error("Registration rejected due to RAT restrictions"); + return OGS_5GMM_CAUSE_5GS_SERVICES_NOT_ALLOWED; + } + return OGS_5GMM_CAUSE_REQUEST_ACCEPTED; } diff --git a/src/amf/namf-handler.c b/src/amf/namf-handler.c index c8ac83b33..c49477399 100644 --- a/src/amf/namf-handler.c +++ b/src/amf/namf-handler.c @@ -510,6 +510,40 @@ cleanup: return OGS_OK; } +static int network_deregister ( + amf_ue_t *amf_ue, OpenAPI_deregistration_reason_e dereg_reason) { + if ((CM_CONNECTED(amf_ue)) && + (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered))) + { + amf_ue->network_initiated_de_reg = true; + + ogs_assert(OGS_OK == + nas_5gs_send_de_registration_request(amf_ue, dereg_reason)); + + amf_sbi_send_release_all_sessions( + amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + + if ((ogs_list_count(&amf_ue->sess_list) == 0) && + (PCF_AM_POLICY_ASSOCIATED(amf_ue))) + { + ogs_assert(true == + amf_ue_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL, NULL, + amf_npcf_am_policy_control_build_delete, amf_ue, NULL)); + } + + OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_de_registered); + return OGS_OK; + } + else if (CM_IDLE(amf_ue)) { + /* TODO: need to page UE */ + /*ngap_send_paging(amf_ue);*/ + return OGS_OK; + } else { + return OGS_ERROR; + } +} + int amf_namf_callback_handle_dereg_notify( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { @@ -565,38 +599,12 @@ int amf_namf_callback_handle_dereg_notify( * session associated with non-emergency service as described in clause 4.3.4. */ - - if ((CM_CONNECTED(amf_ue)) && - (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered))) - { - amf_ue->network_initiated_de_reg = true; - - ogs_assert(OGS_OK == - nas_5gs_send_de_registration_request(amf_ue, - DeregistrationData->dereg_reason)); - - amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); - - if ((ogs_list_count(&amf_ue->sess_list) == 0) && - (PCF_AM_POLICY_ASSOCIATED(amf_ue))) - { - ogs_assert(true == - amf_ue_sbi_discover_and_send( - OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL, NULL, - amf_npcf_am_policy_control_build_delete, amf_ue, NULL)); - } - - 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);*/ - } - else { - status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; - ogs_error("[%s] Deregistration notification for UE in wrong state", amf_ue->supi); - goto cleanup; + if (network_deregister( + amf_ue, DeregistrationData->dereg_reason) == -1) { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + ogs_error("[%s] Deregistration notification for UE in wrong state", + amf_ue->supi); + goto cleanup; } cleanup: @@ -609,6 +617,114 @@ cleanup: return OGS_OK; } +static int update_rat_res_add_one(cJSON *restriction, + OpenAPI_list_t *restrictions, long index) +{ + void *restr; + + if (!cJSON_IsString(restriction)) { + ogs_error("Invalid type of ratRestriction element"); + return OGS_ERROR; + } + + restr = (void *) OpenAPI_rat_type_FromString(cJSON_GetStringValue(restriction)); + + if (index == restrictions->count) { + OpenAPI_list_add(restrictions, restr); + } else if (restrictions->count < index && index <= 0) { + OpenAPI_list_insert_prev( + restrictions, OpenAPI_list_find(restrictions, index), restr); + } else { + ogs_error("Can't add RAT restriction to invalid index"); + return OGS_ERROR; + } + return OGS_OK; +} + +static int update_rat_res_array(cJSON *json_restrictions, + OpenAPI_list_t *restrictions) +{ + cJSON *restriction; + + if (!cJSON_IsArray(json_restrictions)) { + ogs_error("Invalid type of ratRestrictions"); + return OGS_ERROR; + } + + OpenAPI_list_clear(restrictions); + + cJSON_ArrayForEach(restriction, json_restrictions) { + if (update_rat_res_add_one(restriction, restrictions, + restrictions->count) != OGS_OK) { + return OGS_ERROR; + } + } + return OGS_OK; +} + +static int update_rat_res(OpenAPI_change_item_t *item_change, + OpenAPI_list_t *restrictions) +{ + cJSON* json = item_change->new_value->json; + cJSON* json_restrictions; + + if (!item_change->path) { + return OGS_ERROR; + } + + switch (item_change->op) { + case OpenAPI_change_type_REPLACE: + case OpenAPI_change_type_ADD: + if (!strcmp(item_change->path, "")) { + if (!cJSON_IsObject(json)) { + ogs_error("Invalid type of am-data"); + } + json_restrictions = cJSON_GetObjectItemCaseSensitive( + json, "ratRestrictions"); + if (json_restrictions) { + return update_rat_res_array(json_restrictions, restrictions); + } else { + return OGS_OK; + } + } else if (!strcmp(item_change->path, "/ratRestrictions")) { + return update_rat_res_array(json, restrictions); + } else if (strstr(item_change->path, "/ratRestrictions/") == + item_change->path) { + char *index = item_change->path + strlen("/ratRestrictions/"); + long i = strcmp(index, "-") ? atol(index) : restrictions->count; + + return update_rat_res_add_one(json, restrictions, i); + } + return OGS_OK; + + case OpenAPI_change_type__REMOVE: + if (!strcmp(item_change->path, "")) { + OpenAPI_list_clear(restrictions); + return OGS_OK; + } else if (!strcmp(item_change->path, "/ratRestrictions")) { + OpenAPI_list_clear(restrictions); + return OGS_OK; + } else if (strstr(item_change->path, "/ratRestrictions/") == + item_change->path) { + char *index = item_change->path + strlen("/ratRestrictions/"); + long i = atol(index); + + if (restrictions->count < i && i <= 0) { + OpenAPI_list_remove( + restrictions, OpenAPI_list_find(restrictions, i)); + } else { + ogs_error("Can't add RAT restriction to invalid index"); + return OGS_ERROR; + } + } + return OGS_OK; + + default: + return OGS_OK; + } + +} + int amf_namf_callback_handle_sdm_data_change_notify( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { @@ -669,27 +785,11 @@ int amf_namf_callback_handle_sdm_data_change_notify( OpenAPI_list_for_each(item->changes, node_ci) { - /* - OpenAPI_change_item_t *item_change = node_ci->data; - item_change->path; - item_change->from; - item_change->new_value; - item_change->orig_value; - */ - /* - switch (item_change->op) { - case OpenAPI_change_type_ADD: - break; - case OpenAPI_change_type_MOVE: - break; - case OpenAPI_change_type__REMOVE: - break; - case OpenAPI_change_type_REPLACE: - break; - default: - break; + OpenAPI_change_item_t *change_item = node_ci->data; + if (update_rat_res(change_item, amf_ue->rat_restrictions)) { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + goto cleanup; } - */ } break; DEFAULT @@ -705,6 +805,19 @@ int amf_namf_callback_handle_sdm_data_change_notify( res_name = NULL; } + if (amf_ue_is_rat_restricted(amf_ue)) { + if (network_deregister(amf_ue, OpenAPI_deregistration_reason_REREGISTRATION_REQUIRED) == -1) { + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + ogs_error("[%s] Deregistration notification for UE in wrong state", + amf_ue->supi); + goto cleanup; + } + ogs_assert(true == + amf_ue_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL, + amf_nudm_sdm_build_subscription_delete, amf_ue, NULL)); + } + cleanup: if (ueid) ogs_free(ueid); diff --git a/src/amf/nudm-handler.c b/src/amf/nudm-handler.c index 3751b5992..76e60399d 100644 --- a/src/amf/nudm-handler.c +++ b/src/amf/nudm-handler.c @@ -39,6 +39,8 @@ int amf_nudm_sdm_handle_provisioned( recvmsg->AccessAndMobilitySubscriptionData->subscribed_ue_ambr; OpenAPI_nssai_t *NSSAI = recvmsg->AccessAndMobilitySubscriptionData->nssai; + OpenAPI_list_t *RatRestrictions = + recvmsg->AccessAndMobilitySubscriptionData->rat_restrictions; OpenAPI_lnode_t *node = NULL; @@ -132,6 +134,13 @@ int amf_nudm_sdm_handle_provisioned( } } } + + OpenAPI_list_clear(amf_ue->rat_restrictions); + if (RatRestrictions) { + OpenAPI_list_for_each(RatRestrictions, node) { + OpenAPI_list_add(amf_ue->rat_restrictions, node->data); + } + } } if (amf_update_allowed_nssai(amf_ue) == false) { @@ -139,6 +148,11 @@ int amf_nudm_sdm_handle_provisioned( return OGS_ERROR; } + if (amf_ue_is_rat_restricted(amf_ue)) { + ogs_error("Registration rejected due to RAT restrictions"); + return OGS_ERROR; + } + ogs_assert(true == amf_ue_sbi_discover_and_send( OGS_SBI_SERVICE_TYPE_NUDM_SDM, NULL,