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;