srsLTE/srsenb/src/stack/rrc/rrc_endc.cc

419 lines
18 KiB
C++

/**
* Copyright 2013-2022 Software Radio Systems Limited
*
* This file is part of srsRAN.
*
* srsRAN is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsRAN is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srsenb/hdr/stack/rrc/rrc_endc.h"
namespace srsenb {
#define Info(fmt, ...) logger.info("ENDC: " fmt, ##__VA_ARGS__)
#define Error(fmt, ...) logger.error("ENDC: " fmt, ##__VA_ARGS__)
#define Warning(fmt, ...) logger.warning("ENDC: " fmt, ##__VA_ARGS__)
#define Debug(fmt, ...) logger.debug("ENDC: " fmt, ##__VA_ARGS__)
#define procInfo(fmt, ...) parent->logger.info("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procWarning(fmt, ...) parent->logger.warning("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
#define procError(fmt, ...) parent->logger.error("Proc \"%s\" - " fmt, name(), ##__VA_ARGS__)
using namespace asn1::rrc;
/*************************************************************************************************
* rrc_endc class
************************************************************************************************/
rrc::ue::rrc_endc::rrc_endc(rrc::ue* outer_ue, const rrc_endc_cfg_t& endc_cfg_) :
base_t(outer_ue->parent->logger),
rrc_ue(outer_ue),
rrc_enb(outer_ue->parent),
logger(outer_ue->parent->logger),
endc_cfg(endc_cfg_)
{
// start SgNB activation if B1 events are disabled
if (endc_cfg.act_from_b1_event == false) {
start_sgnb_addition();
}
}
rrc::ue::rrc_endc::~rrc_endc()
{
start_sgnb_release();
}
//! Method to add NR fields to a RRC Connection Reconfiguration Message
bool rrc::ue::rrc_endc::fill_conn_recfg(asn1::rrc::rrc_conn_recfg_r8_ies_s* conn_recfg)
{
if (not is_endc_supported()) {
// skipping ENDC-related field
return false;
}
if (not is_endc_activation_running() && endc_cfg.act_from_b1_event) {
// add measConfig
conn_recfg->meas_cfg_present = true;
meas_cfg_s& meas_cfg = conn_recfg->meas_cfg;
meas_cfg.meas_obj_to_add_mod_list_present = true;
// store id of nr meas object to remove it in second reconfiguration message
nr_meas_obj_id = meas_cfg.meas_obj_to_add_mod_list.size() + 1;
meas_obj_to_add_mod_s meas_obj = {};
meas_obj.meas_obj_id = nr_meas_obj_id;
meas_obj.meas_obj.set_meas_obj_nr_r15();
auto& meas_obj_nr = meas_obj.meas_obj.meas_obj_nr_r15();
meas_obj_nr.carrier_freq_r15 = endc_cfg.abs_frequency_ssb;
meas_obj_nr.rs_cfg_ssb_r15.meas_timing_cfg_r15.periodicity_and_offset_r15 = endc_cfg.ssb_period_offset;
meas_obj_nr.rs_cfg_ssb_r15.meas_timing_cfg_r15.ssb_dur_r15 = endc_cfg.ssb_duration;
meas_obj_nr.rs_cfg_ssb_r15.subcarrier_spacing_ssb_r15 = endc_cfg.ssb_ssc;
meas_obj_nr.ext = true;
meas_obj_nr.band_nr_r15.set_present(true);
meas_obj_nr.band_nr_r15.get()->set_setup() = endc_cfg.nr_band;
meas_cfg.meas_obj_to_add_mod_list.push_back(meas_obj);
// report config
meas_cfg.report_cfg_to_add_mod_list_present = true;
// store id of nr report config to remove it in second reconfiguration message
nr_report_cfg_id = meas_cfg.report_cfg_to_add_mod_list.size() + 1;
report_cfg_to_add_mod_s report_cfg = {};
report_cfg.report_cfg_id = nr_report_cfg_id;
report_cfg.report_cfg.set_report_cfg_inter_rat();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.set_event();
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.set_event_b1_nr_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.set_nr_rsrp_r15();
report_cfg.report_cfg.report_cfg_inter_rat()
.trigger_type.event()
.event_id.event_b1_nr_r15()
.b1_thres_nr_r15.nr_rsrp_r15() = 56;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().event_id.event_b1_nr_r15().report_on_leave_r15 =
false;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().hysteresis = 0;
report_cfg.report_cfg.report_cfg_inter_rat().trigger_type.event().time_to_trigger = time_to_trigger_opts::ms100;
report_cfg.report_cfg.report_cfg_inter_rat().max_report_cells = 8;
report_cfg.report_cfg.report_cfg_inter_rat().report_interv = report_interv_opts::ms120;
report_cfg.report_cfg.report_cfg_inter_rat().report_amount = report_cfg_inter_rat_s::report_amount_opts::r1;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.set_present(true);
report_cfg.report_cfg.report_cfg_inter_rat().ext = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrp = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_rsrq = true;
report_cfg.report_cfg.report_cfg_inter_rat().report_quant_cell_nr_r15.get()->ss_sinr = true;
meas_cfg.report_cfg_to_add_mod_list.push_back(report_cfg);
// measIdToAddModList
meas_cfg.meas_id_to_add_mod_list_present = true;
// store id of nr meas to remove it in second reconfiguration message
nr_meas_id = meas_cfg.meas_id_to_add_mod_list.size() + 1;
meas_id_to_add_mod_s meas_id = {};
meas_id.meas_id = nr_meas_id;
meas_id.meas_obj_id = meas_obj.meas_obj_id;
meas_id.report_cfg_id = report_cfg.report_cfg_id;
meas_cfg.meas_id_to_add_mod_list.push_back(meas_id);
// quantityConfig
meas_cfg.quant_cfg_present = true;
meas_cfg.quant_cfg.quant_cfg_eutra_present = true;
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.set_present(true);
meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()->resize(1);
meas_cfg.quant_cfg.ext = true;
auto& meas_quant = meas_cfg.quant_cfg.quant_cfg_nr_list_r15.get()[0];
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15_present = true;
meas_quant[0].meas_quant_cell_nr_r15.filt_coeff_rsrp_r15 = filt_coef_opts::fc3;
// measGapConfig
meas_cfg.meas_gap_cfg_present = false; // No LTE measGaps allowed while in NSA mode
meas_cfg.meas_gap_cfg.set_setup();
meas_cfg.meas_gap_cfg.setup().gap_offset.set_gp0() = 16;
} else if (is_in_state<prepare_recfg_st>()) {
// Deactivate measurement reports, as we do not support measurements after NR activation
conn_recfg->meas_cfg_present = true;
meas_cfg_s& meas_cfg = conn_recfg->meas_cfg;
// Remove meas config
meas_cfg.meas_obj_to_rem_list_present = true;
meas_cfg.meas_obj_to_rem_list.resize(1);
meas_cfg.meas_obj_to_rem_list[0] = nr_meas_obj_id;
// remove report config
meas_cfg.report_cfg_to_rem_list_present = true;
meas_cfg.report_cfg_to_rem_list.resize(1);
meas_cfg.report_cfg_to_rem_list[0] = nr_report_cfg_id;
// remove meas id
meas_cfg.meas_id_to_rem_list_present = true;
meas_cfg.meas_id_to_rem_list.resize(1);
meas_cfg.meas_id_to_rem_list[0] = nr_meas_id;
// TODO: use bearer manager to remove EUTRA DRB
conn_recfg->rr_cfg_ded.drb_to_release_list_present = true;
conn_recfg->rr_cfg_ded.drb_to_release_list.resize(1);
conn_recfg->rr_cfg_ded.drb_to_release_list[0] = 1;
// don't send EUTRA dedicated config again
conn_recfg->rr_cfg_ded.phys_cfg_ded_present = false;
// set MAC main config dedicated
conn_recfg->rr_cfg_ded.mac_main_cfg_present = true;
conn_recfg->rr_cfg_ded.mac_main_cfg.set_explicit_value();
auto& mac_main_cfg = conn_recfg->rr_cfg_ded.mac_main_cfg.explicit_value();
mac_main_cfg.time_align_timer_ded = time_align_timer_opts::infinity;
mac_main_cfg.phr_cfg_present = true;
mac_main_cfg.phr_cfg.set_setup();
mac_main_cfg.phr_cfg.setup().dl_pathloss_change =
asn1::rrc::mac_main_cfg_s::phr_cfg_c_::setup_s_::dl_pathloss_change_opts::db3;
mac_main_cfg.phr_cfg.setup().periodic_phr_timer =
asn1::rrc::mac_main_cfg_s::phr_cfg_c_::setup_s_::periodic_phr_timer_opts::sf500;
mac_main_cfg.phr_cfg.setup().prohibit_phr_timer =
asn1::rrc::mac_main_cfg_s::phr_cfg_c_::setup_s_::prohibit_phr_timer_opts::sf200;
// Disable DC-PHR reporting
mac_main_cfg.ext = false;
mac_main_cfg.mac_main_cfg_v1020.set_present();
mac_main_cfg.dual_connect_phr.set_present();
mac_main_cfg.dual_connect_phr.get()->set_setup();
mac_main_cfg.dual_connect_phr.get()->setup().phr_mode_other_cg_r12 =
asn1::rrc::mac_main_cfg_s::dual_connect_phr_c_::setup_s_::phr_mode_other_cg_r12_opts::real;
// only add reconfigure EN-DC extension/release 15.10 field if ENDC activation is active
conn_recfg->non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present = true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present =
true;
conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present = true;
rrc_conn_recfg_v1510_ies_s& reconf_v1510 = conn_recfg->non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
reconf_v1510.nr_cfg_r15_present = true;
reconf_v1510.nr_cfg_r15.set_setup();
reconf_v1510.nr_cfg_r15.setup().endc_release_and_add_r15 = false;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15_present = true;
reconf_v1510.nr_cfg_r15.setup().nr_secondary_cell_group_cfg_r15 =
get_state<prepare_recfg_st>()->sgnb_config.nr_secondary_cell_group_cfg_r15;
reconf_v1510.sk_counter_r15_present = true;
reconf_v1510.sk_counter_r15 = 0;
reconf_v1510.nr_radio_bearer_cfg1_r15_present = true;
reconf_v1510.nr_radio_bearer_cfg1_r15 = get_state<prepare_recfg_st>()->sgnb_config.nr_radio_bearer_cfg1_r15;
// inform FSM
rrc_recfg_sent_ev recfg_sent{};
trigger(recfg_sent);
}
return true;
}
//! Called when UE capabilities are received
void rrc::ue::rrc_endc::handle_eutra_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_caps)
{
// skip any further checks if eNB runs without NR cells
if (rrc_enb->cfg.num_nr_cells == 0) {
Debug("Skipping UE capabilities. No NR cell configured.");
trigger(disable_endc_ev{});
return;
}
// Only enabled ENDC support if UE caps have been exchanged and UE signals support
if (eutra_caps.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
auto& ue_cap_v1170 =
eutra_caps.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1170.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present) {
if (ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext_present) {
auto& ue_cap_v1330 = ue_cap_v1170.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1330.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext_present) {
if (ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext_present) {
auto& ue_cap_v1510 = ue_cap_v1330.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext
.non_crit_ext.non_crit_ext.non_crit_ext.non_crit_ext;
if (ue_cap_v1510.irat_params_nr_r15_present) {
if (ue_cap_v1510.irat_params_nr_r15.en_dc_r15_present) {
logger.info("Enabling ENDC support for rnti=%d", rrc_ue->rnti);
return;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
trigger(disable_endc_ev{});
}
//! Method called whenever the eNB receives a MeasReport from the UE
void rrc::ue::rrc_endc::handle_ue_meas_report(const meas_report_s& msg)
{
// Ignore event if ENDC isn't supported
if (not is_endc_supported()) {
return;
}
if (not is_in_state<endc_deactivated_st>()) {
Info("Received a MeasReport while already enabling ENDC support. Ignoring...");
return;
}
// Check if meas_id is valid
const meas_results_s& meas_res = msg.crit_exts.c1().meas_report_r8().meas_results;
if (not meas_res.meas_result_neigh_cells_present) {
Info("Received a MeasReport, but the UE did not detect any cell.");
return;
}
// only handle NR cells here, EUTRA is handled in mobility class
if (meas_res.meas_result_neigh_cells.type().value !=
meas_results_s::meas_result_neigh_cells_c_::types::meas_result_neigh_cell_list_nr_r15) {
return;
}
start_sgnb_addition();
}
void rrc::ue::rrc_endc::start_sgnb_addition()
{
// Start EN-DC activation using EPS bearer of EUTRA DRB1
rrc_nr_interface_rrc::sgnb_addition_req_params_t params = {};
const auto& drb_list = rrc_ue->bearer_list.get_established_drbs();
if (drb_list.size() > 0) {
// move first establised DRB to NR cell
const auto& drb1 = drb_list[0];
const auto& erab_list = rrc_ue->bearer_list.get_erabs();
auto erab_it = erab_list.find(drb1.eps_bearer_id);
if (erab_it != erab_list.end()) {
params.eps_bearer_id = drb1.eps_bearer_id;
params.five_qi = erab_it->second.qos_params.qci; // use QCI as 5QI
} else {
logger.error("Couldn't find ERAB config for DRB%d. Aborting SgNB addition for E-UTRA rnti=0x%x",
drb1.drb_id,
rrc_ue->rnti);
return;
}
} else {
logger.error("No LTE DRB established. Aborting SgNB addition for E-UTRA rnti=0x%x", rrc_ue->rnti);
return;
}
logger.info("Triggering SgNB addition for E-UTRA rnti=0x%x", rrc_ue->rnti);
rrc_enb->rrc_nr->sgnb_addition_request(rrc_ue->rnti, params);
sgnb_add_req_sent_ev sgnb_add_req{};
trigger(sgnb_add_req);
}
void rrc::ue::rrc_endc::start_sgnb_release()
{
sgnb_rel_req_ev sgnb_rel_req{nr_rnti};
trigger(sgnb_rel_req);
}
rrc::ue::rrc_endc::prepare_recfg_st::prepare_recfg_st(rrc_endc* parent_) : logger(parent_->logger) {}
void rrc::ue::rrc_endc::prepare_recfg_st::enter(rrc_endc* f, const sgnb_add_req_ack_ev& ev)
{
// store SgNB provided config
sgnb_config = ev.params;
logger.debug(sgnb_config.nr_secondary_cell_group_cfg_r15.data(),
sgnb_config.nr_secondary_cell_group_cfg_r15.size(),
"nr-SecondaryCellGroupConfig-r15:");
logger.debug(sgnb_config.nr_radio_bearer_cfg1_r15.data(),
sgnb_config.nr_radio_bearer_cfg1_r15.size(),
"nr-RadioBearerConfig1-r15:");
}
// The gNB has accepted the SgNB addition and has already allocated the user and established all bearers
void rrc::ue::rrc_endc::handle_sgnb_add_req_ack(wait_sgnb_add_req_resp_st& s, const sgnb_add_req_ack_ev& ev)
{
// TODO: copy buffered PDCP data to SeNB
// TODO: path update procedure with GTPU modify bearer request (for mode 3A and 3X)
// re-register EPS bearer over NR PDCP
rrc_enb->bearer_manager.add_eps_bearer(
ev.params.nr_rnti, ev.params.eps_bearer_id, srsran::srsran_rat_t::nr, lcid_drb_nr);
// change GTPU tunnel RNTI to match NR RNTI
rrc_enb->gtpu->mod_bearer_rnti(rrc_ue->rnti, ev.params.nr_rnti);
// store RNTI for later
nr_rnti = ev.params.nr_rnti;
}
void rrc::ue::rrc_endc::handle_sgnb_rel_req(const sgnb_rel_req_ev& ev)
{
logger.info("Triggering SgNB release for E-UTRA rnti=0x%x", rrc_ue->rnti);
rrc_enb->bearer_manager.rem_user(nr_rnti);
rrc_enb->rrc_nr->sgnb_release_request(nr_rnti);
}
bool rrc::ue::rrc_endc::is_endc_supported()
{
return not is_in_state<endc_disabled_st>();
}
void rrc::ue::rrc_endc::handle_rrc_reest(endc_activated_st& s, const rrc_reest_rx_ev& ev)
{
// Transition GTPU tunnel rnti back from NR RNTI to LTE RNTI, given that the reconfiguration failed
rrc_enb->gtpu->mod_bearer_rnti(nr_rnti, rrc_ue->rnti);
}
void rrc::ue::rrc_endc::handle_endc_disabled(const disable_endc_ev& ev)
{
logger.info("Disabling NR EN-DC support for rnti=0x%x", nr_rnti);
}
bool rrc::ue::rrc_endc::requires_rel_req(const sgnb_rel_req_ev& ev)
{
return not is_in_state<endc_disabled_st>() and not is_in_state<endc_deactivated_st>() and
not is_in_state<wait_sgnb_rel_req_resp_st>();
}
} // namespace srsenb