From 76978f0d14b9af8983cdf5b8fba373b993b8abc5 Mon Sep 17 00:00:00 2001 From: Francisco Date: Wed, 14 Apr 2021 11:37:38 +0100 Subject: [PATCH] s1ap - simplified erab release procedure --- lib/include/srsran/asn1/s1ap_utils.h | 19 +++ .../srsran/interfaces/enb_rrc_interfaces.h | 15 ++- lib/src/asn1/CMakeLists.txt | 2 +- lib/src/asn1/s1ap_utils.cc | 33 ++++++ srsenb/hdr/stack/rrc/rrc.h | 6 +- srsenb/hdr/stack/rrc/rrc_bearer_cfg.h | 2 +- srsenb/hdr/stack/rrc/rrc_ue.h | 2 +- srsenb/hdr/stack/upper/s1ap.h | 9 +- srsenb/src/stack/rrc/rrc.cc | 21 ++-- srsenb/src/stack/rrc/rrc_bearer_cfg.cc | 6 +- srsenb/src/stack/rrc/rrc_ue.cc | 2 +- srsenb/src/stack/upper/s1ap.cc | 109 +++++++++--------- srsenb/test/common/dummy_classes.h | 7 +- 13 files changed, 146 insertions(+), 87 deletions(-) create mode 100644 lib/src/asn1/s1ap_utils.cc diff --git a/lib/include/srsran/asn1/s1ap_utils.h b/lib/include/srsran/asn1/s1ap_utils.h index d9e3376e4..d2c246c4b 100644 --- a/lib/include/srsran/asn1/s1ap_utils.h +++ b/lib/include/srsran/asn1/s1ap_utils.h @@ -49,6 +49,25 @@ using bearers_subject_to_status_transfer_list_l = using rrc_establishment_cause_e = enumerated; using cause_radio_network_e = enumerated; +/************************** + * S1AP Obj Id + *************************/ + +template +uint32_t get_obj_id(const T& obj); + +template +bool lower_obj_id(const T& lhs, const T& rhs) +{ + return get_obj_id(lhs) < get_obj_id(rhs); +} + +template +bool equal_obj_id(const T& lhs, const T& rhs) +{ + return get_obj_id(lhs) == get_obj_id(rhs); +} + } // namespace s1ap } // namespace asn1 diff --git a/lib/include/srsran/interfaces/enb_rrc_interfaces.h b/lib/include/srsran/interfaces/enb_rrc_interfaces.h index dd4141798..c3a316a87 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/enb_rrc_interfaces.h @@ -33,13 +33,18 @@ public: virtual void modify_erabs(uint16_t rnti, srsran::const_span erabs_to_modify) = 0; - virtual bool has_erab(uint16_t rnti, uint32_t erab_id) const = 0; - virtual bool release_erabs(uint32_t rnti) = 0; - virtual void release_erabs(uint32_t rnti, - srsran::const_span erabs_to_release, - const asn1::unbounded_octstring* nas_pdu) = 0; + virtual bool has_erab(uint16_t rnti, uint32_t erab_id) const = 0; + virtual bool release_erabs(uint32_t rnti) = 0; + /** + * Release E-RAB id + * @return error if E-RAB id or rnti were not found + */ + virtual int release_erab(uint16_t rnti, uint16_t erab_id) = 0; virtual void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& ue_paging_id) = 0; + /// Notify UE of ERAB updates (done via RRC Reconfiguration Message) + virtual int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring* nas_pdu) = 0; + /** * Reports the reception of S1 HandoverCommand / HandoverPreparationFailure or abnormal conditions during * S1 Handover preparation back to RRC. diff --git a/lib/src/asn1/CMakeLists.txt b/lib/src/asn1/CMakeLists.txt index 95c602e7d..d99b61f27 100644 --- a/lib/src/asn1/CMakeLists.txt +++ b/lib/src/asn1/CMakeLists.txt @@ -46,7 +46,7 @@ INSTALL(TARGETS rrc_asn1 DESTINATION ${LIBRARY_DIR}) # S1AP ASN1 lib add_library(s1ap_asn1 STATIC - s1ap.cc) + s1ap.cc s1ap_utils.cc) target_compile_options(s1ap_asn1 PRIVATE "-Os") target_link_libraries(s1ap_asn1 asn1_utils srsran_common) INSTALL(TARGETS s1ap_asn1 DESTINATION ${LIBRARY_DIR}) diff --git a/lib/src/asn1/s1ap_utils.cc b/lib/src/asn1/s1ap_utils.cc new file mode 100644 index 000000000..c2e5ed277 --- /dev/null +++ b/lib/src/asn1/s1ap_utils.cc @@ -0,0 +1,33 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/asn1/s1ap_utils.h" +#include "srsran/asn1/s1ap.h" + +namespace asn1 { +namespace s1ap { + +template <> +uint32_t get_obj_id(const erab_item_s& obj) +{ + return obj.erab_id; +} + +template <> +uint32_t get_obj_id >( + const protocol_ie_single_container_s& obj) +{ + return obj.value.erab_to_be_setup_item_ctxt_su_req().erab_id; +} + +} // namespace s1ap +} // namespace asn1 diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index bef3787a9..020cc4be8 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -91,9 +91,7 @@ public: const asn1::s1ap::erab_level_qos_params_s& qos_params, const asn1::unbounded_octstring* nas_pdu); bool release_erabs(uint32_t rnti) override; - void release_erabs(uint32_t rnti, - srsran::const_span erabs_to_release, - const asn1::unbounded_octstring* nas_pdu) override; + int release_erab(uint16_t rnti, uint16_t erab_id) override; void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override; void ho_preparation_complete(uint16_t rnti, rrc::ho_prep_result result, @@ -104,6 +102,8 @@ public: asn1::s1ap::cause_c& failure_cause) override; void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override; + int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring* nas_pdu) override; + // rrc_interface_pdcp void write_pdu(uint16_t rnti, uint32_t lcid, srsran::unique_byte_buffer_t pdu) override; diff --git a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h index 3649b47b2..d05c9a6d4 100644 --- a/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h +++ b/srsenb/hdr/stack/rrc/rrc_bearer_cfg.h @@ -85,7 +85,7 @@ public: uint32_t teid_out, const asn1::unbounded_octstring* nas_pdu, asn1::s1ap::cause_c& cause); - bool release_erab(uint8_t erab_id); + int release_erab(uint8_t erab_id); void release_erabs(); bool modify_erab(uint8_t erab_id, const asn1::s1ap::erab_level_qos_params_s& qos, diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index ffa1cc7f3..7bf236334 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -113,7 +113,7 @@ public: bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_ctxt_su_req_l& e); bool setup_erabs(const asn1::s1ap::erab_to_be_setup_list_bearer_su_req_l& e); bool release_erabs(); - bool release_erab(uint32_t erab_id); + int release_erab(uint32_t erab_id); bool modify_erab(uint16_t erab_id, const asn1::s1ap::erab_level_qos_params_s& qos_params, const asn1::unbounded_octstring* nas_pdu); diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index 149f25ff9..44e64578c 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -141,6 +141,10 @@ private: asn1::s1ap::s1_setup_resp_s s1setupresponse; + // Procedure state + srsran::bounded_vector updated_erabs; + srsran::bounded_vector failed_cfg_erabs; + void build_tai_cgi(); bool connect_mme(); bool setup_s1(); @@ -243,9 +247,8 @@ private: bool send_initial_ctxt_setup_response(const asn1::s1ap::init_context_setup_resp_s& res_); bool send_initial_ctxt_setup_failure(); bool send_erab_setup_response(const asn1::s1ap::erab_setup_resp_s& res_); - bool send_erab_release_response( - const srsran::bounded_vector& erabs_released, - const srsran::static_circular_map& erabs_failed_to_release); + bool send_erab_release_response(srsran::const_span erabs_released, + srsran::const_span erabs_failed); bool send_erab_modify_response( srsran::const_span erabs_modified, srsran::const_span > erabs_failed_to_modify); diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 7c06b8bac..c3f553a65 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -358,23 +358,28 @@ bool rrc::release_erabs(uint32_t rnti) return ret; } -void rrc::release_erabs(uint32_t rnti, - srsran::const_span erabs_to_release, - const asn1::unbounded_octstring* nas_pdu) +int rrc::release_erab(uint16_t rnti, uint16_t erab_id) { - logger.info("Releasing E-RAB for 0x%x", rnti); + logger.info("Releasing E-RAB id=%d for 0x%x", erab_id, rnti); auto user_it = users.find(rnti); if (user_it == users.end()) { logger.warning("Unrecognised rnti: 0x%x", rnti); - return; + return SRSRAN_ERROR; } - for (uint16_t erab_id : erabs_to_release) { - bool ret = user_it->second->release_erab(erab_id); - srsran_expect(ret, "E-RAB id=%d not found", erab_id); + return user_it->second->release_erab(erab_id); +} + +int rrc::notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring* nas_pdu) +{ + auto user_it = users.find(rnti); + if (user_it == users.end()) { + logger.warning("Unrecognised rnti: 0x%x", rnti); + return SRSRAN_ERROR; } user_it->second->send_connection_reconf(nullptr, false, nas_pdu); + return SRSRAN_SUCCESS; } bool rrc::has_erab(uint16_t rnti, uint32_t erab_id) const diff --git a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc index c1f6eec02..a7e55cc0d 100644 --- a/srsenb/src/stack/rrc/rrc_bearer_cfg.cc +++ b/srsenb/src/stack/rrc/rrc_bearer_cfg.cc @@ -290,12 +290,12 @@ int bearer_cfg_handler::add_erab(uint8_t return SRSRAN_SUCCESS; } -bool bearer_cfg_handler::release_erab(uint8_t erab_id) +int bearer_cfg_handler::release_erab(uint8_t erab_id) { auto it = erabs.find(erab_id); if (it == erabs.end()) { logger->warning("The user rnti=0x%x does not contain ERAB-ID=%d", rnti, erab_id); - return false; + return SRSRAN_ERROR; } uint8_t drb_id = erab_id - 4; @@ -305,7 +305,7 @@ bool bearer_cfg_handler::release_erab(uint8_t erab_id) erabs.erase(it); erab_info_list.erase(erab_id); - return true; + return SRSRAN_SUCCESS; } void bearer_cfg_handler::release_erabs() diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 710964796..af88d7922 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -1050,7 +1050,7 @@ bool rrc::ue::release_erabs() return true; } -bool rrc::ue::release_erab(uint32_t erab_id) +int rrc::ue::release_erab(uint32_t erab_id) { return bearer_list.release_erab(erab_id); } diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 856427219..505edc027 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -60,6 +60,22 @@ asn1::bounded_bitstring<1, 160, true, true> addr_to_asn1(const char* addr_str) return transport_layer_addr; } +/// Helper to add ERAB items that are duplicates in the received S1AP message +template +void add_repeated_erab_ids(const List& list, + srsran::bounded_vector& failed_cfg_erabs) +{ + for (auto it = list.begin(); it != list.end(); ++it) { + for (auto it2 = it + 1; it2 != list.end(); ++it2) { + if (get_obj_id(*it) == get_obj_id(*it2)) { + failed_cfg_erabs.push_back(erab_item_s()); + failed_cfg_erabs.back().erab_id = get_obj_id(*it); + failed_cfg_erabs.back().cause.set_radio_network().value = cause_radio_network_opts::multiple_erab_id_instances; + } + } + } +} + /********************************************************* * TS 36.413 - Section 8.4.1 - "Handover Preparation" *********************************************************/ @@ -823,65 +839,51 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg) */ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) { - if (msg.ext) { - logger.warning("Not handling S1AP message extension"); - } + WarnUnsupportFeature(msg.ext, "S1AP message extension"); + ue* u = handle_s1apmsg_ue_id(msg.protocol_ies.enb_ue_s1ap_id.value.value, msg.protocol_ies.mme_ue_s1ap_id.value.value); if (u == nullptr) { return false; } - srsran::bounded_vector erabs_to_release; - srsran::static_circular_map erabs_failed_to_release; - const auto& msg_erabs = msg.protocol_ies.erab_to_be_released_list.value; + failed_cfg_erabs.clear(); + updated_erabs.clear(); - for (const auto& msg_erab : msg_erabs) { - const erab_item_s& e = msg_erab.value.erab_item(); - if (e.erab_id >= erabs_failed_to_release.capacity()) { - logger.warning("Not handling E-RAB Ids above %zd", erabs_to_release.capacity()); - continue; - } - if (erabs_to_release.full()) { - logger.warning("Not handling more than %zd releases per ERAB release request message", - erabs_to_release.capacity()); - break; - } + auto is_repeated_erab_id = [this](uint8_t erab_id) { + return (std::count(updated_erabs.begin(), updated_erabs.end(), erab_id) > 0) or + (std::any_of(failed_cfg_erabs.begin(), failed_cfg_erabs.end(), [erab_id](const erab_item_s& e) { + return e.erab_id == erab_id; + })); + }; + for (const auto& item : msg.protocol_ies.erab_to_be_released_list.value) { + const auto& erab = item.value.erab_item(); - // Check if E-RAB exists. If not, add to "erabs_failed_to_modify" with "unknown_erab_id" cause - if (not rrc->has_erab(u->ctxt.rnti, e.erab_id)) { - erabs_failed_to_release.overwrite(e.erab_id, erab_item_s()); - erabs_failed_to_release[e.erab_id].cause.set_radio_network().value = cause_radio_network_opts::unknown_erab_id; + if (is_repeated_erab_id(erab.erab_id)) { + // TS 36.413, 8.2.3.3 - ignore the duplication of E-RAB ID IEs continue; } - // Check Repeated E-RABs in the modification list. If repeated, add to the list of "erabs_failed_to_modify" - // with cause "multiple_erab_id_instances" - for (const auto& msg_erab2 : msg_erabs) { - const erab_item_s& e2 = msg_erab2.value.erab_item(); - if (&e2 != &e and e2.erab_id == e.erab_id) { - erabs_failed_to_release.overwrite(e.erab_id, erab_item_s()); - erabs_failed_to_release[e.erab_id].cause.set_radio_network().value = - cause_radio_network_opts::multiple_erab_id_instances; - break; - } - } - if (erabs_failed_to_release.has_space(e.erab_id)) { - continue; + if (rrc->release_erab(u->ctxt.rnti, erab.erab_id) == SRSRAN_SUCCESS) { + updated_erabs.push_back(erab.erab_id); + } else { + failed_cfg_erabs.push_back(erab_item_s()); + failed_cfg_erabs.back().erab_id = erab.erab_id; + failed_cfg_erabs.back().cause.set_radio_network().value = cause_radio_network_opts::unknown_erab_id; } - - // Add to the list to modify - erabs_to_release.push_back(e.erab_id); } - // Release E-RABs from RRC - std::sort(erabs_to_release.begin(), erabs_to_release.end()); - erabs_to_release.erase(std::unique(erabs_to_release.begin(), erabs_to_release.end()), erabs_to_release.end()); - rrc->release_erabs( - u->ctxt.rnti, erabs_to_release, msg.protocol_ies.nas_pdu_present ? &msg.protocol_ies.nas_pdu.value : nullptr); + // Sort E-RABs to be sent + std::sort(failed_cfg_erabs.begin(), failed_cfg_erabs.end(), &lower_obj_id); + std::sort(updated_erabs.begin(), updated_erabs.end()); + + // Notify RRC of E-RAB update. (RRC reconf message is going to be sent. + if (not updated_erabs.empty()) { + rrc->notify_ue_erab_updates(u->ctxt.rnti, nullptr); + } // Send E-RAB release response back to the MME - if (not u->send_erab_release_response(erabs_to_release, erabs_failed_to_release)) { + if (not u->send_erab_release_response(updated_erabs, failed_cfg_erabs)) { logger.info("Failed to send ERABReleaseResponse"); return false; } @@ -1479,14 +1481,9 @@ bool s1ap::ue::send_uectxtmodifyfailure(const cause_c& cause) * @param erabs_failed_to_release * @return true if message was sent */ -bool s1ap::ue::send_erab_release_response( - const srsran::bounded_vector& erabs_released, - const srsran::static_circular_map& erabs_failed_to_release) +bool s1ap::ue::send_erab_release_response(srsran::const_span erabs_released, + srsran::const_span erabs_failed) { - if (not s1ap_ptr->mme_connected) { - return false; - } - asn1::s1ap::s1ap_pdu_c tx_pdu; tx_pdu.set_successful_outcome().load_info_obj(ASN1_S1AP_ID_ERAB_RELEASE); @@ -1507,14 +1504,12 @@ bool s1ap::ue::send_erab_release_response( } // Fill in which E-RABs were *not* successfully released - if (not erabs_failed_to_release.empty()) { + if (not erabs_failed.empty()) { container.erab_failed_to_release_list_present = true; - container.erab_failed_to_release_list.value.resize(erabs_failed_to_release.size()); - size_t count = 0; - for (const auto& erab : erabs_failed_to_release) { - container.erab_failed_to_release_list.value[count].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); - container.erab_failed_to_release_list.value[count].value.erab_item() = erab->second; - count++; + container.erab_failed_to_release_list.value.resize(erabs_failed.size()); + for (size_t i = 0; i < erabs_failed.size(); ++i) { + container.erab_failed_to_release_list.value[i].load_info_obj(ASN1_S1AP_ID_ERAB_ITEM); + container.erab_failed_to_release_list.value[i].value.erab_item() = erabs_failed[i]; } } diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index d2be0e658..af66d1c11 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -175,10 +175,7 @@ public: {} bool has_erab(uint16_t rnti, uint32_t erab_id) const override { return true; } bool release_erabs(uint32_t rnti) override { return true; } - void release_erabs(uint32_t rnti, - srsran::const_span erabs_to_release, - const asn1::unbounded_octstring* nas_pdu) override - {} + int release_erab(uint16_t rnti, uint16_t erab_id) override { return SRSRAN_SUCCESS; } void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& ue_paging_id) override {} void ho_preparation_complete(uint16_t rnti, ho_prep_result result, @@ -192,6 +189,8 @@ public: return SRSRAN_INVALID_RNTI; } void set_erab_status(uint16_t rnti, const asn1::s1ap::bearers_subject_to_status_transfer_list_l& erabs) override {} + + int notify_ue_erab_updates(uint16_t rnti, const asn1::unbounded_octstring* nas_pdu) { return SRSRAN_SUCCESS; } }; } // namespace srsenb