mirror of https://github.com/PentHertz/srsLTE.git
fix+refactor of the ue rrc handover preparation procedure to avoid deadlocking
This commit is contained in:
parent
960c0e97cd
commit
37ce475398
|
@ -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_select_proc> phy_cell_selector;
|
||||
srslte::proc_t<cell_search_proc, phy_interface_rrc_lte::cell_search_ret_t> cell_searcher;
|
||||
srslte::proc_t<si_acquire_proc> si_acquirer;
|
||||
srslte::proc_t<serving_cell_config_proc> serv_cell_cfg;
|
||||
|
@ -536,6 +537,7 @@ private:
|
|||
srslte::proc_t<plmn_search_proc> plmn_searcher;
|
||||
srslte::proc_t<cell_reselection_proc> cell_reselector;
|
||||
srslte::proc_t<connection_reest_proc> connection_reest;
|
||||
srslte::proc_t<ho_prep_proc> 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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<rrc_meas>(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});
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "srsue/hdr/stack/rrc/rrc_procedures.h"
|
||||
#include "srslte/common/security.h"
|
||||
#include "srslte/common/tti_point.h"
|
||||
#include <inttypes.h> // 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
|
||||
|
|
Loading…
Reference in New Issue