From 0e7e0309075172df2213f9f2eb925573cb35e1ca Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 15 Sep 2025 18:09:11 +0200 Subject: [PATCH 01/15] Fix clean_bwp_structures Also zero out the pointer in spCellConfigDedicated to avoid use-after-free. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index a68c12092b..86735466de 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3472,9 +3472,9 @@ void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig) asn_sequence_del(&rel_dl->list, i, 1); } if (rel_dl->list.count == 0) - free_and_zero(rel_dl); + free_and_zero(spCellConfigDedicated->downlinkBWP_ToReleaseList); if (add_dl->list.count == 0) - free_and_zero(add_dl); + free_and_zero(spCellConfigDedicated->downlinkBWP_ToAddModList); } if (spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList) { struct NR_UplinkConfig__uplinkBWP_ToReleaseList *rel_ul = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList; @@ -3492,9 +3492,9 @@ void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig) asn_sequence_del(&rel_ul->list, i, 1); } if (rel_ul->list.count == 0) - free_and_zero(rel_ul); + free_and_zero(spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList); if (add_ul->list.count == 0) - free_and_zero(add_ul); + free_and_zero(spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList); } } From aa7d3668e32c5ed84823489634048fffccf785f2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 23 Sep 2025 11:13:25 +0200 Subject: [PATCH 02/15] Fix for segfault caused by freed csi_MeasConfig --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 6 ++++-- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 8 ++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 86735466de..48768750e0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3922,7 +3922,7 @@ bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t * return false; } -void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE, int new_bwp_id) +void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, NR_UE_info_t *UE, int new_bwp_id) { DevAssert(UE->CellGroup != NULL); NR_CellGroupConfig_t *cellGroup_for_UE = NULL; @@ -3930,7 +3930,8 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_ AssertFatal(UE->current_DL_BWP.bwp_id == UE->current_UL_BWP.bwp_id, "We only support same BWP for UL and DL\n"); if (new_bwp_id == UE->current_DL_BWP.bwp_id) LOG_E(NR_MAC, "Source BWP ID and target BWP ID are the same, can't perform switch\n"); - else + else { + UE->sc_info.csi_MeasConfig = NULL; // to avoid segfault when freeing csi_MeasConfig in configDedicated cellGroup_for_UE = update_cellGroupConfig_for_BWP_switch(UE->CellGroup, &nrmac->radio_config, UE->capability, @@ -3938,6 +3939,7 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_ UE->uid, UE->current_DL_BWP.bwp_id, new_bwp_id); + } } uint8_t buf[2048]; asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index e280a8cbe2..d5626c24df 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -478,7 +478,7 @@ void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpac void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl); bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl); -void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE, int new_bwp_id); +void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, NR_UE_info_t *UE, int new_bwp_id); bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c); nr_lc_config_t *nr_mac_get_lc_config(NR_UE_sched_ctrl_t* sched_ctrl, int lcid); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 3d0e3ed246..a828ec7930 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -3367,10 +3367,14 @@ static NR_CSI_MeasConfig_t *get_csiMeasConfig(const NR_ServingCellConfig_t *conf pdsch_Config = configDedicated->initialDownlinkBWP->pdsch_Config; curr_bwp = NRRIV2BW(scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); } else { - NR_BWP_Downlink_t *bwp = configDedicated->downlinkBWP_ToAddModList->list.array[0]; + NR_BWP_Downlink_t *bwp = NULL; + for (int i = 0; i < configDedicated->downlinkBWP_ToAddModList->list.count; i++) { + if (bwp_id == configDedicated->downlinkBWP_ToAddModList->list.array[i]->bwp_Id) + bwp = configDedicated->downlinkBWP_ToAddModList->list.array[i]; + } + AssertFatal(bwp, "BWP ID doesn't match\n"); pdsch_Config = bwp->bwp_Dedicated->pdsch_Config; curr_bwp = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); - AssertFatal(bwp_id == bwp->bwp_Id, "BWP ID doesn't match\n"); } const int pdsch_AntennaPorts = From ca041936801da51a8aece17cea8aeb448a788d4e Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 23 Sep 2025 17:36:37 +0200 Subject: [PATCH 03/15] Remove hardcoded max_rank = 1 in PUSCH configuration and set it with appropriate function --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 96 +++++++++----------- 1 file changed, 45 insertions(+), 51 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index a828ec7930..40b235e81c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -1505,10 +1505,38 @@ static NR_PTRS_UplinkConfig_t *config_ulptrs(const nr_ptrs_config_t *ptrs) return ulptrs; } -static NR_SetupRelease_PUSCH_Config_t *config_pusch(const bool use_deltaMCS, +long ue_supported_ul_layers(const NR_UE_NR_Capability_t *uecap) +{ + long ul_max_layers = 1; + if (uecap + && uecap->featureSets + && uecap->featureSets->featureSetsUplinkPerCC + && uecap->featureSets->featureSetsUplinkPerCC->list.count > 0) { + NR_FeatureSetUplinkPerCC_t *ul_feature_setup_per_cc = uecap->featureSets->featureSetsUplinkPerCC->list.array[0]; + if (ul_feature_setup_per_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH) { + switch (*ul_feature_setup_per_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH) { + case NR_MIMO_LayersUL_twoLayers: + ul_max_layers = 2; + break; + case NR_MIMO_LayersUL_fourLayers: + ul_max_layers = 4; + break; + default: + ul_max_layers = 1; + } + } + } + return ul_max_layers; +} + +static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap) +{ + return min(ue_supported_ul_layers(uecap), configuration->pusch_AntennaPorts); +} + +static NR_SetupRelease_PUSCH_Config_t *config_pusch(const nr_mac_config_t *configuration, const NR_ServingCellConfigCommon_t *scc, - const NR_UE_NR_Capability_t *uecap, - const nr_ptrs_config_t *ptrs) + const NR_UE_NR_Capability_t *uecap) { NR_SetupRelease_PUSCH_Config_t *setup_puschconfig = calloc(1, sizeof(*setup_puschconfig)); setup_puschconfig->present = NR_SetupRelease_PUSCH_Config_PR_setup; @@ -1526,8 +1554,8 @@ static NR_SetupRelease_PUSCH_Config_t *config_pusch(const bool use_deltaMCS, if (!pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup) pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup = calloc(1, sizeof(*pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup)); NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup; - if (ptrs) { - NR_PTRS_UplinkConfig_t *ptrs_config = config_ulptrs(ptrs); + if (configuration->ptrs) { + NR_PTRS_UplinkConfig_t *ptrs_config = config_ulptrs(configuration->ptrs); NR_SetupRelease_PTRS_UplinkConfig_t *phaseTrackingRS = calloc(1, sizeof(*phaseTrackingRS)); phaseTrackingRS->present = NR_SetupRelease_PTRS_UplinkConfig_PR_setup; phaseTrackingRS->choice.setup = ptrs_config; @@ -1569,7 +1597,7 @@ static NR_SetupRelease_PUSCH_Config_t *config_pusch(const bool use_deltaMCS, asn1cSeqAdd(&pusch_Config->pusch_PowerControl->pathlossReferenceRSToAddModList->list, plrefRS); pusch_Config->pusch_PowerControl->pathlossReferenceRSToReleaseList = NULL; pusch_Config->pusch_PowerControl->twoPUSCH_PC_AdjustmentStates = NULL; - if (use_deltaMCS) { + if (configuration->use_deltaMCS) { if (!pusch_Config->pusch_PowerControl->deltaMCS) pusch_Config->pusch_PowerControl->deltaMCS = calloc(1, sizeof(*pusch_Config->pusch_PowerControl->deltaMCS)); *pusch_Config->pusch_PowerControl->deltaMCS = NR_PUSCH_PowerControl__deltaMCS_enabled; @@ -1582,14 +1610,14 @@ static NR_SetupRelease_PUSCH_Config_t *config_pusch(const bool use_deltaMCS, pusch_Config->resourceAllocation = NR_PUSCH_Config__resourceAllocation_resourceAllocationType1; pusch_Config->pusch_TimeDomainAllocationList = NULL; pusch_Config->pusch_AggregationFactor = NULL; - set_ul_mcs_table(uecap, scc, pusch_Config); + set_ul_mcs_table(configuration->force_UL256qam_off ? NULL : uecap, scc, pusch_Config); pusch_Config->transformPrecoder = NULL; if (!pusch_Config->codebookSubset) pusch_Config->codebookSubset = calloc(1, sizeof(*pusch_Config->codebookSubset)); *pusch_Config->codebookSubset = NR_PUSCH_Config__codebookSubset_nonCoherent; if (!pusch_Config->maxRank) pusch_Config->maxRank = calloc(1, sizeof(*pusch_Config->maxRank)); - *pusch_Config->maxRank = 1; + *pusch_Config->maxRank = set_ul_max_layers(configuration, uecap); pusch_Config->rbg_Size = NULL; pusch_Config->uci_OnPUSCH = NULL; pusch_Config->tp_pi2BPSK = NULL; @@ -1855,10 +1883,7 @@ static NR_BWP_Uplink_t *config_uplinkBWP(long bwp_loop, scheduling_request_config(scc, pucch_Config, ubwp->bwp_Common->genericParameters.subcarrierSpacing); set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME, ubwp->bwp_Common->genericParameters.subcarrierSpacing); - ubwp->bwp_Dedicated->pusch_Config = config_pusch(configuration->use_deltaMCS, - scc, - configuration->force_UL256qam_off ? NULL : uecap, - configuration->ptrs); + ubwp->bwp_Dedicated->pusch_Config = config_pusch(configuration, scc, uecap); ubwp->bwp_Dedicated->srs_Config = get_config_srs(scc, NULL, @@ -3268,6 +3293,7 @@ static void fill_harq_IEs(NR_ServingCellConfig_t *scc, int num_dlharq, int num_u static NR_BWP_UplinkDedicated_t *configure_initial_ul_bwp(const NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *configuration, int maxMIMO_Layers, + const NR_UE_NR_Capability_t *uecap, int id) { NR_BWP_UplinkDedicated_t *initialUplinkBWP = calloc(1, sizeof(*initialUplinkBWP)); @@ -3282,14 +3308,14 @@ static NR_BWP_UplinkDedicated_t *configure_initial_ul_bwp(const NR_ServingCellCo pucch_Config->resourceToAddModList = calloc(1, sizeof(*pucch_Config->resourceToAddModList)); pucch_Config->resourceToReleaseList = NULL; int num_pucch2 = get_nb_pucch2_per_slot(scc, curr_bwp); - config_pucch_resset0(pucch_Config, id, curr_bwp, num_pucch2, NULL); - config_pucch_resset1(pucch_Config, id, num_pucch2, NULL); + config_pucch_resset0(pucch_Config, id, curr_bwp, num_pucch2, uecap); + config_pucch_resset1(pucch_Config, id, num_pucch2, uecap); set_pucch_power_config(pucch_Config, configuration->do_CSIRS); - initialUplinkBWP->pusch_Config = config_pusch(configuration->use_deltaMCS, scc, NULL, configuration->ptrs); + initialUplinkBWP->pusch_Config = config_pusch(configuration, scc, uecap); // We are using do_srs = 0 here because the periodic SRS will only be enabled in update_cellGroupConfig() if do_srs == 1 - initialUplinkBWP->srs_Config = get_config_srs(scc, NULL, curr_bwp, id, 0, maxMIMO_Layers, configuration->minRXTXTIME, 0); + initialUplinkBWP->srs_Config = get_config_srs(scc, uecap, curr_bwp, id, 0, maxMIMO_Layers, configuration->minRXTXTIME, 0); scheduling_request_config(scc, pucch_Config, scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing); set_dl_DataToUL_ACK(pucch_Config, configuration->minRXTXTIME, genericParameters->subcarrierSpacing); @@ -3510,7 +3536,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, asn1cCallocOne(configDedicated->firstActiveDownlinkBWP_Id, first_active_bwp); asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_bwp); if (first_active_bwp == 0) { - uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, maxMIMO_Layers, uid); + uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, maxMIMO_Layers, NULL, uid); configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); } else { configDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); @@ -3743,35 +3769,6 @@ NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, return cellGroupConfig; } -long ue_supported_ul_layers(const NR_UE_NR_Capability_t *uecap) -{ - long ul_max_layers = 1; - if (uecap - && uecap->featureSets - && uecap->featureSets->featureSetsUplinkPerCC - && uecap->featureSets->featureSetsUplinkPerCC->list.count > 0) { - NR_FeatureSetUplinkPerCC_t *ul_feature_setup_per_cc = uecap->featureSets->featureSetsUplinkPerCC->list.array[0]; - if (ul_feature_setup_per_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH) { - switch (*ul_feature_setup_per_cc->mimo_CB_PUSCH->maxNumberMIMO_LayersCB_PUSCH) { - case NR_MIMO_LayersUL_twoLayers: - ul_max_layers = 2; - break; - case NR_MIMO_LayersUL_fourLayers: - ul_max_layers = 4; - break; - default: - ul_max_layers = 1; - } - } - } - return ul_max_layers; -} - -static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap) -{ - return min(ue_supported_ul_layers(uecap), configuration->pusch_AntennaPorts); -} - NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap, @@ -3821,7 +3818,7 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_ configDedicated->initialDownlinkBWP = calloc_or_fail(1, sizeof(*configDedicated->initialDownlinkBWP)); if (!uplinkConfig->initialUplinkBWP) uplinkConfig->initialUplinkBWP = calloc_or_fail(1, sizeof(*uplinkConfig->initialUplinkBWP)); - uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, ul_maxMIMO_Layers, uid); + uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, ul_maxMIMO_Layers, uecap, uid); configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); } else { if (!configDedicated->downlinkBWP_ToAddModList) @@ -4059,10 +4056,7 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC ulConfig->initialUplinkBWP = initialUplinkBWP; initialUplinkBWP->pucch_Config = NULL; - initialUplinkBWP->pusch_Config = config_pusch(configuration->use_deltaMCS, - servingcellconfigcommon, - uecap, - configuration->ptrs); + initialUplinkBWP->pusch_Config = config_pusch(configuration, servingcellconfigcommon, uecap); long maxMIMO_Layers = set_ul_max_layers(configuration, uecap); int curr_bwp = NRRIV2BW(servingcellconfigcommon->downlinkConfigCommon->initialDownlinkBWP->genericParameters.locationAndBandwidth, From eb9ac76f4d68635fe00b90d093a57a472ead6215 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 24 Sep 2025 09:11:04 +0200 Subject: [PATCH 04/15] Set MCS table also in initial BWP function --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 40b235e81c..91a9180ba0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -3325,6 +3325,7 @@ static NR_BWP_UplinkDedicated_t *configure_initial_ul_bwp(const NR_ServingCellCo static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCellConfigCommon_t *scc, const int pdsch_AntennaPorts, uint64_t bitmap, + const NR_UE_NR_Capability_t *uecap, const nr_mac_config_t *configuration) { NR_BWP_DownlinkDedicated_t *bwp_Dedicated = calloc(1, sizeof(*bwp_Dedicated)); @@ -3356,6 +3357,11 @@ static NR_BWP_DownlinkDedicated_t *configure_initial_dl_bwp(const NR_ServingCell bwp_Dedicated->pdcch_Config->choice.setup = pdcch_Config; bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts, configuration->ptrs); + // we might call configuration of initial BWP for BWP switch when we already have UE capabilities + set_dl_mcs_table(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing, + configuration->force_256qam_off ? NULL : uecap, + bwp_Dedicated, + scc); return bwp_Dedicated; } @@ -3537,7 +3543,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_bwp); if (first_active_bwp == 0) { uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, maxMIMO_Layers, NULL, uid); - configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); + configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, NULL, configuration); } else { configDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); NR_BWP_Downlink_t *bwp = config_downlinkBWP(scc, @@ -3819,7 +3825,7 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_ if (!uplinkConfig->initialUplinkBWP) uplinkConfig->initialUplinkBWP = calloc_or_fail(1, sizeof(*uplinkConfig->initialUplinkBWP)); uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, ul_maxMIMO_Layers, uecap, uid); - configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, configuration); + configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, uecap, configuration); } else { if (!configDedicated->downlinkBWP_ToAddModList) configDedicated->downlinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); From b547dfe056720a39ea467e2bad1ef75a0166d3a8 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 10 Oct 2025 11:36:17 +0200 Subject: [PATCH 05/15] apply new configuration after receiving ACK for RRCreconfiguration message --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 19 +++++++++++++++++++ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 1 + .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 13 ++++++------- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 10 +++++++--- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 7 ++++++- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 86eed9d575..34a8519bdb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -592,6 +592,19 @@ static bool allocate_dl_retransmission(gNB_MAC_INST *nr_mac, return true; } +static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE) +{ + if (UE->reconfigSpCellConfig) { + // in case of reestablishment, the spCellConfig had to be released + // temporarily. Reapply now before doing the reconfiguration. + UE->CellGroup->spCellConfig = UE->reconfigSpCellConfig; + // UE->reconfigSpCellConfig to be NULLed after receiving reconfiguration complete + } + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); + UE->await_reconfig = false; +} + typedef struct UEsched_s { float coef; NR_UE_info_t * UE; @@ -866,6 +879,12 @@ static void pf_dl(gNB_MAC_INST *mac, .tda_info = tda_info, }; + sched_pdsch.action = NULL; + int srb1 = 1; + /* everything that's only 3 bytes is an ack. To be safe, use a bit more. */ + if (iterator->UE->await_reconfig && sched_ctrl->rlc_status[srb1].bytes_in_buffer > 10) + sched_pdsch.action = ack_reconfig; + // Fix me: currently, the RLC does not give us the total number of PDUs // awaiting. Therefore, for the time being, we put a fixed overhead of 12 // (for 4 PDUs) and optionally + 2 for TA. Once RLC gives the number of diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 48768750e0..00bcdded3b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3948,6 +3948,7 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, NR_UE_info_t *UE, buf, sizeof(buf)); AssertFatal(enc_rval.encoded > 0, "ASN1 encoding of CellGroupConfig failed, failed type %s\n", enc_rval.failed_type->name); + UE->await_reconfig = true; du_to_cu_rrc_information_t du2cu = { .cellGroupConfig = buf, .cellGroupConfig_length = (enc_rval.encoded + 7) >> 3, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 27ecbdcbd0..7d73234350 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -393,16 +393,15 @@ int get_pucch_resourceid(NR_PUCCH_Config_t *pucch_Config, int O_uci, int pucch_r return *resource_id; } -static void handle_dl_harq(NR_UE_info_t * UE, - int8_t harq_pid, - bool success, - int harq_round_max) +static void handle_dl_harq(gNB_MAC_INST *mac, NR_UE_info_t * UE, int8_t harq_pid, bool success, int harq_round_max) { NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_harq_t *harq = &sched_ctrl->harq_processes[harq_pid]; harq->feedback_slot = -1; harq->is_waiting = false; if (success) { + if (harq->sched_pdsch.action) + harq->sched_pdsch.action(mac, UE); finish_nr_dl_harq(sched_ctrl, harq_pid); } else if (harq->round >= harq_round_max - 1) { abort_nr_dl_harq(UE, harq_pid); @@ -873,7 +872,7 @@ static NR_UE_harq_t *find_harq(frame_t frame, slot_t slot, NR_UE_info_t * UE, in frame, slot); remove_front_nr_list(&sched_ctrl->feedback_dl_harq); - handle_dl_harq(UE, pid, 0, harq_round_max); + handle_dl_harq(NULL, UE, pid, false, harq_round_max); pid = sched_ctrl->feedback_dl_harq.head; if (pid < 0) return NULL; @@ -930,7 +929,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value); nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0); bool success = harq_value == 0 && harq_confidence == 0; - handle_dl_harq(UE, pid, success, nrmac->dl_bler.harq_round_max); + handle_dl_harq(nrmac, UE, pid, success, nrmac->dl_bler.harq_round_max); if (is_ra) { bool ue_rejected = nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success); if (ue_rejected) { @@ -1009,7 +1008,7 @@ void handle_nr_uci_pucch_2_3_4(module_id_t mod_id, frame_t frame, slot_t slot, c const int8_t pid = sched_ctrl->feedback_dl_harq.head; remove_front_nr_list(&sched_ctrl->feedback_dl_harq); LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit, pid, acknack); - handle_dl_harq(UE, pid, uci_234->harq.harq_crc != 1 && acknack, nrmac->dl_bler.harq_round_max); + handle_dl_harq(nrmac, UE, pid, uci_234->harq.harq_crc != 1 && acknack, nrmac->dl_bler.harq_round_max); } free(uci_234->harq.harq_payload); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 8f98aabbee..ddec1b648e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -770,9 +770,12 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req) } else if (req->reconfig_compl) { LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n"); if (UE->reconfigSpCellConfig) { - // in case of reestablishment, the spCellConfig had to be released - // temporarily. Reapply now before doing the reconfiguration. - UE->CellGroup->spCellConfig = UE->reconfigSpCellConfig; + if (UE->await_reconfig) { + // in case of reestablishment, the spCellConfig had to be released + // temporarily. Reapply now before doing the reconfiguration. + UE->CellGroup->spCellConfig = UE->reconfigSpCellConfig; + UE->await_reconfig = false; + } UE->reconfigSpCellConfig = NULL; for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); @@ -971,6 +974,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) * reconfiguration has succeeded (indicated by the CU) */ UE->reconfigSpCellConfig = UE->CellGroup->spCellConfig; UE->CellGroup->spCellConfig = NULL; + UE->await_reconfig = true; mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index aa8b2b8644..745c7165ba 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -475,6 +475,9 @@ typedef struct NR_pdsch_dmrs { NR_PTRS_DownlinkConfig_t *phaseTrackingRS; } NR_pdsch_dmrs_t; +struct NR_UE_info; +struct gNB_MAC_INST_s; +typedef void (*feedback_action_t)(struct gNB_MAC_INST_s *mac, struct NR_UE_info *ue); typedef struct NR_sched_pdsch { /// RB allocation within active BWP uint16_t rbSize; @@ -501,6 +504,7 @@ typedef struct NR_sched_pdsch { // time_domain_allocation is the index of a list of tda int time_domain_allocation; NR_tda_info_t tda_info; + feedback_action_t action; } NR_sched_pdsch_t; typedef struct NR_UE_harq { @@ -772,7 +776,7 @@ typedef struct measgap_config { } measgap_config_t; /*! \brief UE list used by gNB to order UEs/CC for scheduling*/ -typedef struct { +typedef struct NR_UE_info { rnti_t rnti; uid_t uid; // unique ID of this UE /// scheduling control info @@ -795,6 +799,7 @@ typedef struct { float dl_thr_ue; long pdsch_HARQ_ACK_Codebook; bool is_redcap; + bool await_reconfig; NR_RA_t *ra; } NR_UE_info_t; From 88d1964f9c964c3dba53d6b5693cf0ccf3dfaa6d Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 12 Oct 2025 10:46:01 +0200 Subject: [PATCH 06/15] Validate BWP switch Return from triggering reconfiguration with BWP switch if BWP is the same as before the switch, and add check to verify if BWP triggered by switch command exists --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 00bcdded3b..21e28dbe98 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3922,14 +3922,32 @@ bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t * return false; } +static bool verify_bwp_switch(const NR_UE_info_t *UE, const nr_mac_config_t *configuration, int new_bwp_id) +{ + if (new_bwp_id == UE->current_DL_BWP.bwp_id) { + LOG_E(NR_MAC, "Source BWP ID and target BWP ID are the same, can't perform switch\n"); + return false; + } + + if (new_bwp_id == 0) + return true; + for (int i = 0; i < configuration->num_additional_bwps; i++) { + const nr_bwp_config_t *bwp_config = &configuration->bwp_config[i]; + if (bwp_config->id == new_bwp_id) + return true; + } + LOG_E(NR_MAC, "New BWP %d does not belong to the list of configured BWPs, can't perform switch\n", new_bwp_id); + return false; +} + void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, NR_UE_info_t *UE, int new_bwp_id) { DevAssert(UE->CellGroup != NULL); NR_CellGroupConfig_t *cellGroup_for_UE = NULL; if (new_bwp_id >= 0) { AssertFatal(UE->current_DL_BWP.bwp_id == UE->current_UL_BWP.bwp_id, "We only support same BWP for UL and DL\n"); - if (new_bwp_id == UE->current_DL_BWP.bwp_id) - LOG_E(NR_MAC, "Source BWP ID and target BWP ID are the same, can't perform switch\n"); + if (!verify_bwp_switch(UE, &nrmac->radio_config, new_bwp_id)) + return; else { UE->sc_info.csi_MeasConfig = NULL; // to avoid segfault when freeing csi_MeasConfig in configDedicated cellGroup_for_UE = update_cellGroupConfig_for_BWP_switch(UE->CellGroup, From b2878f4ab1d4053ee1bfadd68064a60b1daf4463 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sun, 12 Oct 2025 10:50:53 +0200 Subject: [PATCH 07/15] fix BWP start for ULSCH at UE --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index bd9ea09041..e566f3db9e 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -586,11 +586,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac, pusch_config_pdu->pusch_uci.harq_ack_bit_length = 0; + pusch_config_pdu->bwp_start = current_UL_BWP->BWPStart; if (dci_format == NR_UL_DCI_FORMAT_0_0 && ss_type == NR_SearchSpace__searchSpaceType_PR_common) { - pusch_config_pdu->bwp_start = sc_info->initial_ul_BWPStart; pusch_config_pdu->bwp_size = sc_info->initial_ul_BWPSize; } else { - pusch_config_pdu->bwp_start = current_UL_BWP->BWPStart; pusch_config_pdu->bwp_size = current_UL_BWP->BWPSize; } From 3e5d868018c9bf8ef9849dd65af93a01640cf47c Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 21 Oct 2025 16:48:29 +0200 Subject: [PATCH 08/15] set coresetID !=0 for dedicated BWP (needed if CSET0 doesn't fit that BWP) --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 91a9180ba0..a154335b10 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -1771,7 +1771,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1; agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0; agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0; - ss = rrc_searchspace_config(true, searchspaceid, 0, agg_level_candidates); + ss = rrc_searchspace_config(true, searchspaceid, coreset->controlResourceSetId, agg_level_candidates); } asn1cSeqAdd(&bwp->bwp_Common->pdcch_ConfigCommon->choice.setup->commonSearchSpaceList->list, ss); @@ -1812,7 +1812,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t verify_agg_levels(num_cces, configuration->num_agg_level_candidates, coreset2->controlResourceSetId, rrc_num_agg_level_candidates); searchspaceid = 10 + bwp->bwp_Id; - NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, searchspaceid, is_SA ? 0 : coreset2->controlResourceSetId, agg_level_candidates); + NR_SearchSpace_t *ss2 = rrc_searchspace_config(true, searchspaceid, coreset2->controlResourceSetId, agg_level_candidates); asn1cSeqAdd(&bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2); searchspaceid = 20 + bwp->bwp_Id; From 98618a7dc8c2c9bdf7fc3d2c789f57658cbd46d1 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 28 Oct 2025 10:29:14 +0100 Subject: [PATCH 09/15] The network must configure BWPs with consecutive IDs from 1 ... so if we want to have 1 BWP configured at any given time we need to reconfigure BWP 1 every time. This means that since the gNB has more than 1 BWPs (for use for different UEs), that there is a "gNB BWP ID" (as used by the gNB), which can be any BWP ID X, and one "UE BWP ID", which is always 1. This commit implements this distinction. --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 1 - openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 1 - .../NR_MAC_UE/nr_ue_dci_configuration.c | 3 - openair2/LAYER2/NR_MAC_gNB/config.c | 5 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 2 - .../LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c | 1 - .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 3 +- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 109 ++++---------- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 10 +- .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 1 - openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 - .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 + openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 138 ++++++------------ openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h | 14 +- 15 files changed, 101 insertions(+), 194 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 13f2eca955..563b3f2ca2 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -2781,7 +2781,6 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, nr_dci_format_t format, nr_rnti_type_t rnti_type, NR_ControlResourceSet_t *coreset, - int bwp_id, int ss_type, uint16_t cset0_bwp_size, uint16_t alt_size) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index f76f54b158..8f795452b8 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -159,7 +159,6 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP, nr_dci_format_t format, nr_rnti_type_t rnti_type, NR_ControlResourceSet_t *coreset, - int bwp_id, int ss_type, uint16_t cset0_bwp_size, uint16_t alt_size); diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c index 8a2074422e..7d630c3002 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c @@ -198,7 +198,6 @@ static void config_dci_pdu(NR_UE_MAC_INST_t *mac, NR_UL_DCI_FORMAT_0_0, rnti_type, coreset, - dl_bwp_id, ss->searchSpaceType->present, mac->type0_PDCCH_CSS_config.num_rbs, 0); @@ -211,7 +210,6 @@ static void config_dci_pdu(NR_UE_MAC_INST_t *mac, NR_DL_DCI_FORMAT_1_0, rnti_type, coreset, - dl_bwp_id, ss->searchSpaceType->present, mac->type0_PDCCH_CSS_config.num_rbs, 0); @@ -225,7 +223,6 @@ static void config_dci_pdu(NR_UE_MAC_INST_t *mac, dci_format[i], rnti_type, coreset, - dl_bwp_id, ss->searchSpaceType->present, mac->type0_PDCCH_CSS_config.num_rbs, alt_size); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 893a94147e..8b30bf78f0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -1116,8 +1116,9 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t NR_SCHED_LOCK(&nrmac->sched_lock); NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup); - DevAssert(UE->uid < MAX_MOBILES_PER_GNB); // test-mode: we assume we can always create a UE - free_and_zero(UE->ra); // test-mode (sims, phy-test): UE will not do RA + DevAssert(UE->uid < MAX_MOBILES_PER_GNB); // physical simulators: we assume we can always create a UE + free_and_zero(UE->ra); // physical simulators: UE will not do RA + UE->local_bwp_id = 1; // for physical simulators bool res = add_connected_nr_ue(nrmac, UE); if (!res) { LOG_E(NR_MAC, "Error adding UE %04x\n", rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index f8df95f679..e50358ae10 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -958,7 +958,6 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP, &uldci_payload, NR_UL_DCI_FORMAT_0_0, TYPE_TC_RNTI_, - ul_bwp->bwp_id, ss, coreset, 0, // parameter not needed for DCI 0_0 @@ -1385,7 +1384,6 @@ static void prepare_dl_pdus(gNB_MAC_INST *nr_mac, &dci_payload, NR_DL_DCI_FORMAT_1_0, rnti_type, - dl_bwp->bwp_id, sched_ctrl->search_space, coreset, 0, // parameter not needed for DCI 1_0 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c index 1f6fb64181..eb063b48ef 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_bch.c @@ -473,7 +473,6 @@ static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac, &dci_payload, dci_format, rnti_type, - 0, search_space, coreset, 0, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 34a8519bdb..e5aa8398b4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -601,6 +601,8 @@ static void ack_reconfig(gNB_MAC_INST *mac, NR_UE_info_t *UE) // UE->reconfigSpCellConfig to be NULLed after receiving reconfiguration complete } NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; + /* clean BWP structures */ + clean_bwp_structures(UE->CellGroup->spCellConfig); configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1); UE->await_reconfig = false; } @@ -1210,7 +1212,6 @@ void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE &dci_payload, current_BWP->dci_format, rnti_type, - bwp_id, sched_ctrl->search_space, sched_ctrl->coreset, UE->pdsch_HARQ_ACK_Codebook, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 21e28dbe98..14dedb1de9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -907,8 +907,10 @@ dci_pdu_rel15_t prepare_dci_dl_payload(const gNB_MAC_INST *gNB_mac, dci_payload.dai[0].val = pucch ? (pucch->dai_c - 1) & 3 : 0; // bwp indicator // as per table 7.3.1.1.2-1 in 38.212 - if (dl_BWP) - dci_payload.bwp_indicator.val = UE->sc_info.n_dl_bwp < 4 ? dl_BWP->bwp_id : dl_BWP->bwp_id - 1; + if (dl_BWP) { + int ext_bwp_id = dl_BWP->bwp_id ? 1 : 0; // BWP-ID sent to the UE is always 1 except for BWP 0 + dci_payload.bwp_indicator.val = UE->sc_info.n_dl_bwp < 4 ? ext_bwp_id : ext_bwp_id - 1; + } return dci_payload; } @@ -1182,7 +1184,6 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, NR_UE_UL_BWP_t *ul_bwp, NR_SearchSpace__searchSpaceType_PR ss_type) { - int bwp_id = ul_bwp->bwp_id; nr_dci_format_t dci_format = ul_bwp->dci_format; // 3GPP TS 38.214 Section 6.1.2.2.2 Uplink resource allocation type 1 @@ -1214,7 +1215,8 @@ void config_uldci(const NR_UE_ServingCell_Info_t *sc_info, LOG_D(NR_MAC,"Configuring DCI Format 0_1\n"); dci_pdu_rel15->dai[0].val = 0; //TODO // bwp indicator as per table 7.3.1.1.2-1 in 38.212 - dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? bwp_id : bwp_id - 1; + int ext_bwp_id = ul_bwp->bwp_id ? 1 : 0; // BWP-ID sent to the UE is always 1 except for BWP 0 + dci_pdu_rel15->bwp_indicator.val = sc_info->n_ul_bwp < 4 ? ext_bwp_id : ext_bwp_id - 1; // SRS resource indicator if (pusch_Config && pusch_Config->txConfig != NULL) { AssertFatal(*pusch_Config->txConfig == NR_PUSCH_Config__txConfig_codebook, @@ -1640,7 +1642,6 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, int rnti_type, - int bwp_id, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, long pdsch_HARQ_ACK_Codebook, @@ -1671,7 +1672,6 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, NR_UL_DCI_FORMAT_0_0, rnti_type, coreset, - bwp_id, ss->searchSpaceType->present, cset0_bwp_size, 0); @@ -1685,7 +1685,6 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, NR_DL_DCI_FORMAT_1_0, rnti_type, coreset, - bwp_id, ss->searchSpaceType->present, cset0_bwp_size, 0); @@ -1702,10 +1701,10 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, dci_format, rnti_type, coreset, - bwp_id, ss->searchSpaceType->present, cset0_bwp_size, alt_size); + if (dci_size == 0) return; pdcch_dci_pdu->PayloadSizeBits = dci_size; @@ -2703,38 +2702,26 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, AssertFatal(dl_bwp_switch == ul_bwp_switch, "Different UL and DL BWP not supported\n"); DL_BWP->bwp_id = dl_bwp_switch; UL_BWP->bwp_id = ul_bwp_switch; + UE->local_bwp_id = dl_bwp_switch; // assuming they are the same } else { - // (re)configuring BWP - // TODO BWP switching not via RRC reconfiguration - // via RRC if firstActiveXlinkBWP_Id is NULL, MAC stays on the same BWP as before - if (servingCellConfig->firstActiveDownlinkBWP_Id) - DL_BWP->bwp_id = *servingCellConfig->firstActiveDownlinkBWP_Id; - if (servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id) - UL_BWP->bwp_id = *servingCellConfig->uplinkConfig->firstActiveUplinkBWP_Id; + DL_BWP->bwp_id = UE->local_bwp_id; + UL_BWP->bwp_id = UE->local_bwp_id; } const struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList = servingCellConfig->downlinkBWP_ToAddModList; if(bwpList) - sc_info->n_dl_bwp = bwpList->list.count; - if (DL_BWP->bwp_id>0) { - for (int i=0; ilist.count; i++) { - dl_bwp = bwpList->list.array[i]; - if(dl_bwp->bwp_Id == DL_BWP->bwp_id) - break; - } - AssertFatal(dl_bwp!=NULL,"Couldn't find DLBWP corresponding to BWP ID %ld\n",DL_BWP->bwp_id); + sc_info->n_dl_bwp = 1; + if (DL_BWP->bwp_id > 0) { + dl_bwp = bwpList->list.array[0]; + AssertFatal(dl_bwp, "Couldn't find DLBWP corresponding to BWP ID %ld\n", DL_BWP->bwp_id); } const struct NR_UplinkConfig__uplinkBWP_ToAddModList *ubwpList = servingCellConfig->uplinkConfig->uplinkBWP_ToAddModList; if(ubwpList) - sc_info->n_ul_bwp = ubwpList->list.count; - if (UL_BWP->bwp_id>0) { - for (int i=0; ilist.count; i++) { - ul_bwp = ubwpList->list.array[i]; - if(ul_bwp->bwp_Id == UL_BWP->bwp_id) - break; - } - AssertFatal(ul_bwp!=NULL,"Couldn't find ULBWP corresponding to BWP ID %ld\n",UL_BWP->bwp_id); + sc_info->n_ul_bwp = 1; + if (UL_BWP->bwp_id > 0) { + ul_bwp = ubwpList->list.array[0]; + AssertFatal(ul_bwp, "Couldn't find ULBWP corresponding to BWP ID %ld\n", UL_BWP->bwp_id); } // selection of dedicated BWPs @@ -2762,12 +2749,12 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac, } // TDA lists - if (DL_BWP->bwp_id>0) + if (DL_BWP->bwp_id > 0) DL_BWP->tdaList_Common = dl_bwp->bwp_Common->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; else DL_BWP->tdaList_Common = scc->downlinkConfigCommon->initialDownlinkBWP->pdsch_ConfigCommon->choice.setup->pdsch_TimeDomainAllocationList; - if(UL_BWP->bwp_id>0) + if(UL_BWP->bwp_id > 0) UL_BWP->tdaList_Common = ul_bwp->bwp_Common->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; else UL_BWP->tdaList_Common = scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList; @@ -3217,9 +3204,10 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt NR_NZP_CSI_RS_ResourceSetId_t *nzp = NULL; for (int csi_list=0; csi_listcsi_ResourceConfigToAddModList->list.count; csi_list++) { NR_CSI_ResourceConfig_t *csires = csi_measconfig->csi_ResourceConfigToAddModList->list.array[csi_list]; - if(csires->bwp_Id == dl_bwp->bwp_id && - csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB && - csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) { + if (csires->bwp_Id > 1) + LOG_E(NR_MAC, "Invalid CSI resource BWP ID %ld, we only configure BWP up to 1\n", csires->bwp_Id); + else if (csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB && + csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList) { nzp = csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList->list.array[0]; } } @@ -3456,46 +3444,11 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot void clean_bwp_structures(NR_SpCellConfig_t *spCellConfig) { NR_ServingCellConfig_t *spCellConfigDedicated = spCellConfig->spCellConfigDedicated; - if (spCellConfigDedicated->downlinkBWP_ToReleaseList) { - struct NR_ServingCellConfig__downlinkBWP_ToReleaseList *rel_dl = spCellConfigDedicated->downlinkBWP_ToReleaseList; - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *add_dl = spCellConfigDedicated->downlinkBWP_ToAddModList; - int num_rel = rel_dl->list.count; - int num_add = add_dl->list.count; - for (int i = 0; i < num_rel; i++) { - NR_BWP_Id_t *rel_id = rel_dl->list.array[i]; - for (int j = 0; j < num_add; j++) { - NR_BWP_Downlink_t *dl_bwp = add_dl->list.array[j]; - if (*rel_id == dl_bwp->bwp_Id) { - asn_sequence_del(&add_dl->list, j, 1); - } - } - asn_sequence_del(&rel_dl->list, i, 1); - } - if (rel_dl->list.count == 0) - free_and_zero(spCellConfigDedicated->downlinkBWP_ToReleaseList); - if (add_dl->list.count == 0) - free_and_zero(spCellConfigDedicated->downlinkBWP_ToAddModList); - } - if (spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList) { - struct NR_UplinkConfig__uplinkBWP_ToReleaseList *rel_ul = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList; - struct NR_UplinkConfig__uplinkBWP_ToAddModList *add_ul = spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList; - int num_rel = rel_ul->list.count; - int num_add = add_ul->list.count; - for (int i = 0; i < num_rel; i++) { - NR_BWP_Id_t *rel_id = rel_ul->list.array[i]; - for (int j = 0; j < num_add; j++) { - NR_BWP_Uplink_t *ul_bwp = add_ul->list.array[j]; - if (*rel_id == ul_bwp->bwp_Id) { - asn_sequence_del(&add_ul->list, j, 1); - } - } - asn_sequence_del(&rel_ul->list, i, 1); - } - if (rel_ul->list.count == 0) - free_and_zero(spCellConfigDedicated->uplinkConfig->uplinkBWP_ToReleaseList); - if (add_ul->list.count == 0) - free_and_zero(spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList); - } + if (spCellConfigDedicated->downlinkBWP_ToAddModList && spCellConfigDedicated->downlinkBWP_ToAddModList->list.count > 1) + asn_sequence_del(&spCellConfigDedicated->downlinkBWP_ToAddModList->list, 0, 1); + if (spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList + && spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.count > 1) + asn_sequence_del(&spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list, 0, 1); } void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) @@ -3517,8 +3470,6 @@ void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group) /* remove reestablishRLC, we don't need it anymore */ for (int i = 0; i < cell_group->rlc_BearerToAddModList->list.count; ++i) free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC); - /* clean BWP structures */ - clean_bwp_structures(spCellConfig); } int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs) @@ -3818,6 +3769,7 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, &mac->radio_config, &mac->rlc_config); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = cellGroupConfig; + UE->local_bwp_id = mac->radio_config.first_active_bwp; if (!cellGroupConfig) return true; @@ -3950,6 +3902,7 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, NR_UE_info_t *UE, return; else { UE->sc_info.csi_MeasConfig = NULL; // to avoid segfault when freeing csi_MeasConfig in configDedicated + UE->local_bwp_id = new_bwp_id; cellGroup_for_UE = update_cellGroupConfig_for_BWP_switch(UE->CellGroup, &nrmac->radio_config, UE->capability, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 7d73234350..eb32fde2e6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -253,9 +253,10 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot) "Only periodic CSI reporting is implemented currently\n"); const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; - if(pucchcsires->uplinkBandwidthPartId != ul_bwp->bwp_id) + if(pucchcsires->uplinkBandwidthPartId > 1) { + LOG_E(NR_MAC, "Invalid PUCCH BWP ID %ld, we only configure BWP up to 1\n", pucchcsires->uplinkBandwidthPartId); continue; - + } // we schedule CSI reporting max_fb_time slots in advance int period, offset; csi_period_offset(csirep, NULL, &period, &offset); @@ -748,7 +749,6 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16 = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; - NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; const int n_slots_frame = nrmac->frame_structure.numb_slots_frame; int cumul_bits = 0; @@ -763,8 +763,10 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, NR_CSI_ReportConfig_t *csirep = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; uint8_t cqi_table = (dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_1 && csirep->cqi_Table) ? *csirep->cqi_Table : NR_CSI_ReportConfig__cqi_Table_table1; const NR_PUCCH_CSI_Resource_t *pucchcsires = csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list.array[0]; - if(pucchcsires->uplinkBandwidthPartId != ul_bwp->bwp_id) + if(pucchcsires->uplinkBandwidthPartId > 1) { + LOG_E(NR_MAC, "Invalid PUCCH BWP ID %ld, we only configure BWP up to 1\n", pucchcsires->uplinkBandwidthPartId); continue; + } int period, offset; csi_period_offset(csirep, NULL, &period, &offset); // verify if report with current id has been scheduled for this frame and slot diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 9904067aa5..3faeee66b2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -2606,7 +2606,6 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE &uldci_payload, current_BWP->dci_format, TYPE_C_RNTI_, - current_BWP->bwp_id, ss, coreset, UE->pdsch_HARQ_ACK_Codebook, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index d5626c24df..af0d102212 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -258,7 +258,6 @@ void fill_dci_pdu_rel15(const NR_UE_ServingCell_Info_t *servingCellInfo, dci_pdu_rel15_t *dci_pdu_rel15, int dci_format, int rnti_type, - int bwp_id, NR_SearchSpace_t *ss, NR_ControlResourceSet_t *coreset, long pdsch_HARQ_ACK_Codebook, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index ddec1b648e..6d105078b7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -576,6 +576,7 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc, mac->frame); // TODO: in NSA we assign capabilities here, otherwise outside => not logic UE->capability = cap; + UE->local_bwp_id = 1; // get_default_secondaryCellGroup sets 1st active BWP as 1 } // note: we don't pass the cellGroupConfig to add_new_nr_ue() because we need // the uid to create the CellGroupConfig (which is in the UE context created diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 745c7165ba..1a4ea9f3af 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -801,6 +801,11 @@ typedef struct NR_UE_info { bool is_redcap; bool await_reconfig; NR_RA_t *ra; + // 3GPP mandates that BWPs are enumerated consecutively, but we only send one (dedicated) + // BWP to the UE (and modify that BWP on reconfiguration); consequently, the BWP ID for a + // dedicated BWP is always 1 from the UE's point of view, even if the gNB has multiple BWPs. + // The below ID is the "true" (non-consecutive) BWP ID from the gNB's point of view + NR_BWP_Id_t local_bwp_id; } NR_UE_info_t; typedef struct { diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index a154335b10..3cd448b216 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -1724,20 +1724,18 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t const NR_UE_NR_Capability_t *uecap, int dl_antenna_ports, bool force_256qam_off, - int bwp_loop, bool is_SA, const nr_mac_config_t *configuration) { NR_BWP_Downlink_t *bwp = calloc_or_fail(1, sizeof(*bwp)); + bwp->bwp_Id = 1; bwp->bwp_Common = calloc(1,sizeof(*bwp->bwp_Common)); - if(configuration->num_additional_bwps > 0) { - const nr_bwp_config_t *bwp_config = &configuration->bwp_config[bwp_loop]; - bwp->bwp_Id = bwp_config->id; + if(configuration->num_additional_bwps > 0 && configuration->first_active_bwp > 0) { + const nr_bwp_config_t *bwp_config = &configuration->bwp_config[configuration->first_active_bwp - 1]; bwp->bwp_Common->genericParameters.locationAndBandwidth = bwp_config->location_and_bw; bwp->bwp_Common->genericParameters.subcarrierSpacing = bwp_config->scs; bwp->bwp_Common->genericParameters.cyclicPrefix = NULL; } else { - bwp->bwp_Id=bwp_loop+1; bwp->bwp_Common->genericParameters.locationAndBandwidth = PRBalloc_to_locationandbandwidth(scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,0); bwp->bwp_Common->genericParameters.subcarrierSpacing = scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.subcarrierSpacing; bwp->bwp_Common->genericParameters.cyclicPrefix = scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters.cyclicPrefix; @@ -1830,8 +1828,7 @@ static NR_BWP_Downlink_t *config_downlinkBWP(const NR_ServingCellConfigCommon_t return bwp; } -static NR_BWP_Uplink_t *config_uplinkBWP(long bwp_loop, - bool is_SA, +static NR_BWP_Uplink_t *config_uplinkBWP(bool is_SA, int uid, int maxMIMO_Layers, const nr_mac_config_t *configuration, @@ -1839,14 +1836,14 @@ static NR_BWP_Uplink_t *config_uplinkBWP(long bwp_loop, const NR_UE_NR_Capability_t *uecap) { NR_BWP_Uplink_t *ubwp = calloc_or_fail(1, sizeof(*ubwp)); + ubwp->bwp_Id = 1; ubwp->bwp_Common = calloc(1, sizeof(*ubwp->bwp_Common)); - if(configuration->num_additional_bwps > 0) { - ubwp->bwp_Id = configuration->bwp_config[bwp_loop].id; - ubwp->bwp_Common->genericParameters.locationAndBandwidth = configuration->bwp_config[bwp_loop].location_and_bw; - ubwp->bwp_Common->genericParameters.subcarrierSpacing = configuration->bwp_config[bwp_loop].scs; + if(configuration->num_additional_bwps > 0 && configuration->first_active_bwp > 0) { + int bwp_idx = configuration->first_active_bwp - 1; + ubwp->bwp_Common->genericParameters.locationAndBandwidth = configuration->bwp_config[bwp_idx].location_and_bw; + ubwp->bwp_Common->genericParameters.subcarrierSpacing = configuration->bwp_config[bwp_idx].scs; ubwp->bwp_Common->genericParameters.cyclicPrefix = NULL; } else { - ubwp->bwp_Id=bwp_loop+1; ubwp->bwp_Common->genericParameters.locationAndBandwidth = PRBalloc_to_locationandbandwidth(scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth,0); ubwp->bwp_Common->genericParameters.subcarrierSpacing = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.subcarrierSpacing; ubwp->bwp_Common->genericParameters.cyclicPrefix = scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.cyclicPrefix; @@ -1889,7 +1886,7 @@ static NR_BWP_Uplink_t *config_uplinkBWP(long bwp_loop, NULL, curr_bwp, uid, - bwp_loop + 1, + ubwp->bwp_Id, maxMIMO_Layers, configuration->minRXTXTIME, configuration->do_SRS); @@ -3537,7 +3534,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, uint64_t bitmap = get_ssb_bitmap(scc); int first_active_bwp = 0; if (configuration->num_additional_bwps > 0) - first_active_bwp = configuration->first_active_bwp; + first_active_bwp = configuration->first_active_bwp > 0 ? 1 : 0; asn1cCallocOne(configDedicated->firstActiveDownlinkBWP_Id, first_active_bwp); asn1cCallocOne(uplinkConfig->firstActiveUplinkBWP_Id, first_active_bwp); @@ -3550,12 +3547,11 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, NULL, 0, false, - first_active_bwp - 1, true, configuration); asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, bwp); uplinkConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); - NR_BWP_Uplink_t *ubwp = config_uplinkBWP(first_active_bwp - 1, true, uid, maxMIMO_Layers, configuration, scc, NULL); + NR_BWP_Uplink_t *ubwp = config_uplinkBWP(true, uid, maxMIMO_Layers, configuration, scc, NULL); asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ubwp); } @@ -3775,46 +3771,22 @@ NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, return cellGroupConfig; } -NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, - const nr_mac_config_t *configuration, - const NR_UE_NR_Capability_t *uecap, - const NR_ServingCellConfigCommon_t *scc, - int uid, - int old_bwp, - int new_bwp) +NR_CellGroupConfig_t *update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, + const nr_mac_config_t *configuration, + const NR_UE_NR_Capability_t *uecap, + const NR_ServingCellConfigCommon_t *scc, + int uid, + int old_bwp, + int new_bwp) { NR_SpCellConfig_t *spCellConfig = cellGroupConfig->spCellConfig; NR_ServingCellConfig_t *configDedicated = spCellConfig->spCellConfigDedicated; - *configDedicated->firstActiveDownlinkBWP_Id = new_bwp; + *configDedicated->firstActiveDownlinkBWP_Id = new_bwp != 0; // 1 for any BWP != 0 NR_UplinkConfig_t *uplinkConfig = configDedicated->uplinkConfig; - *uplinkConfig->firstActiveUplinkBWP_Id = new_bwp; + *uplinkConfig->firstActiveUplinkBWP_Id = new_bwp != 0; // 1 for any BWP != 0 + nr_mac_config_t local_config = *configuration; long ul_maxMIMO_Layers = set_ul_max_layers(configuration, uecap); - - // release old BWP - struct NR_ServingCellConfig__downlinkBWP_ToAddModList *dl_BWP_list = configDedicated->downlinkBWP_ToAddModList; - struct NR_UplinkConfig__uplinkBWP_ToAddModList *ul_BWP_list = uplinkConfig->uplinkBWP_ToAddModList; - if (old_bwp > 0) { // we need to remove old BWP only if it is not the initial - AssertFatal(dl_BWP_list, "Source BWP %d should be present in the list\n", old_bwp); - AssertFatal(ul_BWP_list, "Source BWP %d should be present in the list\n", old_bwp); - NR_BWP_Id_t id = dl_BWP_list->list.array[0]->bwp_Id; - if (!configDedicated->downlinkBWP_ToReleaseList) - configDedicated->downlinkBWP_ToReleaseList = calloc_or_fail(1, sizeof(*configDedicated->downlinkBWP_ToReleaseList)); - asn1cSequenceAdd(configDedicated->downlinkBWP_ToReleaseList->list, NR_BWP_Id_t, rel_id); - *rel_id = id; - AssertFatal(configDedicated->downlinkBWP_ToReleaseList->list.count == 1, - "logic error: there shouldn't be more than 1 BWP to release, but downlinkBWP_ToReleaseList has %d\n", - configDedicated->downlinkBWP_ToReleaseList->list.count); - - id = ul_BWP_list->list.array[0]->bwp_Id; - if (!uplinkConfig->uplinkBWP_ToReleaseList) - uplinkConfig->uplinkBWP_ToReleaseList = calloc_or_fail(1, sizeof(*uplinkConfig->uplinkBWP_ToReleaseList)); - asn1cSequenceAdd(uplinkConfig->uplinkBWP_ToReleaseList->list, NR_BWP_Id_t, ul_rel_id); - *ul_rel_id = id; - AssertFatal(uplinkConfig->uplinkBWP_ToReleaseList->list.count == 1, - "logic error: there shouldn't be more than 1 BWP to release, but uplinkBWP_ToReleaseList has %d\n", - uplinkConfig->uplinkBWP_ToReleaseList->list.count); - } - + local_config.first_active_bwp = new_bwp; uint64_t bitmap = get_ssb_bitmap(scc); const int pdsch_AntennaPorts = configuration->pdsch_AntennaPorts.N1 * configuration->pdsch_AntennaPorts.N2 * configuration->pdsch_AntennaPorts.XP; @@ -3824,23 +3796,22 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_ configDedicated->initialDownlinkBWP = calloc_or_fail(1, sizeof(*configDedicated->initialDownlinkBWP)); if (!uplinkConfig->initialUplinkBWP) uplinkConfig->initialUplinkBWP = calloc_or_fail(1, sizeof(*uplinkConfig->initialUplinkBWP)); - uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, configuration, ul_maxMIMO_Layers, uecap, uid); - configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, uecap, configuration); + uplinkConfig->initialUplinkBWP = configure_initial_ul_bwp(scc, &local_config, ul_maxMIMO_Layers, uecap, uid); + configDedicated->initialDownlinkBWP = configure_initial_dl_bwp(scc, pdsch_AntennaPorts, bitmap, uecap, &local_config); } else { if (!configDedicated->downlinkBWP_ToAddModList) configDedicated->downlinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); NR_BWP_Downlink_t *dl_bwp = config_downlinkBWP(scc, uecap, pdsch_AntennaPorts, - configuration->force_256qam_off, - new_bwp - 1, + local_config.force_256qam_off, true, - configuration); + &local_config); asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, dl_bwp); if (!uplinkConfig->uplinkBWP_ToAddModList) uplinkConfig->uplinkBWP_ToAddModList = calloc_or_fail(1, sizeof(*uplinkConfig->uplinkBWP_ToAddModList)); - NR_BWP_Uplink_t *ul_bwp = config_uplinkBWP(new_bwp - 1, true, uid, ul_maxMIMO_Layers, configuration, scc, uecap); + NR_BWP_Uplink_t *ul_bwp = config_uplinkBWP(true, uid, ul_maxMIMO_Layers, &local_config, scc, uecap); asn1cSeqAdd(&uplinkConfig->uplinkBWP_ToAddModList->list, ul_bwp); } @@ -3848,9 +3819,9 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_ configDedicated->csi_MeasConfig->choice.setup = get_csiMeasConfig(configDedicated, uecap, scc, - configuration, + &local_config, uid, - new_bwp, + *uplinkConfig->firstActiveUplinkBWP_Id, bitmap); // we temporarily need to keep both the old and the new BWP in the CG used by the gNB @@ -4077,44 +4048,27 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC configuration->do_SRS); // Downlink BWPs - int n_dl_bwp = 1; int firstActiveDownlinkBWP_Id = 1; - if (configuration->num_additional_bwps > 0) { - n_dl_bwp = configuration->num_additional_bwps; - firstActiveDownlinkBWP_Id = configuration->first_active_bwp; - } configDedicated->downlinkBWP_ToAddModList = calloc(1, sizeof(*configDedicated->downlinkBWP_ToAddModList)); - for (int bwp_loop = 0; bwp_loop < n_dl_bwp; bwp_loop++) { - NR_BWP_Downlink_t *bwp = config_downlinkBWP(servingcellconfigcommon, - uecap, - dl_antenna_ports, - configuration->force_256qam_off, - bwp_loop, - false, - configuration); - asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, bwp); - configDedicated->firstActiveDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->firstActiveDownlinkBWP_Id)); - *configDedicated->firstActiveDownlinkBWP_Id = firstActiveDownlinkBWP_Id; - configDedicated->defaultDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->defaultDownlinkBWP_Id)); - *configDedicated->defaultDownlinkBWP_Id = 1; - } + NR_BWP_Downlink_t *bwp = config_downlinkBWP(servingcellconfigcommon, + uecap, + dl_antenna_ports, + configuration->force_256qam_off, + false, + configuration); + asn1cSeqAdd(&configDedicated->downlinkBWP_ToAddModList->list, bwp); + configDedicated->firstActiveDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->firstActiveDownlinkBWP_Id)); + *configDedicated->firstActiveDownlinkBWP_Id = firstActiveDownlinkBWP_Id; + configDedicated->defaultDownlinkBWP_Id = calloc(1, sizeof(*configDedicated->defaultDownlinkBWP_Id)); + *configDedicated->defaultDownlinkBWP_Id = 1; // Uplink BWPs - int n_ul_bwp = 1; int firstActiveUplinkBWP_Id = 1; - if (configuration->num_additional_bwps > 0) { - n_ul_bwp = configuration->num_additional_bwps; - firstActiveUplinkBWP_Id = configuration->first_active_bwp; - } - if (n_ul_bwp > 0) { - ulConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*ulConfig->uplinkBWP_ToAddModList)); - for (int bwp_loop = 0; bwp_loop < n_ul_bwp; bwp_loop++) { - NR_BWP_Uplink_t *ubwp = config_uplinkBWP(bwp_loop, false, uid, maxMIMO_Layers, configuration, servingcellconfigcommon, uecap); - asn1cSeqAdd(&ulConfig->uplinkBWP_ToAddModList->list, ubwp); - } - ulConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*ulConfig->firstActiveUplinkBWP_Id)); - *ulConfig->firstActiveUplinkBWP_Id = firstActiveUplinkBWP_Id; - } + ulConfig->uplinkBWP_ToAddModList = calloc(1, sizeof(*ulConfig->uplinkBWP_ToAddModList)); + NR_BWP_Uplink_t *ubwp = config_uplinkBWP(false, uid, maxMIMO_Layers, configuration, servingcellconfigcommon, uecap); + asn1cSeqAdd(&ulConfig->uplinkBWP_ToAddModList->list, ubwp); + ulConfig->firstActiveUplinkBWP_Id = calloc(1, sizeof(*ulConfig->firstActiveUplinkBWP_Id)); + *ulConfig->firstActiveUplinkBWP_Id = firstActiveUplinkBWP_Id; configDedicated->bwp_InactivityTimer = NULL; configDedicated->downlinkBWP_ToReleaseList = NULL; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index 270aed4b71..b776d667d6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -124,13 +124,13 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, NR_RLC_Config_PR rlc_conf, long priority, const nr_rlc_configuration_t *default_rlc_config); -NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, - const nr_mac_config_t *configuration, - const NR_UE_NR_Capability_t *uecap, - const NR_ServingCellConfigCommon_t *scc, - int uid, - int old_bwp, - int new_bwp); +NR_CellGroupConfig_t *update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig, + const nr_mac_config_t *configuration, + const NR_UE_NR_Capability_t *uecap, + const NR_ServingCellConfigCommon_t *scc, + int uid, + int old_bwp, + int new_bwp); NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len); measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime); int encode_measgap_config(const measgap_config_t *c, uint8_t *buf); From ca0cc079a6307d20d96c6c1dda00c1a88c26a7a2 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 24 Nov 2025 15:49:40 +0100 Subject: [PATCH 10/15] avoid having negative BWP size if BWP start > BWP size --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 7 ++++--- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index e5aa8398b4..d5c1048ad6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -398,7 +398,8 @@ bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) // except for the case when DCI format 1_0 is decoded in any common search space in which case the size of CORESET 0 shall be // used if CORESET 0 is configured for the cell and the size of initial DL bandwidth part shall be used if CORESET 0 is not // configured for the cell. - if (dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0 && sched_ctrl->search_space->searchSpaceType + if (dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0 + && sched_ctrl->search_space->searchSpaceType && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { if (sched_ctrl->coreset->controlResourceSetId == 0) { bwp_info.bwpStart = nr_mac->cset0_bwp_start; @@ -406,9 +407,9 @@ bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE) bwp_info.bwpStart = dl_bwp->BWPStart + sched_ctrl->sched_pdcch.rb_start; } if (nr_mac->cset0_bwp_size > 0) { - bwp_info.bwpSize = min(dl_bwp->BWPSize - bwp_info.bwpStart, nr_mac->cset0_bwp_size); + bwp_info.bwpSize = min(dl_bwp->BWPSize, nr_mac->cset0_bwp_size); } else { - bwp_info.bwpSize = min(dl_bwp->BWPSize - bwp_info.bwpStart, UE->sc_info.initial_dl_BWPSize); + bwp_info.bwpSize = min(dl_bwp->BWPSize, UE->sc_info.initial_dl_BWPSize); } } else { bwp_info.bwpSize = dl_bwp->BWPSize; diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3faeee66b2..f72c1c88ee 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -163,7 +163,8 @@ bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE) // contiguously allocated non-interleaved virtual resource blocks within the active bandwidth part of size PRBs except for the // case when DCI format 0_0 is decoded in any common search space in which case the size of the initial UL bandwidth part shall // be used. - if (ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_0 && sched_ctrl->search_space->searchSpaceType + if (ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_0 + && sched_ctrl->search_space->searchSpaceType && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { bwp_info.bwpSize = min(ul_bwp->BWPSize, UE->sc_info.initial_ul_BWPSize); } else { From 805c968b594d83095e733678495971bdf7ea2cde Mon Sep 17 00:00:00 2001 From: francescomani Date: Thu, 27 Nov 2025 15:16:46 +0100 Subject: [PATCH 11/15] Add a check for BWP start and size validity in configuration --- openair2/GNB_APP/gnb_config.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 081ce8607f..1f641fc6d9 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1368,7 +1368,7 @@ void nfapi_stop_l1() } } -static void get_bwp_config(nr_mac_config_t *configuration) +static void get_bwp_config(nr_mac_config_t *configuration, const NR_ServingCellConfigCommon_t *scc) { char path[MAX_OPTNAME_SIZE * 2 + 8]; snprintf(path, sizeof(path), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); @@ -1377,10 +1377,13 @@ static void get_bwp_config(nr_mac_config_t *configuration) AssertFatal(configuration->num_additional_bwps >= 0 && configuration->num_additional_bwps <= 4, "Invalid number of additional BWPs %d\n", configuration->num_additional_bwps); + int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; for (int i = 0; i < configuration->num_additional_bwps; i++) { configuration->bwp_config[i].id = i + 1; int bwp_start = *BWPParamList.paramarray[i][GNB_BWP_START_IDX].iptr; + AssertFatal(bwp_start >= 0 && bwp_start < bw, "Invalid BWP start value %d\n", bwp_start); int bwp_size = *BWPParamList.paramarray[i][GNB_BWP_SIZE_IDX].iptr; + AssertFatal(bwp_start + bwp_size <= bw, "BWP start %d and BWP size %d exceeds full BW %d\n", bwp_start, bwp_size, bw); configuration->bwp_config[i].location_and_bw = PRBalloc_to_locationandbandwidth(bwp_size, bwp_start); configuration->bwp_config[i].scs = *BWPParamList.paramarray[i][GNB_BWP_SCS_IDX].iptr; LOG_I(GNB_APP, @@ -1418,12 +1421,6 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.pdsch_AntennaPorts.XP, config.pusch_AntennaPorts); - // BWP - get_bwp_config(&config); - AssertFatal(config.num_additional_bwps <= 4, "Impossible to configure more than 4 additional BWPs\n"); - config.first_active_bwp = *GNBParamList.paramarray[0][GNB_1ST_ACTIVE_BWP_IDX].iptr; - AssertFatal(config.first_active_bwp <= config.num_additional_bwps, "1st active BWP does not belog to the configured BWPs\n"); - // RU GET_PARAMS_LIST(RUParamList, RUParams, RUPARAMS_DESC, CONFIG_STRING_RU_LIST, NULL); int num_tx = 0; @@ -1524,7 +1521,11 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.num_agg_level_candidates[PDCCH_AGG_LEVEL16]); NR_ServingCellConfigCommon_t *scc = get_scc_config(cfg, config.minRXTXTIME, config.do_SRS); - //xer_fprint(stdout, &asn_DEF_NR_ServingCellConfigCommon, scc); + // BWP + get_bwp_config(&config, scc); + AssertFatal(config.num_additional_bwps <= 4, "Impossible to configure more than 4 additional BWPs\n"); + config.first_active_bwp = *GNBParamList.paramarray[0][GNB_1ST_ACTIVE_BWP_IDX].iptr; + AssertFatal(config.first_active_bwp <= config.num_additional_bwps, "1st active BWP does not belog to the configured BWPs\n"); if (MacRLC_ParamList.numelt > 0) { /* NR RLC config is needed by mac_top_init_gNB() */ From 5c3c374c1bc9b8b69a9085cb9a032b4d12094163 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 20 Oct 2025 14:44:36 +0200 Subject: [PATCH 12/15] Add implementation to trigger BWP switch from external source --- openair2/LAYER2/NR_MAC_gNB/config.c | 18 ++++++++++++++++++ openair2/LAYER2/NR_MAC_gNB/mac_config.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 8b30bf78f0..35b6fa509a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -1065,6 +1065,24 @@ bool nr_update_sib19(const gnb_sat_position_update_t *sat_position) return true; } +bool nr_trigger_bwp_switch(uint16_t rnti, int bwp_id) +{ + gNB_MAC_INST *nrmac = RC.nrmac[0]; + NR_SCHED_LOCK(&nrmac->sched_lock); + NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, rnti); + bool success = false; + if (!UE) { + LOG_W(NR_MAC, "could not find UE for RNTI %04x\n", rnti); + } else if (UE->current_DL_BWP.bwp_id == bwp_id) { + LOG_W(NR_MAC, "UE %04x is already on BWP ID %d, not triggering reconfiguration\n", rnti, bwp_id); + } else { // UE != NULL && current_DL_BWP.bwp_id != bwp_id + nr_mac_trigger_reconfiguration(nrmac, UE, bwp_id); + success = true; + } + NR_SCHED_UNLOCK(&nrmac->sched_lock); + return success; +} + void prepare_du_configuration_update(gNB_MAC_INST *mac, f1ap_served_cell_info_t *info, NR_BCCH_BCH_Message_t *mib, diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_config.h b/openair2/LAYER2/NR_MAC_gNB/mac_config.h index 1fdbe62115..6089d39975 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_config.h @@ -43,4 +43,6 @@ typedef struct gnb_sat_position_update_s { bool nr_update_sib19(const gnb_sat_position_update_t *sat_position); +bool nr_trigger_bwp_switch(uint16_t rnti, int bwp_id); + #endif /*__LAYER2_NR_MAC_CONFIG_H__*/ From 8d2478662d7e129c11996b02ea77083bea978e5b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 20 Oct 2025 14:44:53 +0200 Subject: [PATCH 13/15] Add BWP switch test in CI Trigger various BWP switches through telnet, and test traffic after each switch. --- .../gnb-du.sa.band78.106prb.usrpb200.conf | 6 +- .../container_sa_e1_b200_quectel.xml | 125 ++++++++++++------ common/utils/telnetsrv/telnetsrv_ci.c | 22 +++ 3 files changed, 110 insertions(+), 43 deletions(-) diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf index 4daf7c62fd..58ba62696a 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf @@ -146,7 +146,11 @@ gNBs = ); first_active_bwp = 1; - bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}); + bwp_list = ( + { scs = 1; bwpStart = 0; bwpSize = 106;}, + { scs = 1; bwpStart = 0; bwpSize = 36;}, + { scs = 1; bwpStart = 36; bwpSize = 70;} + ); # ------- SCTP definitions SCTP : diff --git a/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml b/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml index 89a5ebfd6c..836143431a 100644 --- a/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml +++ b/ci-scripts/xml_files/container_sa_e1_b200_quectel.xml @@ -30,20 +30,28 @@ 310000 800813 330101 - 330102 - 330103 310001 400001 350000 - 370001 - 370000 - 370002 370003 370004 + 370002 360001 100002 360002 350000 + 410002 + 370012 + 400002 + 410003 + 370013 + 400003 + 410000 + 350000 + 400000 + 410001 + 350000 + 400001 310011 310002 330201 @@ -88,24 +96,10 @@ Deploy_Object - Deploy gNB-CU-CP in a container + Deploy gNB-CU-CP/gNB-CU-UP/gNB-DU (TDD/n76/40MHz/B200) ofqot ci-scripts/yaml_files/sa_e1_b200_gnb - gnb_cucp - - - Deploy_Object - Deploy gNB-CU-UP in a container - ofqot - ci-scripts/yaml_files/sa_e1_b200_gnb - gnb_cuup - - - Deploy_Object - Deploy gNB-DU (TDD/Band78/40MHz/B200) in a container - ofqot - ci-scripts/yaml_files/sa_e1_b200_gnb - gnb_du_tdd + gnb_cucp gnb_cuup gnb_du_tdd @@ -132,16 +126,6 @@ 25 - - Iperf - iperf (DL/80Mbps/UDP)(30 sec) - -u -b 80M -t 30 -R - idefix - sabox-nepes - 10 - 95 - - Custom_Command Check UE is on dedicated BWP ID 1 @@ -149,19 +133,76 @@ echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 1 (dedicated) UL BWP ID 1 (dedicated)' - + + Custom_Command + Switch to dedicated BWP ID 1 + ofqot + echo ci trigger_bwp_switch 1 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 1 for UE' + + + + Custom_Command + Check UE is on initial BWP ID 0 + ofqot + echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 0 (initial) UL BWP ID 0 (initial)' + + + + Custom_Command + Switch to dedicated BWP ID 2 + ofqot + echo ci trigger_bwp_switch 2 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 2 for UE' + + + Iperf - iperf (UL/8Mbps/UDP)(30 sec) - -u -b 8M -t 30 + iperf (DL/TCP)(10 sec)(single-ue profile) + -t 10 -R idefix sabox-nepes - 1 - 95 + 35 + + + + Custom_Command + Check UE is on dedicated BWP ID 2 + ofqot + echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 2 (dedicated) UL BWP ID 2 (dedicated)' + + + + Custom_Command + Switch to dedicated BWP ID 3 + ofqot + echo ci trigger_bwp_switch 3 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 3 for UE' + + + + Iperf + iperf (DL/TCP)(10 sec)(single-ue profile) + -t 10 -R + idefix + sabox-nepes + 85 + + + + Custom_Command + Check UE is on dedicated BWP ID 3 + ofqot + echo ci get_current_bwp | nc -N 127.0.0.1 9091 | grep 'DL BWP ID 3 (dedicated) UL BWP ID 3 (dedicated)' + + + + Custom_Command + Switch to initial BWP ID 0 + ofqot + echo ci trigger_bwp_switch 0 | nc -N 127.0.0.1 9091 | grep 'triggered BWP switch to BWP ID 0 for UE' Iperf - iperf (BIDIR TCP)(10 sec)(single-ue profile) + iperf (BIDIR TCP)(20 sec)(single-ue profile) -t 20 --bidir idefix sabox-nepes @@ -169,17 +210,17 @@ Iperf - iperf (DL/TCP)(30 sec)(single-ue profile) - -t 30 -R + iperf (DL/TCP)(20 sec)(single-ue profile) + -t 20 -R idefix sabox-nepes - 30 + 140 Iperf - iperf (UL/TCP)(30 sec)(single-ue profile) - -t 30 + iperf (UL/TCP)(20 sec)(single-ue profile) + -t 20 idefix sabox-nepes 15 diff --git a/common/utils/telnetsrv/telnetsrv_ci.c b/common/utils/telnetsrv/telnetsrv_ci.c index 8b00d529c5..11c8ce5dc1 100644 --- a/common/utils/telnetsrv/telnetsrv_ci.c +++ b/common/utils/telnetsrv/telnetsrv_ci.c @@ -38,6 +38,7 @@ #include "openair2/LAYER2/nr_rlc/nr_rlc_ue_manager.h" #include "openair2/LAYER2/nr_rlc/nr_rlc_entity_am.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" +#include "openair2/LAYER2/NR_MAC_gNB/mac_config.h" #include "openair2/RRC/NR/rrc_gNB_mobility.h" #include "openair3/NGAP/ngap_gNB_ue_context.h" @@ -276,6 +277,8 @@ static int get_current_bwp(char *buf, int debug, telnet_printfunc_t prnt) if (rnti < 0) ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, rnti); + if (!UE) + ERROR_MSG_RET("could not find UE with RNTI %04x\n", rnti); int dl_bwp = UE->current_DL_BWP.bwp_id; const char *dl_bwp_text = dl_bwp > 0 ? "dedicated" : "initial"; int ul_bwp = UE->current_UL_BWP.bwp_id; @@ -365,6 +368,24 @@ static int trigger_ngap_pdu_session_release(char *buf, int debug, telnet_printfu return 0; } +static int trigger_bwp_switch(char *buf, int debug, telnet_printfunc_t prnt) +{ + char *sbwpId = strtok(buf, " "); + int bwpId = atoi(sbwpId); + char *srnti = strtok(NULL, " "); + prnt("bwpId %d rnti %s\n", bwpId, srnti); + int rnti = fetch_rnti(srnti, prnt); + if (rnti < 0) + ERROR_MSG_RET("could not identify UE (no UE, no such RNTI, or multiple UEs)\n"); + if (!nr_trigger_bwp_switch(rnti, bwpId)) { + prnt("failed trigger BWP switch for UE %04x BWP ID %d\n", rnti, bwpId); + return -1; + } else { + prnt("triggered BWP switch to BWP ID %d for UE %04x\n", bwpId, rnti); + return 0; + } +} + static telnetshell_cmddef_t cicmds[] = { {"get_single_rnti", "", get_single_rnti}, {"force_reestab", "[rnti(hex,opt)]", trigger_reestab}, @@ -374,6 +395,7 @@ static telnetshell_cmddef_t cicmds[] = { {"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho}, {"fetch_du_by_ue_id", "[rrc_ue_id(int,opt)]", fetch_du_by_ue_id}, {"get_current_bwp", "[rnti(hex,opt)]", get_current_bwp}, + {"trigger_bwp_switch", "newBWPId [rnti(hex,opt)]", trigger_bwp_switch}, {"trigger_n2_ho", "[neighbour_pci(uint32_t),ueId(uint32_t)]", rrc_gNB_trigger_n2_ho}, {"pdu_session_release", "[gNB_ue_ngap_id(int,opt)]", trigger_ngap_pdu_session_release}, {"", "", NULL}, From f5b885e8030c64d58157c30208be25fc6fc402ea Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 25 Nov 2025 14:43:31 +0100 Subject: [PATCH 14/15] Move BWP doc into mac-usage.md --- doc/MAC/mac-usage.md | 26 ++++++++++++++++++++++ doc/RUN_NR_multiple_BWPs.md | 44 ------------------------------------- 2 files changed, 26 insertions(+), 44 deletions(-) delete mode 100644 doc/RUN_NR_multiple_BWPs.md diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index a3b174f50c..2fa56c2ce4 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -420,3 +420,29 @@ Note that you should increase the aggregation level candidates as described in [the corresponding section above](#pdcch-aggregation-level). This is because the scheduler has to schedule multiple DCIs in a single DL slots for multiple UL slots. As a suggestion, you could try `uess_agg_levels = [4, 2, 2, 0, 0]`. + +## Multiple Dedicated BWPs + +A maximum of 4 dedicated BWPs can be configured for a UE per standard, but only +1 BWP can be active in UL and DL direction at a given time. In the code we +only configure a single BWP for the UE at a given time and we would switch by +reconfiguring this BWP. All this procedure is transparent for users and LOGs +mark BWP switching according to the configuration file enumeration. It is +possible to configure multiple dedicated BWPs and 1st active BWP via +configuration file. + +### Setup of the Configuration files ## + +In the configuration file you have the option to select the 1st active BWP, the +BWP location and SCS of each BWP in the following way (example with 2 +additional BWPs): + +``` + first_active_bwp = 1; + bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}, + { scs = 1; bwpStart = 0; bwpSize = 24;}); +``` + +This example configures 3 additional BWPs, with IDs from 1 to 3. A similar +example can be found in configuration file +`ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf` tested in CI. diff --git a/doc/RUN_NR_multiple_BWPs.md b/doc/RUN_NR_multiple_BWPs.md deleted file mode 100644 index e8598a0445..0000000000 --- a/doc/RUN_NR_multiple_BWPs.md +++ /dev/null @@ -1,44 +0,0 @@ -# Procedure to add dedicated Bandwidth part (BWP) - -## Contributed by 5G Testbed IISc - -### Developers: Abhijith A, Shruthi S - -# Terminology # - -## Bandwidth part (BWP) ## -Bandwidth Part (BWP) is a set of contiguous Resource Blocks in the resource grid. - -Parameters of a BWP are communicated to UE using RRC parameters: BWP-Downlink and BWP-Uplink. - -A UE can be configured with a set of 4 BWPs in uplink (UL) and downlink (DL) direction (3GPP TS 38.331 Annex B.2 Description of BWP configuration options). But only 1 BWP can be active in UL and DL direction at a given time. - -# Procedure to run multiple dedicated BWPs # - -A maximum of 4 dedicated BWPs can be configured for a UE. - -To configure multiple BWPs, add the following parameters in the physical parameters section: - -## Setup of the Configuration files ## - -In the configuration file you have the option to select the 1st active BWP, the RIV and SCS of each BWP in the following way (example with 3 additional BWPs): -``` - first_active_bwp = 1; - bwp_list = ({ scs = 1; bwpStart = 0; bwpSize = 106;}, - { scs = 1; bwpStart = 0; bwpSize = 51;}, - { scs = 1; bwpStart = 0; bwpSize = 24;}); -``` - -This example configures 3 additional BWPs, with IDs from 1 to 3. Find these parameters in this configuration file: "ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf" - -# Testing gNB and UE in RF simulator - -## gNB command: -``` - sudo ./nr-softmodem -O ../../../ci-scripts/conf_files/gnb.sa.band78.106prb.rfsim.neighbour.conf --rfsim --rfsimulator.serveraddr server -``` - -## UE command: -``` - sudo ./nr-uesoftmodem -C 3319680000 -r 106 --numerology 1 --ssb 516 --band 78 --rfsim --rfsimulator.serveraddr 127.0.0.1 -``` From f46ddb6aa8f59818e27107f9bb17567135edb78d Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Mon, 1 Dec 2025 16:18:09 +0100 Subject: [PATCH 15/15] Fix: CFRA: UE can always use dedicated search space In all cases (CFRA in SA for HO, or CFRA in NSA/do-ra for access), the UE has the full configuration already. We can therefore directly switch to a dedicated search space, as it is already known to the UE. --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index f72c1c88ee..abe5cd8361 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -773,10 +773,9 @@ static void nr_rx_ra_sdu(const module_id_t mod_id, nr_mac_reset_ul_failure(sched_ctrl); reset_dl_harq_list(sched_ctrl); reset_ul_harq_list(sched_ctrl); - // we configure the UE using common search space with DCIX0 while waiting for a reconfiguration in SA - // in NSA (or do-ra) there is no reconfiguration in NR - int ss_type = IS_SA_MODE(get_softmodem_params()) ? NR_SearchSpace__searchSpaceType_PR_common - : NR_SearchSpace__searchSpaceType_PR_ue_Specific; + // we configure the UE using dedicated search space: In SA (CFRA used for + // handover) and NSA (or do-ra), the UE has the full config already. + int ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific; configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1); // initialize ta_frame in case there is no Msg3 received UE->UE_sched_ctrl.ta_frame = (frame + 100) % MAX_FRAME_NUMBER;