From 5d05078f4e77b47d448096830c6f6baf0b0f3fe4 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 3 Sep 2024 14:15:22 +0200 Subject: [PATCH] Validate neighbour config when DUs connect --- openair2/GNB_APP/gnb_config.c | 5 +++ openair2/RRC/NR/rrc_gNB_du.c | 72 +++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ef69264ac9..0cbe75bbeb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1697,6 +1697,11 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); AssertFatal(a3_event != NULL, "out of memory\n"); a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; + AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024, + "entry %s.%s must be -1<=PCI<1024, but is %d\n", + measurement_path, + MEASUREMENT_EVENTS_PCI_ID, + a3_event->pci); a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 43b657d91e..97bbb685c9 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -40,12 +40,17 @@ int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info) return cell_info->mode == F1AP_MODE_TDD ? cell_info->tdd.tbw.scs : cell_info->fdd.dl_tbw.scs; } +static int ssb_arfcn_mtc(const NR_MeasurementTimingConfiguration_t *mtc) +{ + /* format has been verified when accepting MeasurementTimingConfiguration */ + NR_MeasTimingList_t *mtlist = mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; + return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; +} + int get_ssb_arfcn(const struct nr_rrc_du_container_t *du) { DevAssert(du != NULL && du->mtc != NULL); - /* format has been verified when accepting MeasurementTimingConfiguration */ - NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming; - return mtlist->list.array[0]->frequencyAndTiming->carrierFreq; + return ssb_arfcn_mtc(du->mtc); } static int du_compare(const nr_rrc_du_container_t *a, const nr_rrc_du_container_t *b) @@ -197,6 +202,58 @@ static void label_intra_frequency_neighbours(gNB_RRC_INST *rrc, for_each(cell_neighbour_list, (void *)&ssb_arfcn, is_intra_frequency_neighbour); } +static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_configuration, const f1ap_served_cell_info_t *cell, int ssb_arfcn) +{ + for (int c = 0; c < neighbour_cell_configuration->size; c++) { + const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); + for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { + const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + if (nc->nrcell_id != cell->nr_cellid) + continue; + // current cell is in the nc config, check that config matches + if (nc->physicalCellId != cell->nr_pci) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: PCI mismatch (%d vs %d)\n", cell->nr_cellid, cell->nr_pci, nc->physicalCellId); + return false; + } + if (cell->tac && nc->tac != *cell->tac) { + LOG_W(NR_RRC, "Cell %ld in neighbour config: TAC mismatch (%d vs %d)\n", cell->nr_cellid, *cell->tac, nc->tac); + return false; + } + if (ssb_arfcn != nc->absoluteFrequencySSB) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SSB ARFCN mismatch (%d vs %d)\n", + cell->nr_cellid, + ssb_arfcn, + nc->absoluteFrequencySSB); + return false; + } + if (get_ssb_scs(cell) != nc->subcarrierSpacing) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: SCS mismatch (%d vs %d)\n", + cell->nr_cellid, + get_ssb_scs(cell), + nc->subcarrierSpacing); + return false; + } + if (cell->plmn.mcc != nc->plmn.mcc || cell->plmn.mnc != nc->plmn.mnc + || cell->plmn.mnc_digit_length != nc->plmn.mnc_digit_length) { + LOG_W(NR_RRC, + "Cell %ld in neighbour config: PLMN mismatch (%03d.%0*d vs %03d.%0*d)\n", + cell->nr_cellid, + cell->plmn.mcc, + cell->plmn.mnc_digit_length, + cell->plmn.mnc, + nc->plmn.mcc, + nc->plmn.mnc_digit_length, + nc->plmn.mnc); + return false; + } + LOG_D(NR_RRC, "Cell %ld is neighbor of cell %ld\n", cell->nr_cellid, neighbour_config->nr_cell_id); + } + } + return true; +} + void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) { AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); @@ -264,6 +321,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) NR_MeasurementTimingConfiguration_t *mtc = extract_mtc(cell_info->measurement_timing_config, cell_info->measurement_timing_config_len); + if (rrc->neighbour_cell_configuration + && !valid_du_in_neighbour_configs(rrc->neighbour_cell_configuration, cell_info, ssb_arfcn_mtc(mtc))) { + LOG_E(NR_RRC, "problem with DU %ld in neighbor configuration, rejecting DU\n", req->gNB_DU_id); + f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified}; + rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); + ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); + return; + } + const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info; NR_MIB_t *mib = NULL; NR_SIB1_t *sib1 = NULL;