RRC/SIB2: load cell reselection config from gNB

Introduce a typed SIB2 cell reselection configuration, load it from the
gNB configuration into the RRC gNB instance, and use it to build and
encode SIB2 instead of relying on a fixed SIB2 definition.
Validate SIB2 parameters against explicit bounds and make the SIB2
encoder consume a pre-built ASN.1 structure with safer error handling.

Changes:
- Add SIB2 mobility timer and q-HystSF enums plus SIB2 config structs
  (`sib2_speed_state_reselection_pars_t`, `sib2_config_t`) and a
  `sib2_config` field on `gNB_RRC_INST` in `nr_rrc_defs.h`.
- Define SIB2 configuration option names, defaults
  (`GNB_CONFIG_STRING_SIB2_*`, `GNBSIB2PARAMS_DESC`)
  in `gnb_paramdef.h` for q_Hyst, thresholds, mobility timers, scaling
  factors and deriveSSB_IndexFromCell.
- Add `sib2_config` parameter keys, defaults, and range/value checks in
  `gnb_paramdef.h` (`GNBSIB2PARAMS_DESC`).
- Add SIB2 `fill_sib2_configuration()` in `gnb_config.c` to read SIB2
  parameters from the config file log the resulting configuration and
  store it in `rrc->sib2_config` via `RCconfig_NRRRC()`.
- Add `get_q_hyst_asn1()` and `get_sib2_from_cfg()` in `rrc_gNB_du.c`, and
  update `rrc_gNB_process_f1_setup_req()` to encode/add SIB2 from config with
  explicit encode-failure handling and logging.
- Change `do_SIB2_NR` signature in `asn1_msg.h/.c` to
  `byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2)`, remove internal default
  SIB2 construction, and add ASN.1 constraint/encode error logging.
This commit is contained in:
Guido Casati
2026-04-10 10:22:50 +02:00
parent 52d5705f47
commit 9afa94040d
6 changed files with 395 additions and 35 deletions
+61
View File
@@ -2171,6 +2171,64 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc)
}
}
/** @brief Parse and populate SIB2 configuration from config file
* @param[in] gnb_idx gNB index
* @return populated SIB2 configuration */
static sib2_config_t fill_sib2_configuration(uint8_t gnb_idx)
{
sib2_config_t sib2 = {0};
char sib2_path[MAX_OPTNAME_SIZE * 2 + 8];
snprintf(sib2_path, sizeof(sib2_path), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_SIB2_CONFIG);
GET_PARAMS(SIB2Params, GNBSIB2PARAMS_DESC, sib2_path);
const int n_sib2_params = sizeofArray(SIB2Params);
cell_reselection_info_common_t *common = &sib2.cell_reselection_info_common;
common->q_Hyst = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_HYST)->iptr;
/* speedStateReselectionPars */
common->speedStateReselectionPars = calloc_or_fail(1, sizeof(*common->speedStateReselectionPars));
sib2_speed_state_reselection_pars_t *speed = common->speedStateReselectionPars;
/* Cell reselection serving frequency information */
cell_reselection_serving_freq_info_t *serv = &sib2.cell_reselection_serving_freq_info;
serv->cellReselectionPriority = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY)->iptr;
serv->threshServingLowP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P)->iptr;
serv->threshServingLowQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q)->iptr;
serv->s_NonIntraSearchP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P)->iptr;
serv->s_NonIntraSearchQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q)->iptr;
/* Intra-frequency cell reselection parameters */
intra_freq_cell_reselection_info_t *intra = &sib2.intra_freq_cell_reselection_info;
intra->q_RxLevMin = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN)->iptr;
intra->q_QualMin = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_Q_QUALMIN)->iptr;
intra->s_IntraSearchP = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P)->iptr;
intra->s_IntraSearchQ = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q)->iptr;
intra->t_ReselectionNR = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_T_RESEL_NR)->iptr;
/* deriveSSB_IndexFromCell (0/1) */
int derive_ssb = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX)->iptr;
sib2.deriveSSB_IndexFromCell = (derive_ssb != 0);
/* Speed-state pars: optional parameters are omitted from the config file (default applied), not set to -1. */
speed->t_Evaluation = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL)->iptr;
speed->t_HystNormal = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL)->iptr;
speed->n_CellChangeMedium = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED)->iptr;
speed->n_CellChangeHigh = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH)->iptr;
speed->sf_Medium = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM)->iptr;
speed->sf_High = *gpd(SIB2Params, n_sib2_params, GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH)->iptr;
LOG_I(GNB_APP,
"gNB %d SIB2 config: q_Hyst=%d dB, cellReselPrio=%d, q_RxLevMin=%d dBm, t_ReselectionNR=%d s\n",
gnb_idx,
common->q_Hyst,
serv->cellReselectionPriority,
intra->q_RxLevMin,
intra->t_ReselectionNR);
return sib2;
}
/**
* @brief Allocates and initializes RRC instances
* Currently assuming 1 instance
@@ -2270,6 +2328,9 @@ gNB_RRC_INST *RCconfig_NRRRC()
}//
}//End for (k=0; k <num_gnbs ; k++)
openair_rrc_gNB_configuration(rrc, &nrrrc_config);
/* Load SIB2 configuration */
rrc->sib2_config = fill_sib2_configuration(i);
}//End if (num_gnbs>0)
if (!NODE_IS_DU(rrc->node_type))
+90
View File
@@ -10,6 +10,7 @@
#define __GNB_APP_GNB_PARAMDEF__H__
#include "common/config/config_paramdesc.h"
#include "common/config/config_userapi.h"
#include "common/ngran_types.h"
#include "RRC_nr_paramsvalues.h"
@@ -374,6 +375,95 @@ typedef enum {
#define MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX 1
#define MEASUREMENT_EVENTS_MAX_RS_INDEX_TO_REPORT 2
/*-------------------------------------------------------------------------------------------------------------------------------------*/
/* SIB2 cell reselection configuration parameters */
/*-------------------------------------------------------------------------------------------------------------------------------------*/
#define GNB_CONFIG_STRING_SIB2_CONFIG "sib2_config"
/* clang-format off */
/* SIB2 top-level parameters (per cell) */
#define GNB_CONFIG_STRING_SIB2_Q_HYST "q_Hyst"
#define GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY "cellReselectionPriority"
#define GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P "threshServingLowP"
#define GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q "threshServingLowQ"
#define GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P "s_NonIntraSearchP"
#define GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q "s_NonIntraSearchQ"
#define GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN "q_RxLevMin"
#define GNB_CONFIG_STRING_SIB2_Q_QUALMIN "q_QualMin"
#define GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P "s_IntraSearchP"
#define GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q "s_IntraSearchQ"
#define GNB_CONFIG_STRING_SIB2_T_RESEL_NR "t_ReselectionNR"
#define GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX "deriveSSB_IndexFromCell"
/* SIB2 speedStateReselectionPars parameters */
#define GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL "speed_t_Evaluation"
#define GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL "speed_t_HystNormal"
#define GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED "speed_n_CellChangeMedium"
#define GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH "speed_n_CellChangeHigh"
#define GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM "speed_sf_Medium"
#define GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH "speed_sf_High"
#define GNBSIB2PARAMS_DESC { /* optname helpstr paramflags XXXptr def val type numelt */ \
{GNB_CONFIG_STRING_SIB2_Q_HYST, \
"SIB2 q-Hyst (0,1,2,3,4,5,6,8,10..24 dB)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s1 = {config_check_intval, {0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24}, 16}}}, \
{GNB_CONFIG_STRING_SIB2_CELLRESEL_PRIORITY, \
"SIB2 cellReselectionPriority (0..7)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 7}}}}, \
{GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_P, \
"SIB2 threshServingLowP (0..31)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_THRESH_SERVING_LOW_Q, \
"SIB2 threshServingLowQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_P, \
"SIB2 s-NonIntraSearchP (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_S_NONINTRASEARCH_Q, \
"SIB2 s-NonIntraSearchQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_Q_RXLEVMIN, \
"SIB2 q-RxLevMin (-70..-22)", 0, .iptr=NULL, .defintval=-56, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-70, -22}}}}, \
{GNB_CONFIG_STRING_SIB2_Q_QUALMIN, \
"SIB2 q-QualMin (-43..-12 or -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s1 = {config_check_intval, \
{-1, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, \
-27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12}, 33}}}, \
{GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_P, \
"SIB2 s-IntraSearchP (0..31)", 0, .iptr=NULL, .defintval=22, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_S_INTRASEARCH_Q, \
"SIB2 s-IntraSearchQ (0..31, -1=disabled)", 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {-1, 31}}}}, \
{GNB_CONFIG_STRING_SIB2_T_RESEL_NR, \
"SIB2 t-ReselectionNR (0..7)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 7}}}}, \
{GNB_CONFIG_STRING_SIB2_DERIVE_SSB_IDX, \
"SIB2 deriveSSB-IndexFromCell (0/1)", PARAMFLAG_BOOL, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_SIB2_SPEED_T_EVAL, \
"SIB2 speed t-Evaluation (0=s30,1=s60,2=s120,3=s180,4=s240)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 4}}}}, \
{GNB_CONFIG_STRING_SIB2_SPEED_T_HYST_NORMAL, \
"SIB2 speed t-HystNormal (0=s30,1=s60,2=s120,3=s180,4=s240)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 4}}}}, \
{GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_MED, \
"SIB2 speed n-CellChangeMedium (1..16)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {1, 16}}}}, \
{GNB_CONFIG_STRING_SIB2_SPEED_N_CELL_CHG_HIGH, \
"SIB2 speed n-CellChangeHigh (1..16)", 0, .iptr=NULL, .defintval=2, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {1, 16}}}}, \
{GNB_CONFIG_STRING_SIB2_SPEED_SF_MEDIUM, \
"SIB2 speed sf-Medium (0=dB-6,1=dB-4,2=dB-2,3=dB0)", 0, .iptr=NULL, .defintval=1, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 3}}}}, \
{GNB_CONFIG_STRING_SIB2_SPEED_SF_HIGH, \
"SIB2 speed sf-High (0=dB-6,1=dB-4,2=dB-2,3=dB0)", 0, .iptr=NULL, .defintval=0, TYPE_INT, 0, \
.chkPptr = &(checkedparam_t){.s2 = {config_check_intrange, {0, 3}}}}, \
}
/* clang-format on */
/* PLMN ID configuration */
#define GNB_CONFIG_STRING_PLMN_LIST "plmn_list"
+17 -31
View File
@@ -223,39 +223,25 @@ NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityR
return NULL;
}
//------------------------------------------------------------------------------
int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc)
byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2)
{
NR_SIB2_t *sib2 = calloc(1, sizeof(*sib2));
sib2->cellReselectionInfoCommon.q_Hyst = NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB0;
struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars *speed = calloc(1, sizeof(*speed));
NR_MobilityStateParameters_t mobilityStateParameters = {0};
mobilityStateParameters.t_Evaluation = NR_MobilityStateParameters__t_Evaluation_s30;
mobilityStateParameters.t_HystNormal = NR_MobilityStateParameters__t_HystNormal_s30;
mobilityStateParameters.n_CellChangeMedium = 1;
mobilityStateParameters.n_CellChangeHigh = 2;
speed->mobilityStateParameters = mobilityStateParameters;
struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF qhyst = {0};
qhyst.sf_Medium = NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF__sf_Medium_dB_4;
qhyst.sf_High = NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF__sf_High_dB_6;
speed->q_HystSF = qhyst;
sib2->cellReselectionInfoCommon.speedStateReselectionPars = speed;
sib2->cellReselectionServingFreqInfo.cellReselectionPriority = 0; // INTEGER (0..7)
sib2->cellReselectionServingFreqInfo.threshServingLowP = 0;
NR_ReselectionThresholdQ_t *threshServingLowQ = calloc(1, sizeof(*threshServingLowQ));
*threshServingLowQ = 0;
sib2->cellReselectionServingFreqInfo.threshServingLowQ = threshServingLowQ;
sib2->intraFreqCellReselectionInfo.q_RxLevMin = -56; // INTEGER (-70..-22)
sib2->intraFreqCellReselectionInfo.s_IntraSearchP = 22; // INTEGER (0..31)
sib2->intraFreqCellReselectionInfo.t_ReselectionNR = 1; // INTEGER (0..7)
sib2->intraFreqCellReselectionInfo.deriveSSB_IndexFromCell = true;
sib2->intraFreqCellReselectionInfo.smtc = ssbmtc;
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_SIB2, sib2, errbuf, &errlen);
if (ret != 0) {
LOG_E(NR_RRC, "SIB2 constraint check failed: %s\n", errbuf);
return msg;
}
ssize_t size = uper_encode_to_new_buffer(&asn_DEF_NR_SIB2, NULL, (void *)sib2, (void **)msg_SIB2);
AssertFatal (size > 0, "ASN1 message encoding failed (encoded %lu bytes)!\n", size);
ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2);
return size;
int val = uper_encode_to_new_buffer(&asn_DEF_NR_SIB2, NULL, (void *)sib2, (void **)&msg.buf);
if (val <= 0) {
LOG_E(NR_RRC, "Failed to encode SIB2\n");
return msg;
}
msg.len = val;
return msg;
}
int do_RRCReject(uint8_t *const buffer)
+2 -1
View File
@@ -33,6 +33,7 @@
#include "NR_MeasurementTimingConfiguration.h"
#include "NR_UE-NR-Capability.h"
#include "NR_UE-CapabilityRAT-ContainerList.h"
#include "NR_SIB2.h"
#include "ds/seq_arr.h"
#include "ds/byte_array.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
@@ -65,7 +66,7 @@ typedef struct {
*/
int xer_sprint_NR(char *string, size_t string_size, struct asn_TYPE_descriptor_s *td, void *sptr);
int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc);
byte_array_t do_SIB2_NR(const NR_SIB2_t *sib2);
int do_RRCReject(uint8_t *const buffer);
+97
View File
@@ -418,6 +418,101 @@ typedef struct nr_rrc_cuup_container_t {
sctp_assoc_t assoc_id;
} nr_rrc_cuup_container_t;
/**Timers for SIB2 MobilityStateParameters (TS 38.331)
* Value set shared by T-Evaluation and T-HystNormal: (s30, s60, s120, s180, s240). */
typedef enum sib2_mobility_state_timer_e {
SIB2_MOBILITY_STATE_TIMER_S30,
SIB2_MOBILITY_STATE_TIMER_S60,
SIB2_MOBILITY_STATE_TIMER_S120,
SIB2_MOBILITY_STATE_TIMER_S180,
SIB2_MOBILITY_STATE_TIMER_S240,
} sib2_mobility_state_timer_t;
/** Q-HystSF scaling factors for Q_hyst (TS 38.331)
* Speed-dependent offsets (-6, -4, -2, 0 dB) applied to the base Q_hyst
* when the UE is in medium or high mobility state. */
typedef enum sib2_q_hystsf_e {
SIB2_Q_HYSTSF_DB_6,
SIB2_Q_HYSTSF_DB_4,
SIB2_Q_HYSTSF_DB_2,
SIB2_Q_HYSTSF_DB0,
} sib2_q_hystsf_t;
/** SIB2 speedStateReselectionPars configuration
* Mirrors TS 38.331 MobilityStateParameters and Q-hystSF. */
typedef struct sib2_speed_state_reselection_pars_s {
/* t-Evaluation: duration for evaluating allowed reselections
* to enter mobility states (s30, s60, s120, s180, s240) */
sib2_mobility_state_timer_t t_Evaluation;
/* t-HystNormal: additional time period to evaluate reselection criteria
* before returning to normal mobility (s30, s60, s120, s180, s240) */
sib2_mobility_state_timer_t t_HystNormal;
/* n-CellChangeMedium: max number of cell reselections to enter medium mobility state (1..16) */
int n_CellChangeMedium;
/* n-CellChangeHigh: max number of cell reselections to enter high mobility state (1..16) */
int n_CellChangeHigh;
/* sf-Medium: speed-dependent scaling factor for Qhyst in medium state (-6, -4, -2, 0 dB) */
sib2_q_hystsf_t sf_Medium;
/* sf-High: speed-dependent scaling factor for Qhyst in high state (-6, -4, -2, 0 dB) */
sib2_q_hystsf_t sf_High;
} sib2_speed_state_reselection_pars_t;
/** SIB2 cellReselectionServingFreqInfo (TS 38.331) */
typedef struct {
/* s-NonIntraSearchP: Srxlev threshold to trigger NR inter-freq / inter-RAT measurements (0..31)*2 dB.
* Set to -1 to omit (optional ASN.1 field). */
int s_NonIntraSearchP;
/* s-NonIntraSearchQ: Squal threshold to trigger NR inter-freq / inter-RAT measurements (0..31)*2 dB */
int s_NonIntraSearchQ;
/* threshServingLowP: Srxlev threshold (dB) used by the UE on the serving cell
* when reselecting towards a lower-priority RAT/frequency (0..31)*2 dB */
int threshServingLowP;
/* threshServingLowQ: Squal threshold (dB) used by the UE on the serving cell
* when reselecting towards a lower-priority RAT/frequency (0..31)*2 dB.
* Set to -1 to omit (optional ASN.1 field). */
int threshServingLowQ;
/* cellReselectionPriority: absolute priority of serving NR frequency (0..7) */
int cellReselectionPriority;
} cell_reselection_serving_freq_info_t;
/** SIB2 cellReselectionInfoCommon (TS 38.331) */
typedef struct {
/* q-Hyst: hysteresis added to serving-cell ranking R_s (0..24 dB) */
int q_Hyst;
/* speedStateReselectionPars: MobilityStateParameters + q-HystSF */
sib2_speed_state_reselection_pars_t *speedStateReselectionPars;
} cell_reselection_info_common_t;
/** SIB2 intraFreqCellReselectionInfo (TS 38.331) */
typedef struct {
/* q-RxLevMin: minimum required RX level in the cell (dBm) */
int q_RxLevMin;
/* q-QualMin: minimum required quality level in the cell (dB); */
int q_QualMin;
/* s-IntraSearchP: Srxlev threshold for intra-freq meas (0..31) */
int s_IntraSearchP;
/* s-IntraSearchQ: Squal threshold for intra-freq meas (0..31) */
int s_IntraSearchQ;
/* t-ReselectionNR: NR cell reselection timer (0..7) */
int t_ReselectionNR;
} intra_freq_cell_reselection_info_t;
/** SIB2 configuration for idle/inactive cell reselection
* (maps to SIB2 reselection parameters in TS 38.304/38.331, per cell).
* @note Squal = Cell selection quality value (dB)
* Srxlev = Cell selection RX level value (dB) */
typedef struct sib2_config_s {
// cellReselectionInfoCommon
cell_reselection_info_common_t cell_reselection_info_common;
// cellReselectionServingFreqInfo
cell_reselection_serving_freq_info_t cell_reselection_serving_freq_info;
// intraFreqCellReselectionInfo
intra_freq_cell_reselection_info_t intra_freq_cell_reselection_info;
/* deriveSSB_IndexFromCell: SIB2 deriveSSB-IndexFromCell - whether UE may
* assume SFN/SSB alignment across cells on serving freq (per TS 38.304/38.133) */
bool deriveSSB_IndexFromCell;
} sib2_config_t;
//---NR---(completely change)---------------------
typedef struct gNB_RRC_INST_s {
@@ -432,6 +527,8 @@ typedef struct gNB_RRC_INST_s {
// RRC configuration
nr_rrc_config_t configuration;
seq_arr_t *SIBs;
// SIB2 configuration for cell reselection parameters
sib2_config_t sib2_config;
// gNB N3 GTPU instance
instance_t e1_inst;
+128 -3
View File
@@ -23,6 +23,8 @@
#include "f1ap_messages_types.h"
#include "ngap_messages_types.h"
#include "nr_rrc_defs.h"
#include "NR_SIB2.h"
#include "openair2/RRC/NR/MESSAGES/asn1_msg.h"
#include "rrc_gNB_mobility.h"
#include "openair2/F1AP/f1ap_common.h"
#include "openair2/F1AP/f1ap_ids.h"
@@ -55,6 +57,121 @@ static NR_SSB_MTC_t *get_ssb_mtc(const NR_MeasurementTimingConfiguration_t *mtc)
return ssb_mtc;
}
/** @brief Map config q_Hyst (dB: 0,1,2,3,4,5,6,8,10..24) to ASN.1 q-Hyst enum index (0..15).
* ASN.1 NR_SIB2 cellReselectionInfoCommon.q-Hyst is encoded with 16 values. */
static long get_q_hyst_asn1(int q_hyst_db)
{
switch (q_hyst_db) {
case 0:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB0;
case 1:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB1;
case 2:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB2;
case 3:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB3;
case 4:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB4;
case 5:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB5;
case 6:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB6;
case 8:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB8;
case 10:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB10;
case 12:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB12;
case 14:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB14;
case 16:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB16;
case 18:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB18;
case 20:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB20;
case 22:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB22;
case 24:
return NR_SIB2__cellReselectionInfoCommon__q_Hyst_dB24;
default:
AssertFatal(false, "unexpected q-Hyst value %d (configuration should have been validated)\n", q_hyst_db);
}
}
/** @brief Build NR_SIB2 from validated SIB2 configuration.
* @param cfg Validated SIB2 configuration from config file
* @param ssbmtc SSB-MTC instance to attach to intraFreqCellReselectionInfo.smtc. */
static NR_SIB2_t *get_sib2_from_cfg(const sib2_config_t *cfg, NR_SSB_MTC_t *ssbmtc)
{
NR_SIB2_t *sib2 = calloc_or_fail(1, sizeof(*sib2));
typeof(sib2->cellReselectionInfoCommon) *common = &sib2->cellReselectionInfoCommon;
const cell_reselection_info_common_t *cfg_common = &cfg->cell_reselection_info_common;
/* q-Hyst: ASN.1 enum (0..15) converted from config dB (0,1,2,3,4,5,6,8,10..24). */
common->q_Hyst = get_q_hyst_asn1(cfg_common->q_Hyst);
/* speedStateReselectionPars */
if (cfg_common->speedStateReselectionPars != NULL) {
struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars *speed = calloc_or_fail(1, sizeof(*speed));
NR_MobilityStateParameters_t mobilityStateParameters = {0};
const sib2_speed_state_reselection_pars_t *pars = cfg_common->speedStateReselectionPars;
/* t-Evaluation / t-HystNormal: (0..7) */
mobilityStateParameters.t_Evaluation = pars->t_Evaluation;
mobilityStateParameters.t_HystNormal = pars->t_HystNormal;
/* n-CellChangeMedium / n-CellChangeHigh: (1..16) */
mobilityStateParameters.n_CellChangeMedium = pars->n_CellChangeMedium;
mobilityStateParameters.n_CellChangeHigh = pars->n_CellChangeHigh;
speed->mobilityStateParameters = mobilityStateParameters;
/* q-HystSF: sf-Medium/sf-High (0..3) */
struct NR_SIB2__cellReselectionInfoCommon__speedStateReselectionPars__q_HystSF qhyst = {0};
qhyst.sf_Medium = pars->sf_Medium;
qhyst.sf_High = pars->sf_High;
speed->q_HystSF = qhyst;
common->speedStateReselectionPars = speed;
}
/* cellReselectionServingFreqInfo */
typeof(sib2->cellReselectionServingFreqInfo) *serv = &sib2->cellReselectionServingFreqInfo;
const cell_reselection_serving_freq_info_t *cfg_serv = &cfg->cell_reselection_serving_freq_info;
/* cellReselectionPriority: CellReselectionPriority (0..7) */
serv->cellReselectionPriority = cfg_serv->cellReselectionPriority;
/* threshServingLowP: ReselectionThreshold (0..31) */
serv->threshServingLowP = cfg_serv->threshServingLowP;
/* threshServingLowQ: ReselectionThresholdQ (0..31) */
if (cfg_serv->threshServingLowQ != -1)
asn1cCallocOne(serv->threshServingLowQ, cfg_serv->threshServingLowQ);
/* s-NonIntraSearchP/Q: ReselectionThreshold/ReselectionThresholdQ (0..31) */
if (cfg_serv->s_NonIntraSearchP != -1)
asn1cCallocOne(serv->s_NonIntraSearchP, cfg_serv->s_NonIntraSearchP);
if (cfg_serv->s_NonIntraSearchQ != -1)
asn1cCallocOne(serv->s_NonIntraSearchQ, cfg_serv->s_NonIntraSearchQ);
/* intraFreqCellReselectionInfo */
typeof(sib2->intraFreqCellReselectionInfo) *intra = &sib2->intraFreqCellReselectionInfo;
const intra_freq_cell_reselection_info_t *cfg_intra = &cfg->intra_freq_cell_reselection_info;
/* q-RxLevMin: Q-RxLevMin (-70..-22) */
intra->q_RxLevMin = cfg_intra->q_RxLevMin;
/* q-QualMin: Q-QualMin (-43..-12) */
if (cfg_intra->q_QualMin != -1)
asn1cCallocOne(intra->q_QualMin, cfg_intra->q_QualMin);
/* s-IntraSearchP: ReselectionThreshold (0..31) */
intra->s_IntraSearchP = cfg_intra->s_IntraSearchP;
/* s-IntraSearchQ: ReselectionThresholdQ (0..31) */
if (cfg_intra->s_IntraSearchQ != -1)
asn1cCallocOne(intra->s_IntraSearchQ, cfg_intra->s_IntraSearchQ);
/* t-ReselectionNR: (0..7) */
intra->t_ReselectionNR = cfg_intra->t_ReselectionNR;
/* deriveSSB-IndexFromCell (bool) */
intra->deriveSSB_IndexFromCell = cfg->deriveSSB_IndexFromCell;
/* smtc */
intra->smtc = ssbmtc;
return sib2;
}
/** @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) */
@@ -440,9 +557,17 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
switch (sib->SIB_type) {
case NR_SIB_2: {
NR_SSB_MTC_t *ssbmtc = get_ssb_mtc(new->mtc);
byte_array_t ba = {0};
ba.len = do_SIB2_NR(&ba.buf, ssbmtc);
add_si_msg(&cell, sib->SIB_type, &ba);
NR_SIB2_t *sib2 = get_sib2_from_cfg(&rrc->sib2_config, ssbmtc);
byte_array_t enc = do_SIB2_NR(sib2);
ASN_STRUCT_FREE(asn_DEF_NR_SIB2, sib2);
if (!enc.buf || enc.len == 0) {
free_byte_array(enc);
LOG_E(NR_RRC, "SIB2 encoding failed\n");
break;
}
add_si_msg(&cell, sib->SIB_type, &enc);
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;
default:
AssertFatal(false, "SIB%d not handled yet\n", sib->SIB_type);