From 0526ae8ab1b3a2474aecd2cfd85b8f7e4dc273b1 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Tue, 21 Apr 2020 12:18:08 +0100 Subject: [PATCH] updated rrc mobility parsing. added some utility methods --- lib/include/srslte/common/stack_procedure.h | 19 +++ .../srslte/interfaces/enb_interfaces.h | 24 --- .../interfaces/enb_rrc_interface_types.h | 74 +++++++++ srsenb/hdr/stack/enb_stack_lte.h | 1 + srsenb/hdr/stack/mac/mac.h | 1 + srsenb/hdr/stack/rrc/rrc.h | 29 +--- srsenb/hdr/stack/rrc/rrc_mobility.h | 30 ++-- srsenb/src/enb_cfg_parser.cc | 4 +- srsenb/src/stack/rrc/rrc.cc | 5 +- srsenb/src/stack/rrc/rrc_mobility.cc | 148 +++++++++++++----- srsenb/src/stack/upper/s1ap.cc | 2 - srsenb/test/upper/rrc_mobility_test.cc | 31 ++-- srsenb/test/upper/test_helpers.h | 19 ++- 13 files changed, 267 insertions(+), 120 deletions(-) create mode 100644 lib/include/srslte/interfaces/enb_rrc_interface_types.h diff --git a/lib/include/srslte/common/stack_procedure.h b/lib/include/srslte/common/stack_procedure.h index f49b7b2d1..aae547699 100644 --- a/lib/include/srslte/common/stack_procedure.h +++ b/lib/include/srslte/common/stack_procedure.h @@ -484,6 +484,25 @@ private: std::list proc_list; }; +template +struct deferred_callback { + explicit deferred_callback(Functor&& f_) : f(std::forward(f_)) {} + deferred_callback(const deferred_callback&) = delete; + deferred_callback(deferred_callback&&) noexcept = default; + deferred_callback& operator=(const deferred_callback&) = delete; + deferred_callback& operator=(deferred_callback&&) noexcept = default; + ~deferred_callback() { f(); } + +private: + Functor f; +}; +template +deferred_callback defer_call(Functor&& f) +{ + return deferred_callback{std::forward(f)}; +} +#define DEFER(FUNC) auto on_exit_call = ::srslte::defer_call([&]() { FUNC }) + } // namespace srslte #endif // SRSLTE_RESUMABLE_PROCEDURES_H diff --git a/lib/include/srslte/interfaces/enb_interfaces.h b/lib/include/srslte/interfaces/enb_interfaces.h index 3b5d45222..988a69fd7 100644 --- a/lib/include/srslte/interfaces/enb_interfaces.h +++ b/lib/include/srslte/interfaces/enb_interfaces.h @@ -390,30 +390,6 @@ public: virtual uint8_t* read_pdu_bcch_dlsch(const uint8_t enb_cc_idx, const uint32_t sib_index) = 0; }; -// SCell configuration -struct scell_cfg_t { - uint32_t cell_id; - bool cross_carrier_sched = false; - uint32_t sched_cell_id; - bool ul_allowed; -}; - -// Cell/Sector configuration -struct cell_cfg_t { - uint32_t rf_port; - uint32_t cell_id; - uint16_t tac; - uint32_t pci; - uint16_t root_seq_idx; - uint32_t dl_earfcn; - double dl_freq_hz; - uint32_t ul_earfcn; - double ul_freq_hz; - uint32_t initial_dl_cqi; - std::vector scell_list; -}; -typedef std::vector cell_list_t; - // RRC interface for PDCP class rrc_interface_pdcp { diff --git a/lib/include/srslte/interfaces/enb_rrc_interface_types.h b/lib/include/srslte/interfaces/enb_rrc_interface_types.h new file mode 100644 index 000000000..0608cd6fe --- /dev/null +++ b/lib/include/srslte/interfaces/enb_rrc_interface_types.h @@ -0,0 +1,74 @@ +/* + * Copyright 2013-2020 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_ENB_RRC_INTERFACE_TYPES_H +#define SRSLTE_ENB_RRC_INTERFACE_TYPES_H + +#include + +namespace srsenb { + +// SCell configuration +struct scell_cfg_t { + uint32_t cell_id; + bool cross_carrier_sched = false; + uint32_t sched_cell_id; + bool ul_allowed; +}; + +// Cell to measure for Handover +struct meas_cell_cfg_t { + uint32_t earfcn; + uint16_t pci; + uint32_t eci; + float q_offset; +}; + +// neigh measurement Cell info +struct rrc_meas_cfg_t { + std::vector meas_cells; + std::vector meas_reports; + asn1::rrc::quant_cfg_eutra_s quant_cfg; + // TODO: Add blacklist cells + // TODO: Add multiple meas configs +}; + +// Cell/Sector configuration +struct cell_cfg_t { + uint32_t rf_port; + uint32_t cell_id; + uint16_t tac; + uint32_t pci; + uint16_t root_seq_idx; + uint32_t dl_earfcn; + double dl_freq_hz; + uint32_t ul_earfcn; + double ul_freq_hz; + uint32_t initial_dl_cqi; + std::vector scell_list; + rrc_meas_cfg_t meas_cfg; +}; + +typedef std::vector cell_list_t; + +} // namespace srsenb + +#endif // SRSLTE_ENB_RRC_INTERFACE_TYPES_H diff --git a/srsenb/hdr/stack/enb_stack_lte.h b/srsenb/hdr/stack/enb_stack_lte.h index b92ab2413..b55da1eae 100644 --- a/srsenb/hdr/stack/enb_stack_lte.h +++ b/srsenb/hdr/stack/enb_stack_lte.h @@ -38,6 +38,7 @@ #include "srsenb/hdr/enb.h" #include "srslte/common/multiqueue.h" #include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/enb_rrc_interface_types.h" namespace srsenb { diff --git a/srsenb/hdr/stack/mac/mac.h b/srsenb/hdr/stack/mac/mac.h index 6a59df8cd..f9afd54d1 100644 --- a/srsenb/hdr/stack/mac/mac.h +++ b/srsenb/hdr/stack/mac/mac.h @@ -30,6 +30,7 @@ #include "srslte/common/tti_sync_cv.h" #include "srslte/interfaces/enb_interfaces.h" #include "srslte/interfaces/enb_metrics_interface.h" +#include "srslte/interfaces/enb_rrc_interface_types.h" #include "srslte/interfaces/sched_interface.h" #include "ta.h" #include "ue.h" diff --git a/srsenb/hdr/stack/rrc/rrc.h b/srsenb/hdr/stack/rrc/rrc.h index 656a52a5e..01670f95e 100644 --- a/srsenb/hdr/stack/rrc/rrc.h +++ b/srsenb/hdr/stack/rrc/rrc.h @@ -32,6 +32,7 @@ #include "srslte/common/stack_procedure.h" #include "srslte/common/timeout.h" #include "srslte/interfaces/enb_interfaces.h" +#include "srslte/interfaces/enb_rrc_interface_types.h" #include #include @@ -66,25 +67,6 @@ typedef struct { asn1::rrc::rlc_cfg_c rlc_cfg; } rrc_cfg_qci_t; -//! Cell to measure for HO. Filled by cfg file parser. -struct meas_cell_cfg_t { - uint32_t earfcn; - uint16_t pci; - uint32_t eci; - float q_offset; -}; - -// neigh measurement Cell info -struct rrc_meas_cfg_t { - std::vector meas_cells; - std::vector meas_reports; - asn1::rrc::quant_cfg_eutra_s quant_cfg; - // uint32_t nof_meas_ids; - // srslte::rrc_meas_id_t meas_ids[LIBLTE_RRC_MAX_MEAS_ID]; - // TODO: Add blacklist cells - // TODO: Add multiple meas configs -}; - #define MAX_NOF_QCI 10 struct rrc_cfg_t { @@ -105,7 +87,6 @@ struct rrc_cfg_t { srslte::CIPHERING_ALGORITHM_ID_ENUM eea_preference_list[srslte::CIPHERING_ALGORITHM_ID_N_ITEMS]; srslte::INTEGRITY_ALGORITHM_ID_ENUM eia_preference_list[srslte::INTEGRITY_ALGORITHM_ID_N_ITEMS]; bool meas_cfg_present = false; - rrc_meas_cfg_t meas_cfg; srslte_cell_t cell; cell_list_t cell_list; }; @@ -269,7 +250,8 @@ private: uint16_t rnti = 0; rrc* parent = nullptr; - bool connect_notified = false; + bool connect_notified = false; + std::unique_ptr mobility_handler; bool is_csfb = false; @@ -283,7 +265,6 @@ private: asn1::rrc::security_algorithm_cfg_s last_security_mode_cmd; asn1::rrc::establishment_cause_e establishment_cause; - std::unique_ptr mobility_handler; // S-TMSI for this UE bool has_tmsi = false; @@ -436,8 +417,8 @@ private: uint32_t nof_si_messages = 0; asn1::rrc::sib_type7_s sib7; - class mobility_cfg; - std::unique_ptr enb_mobility_cfg; + class enb_mobility_handler; + std::unique_ptr enb_mobility_cfg; void rem_user_thread(uint16_t rnti); diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h index 6f7940d29..d67fa986b 100644 --- a/srsenb/hdr/stack/rrc/rrc_mobility.h +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -63,21 +63,26 @@ public: asn1::rrc::report_cfg_to_add_mod_list_l& rep_cfgs() { return var_meas.report_cfg_list; } asn1::rrc::meas_id_to_add_mod_list_l& meas_ids() { return var_meas.meas_id_list; } + static var_meas_cfg_t make(const asn1::rrc::meas_cfg_s& meas_cfg); + private: asn1::rrc::var_meas_cfg_s var_meas; srslte::log_ref rrc_log; }; -class rrc::mobility_cfg +class rrc::enb_mobility_handler { public: - explicit mobility_cfg(const rrc_cfg_t* cfg_); + explicit enb_mobility_handler(rrc* rrc_); - std::shared_ptr current_meas_cfg; ///< const to enable ptr comparison as identity comparison + //! Variable used to store the MeasConfig expected for each cell. + // Note: Made const to forbid silent updates and enable comparison based on addr + std::vector > cell_meas_cfg_list; private: // args - const rrc_cfg_t* cfg = nullptr; + rrc* rrc_ptr = nullptr; + const rrc_cfg_t* cfg = nullptr; }; class rrc::ue::rrc_mobility @@ -94,11 +99,18 @@ private: bool start_ho_preparation(uint32_t target_eci, uint8_t measobj_id, bool fwd_direct_path_available); bool start_enb_status_transfer(); - rrc::ue* rrc_ue = nullptr; - rrc* rrc_enb = nullptr; - rrc::mobility_cfg* cfg = nullptr; - srslte::byte_buffer_pool* pool = nullptr; - srslte::log_ref rrc_log; + bool update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg, + uint32_t target_enb_cc_idx, + asn1::rrc::meas_cfg_s* diff_meas_cfg); + bool update_ue_var_meas_cfg(const var_meas_cfg_t& source_var_meas_cfg, + uint32_t target_enb_cc_idx, + asn1::rrc::meas_cfg_s* diff_meas_cfg); + + rrc::ue* rrc_ue = nullptr; + rrc* rrc_enb = nullptr; + rrc::enb_mobility_handler* cfg = nullptr; + srslte::byte_buffer_pool* pool = nullptr; + srslte::log_ref rrc_log; // vars std::shared_ptr ue_var_meas; diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index ff2b6f911..94dbd68c9 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -720,8 +720,8 @@ static int parse_cell_list(all_args_t* args, rrc_cfg_t* rrc_cfg, Setting& root) parse_default_field(cell_cfg.initial_dl_cqi, cellroot, "initial_dl_cqi", 5u); if (cellroot["ho_active"]) { - HANDLEPARSERCODE(parse_meas_cell_list(&rrc_cfg->meas_cfg, cellroot["meas_cell_list"])); - HANDLEPARSERCODE(parse_meas_report_desc(&rrc_cfg->meas_cfg, cellroot["meas_report_desc"])); + HANDLEPARSERCODE(parse_meas_cell_list(&cell_cfg.meas_cfg, cellroot["meas_cell_list"])); + HANDLEPARSERCODE(parse_meas_report_desc(&cell_cfg.meas_cfg, cellroot["meas_report_desc"])); } cell_cfg.scell_list.resize(cellroot["scell_list"].getLength()); diff --git a/srsenb/src/stack/rrc/rrc.cc b/srsenb/src/stack/rrc/rrc.cc index 262e3cc78..bbc302f74 100644 --- a/srsenb/src/stack/rrc/rrc.cc +++ b/srsenb/src/stack/rrc/rrc.cc @@ -74,7 +74,7 @@ void rrc::init(const rrc_cfg_t& cfg_, nof_si_messages = generate_sibs(); config_mac(); - enb_mobility_cfg.reset(new mobility_cfg(&cfg)); + enb_mobility_cfg.reset(new enb_mobility_handler(this)); bzero(&sr_sched, sizeof(sr_sched_t)); running = true; @@ -562,7 +562,7 @@ void rrc::read_pdu_pcch(uint8_t* payload, uint32_t buffer_size) void rrc::ho_preparation_complete(uint16_t rnti, bool is_success, srslte::unique_byte_buffer_t rrc_container) { - users.at(rnti)->handle_ho_preparation_complete(is_success, std::move(rrc_container)); + users.at(rnti)->mobility_handler->handle_ho_preparation_complete(is_success, std::move(rrc_container)); } /******************************************************************************* @@ -2100,6 +2100,7 @@ void rrc::ue::send_connection_reconf_new_bearer(const asn1::s1ap::erab_to_be_set srsenb::sched_interface::ue_bearer_cfg_t bearer_cfg; bearer_cfg.direction = srsenb::sched_interface::ue_bearer_cfg_t::BOTH; parent->mac->bearer_ue_cfg(rnti, lcid, &bearer_cfg); + current_sched_ue_cfg.ue_bearers[lcid] = bearer_cfg; // Configure DRB in RLC parent->rlc->add_bearer(rnti, lcid, srslte::make_rlc_config_t(drb_item.rlc_cfg)); diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index e065839f0..13a837d0b 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -52,6 +52,11 @@ uint32_t eci_to_cellid(uint32_t eci) { return eci & 0xFFu; } +//! extract enb id from ECI +uint32_t eci_to_enbid(uint32_t eci) +{ + return (eci - eci_to_cellid(eci)) >> 8u; +} uint16_t compute_mac_i(uint16_t crnti, uint32_t cellid, uint16_t pci, @@ -250,8 +255,7 @@ struct compute_diff_generator { src_end(src.end()), target_it(target.begin()), target_end(target.end()) - { - } + {} result_t next() { @@ -415,7 +419,12 @@ asn1::rrc::quant_cfg_s* var_meas_cfg_t::add_quant_cfg(const asn1::rrc::quant_cfg bool var_meas_cfg_t::compute_diff_meas_cfg(const var_meas_cfg_t& target_cfg, asn1::rrc::meas_cfg_s* meas_cfg) const { *meas_cfg = {}; - // TODO: Create a flag to disable changing the "this" members (useful for transparent container) + + // Shortcut in case this is the same as target + if (this == &target_cfg) { + return false; + } + // Set a MeasConfig in the RRC Connection Reconfiguration for HO. compute_diff_meas_objs(target_cfg, meas_cfg); compute_diff_report_cfgs(target_cfg, meas_cfg); @@ -507,7 +516,7 @@ void var_meas_cfg_t::compute_diff_meas_objs(const var_meas_cfg_t& target_cfg, me break; case rrc_details::diff_outcome_t::id_added: { // case "entry with matching measObjectId doesn't exist in measObjToAddModList" - Info("HO: UE has now to measure activity of new frequency earfcn=%d.\n", + Info("UE has now to measure activity of new frequency earfcn=%d.\n", result.target_it->meas_obj.meas_obj_eutra().carrier_freq); auto& target_eutra = result.target_it->meas_obj.meas_obj_eutra(); auto& added_eutra = rrc_details::meascfg_add_meas_obj(meas_cfg, *result.target_it)->meas_obj.meas_obj_eutra(); @@ -606,38 +615,75 @@ void var_meas_cfg_t::compute_diff_quant_cfg(const var_meas_cfg_t& target_cfg, as } } +/** + * Convert MeasCfg asn1 struct to var_meas_cfg_t + * @param meas_cfg + * @return + */ +var_meas_cfg_t var_meas_cfg_t::make(const asn1::rrc::meas_cfg_s& meas_cfg) +{ + var_meas_cfg_t var; + if (meas_cfg.meas_id_to_add_mod_list_present) { + var.var_meas.meas_id_list_present = true; + var.var_meas.meas_id_list = meas_cfg.meas_id_to_add_mod_list; + } + if (meas_cfg.meas_obj_to_add_mod_list_present) { + var.var_meas.meas_obj_list_present = true; + var.var_meas.meas_obj_list = meas_cfg.meas_obj_to_add_mod_list; + } + if (meas_cfg.report_cfg_to_add_mod_list_present) { + var.var_meas.report_cfg_list_present = true; + var.var_meas.report_cfg_list = meas_cfg.report_cfg_to_add_mod_list; + } + if (meas_cfg.quant_cfg_present) { + var.var_meas.quant_cfg_present = true; + var.var_meas.quant_cfg = meas_cfg.quant_cfg; + } + if (meas_cfg.report_cfg_to_rem_list_present or meas_cfg.meas_obj_to_rem_list_present or + meas_cfg.meas_id_to_rem_list_present) { + srslte::logmap::get("RRC")->warning("Remove lists not handled by the var_meas_cfg_t method\n"); + } + return var; +} + /************************************************************************************************* * mobility_cfg class ************************************************************************************************/ -rrc::mobility_cfg::mobility_cfg(const rrc_cfg_t* cfg_) : cfg(cfg_) +rrc::enb_mobility_handler::enb_mobility_handler(rrc* rrc_) : rrc_ptr(rrc_), cfg(&rrc_->cfg) { - var_meas_cfg_t var_meas{}; + cell_meas_cfg_list.resize(cfg->cell_list.size()); - if (cfg->meas_cfg_present) { - // inserts all neighbor cells - for (const meas_cell_cfg_t& meascell : cfg->meas_cfg.meas_cells) { - var_meas.add_cell_cfg(meascell); - } + /* Create Template Cell VarMeasCfg List */ - // insert all report cfgs - for (const report_cfg_eutra_s& reportcfg : cfg->meas_cfg.meas_reports) { - var_meas.add_report_cfg(reportcfg); - } + for (size_t i = 0; i < cfg->cell_list.size(); ++i) { + std::unique_ptr var_meas{new var_meas_cfg_t{}}; + + if (cfg->meas_cfg_present) { + // inserts all neighbor cells + for (const meas_cell_cfg_t& meascell : cfg->cell_list[i].meas_cfg.meas_cells) { + var_meas->add_cell_cfg(meascell); + } - // insert all meas ids - // TODO: add this to the parser - if (var_meas.rep_cfgs().size() > 0) { - for (const auto& measobj : var_meas.meas_objs()) { - var_meas.add_measid_cfg(measobj.meas_obj_id, var_meas.rep_cfgs().begin()->report_cfg_id); + // insert same report cfg for all cells + for (const report_cfg_eutra_s& reportcfg : cfg->cell_list[i].meas_cfg.meas_reports) { + var_meas->add_report_cfg(reportcfg); } + + // insert all meas ids + // TODO: add this to the parser + if (var_meas->rep_cfgs().size() > 0) { + for (const auto& measobj : var_meas->meas_objs()) { + var_meas->add_measid_cfg(measobj.meas_obj_id, var_meas->rep_cfgs().begin()->report_cfg_id); + } + } + + // insert quantity config + var_meas->add_quant_cfg(cfg->cell_list[i].meas_cfg.quant_cfg); } - // insert quantity config - var_meas.add_quant_cfg(cfg->meas_cfg.quant_cfg); + cell_meas_cfg_list[i].reset(var_meas.release()); } - - current_meas_cfg = std::make_shared(var_meas); } /************************************************************************************************* @@ -652,8 +698,7 @@ rrc::ue::rrc_mobility::rrc_mobility(rrc::ue* outer_ue) : rrc_log(outer_ue->parent->rrc_log), source_ho_proc(this), ue_var_meas(std::make_shared()) -{ -} +{} //! Method to add Mobility Info to a RRC Connection Reconfiguration Message bool rrc::ue::rrc_mobility::fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg) @@ -664,21 +709,11 @@ bool rrc::ue::rrc_mobility::fill_conn_recfg_msg(asn1::rrc::rrc_conn_recfg_r8_ies return false; } - // Check if there has been any update - if (ue_var_meas.get() == cfg->current_meas_cfg.get()) { - return false; - } - - asn1::rrc::meas_cfg_s* meas_cfg = &conn_recfg->meas_cfg; - bool updated = ue_var_meas->compute_diff_meas_cfg(*cfg->current_meas_cfg, meas_cfg); - // update ue var meas - ue_var_meas = cfg->current_meas_cfg; - - if (updated) { - conn_recfg->meas_cfg_present = true; - return true; - } - return false; + // Check if there has been any update in ue_var_meas + cell_ctxt_t* pcell = rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX); + asn1::rrc::meas_cfg_s& meas_cfg = conn_recfg->meas_cfg; + conn_recfg->meas_cfg_present = update_ue_var_meas_cfg(*ue_var_meas, pcell->enb_cc_idx, &meas_cfg); + return conn_recfg->meas_cfg_present; } //! Method called whenever the eNB receives a MeasReport from the UE. In normal situations, an HO procedure is started @@ -727,8 +762,8 @@ void rrc::ue::rrc_mobility::handle_ue_meas_report(const meas_report_s& msg) // TODO: check what to do here to take the decision. // NOTE: for now just accept anything. - // HO going forward. - auto& L = rrc_enb->cfg.meas_cfg.meas_cells; + // Target cell to handover to was selected. + auto& L = rrc_enb->cfg.cell_list[rrc_ue->get_ue_cc_cfg(UE_PCELL_CC_IDX)->enb_cc_idx].meas_cfg.meas_cells; uint32_t target_eci = std::find_if(L.begin(), L.end(), [pci](meas_cell_cfg_t& c) { return c.pci == pci; })->eci; if (not source_ho_proc.launch(*measid_it, *obj_it, *rep_it, *cell_it, eutra_list[i], target_eci)) { Error("Failed to start HO procedure, as it is already on-going\n"); @@ -896,6 +931,33 @@ void rrc::ue::rrc_mobility::handle_ho_preparation_complete(bool is_success, srsl source_ho_proc.trigger(sourceenb_ho_proc_t::ho_prep_result{is_success, std::move(container)}); } +bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const asn1::rrc::meas_cfg_s& source_meas_cfg, + uint32_t target_enb_cc_idx, + asn1::rrc::meas_cfg_s* diff_meas_cfg) +{ + // Generate equivalent VarMeasCfg + var_meas_cfg_t source_var = var_meas_cfg_t::make(source_meas_cfg); + + // Compute difference measCfg and update UE VarMeasCfg + return update_ue_var_meas_cfg(source_var, target_enb_cc_idx, diff_meas_cfg); +} + +bool rrc::ue::rrc_mobility::update_ue_var_meas_cfg(const var_meas_cfg_t& source_var_meas_cfg, + uint32_t target_enb_cc_idx, + asn1::rrc::meas_cfg_s* diff_meas_cfg) +{ + // Fetch cell VarMeasCfg + auto& target_var_ptr = rrc_enb->enb_mobility_cfg->cell_meas_cfg_list[target_enb_cc_idx]; + + // Calculate difference between source and target VarMeasCfg + bool meas_cfg_present = source_var_meas_cfg.compute_diff_meas_cfg(*target_var_ptr, diff_meas_cfg); + + // Update user varMeasCfg to target + rrc_ue->mobility_handler->ue_var_meas = target_var_ptr; + + return meas_cfg_present; +} + /** * TS 36.413, Section 8.4.6 - eNB Status Transfer * Description: Send "eNBStatusTransfer" message from source eNB to MME diff --git a/srsenb/src/stack/upper/s1ap.cc b/srsenb/src/stack/upper/s1ap.cc index 0fe0d0c0a..440bfcdbc 100644 --- a/srsenb/src/stack/upper/s1ap.cc +++ b/srsenb/src/stack/upper/s1ap.cc @@ -285,8 +285,6 @@ void s1ap::get_metrics(s1ap_metrics_t& m) void s1ap::build_tai_cgi() { uint32_t plmn; - uint32_t tmp32; - uint16_t tmp16; // TAI s1ap_mccmnc_to_plmn(args.mcc, args.mnc, &plmn); diff --git a/srsenb/test/upper/rrc_mobility_test.cc b/srsenb/test/upper/rrc_mobility_test.cc index cb7625500..5265a4de5 100644 --- a/srsenb/test/upper/rrc_mobility_test.cc +++ b/srsenb/test/upper/rrc_mobility_test.cc @@ -237,7 +237,7 @@ int test_correct_meascfg_calculation() } struct mobility_test_params { - enum class test_fail_at { success, wrong_measreport, concurrent_ho, ho_prep_failure } fail_at; + enum class test_fail_at { success, wrong_measreport, concurrent_ho, ho_prep_failure, recover } fail_at; const char* to_string() { switch (fail_at) { @@ -249,15 +249,17 @@ struct mobility_test_params { return "measreport while in handover"; case test_fail_at::ho_prep_failure: return "ho preparation failure"; + case test_fail_at::recover: + return "fail and success"; default: return "none"; } } }; -int test_mobility_class(mobility_test_params test_params) +int test_s1ap_mobility(mobility_test_params test_params) { - printf("\n===== TEST: test_mobility_class() for event \"%s\" =====\n", test_params.to_string()); + printf("\n===== TEST: test_s1ap_mobility() for event \"%s\" =====\n", test_params.to_string()); srslte::scoped_log rrc_log("RRC "); srslte::timer_handler timers; srslte::unique_byte_buffer_t pdu; @@ -266,11 +268,11 @@ int test_mobility_class(mobility_test_params test_params) rrc_cfg_t cfg; TESTASSERT(test_helpers::parse_default_cfg(&cfg, args) == SRSLTE_SUCCESS); report_cfg_eutra_s rep = generate_rep1(); - cfg.meas_cfg.meas_reports.push_back(rep); + cfg.cell_list[0].meas_cfg.meas_reports.push_back(rep); meas_cell_cfg_t cell2 = generate_cell1(); cell2.pci = 2; cell2.eci = 0x19C02; - cfg.meas_cfg.meas_cells.push_back(cell2); + cfg.cell_list[0].meas_cfg.meas_cells.push_back(cell2); cfg.meas_cfg_present = true; srsenb::rrc rrc; @@ -332,7 +334,7 @@ int test_mobility_class(mobility_test_params test_params) return SRSLTE_SUCCESS; } - /* Check HO Required was sent to S1AP */ + /* Test Case: Check HO Required was sent to S1AP */ TESTASSERT(s1ap.last_ho_required.rnti == rnti); TESTASSERT(s1ap.last_ho_required.target_eci == cell2.eci); TESTASSERT(s1ap.last_ho_required.target_plmn.to_string() == "00101"); @@ -360,9 +362,14 @@ int test_mobility_class(mobility_test_params test_params) 0x10, 0x00, 0x01, 0x00, 0x05, 0x00, 0xa7, 0xd0, 0xc1, 0xf6, 0xaf, 0x3e, 0x12, 0xcc, 0x86, 0x0d, 0x30, 0x00, 0x0b, 0x5a, 0x02, 0x17, 0x86, 0x00, 0x05, 0xa0, 0x20}; test_helpers::copy_msg_to_buffer(pdu, ho_cmd_rrc_container, sizeof(ho_cmd_rrc_container)); + TESTASSERT(s1ap.last_enb_status.rnti != rnti); rrc.ho_preparation_complete(rnti, true, std::move(pdu)); - TESTASSERT(rrc_log->error_counter == 0); + asn1::rrc::dl_dcch_msg_s ho_cmd; + TESTASSERT(test_helpers::unpack_asn1(ho_cmd, pdcp.last_sdu.sdu)); + auto& recfg_r8 = ho_cmd.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8(); + TESTASSERT(recfg_r8.mob_ctrl_info_present); + return SRSLTE_SUCCESS; } @@ -377,14 +384,14 @@ int main(int argc, char** argv) argparse::parse_args(argc, argv); TESTASSERT(test_correct_insertion() == 0); TESTASSERT(test_correct_meascfg_calculation() == 0); - TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0); - TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::concurrent_ho}) == 0); - TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::ho_prep_failure}) == 0); - TESTASSERT(test_mobility_class(mobility_test_params{mobility_test_params::test_fail_at::success}) == 0); + TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::wrong_measreport}) == 0); + TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::concurrent_ho}) == 0); + TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::ho_prep_failure}) == 0); + TESTASSERT(test_s1ap_mobility(mobility_test_params{mobility_test_params::test_fail_at::success}) == 0); printf("\nSuccess\n"); srslte::byte_buffer_pool::get_instance()->cleanup(); return SRSLTE_SUCCESS; -} \ No newline at end of file +} diff --git a/srsenb/test/upper/test_helpers.h b/srsenb/test/upper/test_helpers.h index a2fdac3ff..bbed13fdc 100644 --- a/srsenb/test/upper/test_helpers.h +++ b/srsenb/test/upper/test_helpers.h @@ -74,7 +74,11 @@ public: uint32_t target_eci; srslte::plmn_id_t target_plmn; srslte::unique_byte_buffer_t rrc_container; - } last_ho_required; + } last_ho_required = {}; + struct enb_status_transfer_info { + uint16_t rnti; + std::vector bearer_list; + } last_enb_status = {}; bool send_ho_required(uint16_t rnti, uint32_t target_eci, @@ -130,6 +134,17 @@ int parse_default_cfg(rrc_cfg_t* rrc_cfg, srsenb::all_args_t& args) return enb_conf_sections::parse_cfg_files(&args, rrc_cfg, &phy_cfg); } +template +bool unpack_asn1(ASN1Type& asn1obj, const srslte::unique_byte_buffer_t& pdu) +{ + asn1::cbit_ref bref{pdu->msg, pdu->N_bytes}; + if (asn1obj.unpack(bref) != asn1::SRSASN_SUCCESS) { + srslte::logmap::get("TEST")->error("Failed to unpack ASN1 type\n"); + return false; + } + return true; +} + void copy_msg_to_buffer(srslte::unique_byte_buffer_t& pdu, uint8_t* msg, size_t nof_bytes) { srslte::byte_buffer_pool* pool = srslte::byte_buffer_pool::get_instance(); @@ -201,4 +216,4 @@ int bring_rrc_to_reconf_state(srsenb::rrc& rrc, srslte::timer_handler& timers, u } // namespace test_helpers -#endif // SRSENB_TEST_HELPERS_H \ No newline at end of file +#endif // SRSENB_TEST_HELPERS_H