diff --git a/lib/include/srsran/asn1/rrc_utils.h b/lib/include/srsran/asn1/rrc_utils.h index de7832f5d..ecae50bda 100644 --- a/lib/include/srsran/asn1/rrc_utils.h +++ b/lib/include/srsran/asn1/rrc_utils.h @@ -71,6 +71,12 @@ struct ue_eutra_cap_s; } // namespace rrc } // namespace asn1 +namespace srsenb { + +struct ue_cell_ded; + +} // namespace srsenb + /************************ * Conversion Helpers ***********************/ @@ -130,7 +136,8 @@ int get_carrier_freq(const asn1::rrc::meas_obj_to_add_mod_s& obj); /*************************** * EUTRA UE Capabilities **************************/ -rrc_ue_capabilities_t make_rrc_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_cap_s); +rrc_ue_capabilities_t make_rrc_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_cap_s, + const srsenb::ue_cell_ded& pcell); // mbms mbms_notif_cfg_t make_mbms_notif_cfg(const asn1::rrc::mbms_notif_cfg_r9_s& asn1_type); diff --git a/lib/include/srsran/interfaces/rrc_interface_types.h b/lib/include/srsran/interfaces/rrc_interface_types.h index 2081a5589..aae1a5d3c 100644 --- a/lib/include/srsran/interfaces/rrc_interface_types.h +++ b/lib/include/srsran/interfaces/rrc_interface_types.h @@ -449,6 +449,8 @@ struct rrc_ue_capabilities_t { uint8_t category_ul = 0; bool support_dl_256qam = false; bool support_ul_64qam = false; + bool support_ca_bands = false; + bool support_ul_ca = false; }; } // namespace srsran diff --git a/lib/src/asn1/rrc_utils.cc b/lib/src/asn1/rrc_utils.cc index d54393057..8b688d070 100644 --- a/lib/src/asn1/rrc_utils.cc +++ b/lib/src/asn1/rrc_utils.cc @@ -11,6 +11,7 @@ */ #include "srsran/asn1/rrc_utils.h" +#include "srsenb/hdr/stack/rrc/rrc_cell_cfg.h" #include "srsran/asn1/obj_id_cmp_utils.h" #include "srsran/asn1/rrc.h" #include "srsran/config.h" @@ -923,36 +924,144 @@ int get_carrier_freq(const asn1::rrc::meas_obj_to_add_mod_s& obj) */ template -static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, const T& ue_eutra_cap) +static void +set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, const srsenb::ue_cell_ded& pcell, const T& ue_eutra_cap) { if (ue_eutra_cap.non_crit_ext_present) { - set_rrc_ue_eutra_cap_t_gen(ue_cap, ue_eutra_cap.non_crit_ext); + set_rrc_ue_eutra_cap_t_gen(ue_cap, pcell, ue_eutra_cap.non_crit_ext); } } -static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, const asn1::rrc::ue_eutra_cap_s& ue_eutra_cap) +static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, + const srsenb::ue_cell_ded& pcell, + const asn1::rrc::ue_eutra_cap_s& ue_eutra_cap) { ue_cap.release = ue_eutra_cap.access_stratum_release.to_number(); ue_cap.category = ue_eutra_cap.ue_category; if (ue_eutra_cap.non_crit_ext_present) { - set_rrc_ue_eutra_cap_t_gen(ue_cap, ue_eutra_cap.non_crit_ext); + set_rrc_ue_eutra_cap_t_gen(ue_cap, pcell, ue_eutra_cap.non_crit_ext); } } +bool is_ca_band_combo_supported(const band_combination_params_r10_l& enb_band_combo, + const band_combination_params_r10_l& ue_band_combo) +{ + if (enb_band_combo.size() != ue_band_combo.size()) { + return false; + } + + for (unsigned i = 0; i < enb_band_combo.size(); ++i) { + if (ue_band_combo[i].band_eutra_r10 != enb_band_combo[i].band_eutra_r10) { + return false; + } + } + + for (unsigned i = 0; i < enb_band_combo.size(); ++i) { + const auto& enb_band = enb_band_combo[i]; + const auto& ue_band = ue_band_combo[i]; + + if (enb_band.band_params_dl_r10_present and !ue_band.band_params_dl_r10_present) { + return false; + } + // for SCells this depends on the ul_allowed parameter + if (i == 0 and enb_band.band_params_ul_r10_present and !ue_band.band_params_ul_r10_present) { + return false; + } + + if (enb_band.band_params_dl_r10_present and ue_band.band_params_dl_r10_present) { + if (enb_band.band_params_dl_r10.size() != ue_band.band_params_dl_r10.size()) { + return false; + } + for (unsigned j = 0; j < enb_band.band_params_dl_r10.size(); ++j) { + if (enb_band.band_params_dl_r10[j].ca_bw_class_dl_r10 > ue_band.band_params_dl_r10[j].ca_bw_class_dl_r10) { + return false; + } + } + } + + if (enb_band.band_params_ul_r10_present and ue_band.band_params_ul_r10_present) { + if (enb_band.band_params_ul_r10.size() != ue_band.band_params_ul_r10.size()) { + return false; + } + for (unsigned j = 0; j < enb_band.band_params_ul_r10.size(); ++j) { + if (enb_band.band_params_ul_r10[j].ca_bw_class_ul_r10 > ue_band.band_params_ul_r10[j].ca_bw_class_ul_r10) { + return false; + } + } + } + } + return true; +} + +bool is_ul_ca_supported(const band_combination_params_r10_l& ue_band_combo) +{ + uint32_t ul_band_num = 0; + for (const auto& ue_band : ue_band_combo) { + if (ue_band.band_params_ul_r10_present) { + ul_band_num++; + } + } + return ul_band_num == ue_band_combo.size(); +} + static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, + const srsenb::ue_cell_ded& pcell, const asn1::rrc::ue_eutra_cap_v1020_ies_s& ue_eutra_cap) { if (ue_eutra_cap.ue_category_v1020_present) { ue_cap.category = ue_eutra_cap.ue_category_v1020; } + if (ue_eutra_cap.rf_params_v1020_present) { + const asn1::rrc::rf_params_v1020_s& rf_params = ue_eutra_cap.rf_params_v1020; + const srsenb::enb_cell_common* pcell_cfg = pcell.cell_common; + uint32_t cc_num = 1 + pcell_cfg->scells.size(); + band_combination_params_r10_l enb_band_combo; + + // TODO: add proper class (currently hardcoded class A) and mimo_cap checks + for (unsigned i = 0; i < cc_num; ++i) { + ca_mimo_params_dl_r10_s ca_mimo_params_dl; + ca_mimo_params_dl.ca_bw_class_dl_r10 = ca_bw_class_r10_e::a; + ca_mimo_params_dl.supported_mimo_cap_dl_r10_present = false; + ca_mimo_params_dl.supported_mimo_cap_dl_r10 = mimo_cap_dl_r10_opts::nulltype; + + ca_mimo_params_ul_r10_s ca_mimo_params_ul; + ca_mimo_params_ul.ca_bw_class_ul_r10 = ca_bw_class_r10_e::a; + ca_mimo_params_ul.supported_mimo_cap_ul_r10_present = false; + ca_mimo_params_ul.supported_mimo_cap_ul_r10 = mimo_cap_ul_r10_opts::nulltype; + + band_params_r10_s band_params; + uint32_t dl_earfcn = i == 0 ? pcell_cfg->cell_cfg.dl_earfcn : pcell_cfg->scells[i - 1]->cell_cfg.dl_earfcn; + band_params.band_eutra_r10 = (uint8_t)srsran_band_get_band(dl_earfcn); + band_params.band_params_dl_r10_present = true; + band_params.band_params_dl_r10.push_back(ca_mimo_params_dl); + + // PCell always supports UL, SCell depending on the config + if (i == 0 or (i >= 1 and pcell_cfg->cell_cfg.scell_list[i - 1].ul_allowed)) { + band_params.band_params_ul_r10_present = true; + band_params.band_params_ul_r10.push_back(ca_mimo_params_ul); + } + enb_band_combo.push_back(band_params); + } + + // compare the currently used CA band combo with band combos from UE + for (const auto& ue_band_combo : rf_params.supported_band_combination_r10) { + ue_cap.support_ca_bands |= is_ca_band_combo_supported(enb_band_combo, ue_band_combo); + if (ue_cap.support_ca_bands) { + ue_cap.support_ul_ca = is_ul_ca_supported(ue_band_combo); + break; + } + } + } + if (ue_eutra_cap.non_crit_ext_present) { - set_rrc_ue_eutra_cap_t_gen(ue_cap, ue_eutra_cap.non_crit_ext); + set_rrc_ue_eutra_cap_t_gen(ue_cap, pcell, ue_eutra_cap.non_crit_ext); } } static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, + const srsenb::ue_cell_ded& pcell, const asn1::rrc::ue_eutra_cap_v1250_ies_s& ue_eutra_cap) { if (ue_eutra_cap.ue_category_dl_r12_present) { @@ -976,20 +1085,22 @@ static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& } if (ue_eutra_cap.non_crit_ext_present) { - set_rrc_ue_eutra_cap_t_gen(ue_cap, ue_eutra_cap.non_crit_ext); + set_rrc_ue_eutra_cap_t_gen(ue_cap, pcell, ue_eutra_cap.non_crit_ext); } } static void set_rrc_ue_eutra_cap_t_gen(rrc_ue_capabilities_t& ue_cap, + const srsenb::ue_cell_ded& pcell, const asn1::rrc::ue_eutra_cap_v1530_ies_s& ue_eutra_cap) { ; // Do nothing } -rrc_ue_capabilities_t make_rrc_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_cap_s) +rrc_ue_capabilities_t make_rrc_ue_capabilities(const asn1::rrc::ue_eutra_cap_s& eutra_cap_s, + const srsenb::ue_cell_ded& pcell) { rrc_ue_capabilities_t ue_cap; - set_rrc_ue_eutra_cap_t_gen(ue_cap, eutra_cap_s); + set_rrc_ue_eutra_cap_t_gen(ue_cap, pcell, eutra_cap_s); ue_cap.support_ul_64qam |= (ue_cap.category == 5) or (ue_cap.category == 8 and ue_cap.release >= 10); return ue_cap; } diff --git a/srsenb/src/stack/rrc/rrc_mobility.cc b/srsenb/src/stack/rrc/rrc_mobility.cc index 1d8bb1ba5..764297a8a 100644 --- a/srsenb/src/stack/rrc/rrc_mobility.cc +++ b/srsenb/src/stack/rrc/rrc_mobility.cc @@ -1002,7 +1002,7 @@ bool rrc::ue::rrc_mobility::apply_ho_prep_cfg(const ho_prep_info_r8_ies_s& rrc_ue->eutra_capabilities.to_json(js); logger.debug("New rnti=0x%x EUTRA capabilities: %s", rrc_ue->rnti, js.to_string().c_str()); } - rrc_ue->ue_capabilities = srsran::make_rrc_ue_capabilities(rrc_ue->eutra_capabilities); + rrc_ue->ue_capabilities = srsran::make_rrc_ue_capabilities(rrc_ue->eutra_capabilities, *target_cell); rrc_ue->eutra_capabilities_unpacked = true; } } diff --git a/srsenb/src/stack/rrc/rrc_ue.cc b/srsenb/src/stack/rrc/rrc_ue.cc index 7403d536b..922b5e5a2 100644 --- a/srsenb/src/stack/rrc/rrc_ue.cc +++ b/srsenb/src/stack/rrc/rrc_ue.cc @@ -1060,6 +1060,7 @@ int rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) { parent->logger.info("UECapabilityInformation transaction ID: %d", msg->rrc_transaction_id); ue_cap_info_r8_ies_s* msg_r8 = &msg->crit_exts.c1().ue_cap_info_r8(); + const ue_cell_ded* pcell = ue_cell_list.get_ue_cc_idx(UE_PCELL_CC_IDX); for (uint32_t i = 0; i < msg_r8->ue_cap_rat_container_list.size(); i++) { if (msg_r8->ue_cap_rat_container_list[i].rat_type != rat_type_e::eutra) { @@ -1078,9 +1079,16 @@ int rrc::ue::handle_ue_cap_info(ue_cap_info_s* msg) parent->logger.debug("rnti=0x%x EUTRA capabilities: %s", rnti, js.to_string().c_str()); } eutra_capabilities_unpacked = true; - ue_capabilities = srsran::make_rrc_ue_capabilities(eutra_capabilities); + ue_capabilities = srsran::make_rrc_ue_capabilities(eutra_capabilities, *pcell); parent->logger.info("UE rnti: 0x%x category: %d", rnti, eutra_capabilities.ue_category); + if (ue_capabilities.support_ca_bands and ue_capabilities.support_ul_ca) { + parent->logger.info("UE rnti: 0x%x supports DL and UL CA with the used bands.", rnti); + } else if (ue_capabilities.support_ca_bands and not ue_capabilities.support_ul_ca) { + parent->logger.info("UE rnti: 0x%x supports DL CA with the used bands (no UL CA).", rnti); + } else { + parent->logger.info("UE rnti: 0x%x does not support CA with the used bands.", rnti); + } if (endc_handler != nullptr) { endc_handler->handle_eutra_capabilities(eutra_capabilities); @@ -1276,6 +1284,13 @@ void rrc::ue::update_scells() parent->logger.info("UE doesn't support CA. Skipping SCell activation"); return; } + if (not ue_capabilities.support_ca_bands) { + parent->logger.info("UE doesn't support used CA bands. Skipping SCell activation"); + return; + } + if (not ue_capabilities.support_ul_ca) { + parent->logger.info("UE supports only DL CA"); + } if (not eutra_capabilities.non_crit_ext_present or not eutra_capabilities.non_crit_ext.non_crit_ext_present or not eutra_capabilities.non_crit_ext.non_crit_ext.non_crit_ext_present or not eutra_capabilities.non_crit_ext.non_crit_ext.non_crit_ext.rf_params_v1020_present or diff --git a/srsenb/src/stack/rrc/ue_rr_cfg.cc b/srsenb/src/stack/rrc/ue_rr_cfg.cc index 0b9b1b616..856e613bd 100644 --- a/srsenb/src/stack/rrc/ue_rr_cfg.cc +++ b/srsenb/src/stack/rrc/ue_rr_cfg.cc @@ -447,18 +447,22 @@ void fill_scells_reconf(asn1::rrc::rrc_conn_recfg_r8_ies_s& recfg_r8, nonul_cfg.phich_cfg_r10 = scell_cfg.mib.phich_cfg; nonul_cfg.pdsch_cfg_common_r10 = cc_cfg_sib.pdsch_cfg_common; // RadioResourceConfigCommonSCell-r10::ul-Configuration-r10 - asn1cell.rr_cfg_common_scell_r10.ul_cfg_r10_present = true; - auto& ul_cfg = asn1cell.rr_cfg_common_scell_r10.ul_cfg_r10; - ul_cfg.ul_freq_info_r10.ul_carrier_freq_r10_present = true; - ul_cfg.ul_freq_info_r10.ul_carrier_freq_r10 = scell_cfg.cell_cfg.ul_earfcn; - ul_cfg.p_max_r10_present = cell_sib1.p_max_present; - ul_cfg.p_max_r10 = cell_sib1.p_max; - ul_cfg.ul_freq_info_r10.add_spec_emission_scell_r10 = 1; - ul_cfg.ul_pwr_ctrl_common_scell_r10.p0_nominal_pusch_r10 = cc_cfg_sib.ul_pwr_ctrl_common.p0_nominal_pusch; - ul_cfg.ul_pwr_ctrl_common_scell_r10.alpha_r10.value = cc_cfg_sib.ul_pwr_ctrl_common.alpha; - ul_cfg.srs_ul_cfg_common_r10 = cc_cfg_sib.srs_ul_cfg_common; - ul_cfg.ul_cp_len_r10.value = cc_cfg_sib.ul_cp_len.value; - ul_cfg.pusch_cfg_common_r10 = cc_cfg_sib.pusch_cfg_common; + if (ue_caps.support_ul_ca) { + asn1cell.rr_cfg_common_scell_r10.ul_cfg_r10_present = true; + auto& ul_cfg = asn1cell.rr_cfg_common_scell_r10.ul_cfg_r10; + ul_cfg.ul_freq_info_r10.ul_carrier_freq_r10_present = true; + ul_cfg.ul_freq_info_r10.ul_carrier_freq_r10 = scell_cfg.cell_cfg.ul_earfcn; + ul_cfg.p_max_r10_present = cell_sib1.p_max_present; + ul_cfg.p_max_r10 = cell_sib1.p_max; + ul_cfg.ul_freq_info_r10.add_spec_emission_scell_r10 = 1; + ul_cfg.ul_pwr_ctrl_common_scell_r10.p0_nominal_pusch_r10 = cc_cfg_sib.ul_pwr_ctrl_common.p0_nominal_pusch; + ul_cfg.ul_pwr_ctrl_common_scell_r10.alpha_r10.value = cc_cfg_sib.ul_pwr_ctrl_common.alpha; + ul_cfg.srs_ul_cfg_common_r10 = cc_cfg_sib.srs_ul_cfg_common; + ul_cfg.ul_cp_len_r10.value = cc_cfg_sib.ul_cp_len.value; + ul_cfg.pusch_cfg_common_r10 = cc_cfg_sib.pusch_cfg_common; + } else { + asn1cell.rr_cfg_common_scell_r10.ul_cfg_r10_present = false; + } // RadioResourceConfigDedicatedSCell-r10 asn1cell.rr_cfg_ded_scell_r10_present = true; asn1cell.rr_cfg_ded_scell_r10.phys_cfg_ded_scell_r10_present = true;