From 4f6905363fce6a862cc02c763f2c9f644d5365d5 Mon Sep 17 00:00:00 2001 From: Carlo Galiotto Date: Thu, 21 Oct 2021 15:39:40 +0200 Subject: [PATCH] rrc,nr: add MSG3 activity timer to rrc_nr Signed-off-by: Carlo Galiotto --- srsenb/hdr/stack/rrc/rrc_nr.h | 34 ++++++++++- srsenb/src/stack/rrc/rrc_nr.cc | 101 +++++++++++++++++++++++++++++++-- 2 files changed, 129 insertions(+), 6 deletions(-) diff --git a/srsenb/hdr/stack/rrc/rrc_nr.h b/srsenb/hdr/stack/rrc/rrc_nr.h index 4935e0cbb..a8d58937a 100644 --- a/srsenb/hdr/stack/rrc/rrc_nr.h +++ b/srsenb/hdr/stack/rrc/rrc_nr.h @@ -104,7 +104,27 @@ public: class ue { public: - ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg); + enum activity_timeout_type_t { + MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs + UE_INACTIVITY_TIMEOUT, ///< (currently unused) UE inactivity timeout (usually bigger than reestablishment timeout) + MSG5_RX_TIMEOUT, ///< (currently unused) for receiving RRCConnectionSetupComplete/RRCReestablishmentComplete + nulltype + }; + + /// List of results a RRC procedure may produce. + enum class procedure_result_code { + none, + activity_timeout, + error_mme_not_connected, + error_unknown_rnti, + radio_conn_with_ue_lost, + msg3_timeout, + fail_in_radio_interface_proc, + unspecified + }; + + /// @param [in] triggered_by_rach: indicates whether the UE is created as part of a RACH process + ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg, bool triggered_by_rach = false); void send_connection_setup(); void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg); @@ -119,14 +139,23 @@ public: bool is_endc() { return endc; } uint16_t get_eutra_rnti() { return eutra_rnti; } void get_metrics(rrc_ue_metrics_t& ue_metrics) { ue_metrics = {}; /*TODO fill RRC metrics*/ }; + // setters int pack_rrc_reconfiguration(); void deactivate_bearers(); + /// methods to handle activity timer + std::string to_string(const activity_timeout_type_t& type); + void set_activity_timeout(activity_timeout_type_t type); + void set_activity(bool enabled = true); + void activity_timer_expired(const activity_timeout_type_t type); + private: rrc_nr* parent = nullptr; uint16_t rnti = SRSRAN_INVALID_RNTI; + /// for basic DL/UL activity timeout + srsran::unique_timer activity_timer; int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig); int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config); @@ -179,6 +208,9 @@ public: rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE; uint8_t transaction_id = 0; + /// Connection release result. + procedure_result_code con_release_result = procedure_result_code::none; + // RRC configs for UEs asn1::rrc_nr::cell_group_cfg_s cell_group_cfg; asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg; diff --git a/srsenb/src/stack/rrc/rrc_nr.cc b/srsenb/src/stack/rrc/rrc_nr.cc index f89ee463b..439bfa6ca 100644 --- a/srsenb/src/stack/rrc/rrc_nr.cc +++ b/srsenb/src/stack/rrc/rrc_nr.cc @@ -161,7 +161,8 @@ rrc_nr_cfg_t rrc_nr::update_default_cfg(const rrc_nr_cfg_t& current) int rrc_nr::add_user(uint16_t rnti, const sched_nr_ue_cfg_t& uecfg) { if (users.count(rnti) == 0) { - users.insert(std::make_pair(rnti, std::unique_ptr(new ue(this, rnti, uecfg)))); + // in the ue ctor, "triggered_by_rach" is set to true so as to start the MSG3 RX TIMEOUT when we create the ue + users.insert(std::make_pair(rnti, std::unique_ptr(new ue(this, rnti, uecfg, true)))); rlc->add_user(rnti); pdcp->add_user(rnti); logger.info("Added new user rnti=0x%x", rnti); @@ -494,9 +495,9 @@ void rrc_nr::sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_ uecfg.carriers[0].cc = 0; uecfg.ue_bearers[0].direction = mac_lc_ch_cfg_t::BOTH; srsran::phy_cfg_nr_default_t::reference_cfg_t ref_args{}; - ref_args.duplex = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_TDD - ? srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_TDD_CUSTOM_6_4 - : srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD; + ref_args.duplex = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_TDD + ? srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_TDD_CUSTOM_6_4 + : srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD; uecfg.phy_cfg = srsran::phy_cfg_nr_default_t{ref_args}; uecfg.phy_cfg.csi = {}; // disable CSI until RA is complete @@ -545,11 +546,95 @@ void rrc_nr::sgnb_release_request(uint16_t nr_rnti) Every function in UE class is called from a mutex environment thus does not need extra protection. *******************************************************************************/ -rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_) : +rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_, bool triggered_by_rach) : parent(parent_), rnti(rnti_), uecfg(uecfg_) { // Derive UE cfg from rrc_cfg_nr_t uecfg.phy_cfg.pdcch = parent->cfg.cell_list[0].phy_cell.pdcch; + + // Set timer for MSG3_RX_TIMEOUT or UE_INACTIVITY_TIMEOUT + activity_timer = parent->task_sched.get_unique_timer(); + triggered_by_rach ? set_activity_timeout(MSG3_RX_TIMEOUT) : set_activity_timeout(UE_INACTIVITY_TIMEOUT); +} + +void rrc_nr::ue::set_activity_timeout(activity_timeout_type_t type) +{ + uint32_t deadline_ms = 0; + + switch (type) { + case MSG3_RX_TIMEOUT: + // TODO: Retrieve the parameters from somewhere(RRC?) - Currently hardcoded to 100ms + deadline_ms = 100; + break; + case UE_INACTIVITY_TIMEOUT: + // TODO: Add a value for the inactivity timeout - currently no activity set this case + return; + default: + parent->logger.error("Unknown timeout type %d", type); + return; + } + + // Currently we only set the timer for the MSG3_RX_TIMEOUT case + activity_timer.set(deadline_ms, [this, type](uint32_t tid) { activity_timer_expired(type); }); + parent->logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline_ms); + + set_activity(); +} + +void rrc_nr::ue::set_activity(bool enabled) +{ + if (rnti == SRSRAN_MRNTI) { + return; + } + if (not enabled) { + if (activity_timer.is_running()) { + parent->logger.debug("Inactivity timer interrupted for rnti=0x%x", rnti); + } + activity_timer.stop(); + return; + } + + // re-start activity timer with current timeout value + activity_timer.run(); + parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration()); +} + +void rrc_nr::ue::activity_timer_expired(const activity_timeout_type_t type) +{ + parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed()); + + // TODO: Insert a check to ensure the RNTI exists +#if 0 + if (parent->s1ap->user_exists(rnti)) { +#endif + switch (type) { + case UE_INACTIVITY_TIMEOUT: + // TODO: Add action to be executed + break; + case MSG3_RX_TIMEOUT: + // MSG3 timeout, no need to notify S1AP, just remove UE + parent->rem_user(rnti); + con_release_result = procedure_result_code::msg3_timeout; + break; + default: + // Unhandled activity timeout, just remove UE and log an error + parent->rem_user(rnti); + con_release_result = procedure_result_code::activity_timeout; + parent->logger.error( + "Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast(type)); + } +#if 0 + } else { + parent->rem_user_thread(rnti); + } +#endif + state = rrc_nr_state_t::RRC_IDLE; +} + +std::string rrc_nr::ue::to_string(const activity_timeout_type_t& type) +{ + constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE reestablishment"}; + return srsran::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); } void rrc_nr::ue::send_connection_setup() @@ -1289,6 +1374,10 @@ int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti_, const sgnb_ad ack_params.eps_bearer_id = req_params.eps_bearer_id; parent->rrc_eutra->sgnb_addition_ack(eutra_rnti_, ack_params); + // stop activity timer for msg3 + activity_timer.stop(); + parent->logger.debug("SgNB addition req. - Stopping MSG3 activity timer for rnti=0x%x", rnti); + // recognize RNTI as ENDC user endc = true; eutra_rnti = eutra_rnti_; @@ -1302,6 +1391,8 @@ void rrc_nr::ue::crnti_ce_received() if (endc) { // send SgNB addition complete for ENDC users parent->rrc_eutra->sgnb_addition_complete(eutra_rnti, rnti); + activity_timer.stop(); + parent->logger.debug("Received MAC CE-RNTI for 0x%x - stopping MSG3 timer", rnti); // Add DRB1 to MAC for (auto& drb : cell_group_cfg.rlc_bearer_to_add_mod_list) {