[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.
This commit is contained in:
mitmitmitm 2022-11-23 12:45:34 +01:00 committed by Sukchan Lee
parent 3870216a6b
commit 3b043b082a
5 changed files with 207 additions and 52 deletions

View File

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

View File

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

View File

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

View File

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

View File

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