From bb38c01229d58defb9207fcd0bb24185b53f5e71 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Sat, 3 Apr 2021 14:07:44 +0900 Subject: [PATCH] fix : Allow NSSAI in Registration accept (#910) Always Present Allow NSSAI in Registration accept --- configs/open5gs/amf.yaml.in | 4 - lib/app/ogs-context.c | 3 - lib/app/ogs-context.h | 1 - lib/core/ogs-3gpp-types.c | 8 -- src/amf/context.c | 142 ++++++++++++++++++++++++++++++++++++ src/amf/context.h | 4 +- src/amf/gmm-build.c | 28 +++---- src/amf/gmm-sm.c | 80 +++++++++++++++++++- src/amf/nudm-handler.c | 90 +---------------------- tests/slice/nssai-test.c | 67 +++++++++++++++++ 10 files changed, 302 insertions(+), 125 deletions(-) diff --git a/configs/open5gs/amf.yaml.in b/configs/open5gs/amf.yaml.in index fc2e9793e..add7cc66d 100644 --- a/configs/open5gs/amf.yaml.in +++ b/configs/open5gs/amf.yaml.in @@ -251,10 +251,6 @@ nrf: # o Prefer IPv4 instead of IPv6 for estabishing new GTP connections. # prefer_ipv4: true # -# o AMF ignores the UE Requested NSSAI and creates an allowed-NSSAI -# based on the Default S-NSSAI in the Subscription DB. -# ignore_requested_nssai: true -# parameter: # diff --git a/lib/app/ogs-context.c b/lib/app/ogs-context.c index 0144f3a1f..ee1f72404 100644 --- a/lib/app/ogs-context.c +++ b/lib/app/ogs-context.c @@ -351,9 +351,6 @@ int ogs_app_context_parse_config(void) parameter_key, "no_ipv4v6_local_addr_in_packet_filter")) { self.parameter.no_ipv4v6_local_addr_in_packet_filter = ogs_yaml_iter_bool(¶meter_iter); - } else if (!strcmp(parameter_key, "ignore_requested_nssai")) { - self.parameter.ignore_requested_nssai = - ogs_yaml_iter_bool(¶meter_iter); } else ogs_warn("unknown key `%s`", parameter_key); } diff --git a/lib/app/ogs-context.h b/lib/app/ogs-context.h index ac4867e39..85deb5ed1 100644 --- a/lib/app/ogs-context.h +++ b/lib/app/ogs-context.h @@ -75,7 +75,6 @@ typedef struct ogs_app_context_s { int use_openair; int no_ipv4v6_local_addr_in_packet_filter; - int ignore_requested_nssai; } parameter; struct { diff --git a/lib/core/ogs-3gpp-types.c b/lib/core/ogs-3gpp-types.c index 24370362e..2c7b3916a 100644 --- a/lib/core/ogs-3gpp-types.c +++ b/lib/core/ogs-3gpp-types.c @@ -537,14 +537,6 @@ ogs_slice_data_t *ogs_slice_find_by_s_nssai( } } - /* Compare Only SST if DefaultSingleNSSAI */ - for (i = 0; i < num_of_slice_data; i++) { - if (slice_data[i].default_indicator == true && - s_nssai->sst == slice_data[i].s_nssai.sst) { - return slice_data + i; - } - } - return NULL; } diff --git a/src/amf/context.c b/src/amf/context.c index 2e3d6756b..8b365479e 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -2018,3 +2018,145 @@ static bool check_smf_info_nr_tai( return false; } + +void amf_update_allowed_nssai(amf_ue_t *amf_ue) +{ + int i; + ogs_assert(amf_ue); + + /* + * TS23.501 + * + * 5.15.4 UE NSSAI configuration and NSSAI storage aspects + * 5.15.4.1 General + * 5.15.4.1.1 UE Network Slice configuration + * + * S-NSSAIs that the UE provides in the Requested NSSAI which are neither + * in the Allowed NSSAI nor provided as a rejected S-NSSAI, shall, by the + * UE, not be regarded as rejected, i.e. the UE may request to register + * these S-NSSAIs again next time the UE sends a Requested NSSAI + * + * 5.15.5 Detailed Operation Overview + * + * 5.15.5.2 Selection of a Serving AMF supporting the Network Slices + * 5.15.5.2.1 Registration to a set of Network Slices + * + * AMF checks whether it can serve all the S-NSSAI(s) from + * the Requested NSSAI present in the Subscribed S-NSSAIs + * (potentially using configuration for mapping S-NSSAI values + * between HPLMN and Serving PLMN), or all the S-NSSAI(s) marked + * as default in the Subscribed S-NSSAIs in the case that + * no Requested NSSAI was provided or none of the S-NSSAIs + * in the Requested NSSAI are permitted, + * i.e. do not match any of the Subscribed S-NSSAIs or not available + * at the current UE's Tracking Area (see clause 5.15.3). + * + * + * TS24.501 + * + * 4.6.2 Mobility management aspects + * 4.6.2.1 General + * + * The UE in NB-N1 mode does not include the requested NSSAI during + * the registration procedure if the 5GS registration type IE indicates + * "mobility registration updating", procedure is not initiated + * to change the slice(s) that the UE is currently registered to, + * and the UE is still in the current registration area. The AMF does not + * include the allowed NSSAI during a registration procedure with the 5GS + * registration type IE indicating "mobility registration updating" except + * if the allowed NSSAI has changed for the UE. The UE considers + * the last received allowed NSSAI as valid until the UE receives + * a new allowed NSSAI. + * + * 5.5.1.2.4 Initial registration accepted by the network + * + * The AMF shall include the allowed NSSAI for the current PLMN + * and shall include the mapped S-NSSAI(s) for the allowed NSSAI + * contained in the requested NSSAI from the UE if available, + * in the REGISTRATION ACCEPT message if the UE included + * the requested NSSAI in the REGISTRATION REQUEST message + * and the AMF allows one or more S-NSSAIs in the requested NSSAI. + * + * 8.2.7.5 Allowed NSSAI + * + * This IE shall be included: + * a) if: + * 1) one or more S-NSSAIs in the requested NSSAI of + * the REGISTRATION REQUEST message are allowed by the AMF + * for a network not supporting NSSAA; + * 2) one or more S-NSSAIs in the requested NSSAI of + * the REGISTRATION REQUEST message are not subject + * to network slice-specific authentication and authorization + * and are allowed by the AMF; or + * 3) the network slice-specific authentication and authorization + * has been successfully performed for one or more S-NSSAIs in + * the requested NSSAI of the REGISTRATION REQUEST message; or + * b) if: + * 1) the requested NSSAI was not included in the REGISTRATION + * REQUEST message or none of the requested NSSAI are allowed; + * 2) the network not supporting NSSAA has one or more subscribed + * S-NSSAIs marked as default that are available; or + * 3) the network has one or more subscribed S-NSSAIs marked + * as default which are not subject to network slice-specific + * authentication and authorization that are available. + */ + + amf_ue->allowed_nssai.num_of_s_nssai = 0; + amf_ue->rejected_nssai.num_of_s_nssai = 0; + + if (amf_ue->requested_nssai.num_of_s_nssai) { + for (i = 0; i < amf_ue->requested_nssai.num_of_s_nssai; i++) { + ogs_slice_data_t *slice = NULL; + ogs_nas_s_nssai_ie_t *requested = + &amf_ue->requested_nssai.s_nssai[i]; + ogs_nas_s_nssai_ie_t *allowed = + &amf_ue->allowed_nssai. + s_nssai[amf_ue->allowed_nssai.num_of_s_nssai]; + ogs_nas_rejected_s_nssai_t *rejected = + &amf_ue->rejected_nssai. + s_nssai[amf_ue->rejected_nssai.num_of_s_nssai]; + slice = ogs_slice_find_by_s_nssai( + amf_ue->slice, amf_ue->num_of_slice, + (ogs_s_nssai_t *)requested); + if (slice) { + allowed->sst = requested->sst; + allowed->sd.v = requested->sd.v; + allowed->mapped_hplmn_sst = requested->mapped_hplmn_sst; + allowed->mapped_hplmn_sd.v = requested->mapped_hplmn_sd.v; + + amf_ue->allowed_nssai.num_of_s_nssai++; + + } else { + rejected->sst = requested->sst; + rejected->sd.v = requested->sd.v; + + if (rejected->sd.v != OGS_S_NSSAI_NO_SD_VALUE) + rejected->length_of_rejected_s_nssai = 4; + else + rejected->length_of_rejected_s_nssai = 1; + + rejected->cause_value = + OGS_NAS_REJECTED_S_NSSAI_NOT_AVIALABLE_IN_PLMN; + + amf_ue->rejected_nssai.num_of_s_nssai++; + } + } + } + + if (!amf_ue->allowed_nssai.num_of_s_nssai) { + for (i = 0; i < amf_ue->num_of_slice; i++) { + ogs_slice_data_t *slice = &amf_ue->slice[i]; + ogs_nas_s_nssai_ie_t *allowed = + &amf_ue->allowed_nssai.s_nssai[i]; + + if (slice->default_indicator == true) { + allowed->sst = slice->s_nssai.sst; + allowed->sd.v = slice->s_nssai.sd.v; + allowed->mapped_hplmn_sst = 0; + allowed->mapped_hplmn_sd.v = OGS_S_NSSAI_NO_SD_VALUE; + + amf_ue->allowed_nssai.num_of_s_nssai++; + } + } + } +} diff --git a/src/amf/context.h b/src/amf/context.h index a52192943..5e246245a 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -279,8 +279,6 @@ struct amf_ue_s { ogs_nas_s_nssai_ie_t s_nssai[OGS_MAX_NUM_OF_SLICE]; } requested_nssai, allowed_nssai; - bool allowed_nssai_present; - struct { int num_of_s_nssai; ogs_nas_rejected_s_nssai_t s_nssai[OGS_MAX_NUM_OF_SLICE]; @@ -712,6 +710,8 @@ uint8_t amf_selected_enc_algorithm(amf_ue_t *amf_ue); void amf_clear_subscribed_info(amf_ue_t *amf_ue); +void amf_update_allowed_nssai(amf_ue_t *amf_ue); + #ifdef __cplusplus } #endif diff --git a/src/amf/gmm-build.c b/src/amf/gmm-build.c index 579ce68d1..07a1d3dfd 100644 --- a/src/amf/gmm-build.c +++ b/src/amf/gmm-build.c @@ -102,25 +102,21 @@ ogs_pkbuf_t *gmm_build_registration_accept(amf_ue_t *amf_ue) &amf_self()->served_tai[served_tai_index].list2); /* Set Allowed NSSAI */ - if (amf_ue->allowed_nssai_present == true) { - ogs_assert(amf_ue->allowed_nssai.num_of_s_nssai); + ogs_assert(amf_ue->allowed_nssai.num_of_s_nssai); - ogs_nas_build_nssai(allowed_nssai, - amf_ue->allowed_nssai.s_nssai, - amf_ue->allowed_nssai.num_of_s_nssai); + ogs_nas_build_nssai(allowed_nssai, + amf_ue->allowed_nssai.s_nssai, + amf_ue->allowed_nssai.num_of_s_nssai); + registration_accept->presencemask |= + OGS_NAS_5GS_REGISTRATION_ACCEPT_ALLOWED_NSSAI_PRESENT; + + if (amf_ue->rejected_nssai.num_of_s_nssai) { + ogs_nas_build_rejected_nssai(rejected_nssai, + amf_ue->rejected_nssai.s_nssai, + amf_ue->rejected_nssai.num_of_s_nssai); registration_accept->presencemask |= - OGS_NAS_5GS_REGISTRATION_ACCEPT_ALLOWED_NSSAI_PRESENT; - - if (amf_ue->rejected_nssai.num_of_s_nssai) { - ogs_nas_build_rejected_nssai(rejected_nssai, - amf_ue->rejected_nssai.s_nssai, - amf_ue->rejected_nssai.num_of_s_nssai); - registration_accept->presencemask |= - OGS_NAS_5GS_REGISTRATION_ACCEPT_REJECTED_NSSAI_PRESENT; - } - - amf_ue->allowed_nssai_present = false; + OGS_NAS_5GS_REGISTRATION_ACCEPT_REJECTED_NSSAI_PRESENT; } /* 5GS network feature support */ diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index fa23ea7cf..72a6bf377 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -153,8 +153,46 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) break; } - if (amf_sess_xact_count(amf_ue) == xact_count) + if (amf_sess_xact_count(amf_ue) == xact_count) { + + amf_update_allowed_nssai(amf_ue); + + if (!amf_ue->allowed_nssai.num_of_s_nssai) { + int i; + + ogs_error("No Allowed-NSSAI"); + ogs_error(" Number of Subscribed S-NSSAI [%d]", + amf_ue->num_of_slice); + for (i = 0; i < amf_ue->num_of_slice; i++) { + ogs_slice_data_t *slice = &amf_ue->slice[i]; + if (slice->default_indicator == true) { + ogs_error( + " Default S_NSSAI[SST:%d SD:0x%x]", + slice->s_nssai.sst, slice->s_nssai.sd.v); + } else { + ogs_error( + " S_NSSAI[SST:%d SD:0x%x]", + slice->s_nssai.sst, slice->s_nssai.sd.v); + } + } + ogs_error(" Number of Requested NSSAI [%d]", + amf_ue->requested_nssai.num_of_s_nssai); + for (i = 0; i < amf_ue->requested_nssai. + num_of_s_nssai; i++) { + ogs_error(" PLMN_ID[MCC:%d MNC:%d]", + ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id), + ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id)); + ogs_error(" S_NSSAI[SST:%d SD:0x%x]", + amf_ue->requested_nssai.s_nssai[i].sst, + amf_ue->requested_nssai.s_nssai[i].sd.v); + } + + OGS_FSM_TRAN(s, gmm_state_exception); + break; + } + nas_5gs_send_registration_accept(amf_ue); + } OGS_FSM_TRAN(s, &gmm_state_registered); @@ -1086,8 +1124,46 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e) break; } - if (amf_sess_xact_count(amf_ue) == xact_count) + if (amf_sess_xact_count(amf_ue) == xact_count) { + + amf_update_allowed_nssai(amf_ue); + + if (!amf_ue->allowed_nssai.num_of_s_nssai) { + int i; + + ogs_error("No Allowed-NSSAI"); + ogs_error(" Number of Subscribed S-NSSAI [%d]", + amf_ue->num_of_slice); + for (i = 0; i < amf_ue->num_of_slice; i++) { + ogs_slice_data_t *slice = &amf_ue->slice[i]; + if (slice->default_indicator == true) { + ogs_error( + " Default S_NSSAI[SST:%d SD:0x%x]", + slice->s_nssai.sst, slice->s_nssai.sd.v); + } else { + ogs_error( + " S_NSSAI[SST:%d SD:0x%x]", + slice->s_nssai.sst, slice->s_nssai.sd.v); + } + } + ogs_error(" Number of Requested NSSAI [%d]", + amf_ue->requested_nssai.num_of_s_nssai); + for (i = 0; i < amf_ue->requested_nssai. + num_of_s_nssai; i++) { + ogs_error(" PLMN_ID[MCC:%d MNC:%d]", + ogs_plmn_id_mcc(&amf_ue->nr_tai.plmn_id), + ogs_plmn_id_mnc(&amf_ue->nr_tai.plmn_id)); + ogs_error(" S_NSSAI[SST:%d SD:0x%x]", + amf_ue->requested_nssai.s_nssai[i].sst, + amf_ue->requested_nssai.s_nssai[i].sd.v); + } + + OGS_FSM_TRAN(s, gmm_state_exception); + break; + } + nas_5gs_send_registration_accept(amf_ue); + } OGS_FSM_TRAN(s, &gmm_state_registered); diff --git a/src/amf/nudm-handler.c b/src/amf/nudm-handler.c index 597bca9a3..19dd59976 100644 --- a/src/amf/nudm-handler.c +++ b/src/amf/nudm-handler.c @@ -134,97 +134,9 @@ int amf_nudm_sdm_handle_provisioned( } } - /* - * TS23.501 - * - * 5.15.4 UE NSSAI configuration and NSSAI storage aspects - * 5.15.4.1 General - * 5.15.4.1.1 UE Network Slice configuration - * - * S-NSSAIs that the UE provides in the Requested NSSAI which are neither - * in the Allowed NSSAI nor provided as a rejected S-NSSAI, shall, by the - * UE, not be regarded as rejected, i.e. the UE may request to register - * these S-NSSAIs again next time the UE sends a Requested NSSAI - * - * 5.15.5 Detailed Operation Overview - * - * 5.15.5.2 Selection of a Serving AMF supporting the Network Slices - * 5.15.5.2.1 Registration to a set of Network Slices - * - * AMF checks whether it can serve all the S-NSSAI(s) from - * the Requested NSSAI present in the Subscribed S-NSSAIs - * (potentially using configuration for mapping S-NSSAI values - * between HPLMN and Serving PLMN), or all the S-NSSAI(s) marked - * as default in the Subscribed S-NSSAIs in the case that - * no Requested NSSAI was provided or none of the S-NSSAIs - * in the Requested NSSAI are permitted, - * i.e. do not match any of the Subscribed S-NSSAIs or not available - * at the current UE's Tracking Area (see clause 5.15.3). - */ - - amf_ue->allowed_nssai.num_of_s_nssai = 0; - amf_ue->rejected_nssai.num_of_s_nssai = 0; - - if (ogs_app()->parameter.ignore_requested_nssai == 0 && - amf_ue->requested_nssai.num_of_s_nssai) { - for (i = 0; i < amf_ue->requested_nssai.num_of_s_nssai; i++) { - ogs_slice_data_t *slice = NULL; - ogs_nas_s_nssai_ie_t *requested = - &amf_ue->requested_nssai.s_nssai[i]; - ogs_nas_s_nssai_ie_t *allowed = - &amf_ue->allowed_nssai. - s_nssai[amf_ue->allowed_nssai.num_of_s_nssai]; - ogs_nas_rejected_s_nssai_t *rejected = - &amf_ue->rejected_nssai. - s_nssai[amf_ue->rejected_nssai.num_of_s_nssai]; - slice = ogs_slice_find_by_s_nssai( - amf_ue->slice, amf_ue->num_of_slice, - (ogs_s_nssai_t *)requested); - if (slice) { - allowed->sst = requested->sst; - allowed->sd.v = requested->sd.v; - allowed->mapped_hplmn_sst = requested->mapped_hplmn_sst; - allowed->mapped_hplmn_sd.v = requested->mapped_hplmn_sd.v; - - amf_ue->allowed_nssai.num_of_s_nssai++; - - } else { - rejected->sst = requested->sst; - rejected->sd.v = requested->sd.v; - - if (rejected->sd.v != OGS_S_NSSAI_NO_SD_VALUE) - rejected->length_of_rejected_s_nssai = 4; - else - rejected->length_of_rejected_s_nssai = 1; - - rejected->cause_value = - OGS_NAS_REJECTED_S_NSSAI_NOT_AVIALABLE_IN_PLMN; - - amf_ue->rejected_nssai.num_of_s_nssai++; - } - } - } + amf_update_allowed_nssai(amf_ue); if (!amf_ue->allowed_nssai.num_of_s_nssai) { - for (i = 0; i < amf_ue->num_of_slice; i++) { - ogs_slice_data_t *slice = &amf_ue->slice[i]; - ogs_nas_s_nssai_ie_t *allowed = - &amf_ue->allowed_nssai.s_nssai[i]; - - if (slice->default_indicator == true) { - allowed->sst = slice->s_nssai.sst; - allowed->sd.v = slice->s_nssai.sd.v; - allowed->mapped_hplmn_sst = 0; - allowed->mapped_hplmn_sd.v = OGS_S_NSSAI_NO_SD_VALUE; - - amf_ue->allowed_nssai.num_of_s_nssai++; - } - } - } - - if (amf_ue->allowed_nssai.num_of_s_nssai) { - amf_ue->allowed_nssai_present = true; - } else { ogs_error("No Allowed-NSSAI"); ogs_error(" Number of Subscribed S-NSSAI [%d]", amf_ue->num_of_slice); diff --git a/tests/slice/nssai-test.c b/tests/slice/nssai-test.c index 0b6be0967..93856e902 100644 --- a/tests/slice/nssai-test.c +++ b/tests/slice/nssai-test.c @@ -247,6 +247,73 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send Registration request : Uplink Data Status */ + test_ue->registration_request_param.integrity_protected = 0; + test_ue->registration_request_param.guti = 1; + test_ue->registration_request_param.gmm_capability = 1; + + test_ue->registration_request_param.requested_nssai = 1; + test_ue->requested_nssai.s_nssai[2].sd.v = 0x000006; + + test_ue->registration_request_param.last_visited_registered_tai = 1; + test_ue->registration_request_param.ue_usage_setting = 1; + test_ue->registration_request_param.update_type = 1; + nasbuf = testgmm_build_registration_request(test_ue, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->registration_request_param.integrity_protected = 1; + test_ue->registration_request_param.guti = 1; + test_ue->registration_request_param.gmm_capability = 0; + test_ue->registration_request_param.requested_nssai = 0; + test_ue->registration_request_param.last_visited_registered_tai = 0; + test_ue->registration_request_param.ue_usage_setting = 0; + test_ue->registration_request_param.update_type = 0; + gmmbuf = testgmm_build_registration_request(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + ogs_msleep(300); /********** Remove Subscriber in Database */