Add support for RRC redirect.

master
Fabian Eckermann 3 years ago committed by Fabian Eckermann
parent dcf178a8a5
commit 12cc7cb4d7

@ -64,7 +64,7 @@ public:
class nas_5g_interface_procedures
{
public:
virtual int send_registration_request() = 0;
virtual int send_registration_request() = 0;
virtual int send_pdu_session_establishment_request(uint32_t transaction_identity,
uint16_t pdu_session_id,
const pdu_session_cfg_t& pdu_session) = 0;

@ -96,7 +96,6 @@ struct phy_args_t {
srsran::channel::args_t dl_channel_args;
srsran::channel::args_t ul_channel_args;
};
/* RAT agnostic Interface MAC -> PHY */
@ -158,7 +157,7 @@ public:
virtual void meas_stop() = 0;
/* Cell search and selection procedures */
virtual bool cell_search() = 0;
virtual bool cell_search(int earfcn) = 0;
virtual bool cell_select(phy_cell_t cell) = 0;
virtual bool cell_is_camping() = 0;
};

@ -76,7 +76,7 @@ class phy_dummy_interface : public phy_interface_rrc_lte
void meas_stop() override {}
/* Cell search and selection procedures */
bool cell_search() override { return true; }
bool cell_search(int earfcn) override { return true; }
bool cell_select(phy_cell_t cell) override { return true; }
bool cell_is_camping() override { return false; }
};

@ -53,7 +53,7 @@ public:
void meas_stop() final {}
/* Cell search and selection procedures */
bool cell_search() final { return false; }
bool cell_search(int earfcn) final { return false; }
bool cell_select(phy_cell_t cell) final { return false; }
bool cell_is_camping() final { return false; }

@ -68,7 +68,7 @@ public:
/********** RRC INTERFACE ********************/
bool cell_search() final;
bool cell_search(int earfcn) final;
bool cell_select(phy_cell_t cell) final;
// Sets the new PHY configuration for the given CC. The configuration is applied in the background. The notify()

@ -68,7 +68,7 @@ public:
// RRC interface for controling the SYNC state
bool cell_search_init();
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell);
rrc_interface_phy_lte::cell_search_ret_t cell_search_start(phy_cell_t* cell, int earfcn);
bool cell_select_init(phy_cell_t cell);
bool cell_select_start(phy_cell_t cell);
bool cell_is_camping();

@ -40,7 +40,9 @@ public:
struct cell_sel_cmd {
phy_cell_t phy_cell;
};
struct cell_search_cmd {};
struct cell_search_cmd {
int earfcn;
};
struct in_sync_ev {
static const bool log_verbose = false;
};
@ -52,7 +54,7 @@ public:
// PHY procedures interfaces
bool start_cell_select(const phy_cell_t& phy_cell, srsran::event_observer<bool> observer = {});
bool start_cell_search(srsran::event_observer<cell_srch_res> observer);
bool start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn);
void cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t found_cell);
void cell_selection_completed(bool outcome);
void in_sync();
@ -117,7 +119,7 @@ public:
// clang-format on
};
struct searching_cell {
void enter(phy_controller* f);
void enter(phy_controller* f, const cell_search_cmd& ev);
};
private:

@ -211,6 +211,9 @@ private:
meas_cell_list<meas_cell_nr> meas_cells_nr;
// if this is set to a valid earfcn, this earfcn will be used for cell search
int cell_search_earfcn = -1;
bool initiated = false;
asn1::rrc::reest_cause_e m_reest_cause = asn1::rrc::reest_cause_e::nulltype;
uint16_t m_reest_rnti = 0;
@ -328,7 +331,8 @@ private:
bool con_reconfig_ho(const asn1::rrc::rrc_conn_recfg_s& reconfig);
void ho_failed();
void start_go_idle();
void rrc_connection_release(const std::string& cause);
void handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release);
void start_rrc_redirect(uint32_t new_dl_earfcn);
void radio_link_failure_push_cmd();
void radio_link_failure_process();
void leave_connected();

@ -80,9 +80,9 @@ public:
void timer_expired(uint32_t timeout_id) override;
private:
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
rrc_interface_nas* rrc = nullptr;
usim_interface_nas* usim = nullptr;
gw_interface_nas* gw = nullptr;
bool running = false;
@ -108,10 +108,10 @@ private:
typedef std::pair<uint8_t, eps_bearer_t> eps_bearer_map_pair_t;
eps_bearer_map_t eps_bearer;
bool have_guti = false;
bool have_ctxt = false;
bool auth_request = false;
uint8_t current_sec_hdr = LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS;
bool have_guti = false;
bool have_ctxt = false;
bool auth_request = false;
uint8_t current_sec_hdr = LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS;
const uint32_t max_attach_attempts = 5; // Sec. 5.5.1.2.6
uint32_t attach_attempt_counter = 0;
@ -144,8 +144,8 @@ private:
const uint8_t ue_svn_oct2 = 0x3;
// Security
bool eia_caps[8] = {};
bool eea_caps[8] = {};
bool eia_caps[8] = {};
bool eea_caps[8] = {};
// Airplane mode simulation
typedef enum { DISABLED = 0, ENABLED } airplane_mode_state_t;

@ -342,12 +342,12 @@ bool phy::cell_select(phy_cell_t cell)
// This function executes one part of the procedure immediatly and returns to continue in the background.
// When it returns, the caller thread can expect the PHY to have switched to IDLE and have stopped all DL/UL/PRACH
// processing.
bool phy::cell_search()
// processing. If a valid EARFCN (>0) is given, this is used for cell search.
bool phy::cell_search(int earfcn)
{
sfsync.scell_sync_stop();
if (sfsync.cell_search_init()) {
cmd_worker_cell.add_cmd([this]() {
cmd_worker_cell.add_cmd([this, earfcn]() {
// Wait SYNC transitions to IDLE
sfsync.wait_idle();
@ -355,7 +355,7 @@ bool phy::cell_search()
reset();
phy_cell_t found_cell = {};
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell);
rrc_interface_phy_lte::cell_search_ret_t ret = sfsync.cell_search_start(&found_cell, earfcn);
stack->cell_search_complete(ret, found_cell);
});
} else {

@ -179,10 +179,10 @@ void sync::reset()
*
*/
/* A call to cell_search() finds the strongest cell in the set of supported EARFCNs. When the first cell is found,
* returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not found in the
* current frequency it moves to the next one and the next call to cell_search() will look in the next EARFCN in the
* set. If no cells are found in any frequency it returns 0. If error returns -1.
/* A call to cell_search() finds the strongest cell at a given EARFCN or in the set of supported EARFCNs. When the first
* cell is found, returns 1 and stores cell information and RSRP values in the pointers (if provided). If a cell is not
* found in the current frequency it moves to the next one and the next call to cell_search() will look in the next
* EARFCN in the set. If no cells are found in any frequency it returns 0. If error returns -1.
*
* The first part of the procedure (call to _init()) moves the PHY To IDLE, ensuring that no UL/DL/PRACH will happen
*
@ -197,7 +197,6 @@ bool sync::cell_search_init()
}
// Move state to IDLE
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
phy_state.go_idle();
// Stop all intra-frequency measurement before changing frequency
@ -208,10 +207,16 @@ bool sync::cell_search_init()
return true;
}
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell)
rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* found_cell, int earfcn)
{
std::unique_lock<std::mutex> ul(rrc_mutex);
if (earfcn < 0) {
Info("Cell Search: Start EARFCN index=%u/%zd", cellsearch_earfcn_index, worker_com->args->dl_earfcn_list.size());
} else {
Info("Cell Search: Start EARFCN=%d", earfcn);
}
rrc_interface_phy_lte::cell_search_ret_t ret = {};
ret.found = rrc_interface_phy_lte::cell_search_ret_t::ERROR;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;
@ -229,16 +234,20 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
Info("SYNC: Setting Cell Search sampling rate");
}
try {
if (current_earfcn != (int)worker_com->args->dl_earfcn_list.at(cellsearch_earfcn_index)) {
current_earfcn = (int)worker_com->args->dl_earfcn_list[cellsearch_earfcn_index];
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
set_frequency();
if (earfcn < 0) {
try {
if (current_earfcn != (int)worker_com->args->dl_earfcn_list.at(cellsearch_earfcn_index)) {
current_earfcn = (int)worker_com->args->dl_earfcn_list[cellsearch_earfcn_index];
}
} catch (const std::out_of_range& oor) {
Error("Index %d is not a valid EARFCN element.", cellsearch_earfcn_index);
return ret;
}
} catch (const std::out_of_range& oor) {
Error("Index %d is not a valid EARFCN element.", cellsearch_earfcn_index);
return ret;
} else {
current_earfcn = earfcn;
}
Info("Cell Search: changing frequency to EARFCN=%d", current_earfcn);
set_frequency();
// Move to CELL SEARCH and wait to finish
Info("Cell Search: Setting Cell search state");
@ -266,7 +275,7 @@ rrc_interface_phy_lte::cell_search_ret_t sync::cell_search_start(phy_cell_t* fou
}
cellsearch_earfcn_index++;
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size()) {
if (cellsearch_earfcn_index >= worker_com->args->dl_earfcn_list.size() or earfcn < 0) {
Info("Cell Search: No more frequencies in the current EARFCN set");
cellsearch_earfcn_index = 0;
ret.last_freq = rrc_interface_phy_lte::cell_search_ret_t::NO_MORE_FREQS;

@ -508,7 +508,7 @@ int main(int argc, char** argv)
phy_test->start();
// 1. Cell search
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search());
TESTASSERT(phy_test->get_phy_interface_rrc()->cell_search(-1));
TESTASSERT(phy_test->get_stack()->wait_cell_search(default_timeout));
TESTASSERT(phy_test->get_stack()->cell_search_ret.found ==
srsue::rrc_interface_phy_lte::cell_search_ret_t::CELL_FOUND);

@ -166,13 +166,13 @@ void phy_controller::selecting_cell::wait_in_sync::enter(selecting_cell* f)
*************************************/
//! Searches for a cell in the current frequency and retrieves SIB1 if not retrieved yet
bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer)
bool phy_controller::start_cell_search(srsran::event_observer<cell_srch_res> observer, int earfcn)
{
if (is_in_state<searching_cell>()) {
fsmInfo("Cell search already launched.");
return true;
}
trigger(cell_search_cmd{});
trigger(cell_search_cmd{earfcn});
if (not is_in_state<searching_cell>()) {
fsmWarning("Failed to launch cell search");
return false;
@ -186,10 +186,10 @@ void phy_controller::cell_search_completed(cell_search_ret_t cs_ret, phy_cell_t
trigger(cell_srch_res{cs_ret, found_cell});
}
void phy_controller::searching_cell::enter(phy_controller* f)
void phy_controller::searching_cell::enter(phy_controller* f, const cell_search_cmd& ev)
{
otherfsmInfo(f, "Initiating Cell search");
f->phy->cell_search();
f->phy->cell_search(ev.earfcn);
}
void phy_controller::handle_cell_search_res(searching_cell& s, const cell_srch_res& result)

@ -1153,8 +1153,9 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, const rrc_conn_recfg_s& reconfi
}
/* Actions upon reception of RRCConnectionRelease 5.3.8.3 */
void rrc::rrc_connection_release(const std::string& cause)
void rrc::handle_rrc_connection_release(const asn1::rrc::rrc_conn_release_s& release)
{
std::string cause = release.crit_exts.c1().rrc_conn_release_r8().release_cause.to_string();
// Save idleModeMobilityControlInfo, etc.
srsran::console("Received RRC Connection Release (releaseCause: %s)\n", cause.c_str());
@ -1164,6 +1165,36 @@ void rrc::rrc_connection_release(const std::string& cause)
// delay actions by 60ms as per 5.3.8.3
task_sched.defer_callback(60, [this]() { start_go_idle(); });
uint32_t earfcn = 0;
if (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info_present) {
switch (release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type()) {
case asn1::rrc::redirected_carrier_info_c::types_opts::options::eutra:
earfcn = release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.eutra();
break;
default:
srsran::console("Ignoring RedirectedCarrierInfo with unsupported type (%s)\n",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string());
break;
}
if (earfcn != 0) {
srsran::console("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting\n",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
earfcn);
logger.info("RedirectedCarrierInfo present (type %s, earfcn: %d) - Redirecting",
release.crit_exts.c1().rrc_conn_release_r8().redirected_carrier_info.type().to_string(),
earfcn);
// delay actions by 60ms as per 5.3.8.3
task_sched.defer_callback(60, [this, earfcn]() { start_rrc_redirect(earfcn); });
}
}
}
void rrc::start_rrc_redirect(uint32_t new_dl_earfcn)
{
cell_search_earfcn = (int)new_dl_earfcn;
plmn_search();
}
/// TS 36.331, 5.3.12 - UE actions upon leaving RRC_CONNECTED
@ -1818,7 +1849,7 @@ void rrc::parse_dl_dcch(uint32_t lcid, unique_byte_buffer_t pdu)
handle_ue_capability_enquiry(c1->ue_cap_enquiry());
break;
case dl_dcch_msg_type_c::c1_c_::types::rrc_conn_release:
rrc_connection_release(c1->rrc_conn_release().crit_exts.c1().rrc_conn_release_r8().release_cause.to_string());
handle_rrc_connection_release(c1->rrc_conn_release());
break;
case dl_dcch_msg_type_c::c1_c_::types::ue_info_request_r9:
transaction_id = c1->ue_info_request_r9().rrc_transaction_id;

@ -41,7 +41,7 @@ proc_outcome_t rrc::cell_search_proc::init()
{
Info("Starting...");
state = state_t::phy_cell_search;
if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher)) {
if (not rrc_ptr->phy_ctrl->start_cell_search(rrc_ptr->cell_searcher, rrc_ptr->cell_search_earfcn)) {
Warning("Failed to initiate Cell Search.");
return proc_outcome_t::error;
}
@ -1256,11 +1256,14 @@ proc_outcome_t rrc::go_idle_proc::step()
void rrc::go_idle_proc::then(const srsran::proc_state_t& result)
{
if (rrc_ptr->nas->is_registered() and not rrc_ptr->cell_reselector.launch()) {
rrc_ptr->logger.error("Failed to initiate a Cell Reselection procedure...");
return;
// only start cell reselection if no RRC redirect is present (redirect will trigger a cell search)
if (rrc_ptr->cell_search_earfcn < 0) {
if (rrc_ptr->nas->is_registered() and not rrc_ptr->cell_reselector.launch()) {
rrc_ptr->logger.error("Failed to initiate a Cell Reselection procedure...");
return;
}
rrc_ptr->callback_list.add_proc(rrc_ptr->cell_reselector);
}
rrc_ptr->callback_list.add_proc(rrc_ptr->cell_reselector);
}
/**************************************
@ -1362,7 +1365,7 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
{
// Save Current RNTI before MAC Reset
uint16_t crnti = rrc_ptr->mac->get_crnti();
size_t nof_scells_active = rrc_ptr->phy_ctrl->current_config_scells().count();
size_t nof_scells_active = rrc_ptr->phy_ctrl->current_config_scells().count();
// 5.3.7.1 - Conditions for Reestablishment procedure
if (not rrc_ptr->security_is_activated or rrc_ptr->state != RRC_STATE_CONNECTED or crnti == SRSRAN_INVALID_RNTI) {
@ -1384,9 +1387,9 @@ proc_outcome_t rrc::connection_reest_proc::init(asn1::rrc::reest_cause_e cause)
reest_cellid = rrc_ptr->meas_cells.find_cell(reest_source_freq, reest_source_pci)->get_cell_id();
Info("Starting... cause: \"%s\", UE context: {C-RNTI=0x%x, PCI=%d, CELL ID=%d}",
reest_cause == asn1::rrc::reest_cause_opts::recfg_fail
? "Reconfiguration failure"
: cause == asn1::rrc::reest_cause_opts::ho_fail ? "Handover failure" : "Other failure",
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_cellid);

@ -40,7 +40,7 @@ public:
void set_config_mbsfn_sib2(srsran::mbsfn_sf_cfg_t* cfg_list, uint32_t nof_cfgs) override {}
void set_config_mbsfn_sib13(const srsran::sib13_t& sib13) override {}
void set_config_mbsfn_mcch(const srsran::mcch_msg_t& mcch) override {}
bool cell_search() override { return true; }
bool cell_search(int earfcn) override { return true; }
bool cell_is_camping() override { return true; }
void deactivate_scells() override {}
bool cell_select(phy_cell_t cell) override

@ -81,7 +81,7 @@ int test_phy_ctrl_fsm()
TESTASSERT(phy_ctrl.is_in_sync());
// TEST: Correct initiation of Cell Search state
TESTASSERT(phy_ctrl.start_cell_search(csearch_tester));
TESTASSERT(phy_ctrl.start_cell_search(csearch_tester, -1));
TESTASSERT(not phy_ctrl.is_in_sync());
// TEST: Cell Search only listens to a cell search result event

@ -69,7 +69,7 @@ public:
void set_mch_period_stop(uint32_t stop) override{};
// Cell search and selection procedures
bool cell_search() override;
bool cell_search(int earfcn) override;
bool cell_select(phy_cell_t cell) override;
bool cell_is_camping() override;

@ -87,7 +87,7 @@ void lte_ttcn3_phy::meas_stop() {}
// configured by the SS, including the ones that we should not even detect because
// their power is too weak. The cell search should only report the cells that
// are actually visible though.
bool lte_ttcn3_phy::cell_search()
bool lte_ttcn3_phy::cell_search(int earfcn)
{
std::lock_guard<std::mutex> lock(phy_mutex);

Loading…
Cancel
Save