From 73e21daeb25e81e5f8a6de3e070820e9066db97e Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Mon, 21 Sep 2020 18:04:12 +0200 Subject: [PATCH] refactor reestablishment procedure to more closely follow TS. --- srsue/hdr/stack/rrc/rrc_procedures.h | 16 +- srsue/src/stack/rrc/rrc.cc | 2 + srsue/src/stack/rrc/rrc_procedures.cc | 321 ++++++++++++-------------- 3 files changed, 163 insertions(+), 176 deletions(-) diff --git a/srsue/hdr/stack/rrc/rrc_procedures.h b/srsue/hdr/stack/rrc/rrc_procedures.h index 56510bbaa..b06a4e4ad 100644 --- a/srsue/hdr/stack/rrc/rrc_procedures.h +++ b/srsue/hdr/stack/rrc/rrc_procedures.h @@ -101,6 +101,7 @@ public: explicit serving_cell_config_proc(rrc* parent_); srslte::proc_outcome_t init(const std::vector& required_sibs_); srslte::proc_outcome_t step(); + void then(const srslte::proc_state_t& result); static const char* name() { return "Serving Cell Configuration"; } private: @@ -259,14 +260,20 @@ private: class rrc::connection_reest_proc { public: + struct t311_expiry {}; + struct serv_cell_cfg_completed {}; + explicit connection_reest_proc(rrc* rrc_); srslte::proc_outcome_t init(asn1::rrc::reest_cause_e cause); - srslte::proc_outcome_t step(); + srslte::proc_outcome_t step() { return srslte::proc_outcome_t::yield; } + srslte::proc_outcome_t react(const t311_expiry& ev); + srslte::proc_outcome_t react(const cell_selection_proc::cell_selection_complete_ev& e); + srslte::proc_outcome_t react(const serv_cell_cfg_completed& result); static const char* name() { return "Connection re-establishment"; } uint32_t get_source_earfcn() const { return reest_source_freq; } private: - enum class state_t { cell_reselection, cell_configuration } state; + enum class state_t { wait_cell_selection, wait_cell_configuration, wait_reest_msg } state; rrc* rrc_ptr = nullptr; asn1::rrc::reest_cause_e reest_cause = asn1::rrc::reest_cause_e::nulltype; @@ -274,9 +281,10 @@ private: uint16_t reest_source_pci = 0; uint32_t reest_source_freq = 0; - srslte::proc_outcome_t step_cell_reselection(); - srslte::proc_outcome_t step_cell_configuration(); + bool sibs_acquired() const; + bool passes_cell_criteria() const; srslte::proc_outcome_t cell_criteria(); + srslte::proc_outcome_t start_cell_selection(); }; class rrc::ho_proc diff --git a/srsue/src/stack/rrc/rrc.cc b/srsue/src/stack/rrc/rrc.cc index db0f1f184..55d57b74f 100644 --- a/srsue/src/stack/rrc/rrc.cc +++ b/srsue/src/stack/rrc/rrc.cc @@ -657,11 +657,13 @@ void rrc::timer_expired(uint32_t timeout_id) rrc_log->info("Timer T310 expired: Radio Link Failure\n"); radio_link_failure_push_cmd(); } else if (timeout_id == t311.id()) { + rrc_log->console("Timer T311 expired: Going to RRC IDLE\n"); if (connection_reest.is_idle()) { rrc_log->info("Timer T311 expired: Going to RRC IDLE\n"); start_go_idle(); } else { // Do nothing, this is handled by the procedure + connection_reest.trigger(connection_reest_proc::t311_expiry{}); } } else if (timeout_id == t301.id()) { if (state == RRC_STATE_IDLE) { diff --git a/srsue/src/stack/rrc/rrc_procedures.cc b/srsue/src/stack/rrc/rrc_procedures.cc index 9da8c7d5e..8ae036567 100644 --- a/srsue/src/stack/rrc/rrc_procedures.cc +++ b/srsue/src/stack/rrc/rrc_procedures.cc @@ -444,6 +444,13 @@ proc_outcome_t rrc::serving_cell_config_proc::step() return launch_sib_acquire(); } +void rrc::serving_cell_config_proc::then(const srslte::proc_state_t& result) +{ + if (rrc_ptr->connection_reest.is_busy()) { + rrc_ptr->connection_reest.trigger(connection_reest_proc::serv_cell_cfg_completed{}); + } +} + /************************************** * Cell Selection Procedure *************************************/ @@ -661,10 +668,14 @@ proc_outcome_t rrc::cell_selection_proc::step() void rrc::cell_selection_proc::then(const srslte::proc_result_t& proc_result) const { // Inform Connection Request Procedure - Info("Completed with %s. Informing proc %s\n", - proc_result.is_success() ? "success" : "failure", - rrc_ptr->conn_req_proc.get()->name()); - rrc_ptr->conn_req_proc.trigger(proc_result); + if (rrc_ptr->conn_req_proc.is_busy()) { + Info("Completed with %s. Informing proc %s\n", + proc_result.is_success() ? "success" : "failure", + rrc_ptr->conn_req_proc.get()->name()); + rrc_ptr->conn_req_proc.trigger(proc_result); + } else if (rrc_ptr->connection_reest.is_busy()) { + rrc_ptr->connection_reest.trigger(proc_result); + } } /************************************** @@ -1133,215 +1144,181 @@ void rrc::cell_reselection_proc::then(const srslte::proc_state_t& result) * RRC Connection Re-establishment procedure *************************************/ -rrc::connection_reest_proc::connection_reest_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_), state(state_t::cell_reselection) {} +rrc::connection_reest_proc::connection_reest_proc(srsue::rrc* rrc_) : rrc_ptr(rrc_), state(state_t::wait_cell_selection) +{} proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause) { - Info("Starting... Cause: %s\n", - cause == asn1::rrc::reest_cause_opts::recfg_fail - ? "Reconfiguration failure" - : cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure"); - // Save Current RNTI before MAC Reset mac_interface_rrc::ue_rnti_t uernti; rrc_ptr->mac->get_rntis(&uernti); - // If security is activated, RRC connected and C-RNTI available - if (rrc_ptr->security_is_activated && rrc_ptr->state == RRC_STATE_CONNECTED && uernti.crnti != 0) { - // Save reestablishment cause and current C-RNTI - reest_rnti = uernti.crnti; - reest_cause = cause; - reest_source_pci = rrc_ptr->meas_cells.serving_cell().get_pci(); // needed for reestablishment with another cell - reest_source_freq = rrc_ptr->meas_cells.serving_cell().get_earfcn(); + // 5.3.7.1 - Conditions for Reestablishment procedure + if (not rrc_ptr->security_is_activated or rrc_ptr->state != RRC_STATE_CONNECTED or + uernti.crnti == SRSLTE_INVALID_RNTI) { + Warning("Conditions are NOT met to start procedure.\n"); + return proc_outcome_t::error; + } - // the initiation of reestablishment procedure as indicates in 3GPP 36.331 Section 5.3.7.2 - // Cannot be called from here because it has PHY-MAC re-configuration that should be performed in a different thread - Info("Conditions are met. Initiating RRC Connection Reestablishment Procedure\n"); + // Save reestablishment Cause and current C-RNTI context + reest_rnti = uernti.crnti; + reest_cause = cause; + reest_source_pci = rrc_ptr->meas_cells.serving_cell().get_pci(); // needed for reestablishment with another cell + reest_source_freq = rrc_ptr->meas_cells.serving_cell().get_earfcn(); - // stop timer T310, if running; - rrc_ptr->t310.stop(); + Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, DL-EARFCN=%d}\n", + reest_cause == asn1::rrc::reest_cause_opts::recfg_fail + ? "Reconfiguration failure" + : cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure", + reest_rnti, + reest_source_pci, + reest_source_freq); - // start timer T311; - rrc_ptr->t311.run(); + // 5.3.7.2 - Initiation - // Suspend all RB except SRB0 - for (int i = 1; i < SRSLTE_N_RADIO_BEARERS; i++) { - if (rrc_ptr->rlc->has_bearer(i)) { - rrc_ptr->rlc->suspend_bearer(i); - } - } + // 1> stop timer T310, if running; + rrc_ptr->t310.stop(); - // reset MAC; - rrc_ptr->mac->reset(); + // 1> start timer T311; + rrc_ptr->t311.run(); - // configure lower layers to consider the SCell(s), if configured, to be in deactivated state; - rrc_ptr->phy->set_activation_deactivation_scell(0); + // 1> Suspend all RB except SRB0; + for (int i = 1; i < SRSLTE_N_RADIO_BEARERS; i++) { + if (rrc_ptr->rlc->has_bearer(i)) { + rrc_ptr->rlc->suspend_bearer(i); + } + } - // apply the default physical channel configuration as specified in 9.2.4; - // Note: this is done by the MAC Reset procedure + // 1> reset MAC; + rrc_ptr->mac->reset(); - // apply the default semi-persistent scheduling configuration as specified in 9.2.3; - // N.A. + // configure lower layers to consider the SCell(s), if configured, to be in deactivated state; + rrc_ptr->phy->set_activation_deactivation_scell(0); - // apply the default MAC main configuration as specified in 9.2.2; - rrc_ptr->apply_mac_config_dedicated_default(); - // Launch cell reselection - if (not rrc_ptr->cell_reselector.launch()) { - Error("Failed to initiate a Cell re-selection procedure...\n"); - return proc_outcome_t::error; - } - state = state_t::cell_reselection; + // 1> apply the default physical channel configuration as specified in 9.2.4; + // Note: this is done by the MAC Reset procedure - } else { - Warning("Conditions are NOT met to start ConnectionReestablishment\n"); - return proc_outcome_t::success; - } + // 1> apply the default semi-persistent scheduling configuration as specified in 9.2.3; + // N.A. - return proc_outcome_t::yield; + // 1> apply the default MAC main configuration as specified in 9.2.2; + rrc_ptr->apply_mac_config_dedicated_default(); + + // 1> perform cell selection in accordance with the cell selection process as specified in TS 36.304 [4]; + return start_cell_selection(); } -srslte::proc_outcome_t rrc::connection_reest_proc::step_cell_reselection() +bool rrc::connection_reest_proc::sibs_acquired() const { + return rrc_ptr->meas_cells.serving_cell().has_sib1() && rrc_ptr->meas_cells.serving_cell().has_sib2() && + rrc_ptr->meas_cells.serving_cell().has_sib3(); +} - // Run cell reselection - if (not rrc_ptr->cell_reselector.run()) { - // Check T311 - if (not rrc_ptr->t311.is_running()) { - // Abort procedure if T311 expires - Info("T311 expired during cell reselection. Going to IDLE.\n"); - rrc_ptr->start_go_idle(); - return proc_outcome_t::success; - } +// Perform cell selection in accordance to 36.304 +bool rrc::connection_reest_proc::passes_cell_criteria() const +{ + return rrc_ptr->phy_ctrl->is_in_sync() and sibs_acquired() and + rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp()); +} - // Cell reselection finished or not started - if (rrc_ptr->phy_ctrl->is_in_sync()) { - // In-sync, check SIBs - if (rrc_ptr->meas_cells.serving_cell().has_sib1() && rrc_ptr->meas_cells.serving_cell().has_sib2() && - rrc_ptr->meas_cells.serving_cell().has_sib3()) { - Info("In-sync, SIBs available. Going to cell criteria\n"); - return cell_criteria(); - } else { - Info("SIBs missing (%d, %d, %d), launching serving cell configuration procedure\n", - rrc_ptr->meas_cells.serving_cell().has_sib1(), - rrc_ptr->meas_cells.serving_cell().has_sib2(), - rrc_ptr->meas_cells.serving_cell().has_sib3()); - std::vector required_sibs = {0, 1, 2}; - if (!rrc_ptr->serv_cell_cfg.launch(required_sibs)) { - Error("Failed to initiate configure serving cell\n"); - return proc_outcome_t::error; - } - state = state_t::cell_configuration; - } - } else { - // Out-of-sync, relaunch reselection - Info("Serving cell is out-of-sync, re-launching re-selection procedure. T311: %d/%d ms\n", - rrc_ptr->t311.time_elapsed(), - rrc_ptr->t311.duration()); - if (!rrc_ptr->cell_reselector.launch()) { - return proc_outcome_t::error; - } - } +srslte::proc_outcome_t rrc::connection_reest_proc::react(const serv_cell_cfg_completed& ev) +{ + if (state != state_t::wait_cell_configuration) { + return proc_outcome_t::yield; } - - return proc_outcome_t::yield; + return cell_criteria(); } -proc_outcome_t rrc::connection_reest_proc::step_cell_configuration() +// 5.3.7.3 - Actions following cell selection while T311 is running +srslte::proc_outcome_t rrc::connection_reest_proc::cell_criteria() { - if (not rrc_ptr->serv_cell_cfg.run()) { - // Check T311 - if (!rrc_ptr->t311.is_running()) { - // Abort procedure if T311 expires - Info("T311 expired during cell configuration. Going to IDLE.\n"); - rrc_ptr->start_go_idle(); - return proc_outcome_t::success; - } - - // SIBs adquisition not started or finished - if (rrc_ptr->phy_ctrl->is_in_sync()) { - // In-sync - if (rrc_ptr->meas_cells.serving_cell().has_sib1() && rrc_ptr->meas_cells.serving_cell().has_sib2() && - rrc_ptr->meas_cells.serving_cell().has_sib3()) { - // All SIBs are available - return cell_criteria(); - } - // Required SIBs are not available - Error("Failed to configure serving cell. Couldn't acquire SIBs.\n"); - return proc_outcome_t::error; - } else { - // Out-of-sync, relaunch reselection - Info("Serving cell is out-of-sync, re-launching re-selection procedure\n"); - if (!rrc_ptr->cell_reselector.launch()) { - Error("Failed to initiate a Cell re-selection procedure...\n"); - return proc_outcome_t::error; - } - state = state_t::cell_reselection; - } + if (not passes_cell_criteria()) { + Info("Selected Serving cell does not pass criteria. Re-launching re-selection procedure\n"); + return start_cell_selection(); } - return proc_outcome_t::yield; + // Upon selecting a suitable E-UTRA cell, the UE shall: + Info("Cell Selection criteria passed after %dms. Sending RRC Connection Reestablishment Request\n", + rrc_ptr->t311.time_elapsed()); + + // Note: Not explicitly defined in the specs, but UE should apply SIB1 and SIB2 configuration in order to attempt + // a PRACH to a different cell + Info("Applying SIB2 configuration\n"); + rrc_ptr->handle_sib2(); + + // 1> stop timer T311; + rrc_ptr->t311.stop(); + + // 1> start timer T301; + rrc_ptr->t301.run(); + + // 1> apply the timeAlignmentTimerCommon included in SystemInformationBlockType2; + // Not implemented yet. + + // 1> initiate transmission of the RRCConnectionReestablishmentRequest message in accordance with 5.3.7.4; + rrc_ptr->send_con_restablish_request(reest_cause, reest_rnti, reest_source_pci); + + state = state_t::wait_reest_msg; + return proc_outcome_t::success; } -srslte::proc_outcome_t rrc::connection_reest_proc::cell_criteria() +srslte::proc_outcome_t rrc::connection_reest_proc::start_cell_selection() { - // Perform cell selection in accordance to 36.304 - if (rrc_ptr->cell_selection_criteria(rrc_ptr->meas_cells.serving_cell().get_rsrp())) { - // Actions following cell reselection while T311 is running 5.3.7.3 - // Upon selecting a suitable E-UTRA cell, the UE shall: - Info("Cell Selection criteria passed after %dms. Sending RRC Connection Reestablishment Request\n", - rrc_ptr->t311.time_elapsed()); - - // Note: Not explicitly defined in the specs, but UE should apply SIB1 and SIB2 configuration in order to attempt - // a PRACH to a different cell - Info("Applying SIB2 configuration\n"); - rrc_ptr->handle_sib2(); - - // stop timer T311; - rrc_ptr->t311.stop(); - - // start timer T301; - rrc_ptr->t301.run(); - - // apply the timeAlignmentTimerCommon included in SystemInformationBlockType2; - // Not implemented yet. - - // initiate transmission of the RRCConnectionReestablishmentRequest message in accordance with 5.3.7.4; - rrc_ptr->send_con_restablish_request(reest_cause, reest_rnti, reest_source_pci); - } else if (rrc_ptr->t311.is_running()) { - // Upon selecting an inter-RAT cell - Info("Reestablishment Cell Selection criteria failed.\n"); - - // Launch cell reselection - if (not rrc_ptr->cell_reselector.launch()) { - Error("Failed to initiate a Cell re-selection procedure...\n"); - return proc_outcome_t::error; - } - state = state_t::cell_reselection; + // Launch cell reselection + if (not rrc_ptr->cell_selector.launch()) { + Error("Failed to initiate a Cell re-selection procedure...\n"); + // Wait for T311 to expire return proc_outcome_t::yield; } - return proc_outcome_t::success; + rrc_ptr->callback_list.add_proc(rrc_ptr->cell_selector); + state = state_t::wait_cell_selection; + return proc_outcome_t::yield; } -proc_outcome_t rrc::connection_reest_proc::step() +srslte::proc_outcome_t +rrc::connection_reest_proc::react(const cell_selection_proc::cell_selection_complete_ev& cell_selected_ev) { - proc_outcome_t ret = proc_outcome_t::yield; - - /* - * Implementation of procedure in 3GPP 36.331 Section 5.3.7.3: Actions following cell selection while T311 is - * running - */ - switch (state) { - case state_t::cell_reselection: - ret = step_cell_reselection(); - break; + if (state != state_t::wait_cell_selection) { + return proc_outcome_t::yield; + } - case state_t::cell_configuration: - ret = step_cell_configuration(); - break; + // Relaunch cell selection if there is still time + if (cell_selected_ev.is_error() or not rrc_ptr->phy_ctrl->is_in_sync()) { + // Out-of-sync, relaunch reselection + Info("Serving cell is out-of-sync, re-launching re-selection procedure. T311: %d/%d ms\n", + rrc_ptr->t311.time_elapsed(), + rrc_ptr->t311.duration()); + return start_cell_selection(); + } + + // Acquire SIBs if necessary + if (not sibs_acquired()) { + Info("SIBs missing (%d, %d, %d), launching serving cell configuration procedure\n", + rrc_ptr->meas_cells.serving_cell().has_sib1(), + rrc_ptr->meas_cells.serving_cell().has_sib2(), + rrc_ptr->meas_cells.serving_cell().has_sib3()); + std::vector required_sibs = {0, 1, 2}; + if (!rrc_ptr->serv_cell_cfg.launch(required_sibs)) { + Error("Failed to initiate configure serving cell\n"); + // Wait for T311 expiry + return proc_outcome_t::yield; + } + rrc_ptr->callback_list.add_proc(rrc_ptr->serv_cell_cfg); + state = state_t::wait_cell_configuration; + return proc_outcome_t::yield; } - return ret; + return cell_criteria(); +} + +// 5.3.7.6 - T311 expiry +srslte::proc_outcome_t rrc::connection_reest_proc::react(const t311_expiry& ev) +{ + // Abort procedure if T311 expires + Info("T311 expired during cell configuration. Going to RRC idle\n"); + rrc_ptr->start_go_idle(); + return proc_outcome_t::error; } /**************************************