From c6229a9c7a11cd83b6657589a7f809cf72cdfc6b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 29 Jan 2026 14:39:03 +0100 Subject: [PATCH] RRC multi-cell: enforce unique PCI in per-cell neighbour lists Neighbour lists are built per serving cell in fill_neighbour_cell_configuration. Each neighbour in a list is identified by PCI; having two entries with the same PCI in one cell's list would be ambiguous and indicate a configuration error. This commit adds validation so that duplicate PCIs within a cell's neighbour list are detected at configuration load time and cause a fatal assertion with a clear error message. Changes: - Add eq_neighbour_pci() and get_neighbour_by_pci() using common/utils/alg/find.h to look up a neighbour by PCI in a seq_arr. - In fill_neighbour_cell_configuration(), before appending each cell's neighbour list, iterate over neighbours and assert that no PCI appears more than once --- openair2/GNB_APP/gnb_config.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index fadb402a71..8edec8e84f 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -75,6 +75,7 @@ #include "s1ap_messages_types.h" #include "sctp_default_values.h" #include "seq_arr.h" +#include "common/utils/alg/find.h" #include "uper_encoder.h" #include "utils.h" #include "x2ap_messages_types.h" @@ -1851,6 +1852,22 @@ static seq_arr_t *fill_cu_sibs(paramdef_t *GNBparamarray) return SIBs; } +static bool eq_neighbour_pci(const void *vval, const void *vit) +{ + const int *pci = (const int *)vval; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)vit; + return neighbour->physicalCellId == *pci; +} + +/** @brief Find neighbour by PCI within a cell's neighbour list (first match) */ +static nr_neighbour_cell_t *get_neighbour_by_pci(seq_arr_t *neighbour_cells, int pci) +{ + elm_arr_t elm = find_if(neighbour_cells, &pci, eq_neighbour_pci); + if (elm.found) + return (nr_neighbour_cell_t *)elm.it; + return NULL; +} + static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) { char gnbpath[MAX_OPTNAME_SIZE + 8]; @@ -1908,6 +1925,14 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc n.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; n.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; n.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; + if (get_neighbour_by_pci(cell.neighbour_cells, n.physicalCellId) != NULL) { + LOG_E(GNB_APP, + "Cell %ld: duplicate PCI %d in neighbour list (nrcell_id %ld)\n", + cell.nr_cell_id, + n.physicalCellId, + n.nrcell_id); + AssertFatal(false, "PCI must be unique within a cell's neighbour list\n"); + } seq_arr_push_back(cell.neighbour_cells, &n, sizeof(n)); LOG_I(GNB_APP, " [%d] neighbor ID %d cellId %ld PCI %d SCS %d SSB ARFCN %u TAC %u PLMN %03u.%0*u\n",