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:
@@ -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))
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user