From 91a08b1ba735c4b070eb4066c9f046235426ff5a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 19 Dec 2025 15:37:36 +0100 Subject: [PATCH] Fix MAC frequency overwrite during handover causing integrity check failures During N2 handover, the UE receives reconfigurationWithSync which correctly sets the target cell frequency in mac->phy_config.config_req.carrier_config via config_common_ue() call. However, when SIB1 is decoded after reconfiguration, nr_rrc_mac_config_req_sib1() calls config_common_ue_sa() which unconditionally overwrites the frequency with the command-line parameter (downlink_frequency), which corresponds to the source cell frequency. This causes a critical issue during RRC re-establishment: - The UE uses the wrong frequency (source cell) for key derivation (kgnb*) - The gNB uses the correct frequency (target cell) for key derivation - This mismatch results in different kgnb* keys on UE and gNB - Integrity check fails: "Integrity of RRCReestablishment failed, going to IDLE" Root cause: config_common_ue_sa() is used for SIB1 processing (initial cell selection) and uses ServingCellConfigCommonSIB which doesn't contain absoluteFrequencyPointA. It must derive frequency from command-line parameters. However, after handover, the frequency has already been correctly set by config_common_ue() (used for reconfigurationWithSync) which uses ServingCellConfigCommon with absolute frequency information. Solution: Modify config_common_ue_sa() to preserve the existing frequency if it's already initialized (non-zero). Only set frequency from command-line parameters during initial cell selection when dl_frequency is 0. This ensures: - Initial cell selection: frequency derived from command-line parameter, just once - After handover: frequency preserved from reconfigurationWithSync - MAC maintains its own frequency state independently The fix applies to both DL and UL frequencies to maintain consistency. There is probably room for more refactoring to the resync flow, since the functionalities in config_common_ue and config_common_ue_sa are partially overlapping and upon reconfigurationWithSync some other configurations might be applied twice. --- openair2/LAYER2/NR_MAC_UE/config_ue.c | 37 ++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c index 18b331ff46..e97b7fe0c3 100644 --- a/openair2/LAYER2/NR_MAC_UE/config_ue.c +++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c @@ -142,9 +142,21 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth); cfg->carrier_config.dl_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index); - uint64_t dl_bw_khz = (12 * frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth) * - (15 << frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing); - cfg->carrier_config.dl_frequency = (downlink_frequency[cc_idP][0]/1000) - (dl_bw_khz>>1); + /** Only set frequency if not already initialized (e.g., from handover reconfigurationWithSync) + * MAC maintains its own frequency state, don't overwrite it with command-line parameter which + * is related to the initial cell selection. */ + if (cfg->carrier_config.dl_frequency == 0) { + // Initial cell selection: derive from command-line parameter + uint64_t dl_bw_khz = (12 * frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth) * + (15 << frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing); + cfg->carrier_config.dl_frequency = (downlink_frequency[cc_idP][0]/1000) - (dl_bw_khz>>1); + LOG_I(NR_MAC, + "[UE %d] Initial cell selection: dl_frequency=%u kHz (from command-line, band=%d, scs=%ld)\n", + mac->ue_id, + cfg->carrier_config.dl_frequency, + mac->nr_band, + frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing); + } for (int i = 0; i < 5; i++) { if (i == frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) { @@ -165,10 +177,21 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth); cfg->carrier_config.uplink_bandwidth = get_supported_bw_mhz(mac->frequency_range, bw_index); - if (frequencyInfoUL->absoluteFrequencyPointA == NULL) - cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency; - else - cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency + (uplink_frequency_offset[cc_idP][0] / 1000); + /** Only set UL frequency if not already initialized (e.g., from handover reconfigurationWithSync) + * MAC maintains its own frequency state, don't overwrite it with command-line parameter which + * is related to the initial cell selection. */ + if (cfg->carrier_config.uplink_frequency == 0) { + // Initial cell selection: derive from DL frequency + LOG_I(NR_MAC, + "Initial cell selection: uplink_frequency=%u kHz (from dl_frequency=%u kHz, uplink_frequency_offset=%u kHz)\n", + cfg->carrier_config.uplink_frequency, + cfg->carrier_config.dl_frequency, + uplink_frequency_offset[cc_idP][0]); + if (frequencyInfoUL->absoluteFrequencyPointA == NULL) + cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency; + else + cfg->carrier_config.uplink_frequency = cfg->carrier_config.dl_frequency + (uplink_frequency_offset[cc_idP][0] / 1000); + } for (int i = 0; i < 5; i++) { if (i == frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing) {