diff --git a/srsenb/hdr/stack/rrc/rrc_mobility.h b/srsenb/hdr/stack/rrc/rrc_mobility.h index 4b706269c..8a26ee304 100644 --- a/srsenb/hdr/stack/rrc/rrc_mobility.h +++ b/srsenb/hdr/stack/rrc/rrc_mobility.h @@ -50,6 +50,8 @@ public: const asn1::s1ap::sourceenb_to_targetenb_transparent_container_s& container, asn1::s1ap::cause_c& cause); + std::pair get_source_ue_rnti_and_pci(); + private: // helper methods bool update_ue_var_meas_cfg(uint32_t src_earfcn, @@ -109,6 +111,8 @@ private: struct s1_target_ho_st { asn1::s1ap::cause_c failure_cause; std::vector pending_tunnels; + uint16_t src_rnti; + uint32_t src_pci; }; struct wait_recfg_comp {}; struct s1_source_ho_st : public subfsm_t { diff --git a/srsenb/hdr/stack/rrc/rrc_ue.h b/srsenb/hdr/stack/rrc/rrc_ue.h index 8d1df7815..8cbcf0540 100644 --- a/srsenb/hdr/stack/rrc/rrc_ue.h +++ b/srsenb/hdr/stack/rrc/rrc_ue.h @@ -253,6 +253,9 @@ private: void apply_pdcp_srb_updates(const asn1::rrc::rr_cfg_ded_s& pending_rr_cfg); void apply_pdcp_drb_updates(const asn1::rrc::rr_cfg_ded_s& pending_rr_cfg); void apply_rlc_rb_updates(const asn1::rrc::rr_cfg_ded_s& pending_rr_cfg); + + /// Find UE whose Handover source identity matches the passed arguments. + ue* find_handover_source_ue(uint16_t old_rnti, uint32_t old_pci); }; // class ue } // namespace srsenb diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index bdecc72eb..1d8bb1ba5 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -207,7 +207,8 @@ uint16_t rrc::start_ho_ue_resource_alloc(const asn1::s1ap::ho_request_s& rrc::ue::rrc_mobility::rrc_mobility(rrc::ue* outer_ue) : base_t(outer_ue->parent->logger), rrc_ue(outer_ue), rrc_enb(outer_ue->parent), logger(outer_ue->parent->logger) -{} +{ +} //! Method to add Mobility Info to a RRC Connection Reconfiguration Message bool rrc::ue::rrc_mobility::fill_conn_recfg_no_ho_cmd(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg) @@ -584,7 +585,8 @@ bool rrc::ue::rrc_mobility::needs_intraenb_ho(idle_st& s, const ho_meas_report_e rrc::ue::rrc_mobility::s1_source_ho_st::s1_source_ho_st(rrc_mobility* parent_) : base_t(parent_), rrc_enb(parent_->rrc_enb), rrc_ue(parent_->rrc_ue), logger(parent_->logger) -{} +{ +} /** * TS 36.413, Section 8.4.6 - eNB Status Transfer @@ -854,6 +856,9 @@ void rrc::ue::rrc_mobility::handle_ho_requested(idle_st& s, const ho_req_rx_ev& rrc_ue->mac_ctrl.handle_target_enb_ho_cmd(recfg_r8, rrc_ue->ue_capabilities); // Apply PHY updates rrc_ue->apply_reconf_phy_config(recfg_r8, true); + // Save source UE PCI and RNTI. + get_state()->src_rnti = hoprep_r8.as_cfg.source_ue_id.to_number(); + get_state()->src_pci = hoprep_r8.as_context.reest_info.source_pci; // Set admitted E-RABs std::vector admitted_erabs; @@ -1178,4 +1183,13 @@ void rrc::ue::rrc_mobility::handle_recfg_complete(intraenb_ho_st& s, const recfg logger.info("User rnti=0x%x successfully handovered to cell_id=0x%x", rrc_ue->rnti, s.target_cell->cell_cfg.cell_id); } +std::pair rrc::ue::rrc_mobility::get_source_ue_rnti_and_pci() +{ + if (not is_ho_running() or (not is_in_state() and not is_in_state())) { + return std::make_pair(SRSRAN_INVALID_RNTI, (uint32_t)0); + } + const s1_target_ho_st* st = get_state(); + return std::make_pair(st->src_rnti, st->src_pci); +} + } // namespace srsenb diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 23907aa31..7403d536b 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -43,7 +43,8 @@ rrc::ue::ue(rrc* outer_rrc, uint16_t rnti_, const sched_interface::ue_cfg_t& sch bearer_list(rnti_, parent->cfg, outer_rrc->gtpu), ue_security_cfg(parent->cfg), mac_ctrl(rnti, ue_cell_list, bearer_list, parent->cfg, parent->mac, *parent->cell_common_list, sched_ue_cfg) -{} +{ +} rrc::ue::~ue() {} @@ -425,7 +426,8 @@ void rrc::ue::parse_ul_dcch(uint32_t lcid, srsran::unique_byte_buffer_t pdu) std::string rrc::ue::to_string(const activity_timeout_type_t& type) { - constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE establishment", "UE reestablishment"}; + constexpr static const char* options[] = { + "Msg3 reception", "UE inactivity", "UE establishment", "UE reestablishment"}; return srsran::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type); } @@ -640,20 +642,29 @@ void rrc::ue::handle_rrc_con_reest_req(rrc_conn_reest_request_s* msg) return; } - uint16_t old_pci = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.pci; - const enb_cell_common* old_cell = parent->cell_common_list->get_pci(old_pci); - auto old_ue_it = parent->users.find(old_rnti); - - // Reject unrecognized rntis, and PCIs that do not belong to eNB - if (old_ue_it == parent->users.end() or old_cell == nullptr or - old_ue_it->second->ue_cell_list.get_enb_cc_idx(old_cell->enb_cc_idx) == nullptr) { - send_connection_reest_rej(procedure_result_code::error_unknown_rnti); - parent->logger.info( - "RRCReestablishmentReject for rnti=0x%x. Cause: no rnti=0x%x context available", rnti, old_rnti); - srsran::console("RRCReestablishmentReject for rnti=0x%x. Cause: no context available\n", rnti); - return; + uint16_t old_pci = msg->crit_exts.rrc_conn_reest_request_r8().ue_id.pci; + ue* old_ue = nullptr; + { + const enb_cell_common* old_cell = parent->cell_common_list->get_pci(old_pci); + auto old_ue_it = parent->users.find(old_rnti); + + // Reject unrecognized rntis, and PCIs that do not belong to eNB + if (old_ue_it == parent->users.end() or old_cell == nullptr or + old_ue_it->second->ue_cell_list.get_enb_cc_idx(old_cell->enb_cc_idx) == nullptr) { + // Check if old UE context does not belong to an S1-Handover UE. + old_ue = find_handover_source_ue(old_rnti, old_pci); + if (old_ue == nullptr) { + send_connection_reest_rej(procedure_result_code::error_unknown_rnti); + parent->logger.info( + "RRCReestablishmentReject for rnti=0x%x. Cause: no rnti=0x%x context available", rnti, old_rnti); + srsran::console("RRCReestablishmentReject for rnti=0x%x. Cause: no context available\n", rnti); + return; + } + } else { + old_ue = old_ue_it->second.get(); + } } - ue* old_ue = old_ue_it->second.get(); + bool old_ue_supported_endc = old_ue->endc_handler and old_ue->endc_handler->is_endc_supported(); if (not old_ue_supported_endc and req_r8.reest_cause.value == reest_cause_opts::recfg_fail) { // Reestablishment Reject for ReconfigFailures of LTE-only mode @@ -1636,4 +1647,22 @@ int rrc::ue::get_ri(uint32_t m_ri, uint16_t* ri_idx) return ret; } +rrc::ue* rrc::ue::find_handover_source_ue(uint16_t old_rnti, uint32_t old_pci) +{ + for (auto& ue_pair : parent->users) { + rrc::ue& u = *ue_pair.second; + if (u.mobility_handler != nullptr and u.mobility_handler->is_ho_running()) { + std::pair src_ctxt = u.mobility_handler->get_source_ue_rnti_and_pci(); + if (src_ctxt.first == old_rnti and src_ctxt.second == old_pci) { + parent->logger.info("Found old UE Context RNTI=0x%x,PCI=%d used for Reestablishment. It corresponds to a UE " + "performing handover.", + old_rnti, + old_pci); + return &u; + } + } + } + return nullptr; +} + } // namespace srsenb