From 37ce47539866eb4ee5b4238eb4206996c072c881 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Fri, 29 May 2020 16:27:45 +0100 Subject: [PATCH] fix+refactor of the ue rrc handover preparation procedure to avoid deadlocking --- srsue/hdr/stack/rrc/rrc.h | 54 +++---- srsue/hdr/stack/rrc/rrc_procedures.h | 46 +++++- srsue/src/stack/rrc/rrc.cc | 142 ++---------------- srsue/src/stack/rrc/rrc_procedures.cc | 201 +++++++++++++++++++++++++- 4 files changed, 276 insertions(+), 167 deletions(-) diff --git a/srsue/hdr/stack/rrc/rrc.h b/srsue/hdr/stack/rrc/rrc.h index b41b5407c..77b29347b 100644 --- a/srsue/hdr/stack/rrc/rrc.h +++ b/srsue/hdr/stack/rrc/rrc.h @@ -113,13 +113,14 @@ public: } } - cell_t() { + cell_t() + { gettimeofday(&last_update, nullptr); has_valid_sib1 = false; has_valid_sib2 = false; has_valid_sib3 = false; has_valid_sib13 = false; - phy_cell = {0,0,0}; + phy_cell = {0, 0, 0}; rsrp = NAN; rsrq = NAN; sib1 = {}; @@ -128,14 +129,11 @@ public: sib13 = {}; } - cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell_) : cell_t() - { - phy_cell = phy_cell_; - } + cell_t(phy_interface_rrc_lte::phy_cell_t phy_cell_) : cell_t() { phy_cell = phy_cell_; } - uint32_t get_earfcn() { return phy_cell.earfcn; } + uint32_t get_earfcn() const { return phy_cell.earfcn; } - uint32_t get_pci() { return phy_cell.pci; } + uint32_t get_pci() const { return phy_cell.pci; } void set_rsrp(float rsrp_) { @@ -157,9 +155,9 @@ public: } } - float get_rsrp() { return rsrp; } - float get_rsrq() { return rsrq; } - float get_cfo_hz() { return phy_cell.cfo_hz; } + float get_rsrp() const { return rsrp; } + float get_rsrq() const { return rsrq; } + float get_cfo_hz() const { return phy_cell.cfo_hz; } void set_sib1(asn1::rrc::sib_type1_s* sib1_); void set_sib2(asn1::rrc::sib_type2_s* sib2_); @@ -181,7 +179,7 @@ public: asn1::rrc::sib_type3_s* sib3ptr() { return &sib3; } asn1::rrc::sib_type13_r9_s* sib13ptr() { return &sib13; } - uint32_t get_cell_id() { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); } + uint32_t get_cell_id() const { return (uint32_t)sib1.cell_access_related_info.cell_id.to_number(); } bool has_sib1() { return has_valid_sib1; } bool has_sib2() { return has_valid_sib2; } @@ -239,7 +237,7 @@ public: return 0; } - std::string to_string() + std::string to_string() const { char buf[256]; snprintf(buf, @@ -370,16 +368,16 @@ private: void process_pcch(srslte::unique_byte_buffer_t pdu); - stack_interface_rrc* stack = nullptr; - srslte::byte_buffer_pool* pool = nullptr; - srslte::log_ref rrc_log; - phy_interface_rrc_lte* phy = nullptr; - mac_interface_rrc* mac = nullptr; - rlc_interface_rrc* rlc = nullptr; - pdcp_interface_rrc* pdcp = nullptr; - nas_interface_rrc* nas = nullptr; - usim_interface_rrc* usim = nullptr; - gw_interface_rrc* gw = nullptr; + stack_interface_rrc* stack = nullptr; + srslte::byte_buffer_pool* pool = nullptr; + srslte::log_ref rrc_log; + phy_interface_rrc_lte* phy = nullptr; + mac_interface_rrc* mac = nullptr; + rlc_interface_rrc* rlc = nullptr; + pdcp_interface_rrc* pdcp = nullptr; + nas_interface_rrc* nas = nullptr; + usim_interface_rrc* usim = nullptr; + gw_interface_rrc* gw = nullptr; srslte::unique_byte_buffer_t dedicated_info_nas; @@ -407,8 +405,8 @@ private: srslte::phy_cfg_t current_phy_cfg, previous_phy_cfg = {}; srslte::mac_cfg_t current_mac_cfg, previous_mac_cfg = {}; bool current_scell_configured[SRSLTE_MAX_CARRIERS] = {}; - bool pending_mob_reconf = false; - asn1::rrc::rrc_conn_recfg_s mob_reconf = {}; + bool pending_mob_reconf = false; + asn1::rrc::rrc_conn_recfg_s mob_reconf = {}; srslte::as_security_config_t sec_cfg = {}; @@ -516,6 +514,7 @@ private: enum class cs_result_t { changed_cell, same_cell, no_cell }; // RRC procedures (fwd declared) + class phy_cell_select_proc; class cell_search_proc; class si_acquire_proc; class serving_cell_config_proc; @@ -526,6 +525,8 @@ private: class go_idle_proc; class cell_reselection_proc; class connection_reest_proc; + class ho_prep_proc; + srslte::proc_t phy_cell_selector; srslte::proc_t cell_searcher; srslte::proc_t si_acquirer; srslte::proc_t serv_cell_cfg; @@ -536,6 +537,7 @@ private: srslte::proc_t plmn_searcher; srslte::proc_t cell_reselector; srslte::proc_t connection_reest; + srslte::proc_t ho_prep_proc; srslte::proc_manager_list_t callback_list; @@ -572,9 +574,7 @@ private: bool con_reconfig(asn1::rrc::rrc_conn_recfg_s* reconfig); void con_reconfig_failed(); bool con_reconfig_ho(asn1::rrc::rrc_conn_recfg_s* reconfig); - bool ho_prepare(); void ho_failed(); - void start_ho(); void start_go_idle(); void rrc_connection_release(const std::string& cause); void radio_link_failure(); diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index fdb1d605e..25f55a50d 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -35,7 +35,7 @@ namespace srsue { // background workers use this event to signal the result of a cell select phy procedure struct cell_select_event_t { - cell_select_event_t(bool c_) : cs_ret(c_) {} + explicit cell_select_event_t(bool c_) : cs_ret(c_) {} bool cs_ret; }; @@ -43,6 +43,22 @@ struct cell_select_event_t { * Procedures *******************************/ +class rrc::phy_cell_select_proc +{ +public: + explicit phy_cell_select_proc(rrc* parent_); + srslte::proc_outcome_t init(const cell_t& target_cell); + srslte::proc_outcome_t react(cell_select_event_t ev); + void then(const srslte::proc_state_t& result); + srslte::proc_outcome_t step() { return srslte::proc_outcome_t::yield; } + static const char* name() { return "PHY Cell Select"; } + +private: + // args + rrc* rrc_ptr; + const cell_t* target_cell; +}; + class rrc::cell_search_proc { public: @@ -85,8 +101,7 @@ public: struct si_acq_timer_expired { uint32_t timer_id; }; - struct sib_received_ev { - }; + struct sib_received_ev {}; explicit si_acquire_proc(rrc* parent_); srslte::proc_outcome_t init(uint32_t sib_index_); @@ -287,6 +302,31 @@ private: srslte::proc_outcome_t cell_criteria(); }; +class rrc::ho_prep_proc +{ +public: + struct t304_expiry {}; + + explicit ho_prep_proc(rrc* rrc_); + srslte::proc_outcome_t init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf); + srslte::proc_outcome_t react(cell_select_event_t ev); + srslte::proc_outcome_t react(t304_expiry ev); + srslte::proc_outcome_t step(); + void then(const srslte::proc_state_t& result); + static const char* name() { return "Handover Preparation"; } + +private: + rrc* rrc_ptr = nullptr; + + // args + asn1::rrc::rrc_conn_recfg_r8_ies_s recfg_r8; + cell_t ho_src_cell; + uint16_t ho_src_rnti = 0; + + // state + uint32_t target_earfcn; +}; + } // namespace srsue #endif // SRSLTE_RRC_PROCEDURES_H diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index 3a7c6735a..d6d19b336 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -89,6 +89,7 @@ rrc::rrc(stack_interface_rrc* stack_) : last_state(RRC_STATE_CONNECTED), drb_up(false), rrc_log("RRC"), + phy_cell_selector(this), cell_searcher(this), si_acquirer(this), serv_cell_cfg(this), @@ -99,6 +100,7 @@ rrc::rrc(stack_interface_rrc* stack_) : plmn_searcher(this), cell_reselector(this), connection_reest(this), + ho_prep_proc(this), serving_cell(unique_cell_t(new cell_t())) { measurements = std::unique_ptr(new rrc_meas()); @@ -1042,103 +1044,6 @@ void rrc::send_rrc_con_reconfig_complete() send_ul_dcch_msg(RB_ID_SRB1, ul_dcch_msg); } -bool rrc::ho_prepare() -{ - if (pending_mob_reconf) { - rrc_conn_recfg_r8_ies_s* mob_reconf_r8 = &mob_reconf.crit_exts.c1().rrc_conn_recfg_r8(); - mob_ctrl_info_s* mob_ctrl_info = &mob_reconf_r8->mob_ctrl_info; - rrc_log->info("Processing HO command to target PCell=%d\n", mob_ctrl_info->target_pci); - - uint32_t target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq - : serving_cell->get_earfcn(); - - if (not has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) { - rrc_log->console("Received HO command to unknown PCI=%d\n", mob_ctrl_info->target_pci); - rrc_log->error( - "Could not find target cell earfcn=%d, pci=%d\n", serving_cell->get_earfcn(), mob_ctrl_info->target_pci); - return false; - } - - // Section 5.3.5.4 - t310.stop(); - t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { timer_expired(tid); }); - - // Save serving cell and current configuration - ho_src_cell = *serving_cell; - mac_interface_rrc::ue_rnti_t uernti; - mac->get_rntis(&uernti); - ho_src_rnti = uernti.crnti; - - // Reset/Reestablish stack - pdcp->reestablish(); - rlc->reestablish(); - mac->wait_uplink(); - mac->clear_rntis(); - mac->reset(); - phy->reset(); - - mac->set_ho_rnti(mob_ctrl_info->new_ue_id.to_number(), mob_ctrl_info->target_pci); - - // Apply common config, but do not send to lower layers if Dedicated is present (to avoid sending twice) - apply_rr_config_common(&mob_ctrl_info->rr_cfg_common, !mob_reconf_r8->rr_cfg_ded_present); - - if (mob_reconf_r8->rr_cfg_ded_present) { - apply_rr_config_dedicated(&mob_reconf_r8->rr_cfg_ded); - } - - cell_t* target_cell = get_neighbour_cell_handle(target_earfcn, mob_ctrl_info->target_pci); - if (not phy->cell_select(&target_cell->phy_cell)) { - rrc_log->error("Could not synchronize with target cell %s. Removing cell and trying to return to source %s\n", - target_cell->to_string().c_str(), - serving_cell->to_string().c_str()); - - // Remove cell from list to avoid cell re-selection, picking the same cell - target_cell->set_rsrp(-INFINITY); - - return false; - } - - set_serving_cell(target_cell->phy_cell, false); - - // Extract and apply scell config if any - apply_scell_config(mob_reconf_r8); - - if (mob_ctrl_info->rach_cfg_ded_present) { - rrc_log->info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n", - mob_ctrl_info->rach_cfg_ded.ra_preamb_idx, - mob_ctrl_info->rach_cfg_ded.ra_prach_mask_idx); - mac->start_noncont_ho(mob_ctrl_info->rach_cfg_ded.ra_preamb_idx, mob_ctrl_info->rach_cfg_ded.ra_prach_mask_idx); - } else { - rrc_log->info("Starting contention-based RA\n"); - mac->start_cont_ho(); - } - - int ncc = -1; - if (mob_reconf_r8->security_cfg_ho_present) { - ncc = mob_reconf_r8->security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count; - if (mob_reconf_r8->security_cfg_ho.handov_type.intra_lte().key_change_ind) { - rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); - return false; - } - if (mob_reconf_r8->security_cfg_ho.handov_type.intra_lte().security_algorithm_cfg_present) { - sec_cfg.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM)mob_reconf_r8->security_cfg_ho.handov_type.intra_lte() - .security_algorithm_cfg.ciphering_algorithm.to_number(); - sec_cfg.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM)mob_reconf_r8->security_cfg_ho.handov_type.intra_lte() - .security_algorithm_cfg.integrity_prot_algorithm.to_number(); - rrc_log->info("Changed Ciphering to %s and Integrity to %s\n", - ciphering_algorithm_id_text[sec_cfg.cipher_algo], - integrity_algorithm_id_text[sec_cfg.integ_algo]); - } - } - - usim->generate_as_keys_ho(mob_ctrl_info->target_pci, serving_cell->get_earfcn(), ncc, &sec_cfg); - - pdcp->config_security_all(sec_cfg); - send_rrc_con_reconfig_complete(); - } - return true; -} - void rrc::ho_ra_completed(bool ra_successful) { cmd_msg_t msg; @@ -1170,39 +1075,17 @@ void rrc::process_ho_ra_completed(bool ra_successful) bool rrc::con_reconfig_ho(rrc_conn_recfg_s* reconfig) { - rrc_conn_recfg_r8_ies_s* mob_reconf_r8 = &reconfig->crit_exts.c1().rrc_conn_recfg_r8(); - if (mob_reconf_r8->mob_ctrl_info.target_pci == serving_cell->get_pci()) { - rrc_log->console("Warning: Received HO command to own cell\n"); - rrc_log->warning("Received HO command to own cell\n"); - return false; - } - - rrc_log->info("Received HO command to target PCell=%d\n", mob_reconf_r8->mob_ctrl_info.target_pci); - rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", - mob_reconf_r8->mob_ctrl_info.target_pci, - mob_reconf_r8->security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count); - // store mobilityControlInfo mob_reconf = *reconfig; pending_mob_reconf = true; - start_ho(); - return true; -} + if (not ho_prep_proc.launch(*reconfig)) { + rrc_log->error("Unable to launch Handover Preparation procedure\n"); + return false; + } + callback_list.add_proc(ho_prep_proc); -void rrc::start_ho() -{ - callback_list.add_task([this]() { - if (state != RRC_STATE_CONNECTED) { - rrc_log->info("HO interrupted, since RRC is no longer in connected state\n"); - return srslte::proc_outcome_t::success; - } - if (not ho_prepare()) { - con_reconfig_failed(); - return srslte::proc_outcome_t::error; - } - return srslte::proc_outcome_t::success; - }); + return true; } void rrc::start_go_idle() @@ -1275,6 +1158,7 @@ bool rrc::con_reconfig(rrc_conn_recfg_s* reconfig) // HO failure from T304 expiry 5.3.5.6 void rrc::ho_failed() { + ho_prep_proc.trigger(ho_prep_proc::t304_expiry{}); start_con_restablishment(reest_cause_e::ho_fail); } @@ -1304,9 +1188,7 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, rrc_conn_recfg_s* reconfig) rrc_conn_recfg_r8_ies_s* reconfig_r8 = &reconfig->crit_exts.c1().rrc_conn_recfg_r8(); if (reconfig_r8->mob_ctrl_info_present) { - if (!con_reconfig_ho(reconfig)) { - con_reconfig_failed(); - } + con_reconfig_ho(reconfig); } else { if (!con_reconfig(reconfig)) { con_reconfig_failed(); @@ -1401,9 +1283,7 @@ void rrc::cell_search_completed(const phy_interface_rrc_lte::cell_search_ret_t& void rrc::cell_select_completed(bool cs_ret) { - cell_select_event_t ev{cs_ret}; - cell_searcher.trigger(ev); - cell_selector.trigger(ev); + phy_cell_selector.trigger(cell_select_event_t{cs_ret}); } /******************************************************************************* diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index e7527b792..8e7b2ea02 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -20,6 +20,7 @@ */ #include "srsue/hdr/stack/rrc/rrc_procedures.h" +#include "srslte/common/security.h" #include "srslte/common/tti_point.h" #include // for printing uint64_t @@ -33,6 +34,36 @@ namespace srsue { using srslte::proc_outcome_t; using srslte::tti_point; +/************************************** + * PHY Cell Select Procedure + *************************************/ + +rrc::phy_cell_select_proc::phy_cell_select_proc(rrc* parent_) : rrc_ptr(parent_) {} + +srslte::proc_outcome_t rrc::phy_cell_select_proc::init(const cell_t& target_cell_) +{ + target_cell = &target_cell_; + Info("Starting for %s\n", target_cell->to_string().c_str()); + rrc_ptr->stack->start_cell_select(&target_cell->phy_cell); + return proc_outcome_t::yield; +} + +srslte::proc_outcome_t rrc::phy_cell_select_proc::react(cell_select_event_t ev) +{ + if (not ev.cs_ret) { + Error("Couldn't select new serving cell\n"); + return proc_outcome_t::error; + } + return proc_outcome_t::success; +} + +void rrc::phy_cell_select_proc::then(const srslte::proc_state_t& result) +{ + // Warn other procedures that depend on this procedure + rrc_ptr->cell_searcher.trigger(cell_select_event_t{result.is_success()}); + rrc_ptr->cell_selector.trigger(cell_select_event_t{result.is_success()}); +} + /************************************** * Cell Search Procedure *************************************/ @@ -92,7 +123,10 @@ proc_outcome_t rrc::cell_search_proc::handle_cell_found(const phy_interface_rrc_ // set new serving cell in PHY state = state_t::phy_cell_select; - rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell); + if (not rrc_ptr->phy_cell_selector.launch(rrc_ptr->serving_cell->phy_cell)) { + Error("Couldn't start phy cell selection\n"); + return proc_outcome_t::error; + } return proc_outcome_t::yield; } @@ -366,8 +400,7 @@ proc_outcome_t rrc::si_acquire_proc::react(si_acq_timer_expired ev) rrc::serving_cell_config_proc::serving_cell_config_proc(rrc* parent_) : rrc_ptr(parent_), log_h(srslte::logmap::get("RRC")) -{ -} +{} /* * Retrieves all required SIB or configures them if already retrieved before @@ -508,7 +541,10 @@ proc_outcome_t rrc::cell_selection_proc::start_cell_selection() Info("Selected cell: %s\n", rrc_ptr->serving_cell->to_string().c_str()); state = search_state_t::cell_selection; - rrc_ptr->stack->start_cell_select(&rrc_ptr->serving_cell->phy_cell); + if (not rrc_ptr->phy_cell_selector.launch(rrc_ptr->serving_cell->phy_cell)) { + Error("Failed to launch PHY Cell Selection\n"); + return proc_outcome_t::error; + } return proc_outcome_t::yield; } } @@ -735,8 +771,7 @@ void rrc::plmn_search_proc::then(const srslte::proc_state_t& result) const rrc::connection_request_proc::connection_request_proc(rrc* parent_) : rrc_ptr(parent_), log_h(srslte::logmap::get("RRC")) -{ -} +{} proc_outcome_t rrc::connection_request_proc::init(srslte::establishment_cause_t cause_, srslte::unique_byte_buffer_t dedicated_info_nas_) @@ -1292,4 +1327,158 @@ proc_outcome_t rrc::connection_reest_proc::step() return ret; } +/************************************** + * Handover Preparation Procedure + *************************************/ + +rrc::ho_prep_proc::ho_prep_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_) {} + +srslte::proc_outcome_t rrc::ho_prep_proc::init(const asn1::rrc::rrc_conn_recfg_s& rrc_reconf) +{ + Info("Starting...\n"); + recfg_r8 = rrc_reconf.crit_exts.c1().rrc_conn_recfg_r8(); + asn1::rrc::mob_ctrl_info_s* mob_ctrl_info = &recfg_r8.mob_ctrl_info; + + if (recfg_r8.mob_ctrl_info.target_pci == rrc_ptr->serving_cell->get_pci()) { + rrc_ptr->rrc_log->console("Warning: Received HO command to own cell\n"); + Warning("Received HO command to own cell\n"); + return proc_outcome_t::error; + } + + Info("Received HO command to target PCell=%d\n", recfg_r8.mob_ctrl_info.target_pci); + rrc_ptr->rrc_log->console("Received HO command to target PCell=%d, NCC=%d\n", + recfg_r8.mob_ctrl_info.target_pci, + recfg_r8.security_cfg_ho.handov_type.intra_lte().next_hop_chaining_count); + + target_earfcn = (mob_ctrl_info->carrier_freq_present) ? mob_ctrl_info->carrier_freq.dl_carrier_freq + : rrc_ptr->serving_cell->get_earfcn(); + + if (not rrc_ptr->has_neighbour_cell(target_earfcn, mob_ctrl_info->target_pci)) { + rrc_ptr->rrc_log->console("Received HO command to unknown PCI=%d\n", mob_ctrl_info->target_pci); + Error("Could not find target cell earfcn=%d, pci=%d\n", + rrc_ptr->serving_cell->get_earfcn(), + mob_ctrl_info->target_pci); + return proc_outcome_t::error; + } + + // Section 5.3.5.4 + rrc_ptr->t310.stop(); + rrc_ptr->t304.set(mob_ctrl_info->t304.to_number(), [this](uint32_t tid) { rrc_ptr->timer_expired(tid); }); + + // Save serving cell and current configuration + ho_src_cell = *rrc_ptr->serving_cell; + mac_interface_rrc::ue_rnti_t uernti; + rrc_ptr->mac->get_rntis(&uernti); + ho_src_rnti = uernti.crnti; + + // Reset/Reestablish stack + rrc_ptr->pdcp->reestablish(); + rrc_ptr->rlc->reestablish(); + rrc_ptr->mac->wait_uplink(); + rrc_ptr->mac->clear_rntis(); + rrc_ptr->mac->reset(); + rrc_ptr->phy->reset(); + + rrc_ptr->mac->set_ho_rnti(mob_ctrl_info->new_ue_id.to_number(), mob_ctrl_info->target_pci); + + // Apply common config, but do not send to lower layers if Dedicated is present (to avoid sending twice) + rrc_ptr->apply_rr_config_common(&mob_ctrl_info->rr_cfg_common, !recfg_r8.rr_cfg_ded_present); + + if (recfg_r8.rr_cfg_ded_present) { + rrc_ptr->apply_rr_config_dedicated(&recfg_r8.rr_cfg_ded); + } + + cell_t* target_cell = rrc_ptr->get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci); + if (not rrc_ptr->phy_cell_selector.launch(*target_cell)) { + Error("Failed to launch the selection of target cell %s\n", target_cell->to_string().c_str()); + return proc_outcome_t::error; + } + return proc_outcome_t::yield; +} + +srslte::proc_outcome_t rrc::ho_prep_proc::react(srsue::cell_select_event_t ev) +{ + // Check if cell has not been deleted in the meantime + cell_t* target_cell = rrc_ptr->get_neighbour_cell_handle(target_earfcn, recfg_r8.mob_ctrl_info.target_pci); + if (target_cell == nullptr) { + Error("Cell removed from list of neighbours. Aborting handover preparation\n"); + return proc_outcome_t::error; + } + + if (not ev.cs_ret) { + Error("Could not synchronize with target cell %s. Removing cell and trying to return to source %s\n", + target_cell->to_string().c_str(), + rrc_ptr->serving_cell->to_string().c_str()); + + // Remove cell from list to avoid cell re-selection, picking the same cell + target_cell->set_rsrp(-INFINITY); + return proc_outcome_t::error; + } + + rrc_ptr->set_serving_cell(target_cell->phy_cell, false); + + // Extract and apply scell config if any + rrc_ptr->apply_scell_config(&recfg_r8); + + if (recfg_r8.mob_ctrl_info.rach_cfg_ded_present) { + Info("Starting non-contention based RA with preamble_idx=%d, mask_idx=%d\n", + recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx, + recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx); + rrc_ptr->mac->start_noncont_ho(recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_preamb_idx, + recfg_r8.mob_ctrl_info.rach_cfg_ded.ra_prach_mask_idx); + } else { + Info("Starting contention-based RA\n"); + rrc_ptr->mac->start_cont_ho(); + } + + int ncc = -1; + if (recfg_r8.security_cfg_ho_present) { + auto& sec_intralte = recfg_r8.security_cfg_ho.handov_type.intra_lte(); + ncc = sec_intralte.next_hop_chaining_count; + if (sec_intralte.key_change_ind) { + rrc_ptr->rrc_log->console("keyChangeIndicator in securityConfigHO not supported\n"); + return proc_outcome_t::error; + } + if (sec_intralte.security_algorithm_cfg_present) { + rrc_ptr->sec_cfg.cipher_algo = + (srslte::CIPHERING_ALGORITHM_ID_ENUM)sec_intralte.security_algorithm_cfg.ciphering_algorithm.to_number(); + rrc_ptr->sec_cfg.integ_algo = + (srslte::INTEGRITY_ALGORITHM_ID_ENUM)sec_intralte.security_algorithm_cfg.integrity_prot_algorithm.to_number(); + Info("Changed Ciphering to %s and Integrity to %s\n", + srslte::ciphering_algorithm_id_text[rrc_ptr->sec_cfg.cipher_algo], + srslte::integrity_algorithm_id_text[rrc_ptr->sec_cfg.integ_algo]); + } + } + + rrc_ptr->usim->generate_as_keys_ho( + recfg_r8.mob_ctrl_info.target_pci, rrc_ptr->serving_cell->get_earfcn(), ncc, &rrc_ptr->sec_cfg); + + rrc_ptr->pdcp->config_security_all(rrc_ptr->sec_cfg); + return proc_outcome_t::success; +} + +srslte::proc_outcome_t rrc::ho_prep_proc::step() +{ + if (rrc_ptr->state != RRC_STATE_CONNECTED) { + Info("HO interrupted, since RRC is no longer in connected state\n"); + return srslte::proc_outcome_t::error; + } + return proc_outcome_t::success; +} + +srslte::proc_outcome_t rrc::ho_prep_proc::react(t304_expiry ev) +{ + Info("HO preparation timed out.\n"); + return proc_outcome_t::error; +} + +void rrc::ho_prep_proc::then(const srslte::proc_state_t& result) +{ + if (result.is_error()) { + rrc_ptr->con_reconfig_failed(); + } else { + rrc_ptr->send_rrc_con_reconfig_complete(); + } +} + } // namespace srsue