From 49bd895e2906858ef674b520d858caa9a19a4d92 Mon Sep 17 00:00:00 2001 From: Francisco Date: Mon, 12 Apr 2021 17:40:14 +0100 Subject: [PATCH] s1ap - handle invalid or repeated erab ids in s1ap erab release command --- lib/include/srsran/adt/circular_map.h | 2 +- .../srsran/interfaces/enb_rrc_interfaces.h | 7 +- srsenb/hdr/common/common_enb.h | 2 + srsenb/hdr/stack/rrc/rrc.h | 7 +- srsenb/hdr/stack/upper/s1ap.h | 6 +- srsenb/src/stack/rrc/rrc.cc | 21 ++--- srsenb/src/stack/upper/s1ap.cc | 93 ++++++++++++++----- srsenb/test/common/dummy_classes.h | 7 +- 8 files changed, 91 insertions(+), 54 deletions(-) diff --git a/lib/include/srsran/adt/circular_map.h b/lib/include/srsran/adt/circular_map.h index c63590006..1ab4534f3 100644 --- a/lib/include/srsran/adt/circular_map.h +++ b/lib/include/srsran/adt/circular_map.h @@ -233,7 +233,7 @@ public: iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, N); } - const_iterator begin() const { return iterator(this, 0); } + const_iterator begin() const { return const_iterator(this, 0); } const_iterator end() const { return const_iterator(this, N); } iterator find(K id) diff --git a/lib/include/srsran/interfaces/enb_rrc_interfaces.h b/lib/include/srsran/interfaces/enb_rrc_interfaces.h index c39b56a89..cc0260f0b 100644 --- a/lib/include/srsran/interfaces/enb_rrc_interfaces.h +++ b/lib/include/srsran/interfaces/enb_rrc_interfaces.h @@ -33,10 +33,9 @@ public: 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, - const asn1::s1ap::erab_release_cmd_s& msg, - std::vector* erabs_released, - std::vector* erabs_failed_to_release) = 0; + virtual void release_erabs(uint32_t rnti, + srsran::const_span erabs_to_release, + const asn1::unbounded_octstring* nas_pdu) = 0; virtual void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& ue_paging_id) = 0; /** diff --git a/srsenb/hdr/common/common_enb.h b/srsenb/hdr/common/common_enb.h index b0e34e715..7ed9cf72b 100644 --- a/srsenb/hdr/common/common_enb.h +++ b/srsenb/hdr/common/common_enb.h @@ -26,6 +26,8 @@ namespace srsenb { #define SRSENB_N_SRB 3 #define SRSENB_MAX_UES 64 +const uint32_t MAX_ERAB_ID = 15; +const uint32_t MAX_NOF_ERABS = 16; using srsran::lte_drb; using srsran::lte_srb; diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index bda0a43a6..56549acc4 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -91,10 +91,9 @@ 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, - const asn1::s1ap::erab_release_cmd_s& msg, - std::vector* erabs_released, - std::vector* erabs_failed_to_release) override; + void release_erabs(uint32_t rnti, + srsran::const_span erabs_to_release, + const asn1::unbounded_octstring* nas_pdu) override; void add_paging_id(uint32_t ueid, const asn1::s1ap::ue_paging_id_c& UEPagingID) override; void ho_preparation_complete(uint16_t rnti, bool is_success, diff --git a/srsenb/hdr/stack/upper/s1ap.h b/srsenb/hdr/stack/upper/s1ap.h index a365876a0..901a588df 100644 --- a/srsenb/hdr/stack/upper/s1ap.h +++ b/srsenb/hdr/stack/upper/s1ap.h @@ -16,6 +16,7 @@ #include #include "srsenb/hdr/common/common_enb.h" +#include "srsran/adt/circular_map.h" #include "srsran/common/buffer_pool.h" #include "srsran/common/common.h" #include "srsran/common/s1ap_pcap.h" @@ -237,8 +238,9 @@ 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 std::vector& erabs_successfully_released, - const std::vector& erabs_failed_to_release); + bool send_erab_release_response( + const srsran::bounded_vector& erabs_released, + const srsran::static_circular_map& erabs_failed_to_release); 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 0c9390026..3c81b1a35 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -358,10 +358,9 @@ bool rrc::release_erabs(uint32_t rnti) return ret; } -void rrc::release_erabs(uint32_t rnti, - const asn1::s1ap::erab_release_cmd_s& msg, - std::vector* erabs_released, - std::vector* erabs_failed_to_release) +void rrc::release_erabs(uint32_t rnti, + srsran::const_span erabs_to_release, + const asn1::unbounded_octstring* nas_pdu) { logger.info("Releasing E-RAB for 0x%x", rnti); auto user_it = users.find(rnti); @@ -371,18 +370,10 @@ void rrc::release_erabs(uint32_t rnti, return; } - for (uint32_t i = 0; i < msg.protocol_ies.erab_to_be_released_list.value.size(); i++) { - const asn1::s1ap::erab_item_s& erab_to_release = - msg.protocol_ies.erab_to_be_released_list.value[i].value.erab_item(); - bool ret = user_it->second->release_erab(erab_to_release.erab_id); - if (ret) { - erabs_released->push_back(erab_to_release.erab_id); - } else { - erabs_failed_to_release->push_back(erab_to_release.erab_id); - } + 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); } - const asn1::unbounded_octstring* nas_pdu = - msg.protocol_ies.nas_pdu_present ? &msg.protocol_ies.nas_pdu.value : nullptr; user_it->second->send_connection_reconf(nullptr, false, nas_pdu); } diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 04cede167..920079ab4 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -735,15 +735,18 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg) return false; } - // make a copy, sort by ERAB ID using erab_t = erab_to_be_modified_item_bearer_mod_req_s; using failed_erab_t = std::pair; - srsran::bounded_vector erab_mod_list; - std::vector erabs_failed_to_modify; - auto& msg_erabs = msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value; + srsran::bounded_vector erab_mod_list; + srsran::bounded_vector erabs_failed_to_modify; + const auto& msg_erabs = msg.protocol_ies.erab_to_be_modified_list_bearer_mod_req.value; - for (const auto& msg_erab : msg_erabs) { - const erab_t& e = msg_erab.value.erab_to_be_modified_item_bearer_mod_req(); + if (msg_erabs.size() > erab_mod_list.capacity()) { + logger.warning("Not handling more than %d E-RABs per modify request message.", erab_mod_list.capacity()); + } + + for (size_t i = 0; i < SRSRAN_MIN(msg_erabs.size(), erab_mod_list.capacity()); ++i) { + const erab_t& e = msg_erabs[i].value.erab_to_be_modified_item_bearer_mod_req(); // 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)) { @@ -757,7 +760,7 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg) // with cause "multiple_erab_id_instances" for (const auto& msg_erab2 : msg_erabs) { const erab_t& e2 = msg_erab2.value.erab_to_be_modified_item_bearer_mod_req(); - if (&msg_erab2 != &msg_erab and e2.erab_id == e.erab_id) { + if (&e2 != &e and e2.erab_id == e.erab_id) { cause_c cause; cause.set_radio_network().value = cause_radio_network_opts::multiple_erab_id_instances; erabs_failed_to_modify.emplace_back(e.erab_id, cause); @@ -802,9 +805,6 @@ bool s1ap::handle_erabmodifyrequest(const erab_modify_request_s& msg) */ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) { - std::vector erab_successful_release = {}; - std::vector erab_failed_to_release = {}; - if (msg.ext) { logger.warning("Not handling S1AP message extension"); } @@ -814,11 +814,56 @@ bool s1ap::handle_erabreleasecommand(const erab_release_cmd_s& msg) 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; + + 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; + } + + // 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; + 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; + } + + // Add to the list to modify + erabs_to_release.push_back(e.erab_id); + } + // Release E-RABs from RRC - rrc->release_erabs(u->ctxt.rnti, msg, &erab_successful_release, &erab_failed_to_release); + 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); // Send E-RAB release response back to the MME - if (not u->send_erab_release_response(erab_successful_release, erab_failed_to_release)) { + if (not u->send_erab_release_response(erabs_to_release, erabs_failed_to_release)) { logger.info("Failed to send ERABReleaseResponse"); return false; } @@ -1391,8 +1436,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 std::vector& erabs_successfully_released, - const std::vector& erabs_failed_to_release) +bool s1ap::ue::send_erab_release_response( + const srsran::bounded_vector& erabs_released, + const srsran::static_circular_map& erabs_failed_to_release) { if (not s1ap_ptr->mme_connected) { return false; @@ -1406,14 +1452,14 @@ bool s1ap::ue::send_erab_release_response(const std::vector& erabs_suc container.mme_ue_s1ap_id.value = ctxt.mme_ue_s1ap_id.value(); // Fill in which E-RABs were successfully released - if (not erabs_successfully_released.empty()) { + if (not erabs_released.empty()) { container.erab_release_list_bearer_rel_comp_present = true; - container.erab_release_list_bearer_rel_comp.value.resize(erabs_successfully_released.size()); - for (uint32_t i = 0; i < container.erab_release_list_bearer_rel_comp.value.size(); i++) { + container.erab_release_list_bearer_rel_comp.value.resize(erabs_released.size()); + for (size_t i = 0; i < erabs_released.size(); ++i) { container.erab_release_list_bearer_rel_comp.value[i].load_info_obj( ASN1_S1AP_ID_ERAB_RELEASE_ITEM_BEARER_REL_COMP); container.erab_release_list_bearer_rel_comp.value[i].value.erab_release_item_bearer_rel_comp().erab_id = - erabs_successfully_released[i]; + erabs_released[i]; } } @@ -1421,12 +1467,11 @@ bool s1ap::ue::send_erab_release_response(const std::vector& erabs_suc if (not erabs_failed_to_release.empty()) { container.erab_failed_to_release_list_present = true; container.erab_failed_to_release_list.value.resize(erabs_failed_to_release.size()); - for (uint32_t i = 0; i < container.erab_failed_to_release_list.value.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().erab_id = erabs_failed_to_release[i]; - container.erab_failed_to_release_list.value[i].value.erab_item().cause.set(asn1::s1ap::cause_c::types::misc); - container.erab_failed_to_release_list.value[i].value.erab_item().cause.misc() = - asn1::s1ap::cause_misc_opts::unspecified; + 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++; } } diff --git a/srsenb/test/common/dummy_classes.h b/srsenb/test/common/dummy_classes.h index 5e5b62cdd..563ef8948 100644 --- a/srsenb/test/common/dummy_classes.h +++ b/srsenb/test/common/dummy_classes.h @@ -174,10 +174,9 @@ 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, - const asn1::s1ap::erab_release_cmd_s& msg, - std::vector* erabs_released, - std::vector* erabs_failed_to_release) override + void release_erabs(uint32_t rnti, + srsran::const_span erabs_to_release, + const asn1::unbounded_octstring* nas_pdu) override {} 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,