Merge remote-tracking branch 'origin/rrc-sibs' into integration_2026_w16 (!3983)

Add SIB 3,4 support, configurable SIB2 and refactor CU/DU SIB management

This MR makes neighbour and inter-frequency configuration drive how
SIB2/SIB3/SIB4 are built and sent from CU to DUs. It standardizes SIB
payloads as byte_array_t with typed SIB IDs across RRC, F1AP and MAC,
reducing ad‑hoc buffer handling. Neighbour parsing, validation and
lookup are tightened.

Changes

- Minor refactor to gNB neighbour parsing and storage (shared PLMN
  extraction, safer allocation, etc).
- Represent SIB containers uniformly as byte_array_t plus nr_sib_type_t,
  and adapt F1AP, MAC and RRC users to the new container API.
- Make SIB2 cell-reselection information fully config-driven with
  explicit bounds checking and SIB2 ASN.1 building from that config.
- Generate SIB3 intra-frequency neighbours from the per-cell neighbour
  list and propagate them from CU to DU over F1, with MAC
  decoding/attaching them to SystemInformation.
- Generate SIB4 inter-frequency neighbours from a new frequency_list
  plus neighbour SIB3/SIB4 offsets, and propagate them from CU to DU
  over F1, with MAC decoding/attaching them.
- Add basic ASN.1 round-trip tests for SIB2/SIB3/SIB4 and SIB4 range
  checks, and update RRC docs to describe the neighbour/inter-frequency
  configuration model.

Testing:

1. in gNB conf file:

    cu_sibs = (2, 3, 4);

2. Update neighbour config file with SIB3/SIB4 conf:

    (see documentation)

3. run gNB and UE as usual

---

Logs & configs: see MR on Gitlab
This commit is contained in:
Robert Schmidt
2026-04-16 12:42:42 +02:00
25 changed files with 1857 additions and 279 deletions
+2 -2
View File
@@ -48,8 +48,8 @@ typedef union checkedparam {
int num_okintval; /* number of valid values in the checkingval array */
} s1a;
struct {
int (*f2)(configmodule_interface_t *cfg,
paramdef_t *param); /* check an integer against an authorized range, defined by its min and max value */
int (*f2)(const configmodule_interface_t *cfg,
const paramdef_t *param); /* check an integer against an authorized range, defined by its min and max value */
int okintrange[CONFIG_MAX_NUMCHECKVAL]; /* integer array, store min and max values */
} s2;
+53 -9
View File
@@ -183,14 +183,35 @@ int config_check_intval(configmodule_interface_t *cfg, paramdef_t *param)
return -1;
}
for ( int i=0; i<param->chkPptr->s1.num_okintval ; i++) {
if( *(param->uptr) == param->chkPptr->s1.okintval[i] ) {
return 0;
if (param->type == TYPE_INT32 || param->type == TYPE_INT) {
if (param->iptr == NULL) {
fprintf(stderr, "[CONFIG] config_check_intval: %s: NULL iptr\n", param->optname);
return -1;
}
const int v = *param->iptr;
for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) {
if (v == param->chkPptr->s1.okintval[i])
return 0;
}
fprintf(stderr, "[CONFIG] config_check_intval: %s: %i invalid value, authorized values:\n ", param->optname, v);
for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) {
fprintf(stderr, " %i", param->chkPptr->s1.okintval[i]);
}
fprintf(stderr, " \n");
return -1;
} else {
if (param->uptr == NULL) {
fprintf(stderr, "[CONFIG] config_check_intval: %s: NULL uptr\n", param->optname);
return -1;
}
for (int i = 0; i < param->chkPptr->s1.num_okintval; i++) {
if (*(param->uptr) == (uint32_t)param->chkPptr->s1.okintval[i]) {
return 0;
}
}
print_intvalueerror(param, "config_check_intval", param->chkPptr->s1.okintval, param->chkPptr->s1.num_okintval);
return -1;
}
print_intvalueerror(param,"config_check_intval", param->chkPptr->s1.okintval,param->chkPptr->s1.num_okintval);
return -1;
}
int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param)
@@ -211,15 +232,38 @@ int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param
return -1;
}
int config_check_intrange(configmodule_interface_t *cfg, paramdef_t *param)
int config_check_intrange(const configmodule_interface_t *cfg, const paramdef_t *param)
{
UNUSED(cfg);
if( *(param->iptr) >= param->chkPptr->s2.okintrange[0] && *(param->iptr) <= param->chkPptr->s2.okintrange[1] ) {
return 0;
}
fprintf(stderr,"[CONFIG] config_check_intrange: %s: %i invalid value, authorized range: %i %i\n",
param->optname, (int)*(param->uptr), param->chkPptr->s2.okintrange[0], param->chkPptr->s2.okintrange[1]);
fprintf(stderr,
"[CONFIG] config_check_intrange: %s: %i invalid value, authorized range: %i %i\n",
param->optname,
(int)*(param->iptr),
param->chkPptr->s2.okintrange[0],
param->chkPptr->s2.okintrange[1]);
return -1;
}
int config_check_uintrange(const configmodule_interface_t *cfg, const paramdef_t *param)
{
(void)cfg;
const uint32_t *v = param->uptr;
const int *range = param->chkPptr->s2.okintrange;
if (*v >= (uint32_t)range[0] && *v <= (uint32_t)range[1]) {
return 0;
}
fprintf(stderr,
"[CONFIG] config_check_uintrange: %s: %u invalid, authorized range: %i %i\n",
param->optname,
*v,
range[0],
range[1]);
return -1;
}
+2 -1
View File
@@ -51,7 +51,8 @@ int config_get_processedint(configmodule_interface_t *cfg, paramdef_t *cfgoption
/* functions to be used in parameters definition, to check parameters values */
int config_check_intval(configmodule_interface_t *cfg, paramdef_t *param);
int config_check_modify_integer(configmodule_interface_t *cfg, paramdef_t *param);
int config_check_intrange(configmodule_interface_t *cfg, paramdef_t *param);
int config_check_intrange(const configmodule_interface_t *cfg, const paramdef_t *param);
int config_check_uintrange(const configmodule_interface_t *cfg, const paramdef_t *param);
int config_check_strval(configmodule_interface_t *cfg, paramdef_t *param);
int config_checkstr_assign_integer(configmodule_interface_t *cfg, paramdef_t *param);
const paramdef_t *config_get_paramdef_from_name(const paramdef_t *pd, int num, const char *name);
+26 -3
View File
@@ -13,6 +13,7 @@
#include <stdlib.h>
#include "assertions.h"
#include "common/utils/utils.h"
#include "common/utils/ds/byte_array.h"
#define MAX_SI_GROUPS 3
#define NR_MAX_PDSCH_TBS 3824
@@ -79,10 +80,32 @@ static inline const char *rnti_types(nr_rnti_type_t rr)
// the total shift is 2 * 15, in dB scale thats 10log10(2^(15*2))
#define SQ15_SQUARED_NORM_FACTOR_DB 90.3089986992
typedef enum {
NR_SIB_1 = 1,
NR_SIB_2,
NR_SIB_3,
NR_SIB_4,
NR_SIB_5,
NR_SIB_6,
NR_SIB_7,
NR_SIB_8,
NR_SIB_9,
NR_SIB_10,
NR_SIB_11,
NR_SIB_12,
NR_SIB_13,
NR_SIB_14,
NR_SIB_15,
NR_SIB_16,
NR_SIB_17,
NR_SIB_18,
NR_SIB_19,
NR_SIB_20,
NR_SIB_21,
} nr_sib_type_t;
typedef struct {
uint8_t *SIB_buffer;
int SIB_size;
int SIB_type;
nr_sib_type_t SIB_type;
} nr_SIBs_t;
typedef struct nr_bandentry_s {