rrc,nr: add MSG3 activity timer to rrc_nr

Signed-off-by: Carlo Galiotto <carlo@srs.io>
This commit is contained in:
Carlo Galiotto 2021-10-21 15:39:40 +02:00 committed by Francisco Paisana
parent ceec108831
commit 4f6905363f
2 changed files with 129 additions and 6 deletions

View File

@ -104,7 +104,27 @@ public:
class ue
{
public:
ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg);
enum activity_timeout_type_t {
MSG3_RX_TIMEOUT = 0, ///< Msg3 has its own timeout to quickly remove fake UEs from random PRACHs
UE_INACTIVITY_TIMEOUT, ///< (currently unused) UE inactivity timeout (usually bigger than reestablishment timeout)
MSG5_RX_TIMEOUT, ///< (currently unused) for receiving RRCConnectionSetupComplete/RRCReestablishmentComplete
nulltype
};
/// List of results a RRC procedure may produce.
enum class procedure_result_code {
none,
activity_timeout,
error_mme_not_connected,
error_unknown_rnti,
radio_conn_with_ue_lost,
msg3_timeout,
fail_in_radio_interface_proc,
unspecified
};
/// @param [in] triggered_by_rach: indicates whether the UE is created as part of a RACH process
ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg, bool triggered_by_rach = false);
void send_connection_setup();
void send_dl_ccch(asn1::rrc_nr::dl_ccch_msg_s* dl_dcch_msg);
@ -119,14 +139,23 @@ public:
bool is_endc() { return endc; }
uint16_t get_eutra_rnti() { return eutra_rnti; }
void get_metrics(rrc_ue_metrics_t& ue_metrics) { ue_metrics = {}; /*TODO fill RRC metrics*/ };
// setters
int pack_rrc_reconfiguration();
void deactivate_bearers();
/// methods to handle activity timer
std::string to_string(const activity_timeout_type_t& type);
void set_activity_timeout(activity_timeout_type_t type);
void set_activity(bool enabled = true);
void activity_timer_expired(const activity_timeout_type_t type);
private:
rrc_nr* parent = nullptr;
uint16_t rnti = SRSRAN_INVALID_RNTI;
/// for basic DL/UL activity timeout
srsran::unique_timer activity_timer;
int pack_rrc_reconfiguration(asn1::dyn_octstring& packed_rrc_reconfig);
int pack_secondary_cell_group_cfg(asn1::dyn_octstring& packed_secondary_cell_config);
@ -179,6 +208,9 @@ public:
rrc_nr_state_t state = rrc_nr_state_t::RRC_IDLE;
uint8_t transaction_id = 0;
/// Connection release result.
procedure_result_code con_release_result = procedure_result_code::none;
// RRC configs for UEs
asn1::rrc_nr::cell_group_cfg_s cell_group_cfg;
asn1::rrc_nr::radio_bearer_cfg_s radio_bearer_cfg;

View File

@ -161,7 +161,8 @@ rrc_nr_cfg_t rrc_nr::update_default_cfg(const rrc_nr_cfg_t& current)
int rrc_nr::add_user(uint16_t rnti, const sched_nr_ue_cfg_t& uecfg)
{
if (users.count(rnti) == 0) {
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue(this, rnti, uecfg))));
// in the ue ctor, "triggered_by_rach" is set to true so as to start the MSG3 RX TIMEOUT when we create the ue
users.insert(std::make_pair(rnti, std::unique_ptr<ue>(new ue(this, rnti, uecfg, true))));
rlc->add_user(rnti);
pdcp->add_user(rnti);
logger.info("Added new user rnti=0x%x", rnti);
@ -494,9 +495,9 @@ void rrc_nr::sgnb_addition_request(uint16_t eutra_rnti, const sgnb_addition_req_
uecfg.carriers[0].cc = 0;
uecfg.ue_bearers[0].direction = mac_lc_ch_cfg_t::BOTH;
srsran::phy_cfg_nr_default_t::reference_cfg_t ref_args{};
ref_args.duplex = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_TDD
? srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_TDD_CUSTOM_6_4
: srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD;
ref_args.duplex = cfg.cell_list[0].duplex_mode == SRSRAN_DUPLEX_MODE_TDD
? srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_TDD_CUSTOM_6_4
: srsran::phy_cfg_nr_default_t::reference_cfg_t::R_DUPLEX_FDD;
uecfg.phy_cfg = srsran::phy_cfg_nr_default_t{ref_args};
uecfg.phy_cfg.csi = {}; // disable CSI until RA is complete
@ -545,11 +546,95 @@ void rrc_nr::sgnb_release_request(uint16_t nr_rnti)
Every function in UE class is called from a mutex environment thus does not
need extra protection.
*******************************************************************************/
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_) :
rrc_nr::ue::ue(rrc_nr* parent_, uint16_t rnti_, const sched_nr_ue_cfg_t& uecfg_, bool triggered_by_rach) :
parent(parent_), rnti(rnti_), uecfg(uecfg_)
{
// Derive UE cfg from rrc_cfg_nr_t
uecfg.phy_cfg.pdcch = parent->cfg.cell_list[0].phy_cell.pdcch;
// Set timer for MSG3_RX_TIMEOUT or UE_INACTIVITY_TIMEOUT
activity_timer = parent->task_sched.get_unique_timer();
triggered_by_rach ? set_activity_timeout(MSG3_RX_TIMEOUT) : set_activity_timeout(UE_INACTIVITY_TIMEOUT);
}
void rrc_nr::ue::set_activity_timeout(activity_timeout_type_t type)
{
uint32_t deadline_ms = 0;
switch (type) {
case MSG3_RX_TIMEOUT:
// TODO: Retrieve the parameters from somewhere(RRC?) - Currently hardcoded to 100ms
deadline_ms = 100;
break;
case UE_INACTIVITY_TIMEOUT:
// TODO: Add a value for the inactivity timeout - currently no activity set this case
return;
default:
parent->logger.error("Unknown timeout type %d", type);
return;
}
// Currently we only set the timer for the MSG3_RX_TIMEOUT case
activity_timer.set(deadline_ms, [this, type](uint32_t tid) { activity_timer_expired(type); });
parent->logger.debug("Setting timer for %s for rnti=0x%x to %dms", to_string(type).c_str(), rnti, deadline_ms);
set_activity();
}
void rrc_nr::ue::set_activity(bool enabled)
{
if (rnti == SRSRAN_MRNTI) {
return;
}
if (not enabled) {
if (activity_timer.is_running()) {
parent->logger.debug("Inactivity timer interrupted for rnti=0x%x", rnti);
}
activity_timer.stop();
return;
}
// re-start activity timer with current timeout value
activity_timer.run();
parent->logger.debug("Activity registered for rnti=0x%x (timeout_value=%dms)", rnti, activity_timer.duration());
}
void rrc_nr::ue::activity_timer_expired(const activity_timeout_type_t type)
{
parent->logger.info("Activity timer for rnti=0x%x expired after %d ms", rnti, activity_timer.time_elapsed());
// TODO: Insert a check to ensure the RNTI exists
#if 0
if (parent->s1ap->user_exists(rnti)) {
#endif
switch (type) {
case UE_INACTIVITY_TIMEOUT:
// TODO: Add action to be executed
break;
case MSG3_RX_TIMEOUT:
// MSG3 timeout, no need to notify S1AP, just remove UE
parent->rem_user(rnti);
con_release_result = procedure_result_code::msg3_timeout;
break;
default:
// Unhandled activity timeout, just remove UE and log an error
parent->rem_user(rnti);
con_release_result = procedure_result_code::activity_timeout;
parent->logger.error(
"Unhandled reason for activity timer expiration. rnti=0x%x, cause %d", rnti, static_cast<unsigned>(type));
}
#if 0
} else {
parent->rem_user_thread(rnti);
}
#endif
state = rrc_nr_state_t::RRC_IDLE;
}
std::string rrc_nr::ue::to_string(const activity_timeout_type_t& type)
{
constexpr static const char* options[] = {"Msg3 reception", "UE inactivity", "UE reestablishment"};
return srsran::enum_to_text(options, (uint32_t)activity_timeout_type_t::nulltype, (uint32_t)type);
}
void rrc_nr::ue::send_connection_setup()
@ -1289,6 +1374,10 @@ int rrc_nr::ue::handle_sgnb_addition_request(uint16_t eutra_rnti_, const sgnb_ad
ack_params.eps_bearer_id = req_params.eps_bearer_id;
parent->rrc_eutra->sgnb_addition_ack(eutra_rnti_, ack_params);
// stop activity timer for msg3
activity_timer.stop();
parent->logger.debug("SgNB addition req. - Stopping MSG3 activity timer for rnti=0x%x", rnti);
// recognize RNTI as ENDC user
endc = true;
eutra_rnti = eutra_rnti_;
@ -1302,6 +1391,8 @@ void rrc_nr::ue::crnti_ce_received()
if (endc) {
// send SgNB addition complete for ENDC users
parent->rrc_eutra->sgnb_addition_complete(eutra_rnti, rnti);
activity_timer.stop();
parent->logger.debug("Received MAC CE-RNTI for 0x%x - stopping MSG3 timer", rnti);
// Add DRB1 to MAC
for (auto& drb : cell_group_cfg.rlc_bearer_to_add_mod_list) {