RRC/MAC: add SIB3 intra-freqeuncy neighbour support
Introduce NR SIB3 encoding in RRC and wire SIB3 neighbour information into CU–DU F1 Setup and DU SystemInformation. Extend MAC to decode NR SIB3 from CU-provided SIB containers and attach the decoded SIB3 to the DU SystemInformation structure. Changes: - Add NR_SIB3 ASN.1 include and a do_SIB3_NR() encoder in asn1_msg so SIB3 can be serialized into a byte_array_t buffer. - Introduce get_q_offset_asn1() and get_sib3_intra_freq_neighbors() in rrc_gNB_du.c to build an intra-frequency neighbour cell list for SIB3, mapping q_OffsetCell dB values to NR_Q_OffsetRange and optionally filling q_RxLevMinOffsetCell and q_QualMinOffsetCell. - Limit the number of intra-frequency neighbours in SIB3 to NR_maxCellIntra, logging a warning and skipping additional cells when the limit is reached. - Hook SIB3 construction and encoding into rrc_gNB_process_f1_setup_req() so SIB type 3 entries are added to the F1 Setup Response when neighbour configuration and matching neighbours are available. - Handle NR_SIB_3 in nr_mac_configure_other_sib() by validating the CU SIB3 container buffer, decoding it with uper_decode into an NR_SIB3_t, and attaching the resulting SIB3 to the MAC SystemInformation via add_sib_to_systeminformation().
This commit is contained in:
@@ -1008,6 +1008,21 @@ bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_
|
||||
add_sib_to_systeminformation(sysInfo, type);
|
||||
break;
|
||||
}
|
||||
case NR_SIB_3: {
|
||||
struct NR_SystemInformation_IEs__sib_TypeAndInfo__Member *type = calloc_or_fail(1, sizeof(*type));
|
||||
type->present = NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib3;
|
||||
NR_SIB3_t *sib3 = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL, &asn_DEF_NR_SIB3, (void **)&sib3, container->buf, container->len, 0, 0);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(NR_MAC, "cannot decode SIB%d from CU\n", config_sibs[i]);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB3, sib3);
|
||||
free(type);
|
||||
break;
|
||||
}
|
||||
type->choice.sib3 = sib3;
|
||||
add_sib_to_systeminformation(sysInfo, type);
|
||||
break;
|
||||
}
|
||||
default :
|
||||
AssertFatal(false, "Invalid or not supported SIB%d\n", config_sibs[i]);
|
||||
}
|
||||
|
||||
@@ -244,6 +244,27 @@ byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2)
|
||||
return msg;
|
||||
}
|
||||
|
||||
byte_array_t do_SIB3_NR(const NR_SIB3_t *sib3)
|
||||
{
|
||||
byte_array_t msg = {.buf = NULL, .len = 0};
|
||||
char errbuf[256] = {0};
|
||||
size_t errlen = sizeof(errbuf);
|
||||
int ret = asn_check_constraints(&asn_DEF_NR_SIB3, sib3, errbuf, &errlen);
|
||||
if (ret != 0) {
|
||||
LOG_E(NR_RRC, "SIB3 constraint check failed: %s\n", errbuf);
|
||||
return msg;
|
||||
}
|
||||
|
||||
int val = uper_encode_to_new_buffer(&asn_DEF_NR_SIB3, NULL, (void *)sib3, (void **)&msg.buf);
|
||||
if (val <= 0) {
|
||||
LOG_E(NR_RRC, "Failed to encode SIB3\n");
|
||||
return msg;
|
||||
}
|
||||
|
||||
msg.len = val;
|
||||
return msg;
|
||||
}
|
||||
|
||||
int do_RRCReject(uint8_t *const buffer)
|
||||
{
|
||||
asn_enc_rval_t enc_rval;
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "NR_UE-NR-Capability.h"
|
||||
#include "NR_UE-CapabilityRAT-ContainerList.h"
|
||||
#include "NR_SIB2.h"
|
||||
#include "NR_SIB3.h"
|
||||
#include "ds/seq_arr.h"
|
||||
#include "ds/byte_array.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
|
||||
@@ -67,6 +68,7 @@ typedef struct {
|
||||
int xer_sprint_NR(char *string, size_t string_size, struct asn_TYPE_descriptor_s *td, void *sptr);
|
||||
|
||||
byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2);
|
||||
byte_array_t do_SIB3_NR(const NR_SIB3_t *sib3);
|
||||
|
||||
int do_RRCReject(uint8_t *const buffer);
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "ngap_messages_types.h"
|
||||
#include "nr_rrc_defs.h"
|
||||
#include "NR_SIB2.h"
|
||||
#include "NR_SIB3.h"
|
||||
#include "NR_Q-OffsetRange.h"
|
||||
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
|
||||
#include "rrc_gNB_mobility.h"
|
||||
#include "openair2/F1AP/f1ap_common.h"
|
||||
@@ -35,6 +37,7 @@
|
||||
#include "s1ap_messages_types.h"
|
||||
#include "tree.h"
|
||||
#include "uper_decoder.h"
|
||||
#include "common/utils/oai_asn1.h"
|
||||
#include "utils.h"
|
||||
#include "xer_encoder.h"
|
||||
|
||||
@@ -172,6 +175,136 @@ static NR_SIB2_t *get_sib2_from_cfg(const sib2_config_t *cfg, NR_SSB_MTC_t *ssbm
|
||||
return sib2;
|
||||
}
|
||||
|
||||
/** @brief Map internal int enum to ASN.1 Q-OffsetRange value. */
|
||||
static long get_q_offset_asn1(int q_offset_db)
|
||||
{
|
||||
switch (q_offset_db) {
|
||||
case -24:
|
||||
return NR_Q_OffsetRange_dB_24;
|
||||
case -22:
|
||||
return NR_Q_OffsetRange_dB_22;
|
||||
case -20:
|
||||
return NR_Q_OffsetRange_dB_20;
|
||||
case -18:
|
||||
return NR_Q_OffsetRange_dB_18;
|
||||
case -16:
|
||||
return NR_Q_OffsetRange_dB_16;
|
||||
case -14:
|
||||
return NR_Q_OffsetRange_dB_14;
|
||||
case -12:
|
||||
return NR_Q_OffsetRange_dB_12;
|
||||
case -10:
|
||||
return NR_Q_OffsetRange_dB_10;
|
||||
case -8:
|
||||
return NR_Q_OffsetRange_dB_8;
|
||||
case -6:
|
||||
return NR_Q_OffsetRange_dB_6;
|
||||
case -5:
|
||||
return NR_Q_OffsetRange_dB_5;
|
||||
case -4:
|
||||
return NR_Q_OffsetRange_dB_4;
|
||||
case -3:
|
||||
return NR_Q_OffsetRange_dB_3;
|
||||
case -2:
|
||||
return NR_Q_OffsetRange_dB_2;
|
||||
case -1:
|
||||
return NR_Q_OffsetRange_dB_1;
|
||||
case 0:
|
||||
return NR_Q_OffsetRange_dB0;
|
||||
case 1:
|
||||
return NR_Q_OffsetRange_dB1;
|
||||
case 2:
|
||||
return NR_Q_OffsetRange_dB2;
|
||||
case 3:
|
||||
return NR_Q_OffsetRange_dB3;
|
||||
case 4:
|
||||
return NR_Q_OffsetRange_dB4;
|
||||
case 5:
|
||||
return NR_Q_OffsetRange_dB5;
|
||||
case 6:
|
||||
return NR_Q_OffsetRange_dB6;
|
||||
case 8:
|
||||
return NR_Q_OffsetRange_dB8;
|
||||
case 10:
|
||||
return NR_Q_OffsetRange_dB10;
|
||||
case 12:
|
||||
return NR_Q_OffsetRange_dB12;
|
||||
case 14:
|
||||
return NR_Q_OffsetRange_dB14;
|
||||
case 16:
|
||||
return NR_Q_OffsetRange_dB16;
|
||||
case 18:
|
||||
return NR_Q_OffsetRange_dB18;
|
||||
case 20:
|
||||
return NR_Q_OffsetRange_dB20;
|
||||
case 22:
|
||||
return NR_Q_OffsetRange_dB22;
|
||||
case 24:
|
||||
return NR_Q_OffsetRange_dB24;
|
||||
default:
|
||||
AssertFatal(false, "Invalid q_offset_db value %d\n", q_offset_db);
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Build a SIB3 (intra-frequency neighbour cell list) from the configured neighbour cells.
|
||||
* Only neighbours whose SSB ARFCN matches @param serving_ssb_arfcn are included.
|
||||
* @param neighbours list of configured neighbour cells
|
||||
* @param serving_ssb_arfcn SSB ARFCN of the serving cell, used to filter intra-frequency neighbours
|
||||
* @returns allocated NR_SIB3_t on success, NULL if no matching neighbours were found */
|
||||
static NR_SIB3_t *get_sib3_intra_freq_neighbors(const seq_arr_t *neighbours, uint32_t serving_ssb_arfcn)
|
||||
{
|
||||
DevAssert(neighbours);
|
||||
|
||||
NR_SIB3_t *sib3 = calloc_or_fail(1, sizeof(*sib3));
|
||||
sib3->intraFreqNeighCellList = calloc_or_fail(1, sizeof(*sib3->intraFreqNeighCellList));
|
||||
|
||||
int intra_count = 0;
|
||||
FOR_EACH_SEQ_ARR (const nr_neighbour_cell_t *, neigh, neighbours) {
|
||||
if (neigh->absoluteFrequencySSB != serving_ssb_arfcn)
|
||||
continue;
|
||||
|
||||
LOG_D(NR_RRC,
|
||||
"SIB3: intra-frequency neighbour candidate: cell ID %lu, PCI %d (SSB ARFCN %d)\n",
|
||||
neigh->nrcell_id,
|
||||
neigh->physicalCellId,
|
||||
neigh->absoluteFrequencySSB);
|
||||
|
||||
NR_IntraFreqNeighCellInfo_t *cell = calloc_or_fail(1, sizeof(*cell));
|
||||
cell->physCellId = neigh->physicalCellId;
|
||||
|
||||
const nr_neighbour_cell_neighbor_offset_t *off = &neigh->sib3.offset;
|
||||
/* q-OffsetCell: NR_Q-OffsetRange (-24..24 dB), 0 dB default */
|
||||
cell->q_OffsetCell = get_q_offset_asn1(off->q_OffsetCell);
|
||||
|
||||
/* q-RxLevMinOffsetCell / q-QualMinOffsetCell: (1..8) */
|
||||
if (off->q_RxLevMinOffsetCell != -1)
|
||||
asn1cCallocOne(cell->q_RxLevMinOffsetCell, off->q_RxLevMinOffsetCell);
|
||||
if (off->q_QualMinOffsetCell != -1)
|
||||
asn1cCallocOne(cell->q_QualMinOffsetCell, off->q_QualMinOffsetCell);
|
||||
|
||||
/* Add to SIB3 intra-frequency neighbour list */
|
||||
if (sib3->intraFreqNeighCellList->list.count >= NR_maxCellIntra) {
|
||||
LOG_W(NR_RRC, "SIB3: too many intra-frequency neighbors (max %d), skipping cell %ld\n", NR_maxCellIntra, neigh->nrcell_id);
|
||||
asn1cFreeStruc(asn_DEF_NR_IntraFreqNeighCellInfo, cell);
|
||||
break;
|
||||
}
|
||||
asn1cSeqAdd(&sib3->intraFreqNeighCellList->list, cell);
|
||||
++intra_count;
|
||||
}
|
||||
|
||||
if (intra_count == 0) {
|
||||
LOG_W(NR_RRC,
|
||||
"SIB3: no intra-frequency neighbours found for serving SSB ARFCN %u "
|
||||
"(configured neighbours %u), not building SIB3\n",
|
||||
serving_ssb_arfcn,
|
||||
(unsigned)seq_arr_size(neighbours));
|
||||
asn1cFreeStruc(asn_DEF_NR_SIB3, sib3);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return sib3;
|
||||
}
|
||||
|
||||
/** @brief Return the frequency of the SS block of the cell for which this message is included,
|
||||
* or of other SS blocks within the same carrier. MeasurementTimingConfiguration message is
|
||||
* used to convey assistance information for measurement timing between nodes (e.g F1 setup) */
|
||||
@@ -569,6 +702,29 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
free_byte_array(enc);
|
||||
LOG_I(NR_RRC, "DU %ld: added SIB2 to F1 Setup Response (cell %ld)\n", du->gNB_DU_id, new->info.cell_id);
|
||||
} break;
|
||||
case NR_SIB_3: {
|
||||
if (!rrc->neighbour_cell_configuration)
|
||||
break;
|
||||
const neighbour_cell_configuration_t *neighbour_config = get_cell_neighbour_list(rrc, new);
|
||||
if (!neighbour_config)
|
||||
break;
|
||||
const seq_arr_t *neigh_cells = &neighbour_config->neighbour_cells;
|
||||
|
||||
NR_SIB3_t *sib3 = get_sib3_intra_freq_neighbors(neigh_cells, get_ssb_arfcn(new));
|
||||
if (!sib3)
|
||||
break;
|
||||
|
||||
byte_array_t enc = do_SIB3_NR(sib3);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB3, sib3);
|
||||
if (!enc.buf || enc.len == 0) {
|
||||
free_byte_array(enc);
|
||||
LOG_E(NR_RRC, "SIB3 encoding failed\n");
|
||||
break;
|
||||
}
|
||||
add_si_msg(&cell, sib->SIB_type, &enc);
|
||||
free_byte_array(enc);
|
||||
LOG_I(NR_RRC, "DU %ld: added SIB3 to F1 Setup Response (cell %ld)\n", du->gNB_DU_id, new->info.cell_id);
|
||||
} break;
|
||||
default:
|
||||
AssertFatal(false, "SIB%d not handled yet\n", sib->SIB_type);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user