From 372f121cf6e0f20cacb7f13dd839efdb19609edb Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Feb 2026 10:26:21 +0100 Subject: [PATCH] Refactor (RRC): extract rrc_update_ue_pcell() to public API and adopt consistently Move rrc_update_ue_pcell() from static function in rrc_gNB.c to public function in rrc_cell_management.c, making it reusable across RRC code paths. Replace duplicate PCell addition logic in handover paths (intra-CU and inter-CU) and RRCSetup path with calls to this shared function. This eliminates code duplication between handover and RRCSetup paths, centralizes PCell update logic (including cleanup of old PCell's DU serving cells) in a single reusable function and makes the function available for future use in other RRC procedures --- openair2/RRC/NR/rrc_cell_management.c | 19 ++++++++++++++ openair2/RRC/NR/rrc_cell_management.h | 1 + openair2/RRC/NR/rrc_gNB.c | 29 +++++--------------- openair2/RRC/NR/rrc_gNB_mobility.c | 38 +++++++++------------------ 4 files changed, 39 insertions(+), 48 deletions(-) diff --git a/openair2/RRC/NR/rrc_cell_management.c b/openair2/RRC/NR/rrc_cell_management.c index 0df2665c04..844ee6ffdc 100644 --- a/openair2/RRC/NR/rrc_cell_management.c +++ b/openair2/RRC/NR/rrc_cell_management.c @@ -409,3 +409,22 @@ nr_rrc_cell_container_t *rrc_get_pcell_for_ue(gNB_RRC_INST *rrc, const gNB_RRC_U return get_cell_by_cell_id(&rrc->cells, pcell_entry->nci); } +/** @brief Update UE's PCell in serving_cells array + * @param[in] UE UE context + * @param[in] cell Cell container to set as PCell + * @return Pointer to added serving cell entry, or NULL on failure + * @note If UE already has a PCell, removes all serving cells from the old PCell's DU first */ +ue_serving_cell_t *rrc_update_ue_pcell(gNB_RRC_UE_t *UE, const nr_rrc_cell_container_t *cell) +{ + DevAssert(UE != NULL); + DevAssert(cell != NULL); + + // If UE already has a PCell, remove all serving cells from that DU first + const ue_serving_cell_t *existing_pcell = ue_get_pcell_entry(UE); + if (existing_pcell != NULL) { + rrc_remove_ue_scells_from_du(UE, existing_pcell->assoc_id); + } + + // Add the new PCell + return rrc_add_ue_serving_cell(UE, cell, RRC_PCELL_INDEX); +} diff --git a/openair2/RRC/NR/rrc_cell_management.h b/openair2/RRC/NR/rrc_cell_management.h index 99071cceb2..d24fd095dd 100644 --- a/openair2/RRC/NR/rrc_cell_management.h +++ b/openair2/RRC/NR/rrc_cell_management.h @@ -69,5 +69,6 @@ void rrc_remove_ue_scells_from_du(gNB_RRC_UE_t *ue, sctp_assoc_t assoc_id); ue_serving_cell_t *rrc_get_ue_serving_cell_by_id(const gNB_RRC_UE_t *ue, uint8_t serving_cell_id); const ue_serving_cell_t *ue_get_pcell_entry(const gNB_RRC_UE_t *ue); nr_rrc_cell_container_t *rrc_get_pcell_for_ue(gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); +ue_serving_cell_t *rrc_update_ue_pcell(gNB_RRC_UE_t *UE, const nr_rrc_cell_container_t *cell); #endif /* RRC_CELL_MANAGEMENT_H_ */ diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 50a8ed16e1..704317febe 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1416,8 +1416,13 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc, rrc_gNB_generate_RRCReject(rrc, ue_context_p); return; } - /* Add PCell to serving_cells array */ - rrc_add_ue_serving_cell(UE, cell, RRC_PCELL_INDEX); + /* Update PCell in serving_cells array */ + ue_serving_cell_t *added = rrc_update_ue_pcell(UE, cell); + if (added == NULL) { + LOG_E(NR_RRC, "RRCSetup: failed to add PCell (cell %ld)\n", cell->info.cell_id); + rrc_gNB_generate_RRCReject(rrc, ue_context_p); + return; + } UE->ongoing_reconfiguration = false; UE->measConfig = nr_rrc_get_measconfig(rrc, msg->nr_cellid); activate_srb(UE, 1); @@ -1490,26 +1495,6 @@ static const nr_rrc_cell_container_t *get_previous_cell_by_pci_in_du(gNB_RRC_INS return rrc_get_cell_by_pci_for_du(&du->cells, pci); } -/** @brief Update UE's PCell in serving_cells array - * @param[in] UE UE context - * @param[in] cell Cell container to set as PCell - * @return Pointer to added serving cell entry, or NULL on failure - * @note If UE already has a PCell, removes all serving cells from the old PCell's DU first */ -static ue_serving_cell_t *rrc_update_ue_pcell(gNB_RRC_UE_t *UE, const nr_rrc_cell_container_t *cell) -{ - DevAssert(UE != NULL); - DevAssert(cell != NULL); - - // If UE already has a PCell, remove all serving cells from that DU first - const ue_serving_cell_t *existing_pcell = ue_get_pcell_entry(UE); - if (existing_pcell != NULL) { - rrc_remove_ue_scells_from_du(UE, existing_pcell->assoc_id); - } - - // Add the new PCell - return rrc_add_ue_serving_cell(UE, cell, RRC_PCELL_INDEX); -} - static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id, const NR_RRCReestablishmentRequest_IEs_t *req, diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index d18937fbc5..4d2785d9a0 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -453,36 +453,22 @@ bool nr_rrc_update_cell_assoc_after_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) return false; } - if (UE->ho_context->source) { - /* F1 HO (intra-CU): migrate serving cells from source DU to target cell */ - nr_ho_source_cu_t *source_ctx = UE->ho_context->source; - - // Remove SCells that belong to the source DU during handover (cell group changes) - // This also removes PCell if it was on the source DU - rrc_remove_ue_scells_from_du(UE, source_ctx->cell->assoc_id); - - // Update PCell in serving_cells - ue_serving_cell_t *added = rrc_add_ue_serving_cell(UE, target_ctx->cell, RRC_PCELL_INDEX); - if (added == NULL) { - LOG_E(NR_RRC, - "UE %d handover: failed to add PCell (cell %ld) to serving cells\n", - UE->rrc_ue_id, - target_ctx->cell->info.cell_id); - return false; - } - } else { + if (!UE->ho_context->source) { /* Inter-CU (N2/Xn target): this UE context has no serving cells yet */ const ue_serving_cell_t *existing_pcell = ue_get_pcell_entry(UE); AssertFatal(existing_pcell == NULL, "UE context should not have PCell yet (inter-CU target)\n"); + } - ue_serving_cell_t *added = rrc_add_ue_serving_cell(UE, target_ctx->cell, RRC_PCELL_INDEX); - if (added == NULL) { - LOG_E(NR_RRC, - "UE %d handover: failed to add PCell (cell %ld) to serving cells\n", - UE->rrc_ue_id, - target_ctx->cell->info.cell_id); - return false; - } + /* Update PCell: removes all serving cells from existing PCell's DU (if any) + * and adds the target cell as the new PCell. For F1 HO (intra-CU), this + * migrates serving cells from source DU to target DU. */ + ue_serving_cell_t *added = rrc_update_ue_pcell(UE, target_ctx->cell); + if (added == NULL) { + LOG_E(NR_RRC, + "UE %d handover: failed to add PCell (cell %ld) to serving cells\n", + UE->rrc_ue_id, + target_ctx->cell->info.cell_id); + return false; } return true;