From ac535b6338248f8faacaafdab81442b4bdac6799 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 27 Nov 2025 16:50:53 +0100 Subject: [PATCH] fix A3 event configuration While testing the gNB with two hypotetical neighbors, some issues were found with A3 event configuration. The configuration of neighbors is: neighbour_list = ( { nr_cellid = 12345679L; neighbour_cell_configuration = ( { gNB_ID = 0xba0; nr_cellid = 720898; physical_cellId = 1; absoluteFrequencySSB= 621312; subcarrierSpacing = 1; band = 78; plmn = { mcc = 505; mnc = 01; mnc_length = 2 }; tracking_area_code = 1; }, { gNB_ID = 0xea0; nr_cellid = 1345678L; physical_cellId = 2; absoluteFrequencySSB= 640000; subcarrierSpacing = 1; band = 78; plmn = { mcc = 505; mnc = 01; mnc_length = 2 }; tracking_area_code = 1; } ); } ); There were two problems. The first problem is: - when only default A3 event is configured, it is duplicated in the RRC Reconfiguration Report Config To AddMod list with IDs 4 and 5 To test this case, the event configuration is: nr_measurement_configuration = { Periodical = { enable = 1; includeBeamMeasurements = 1; maxNrofRS_IndexesToReport = 4; }; A2 = { enable = 1; threshold = 60; time_to_trigger = 1; }; A3 = ( { physCellId = -1; offset = 15; hysteresis = 2; time_to_trigger = 3 } ); }; The second problem is: - when configuring an A3 event with an unknown physCellId, the gNB does not include any A3 event in the RRC Reconfiguration Report Config To AddMod list (which is correct), but configures some meas ID with nonexistant Report Config IDs To test this case, the event configuration is: nr_measurement_configuration = { Periodical = { enable = 1; includeBeamMeasurements = 1; maxNrofRS_IndexesToReport = 4; }; A2 = { enable = 1; threshold = 60; time_to_trigger = 1; }; A3 = ( { physCellId = 10; offset = 15; hysteresis = 2; time_to_trigger = 3 } ); }; Reworking A3 event configuration as done in this commit solves both issues. --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 8 ++++-- openair2/RRC/NR/MESSAGES/asn1_msg.h | 3 +- openair2/RRC/NR/rrc_gNB.c | 43 +++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 585b1e48e2..2c08f23f6b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -1121,7 +1121,8 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_A2, seq_arr_t *rc_A3_seq, - seq_arr_t *neigh_seq) + seq_arr_t *neigh_seq, + int *neigh_a3_id) { DevAssert(mt != NULL && mt->frequencyAndTiming != NULL); const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming; @@ -1207,7 +1208,10 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, if (neigh_seq) { int i = 0; FOR_EACH_SEQ_ARR(nr_neighbour_cell_t *, neigh_cell, neigh_seq) { - NR_ReportConfigId_t reportConfigId = neigh_cell->physicalCellId == -1 ? 3 : i + 4; + NR_ReportConfigId_t reportConfigId = neigh_a3_id[i]; + /* check that there is a A3 configured for this neighbour */ + if (reportConfigId == -1) + continue; NR_MeasIdToAddMod_t *measid_A3 = get_MeasId(meas_idx + 1, reportConfigId, i + 2); meas_idx++; asn1cSeqAdd(&mc->measIdToAddModList->list, measid_A3); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index eb8da91c2a..f4f4987ceb 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -164,7 +164,8 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, NR_ReportConfigToAddMod_t *rc_PER, NR_ReportConfigToAddMod_t *rc_A2, seq_arr_t *rc_A3_seq, - seq_arr_t *neigh_seq); + seq_arr_t *neigh_seq, + int *neigh_a3_id); void free_MeasConfig(NR_MeasConfig_t *mc); int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index d2f08fd4b4..7a1c96e33b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -622,9 +622,6 @@ static nr_a3_event_t *get_a3_configuration(gNB_RRC_INST *rrc, int pci) return a3_event; } - if (measurementConfiguration->is_default_a3_configuration_exists) - return get_a3_configuration(rrc, -1); - return NULL; } @@ -750,6 +747,10 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell if (neighbour_config) neighbour_cells = neighbour_config->neighbour_cells; + int *neigh_a3_id = NULL; + if (neighbour_cells && neighbour_cells->size) + neigh_a3_id = calloc_or_fail(neighbour_cells->size, sizeof(int)); + if (neighbour_cells && rrc->measurementConfiguration.a3_event_list && rrc->measurementConfiguration.a3_event_list->size > 0) { /* Loop through neighbours and find related A3 configuration If no related A3 but there is default add the default one. @@ -759,16 +760,31 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell bool default_a3_added = false; // To ensure that the default configuration is only added once for (int i = 0; i < neighbour_cells->size; i++) { nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); - if (default_a3_added && neighbourCell->physicalCellId == -1) - continue; seq_arr_push_back(&neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t)); const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId); - if (a3Event) { - NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4; - seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); - if (neighbourCell->physicalCellId == -1) - default_a3_added = true; + if (!a3Event) { + /* no A3 event configured for this neighbour, let's try the default one, if it exists */ + if (default_a3_added) { + /* default A3 exists and is already added, use it for this neighbour */ + neigh_a3_id[i] = 3; + continue; + } + /* try to get the default A3 config */ + a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, -1); + if (!a3Event) { + /* no default A3 config found, so no A3 config for this neighbour */ + neigh_a3_id[i] = -1; + continue; + } + default_a3_added = true; + /* default A3 report config ID is 3 */ + neigh_a3_id[i] = 3; + } else { + /* specific A3 report config ID are 4, 5, ... */ + neigh_a3_id[i] = i + 4; } + NR_ReportConfigId_t reportConfigId = neigh_a3_id[i]; + seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t)); } } if (rrc->measurementConfiguration.per_event) @@ -776,12 +792,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell if (rrc->measurementConfiguration.a2_event) rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event); - NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq); + NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq, neigh_a3_id); // Clean up sequence arrays seq_arr_free(&rc_A3_seq, NULL); seq_arr_free(&neigh_seq, NULL); + free(neigh_a3_id); + return result; } return NULL; @@ -1620,6 +1638,9 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, if (!neigh_cell && neighbour) { // No F1 connection but static neighbour configuration is available const nr_a3_event_t *a3_event_configuration = get_a3_configuration(rrc, neighbour->physicalCellId); + /* if no A3 event configured for this physical cell ID, try to get the default one */ + if (!a3_event_configuration) + a3_event_configuration = get_a3_configuration(rrc, -1); // Additional check - This part can be modified according to additional cell specific Handover Margin // a3-Offset: The actual value is field value * 0.5 dB. if (a3_event_configuration