From 49d302960c284963f1ae1e547be95488f179a92a Mon Sep 17 00:00:00 2001 From: Chieh-Chun Chen Date: Fri, 11 Apr 2025 14:40:52 +0200 Subject: [PATCH 01/48] Fix: modify block_length to Kprime --- openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c index bd3d6b882c..1766c0f072 100644 --- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c +++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_CL.c @@ -350,7 +350,7 @@ int32_t LDPCdecoder(t_nrLDPC_dec_params *p_decParams, uint16_t Zc = p_decParams->Z; uint8_t BG = p_decParams->BG; // uint8_t numMaxIter = p_decParams->numMaxIter; - int block_length = p_decParams->block_length; + int block_length = p_decParams->Kprime; // e_nrLDPC_outMode outMode = p_decParams->outMode; uint8_t row,col; if(BG == 1){ From 49b3e2ee69895e904b776385548f660b205273c7 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 16 Oct 2024 19:02:25 +0200 Subject: [PATCH 02/48] Cleanup commented out code in gnb_config.c and other minor formatting --- openair2/GNB_APP/gnb_config.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index cbb46f0132..a90ce5f90b 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2116,8 +2116,6 @@ gNB_RRC_INST *RCconfig_NRRRC() rrc->eth_params_s.transp_preference = ETH_UDP_MODE; } - - rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr); if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) { @@ -2342,45 +2340,17 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0; for (int l = 0; l < NGParamList.numelt; l++) { - NGAP_REGISTER_GNB_REQ (msg_p).nb_amf += 1; strcpy(NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[l].ipv4_address,*(NGParamList.paramarray[l][GNB_AMF_IPV4_ADDRESS_IDX].strptr)); NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv4 = 1; NGAP_REGISTER_GNB_REQ (msg_p).amf_ip_address[j].ipv6 = 0; - - /* not in configuration yet ... - if (NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr) - NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].numelt; - else - NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = 0; - - AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] <= NGAP_REGISTER_GNB_REQ(msg_p).num_plmn, - "List of broadcast PLMN to be sent to AMF can not be longer than actual " - "PLMN list (max %d, but is %d)\n", - NGAP_REGISTER_GNB_REQ(msg_p).num_plmn, - NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]); - - for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l]; ++el) { - // UINTARRAY gets mapped to int, see config_libconfig.c:223 - NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = NGParamList.paramarray[l][GNB_AMF_BROADCAST_PLMN_INDEX].iptr[el]; - AssertFatal(NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] >= 0 - && NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn, - "index for AMF's MCC/MNC (%d) is an invalid index for the registered PLMN IDs (%d)\n", - NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el], - NGAP_REGISTER_GNB_REQ(msg_p).num_plmn); - } - */ - /* if no broadcasst_plmn array is defined, fill default values */ if (NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] == 0) { NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_num[l] = NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; - for (int el = 0; el < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++el) NGAP_REGISTER_GNB_REQ(msg_p).broadcast_plmn_index[l][el] = el; } - } - // SCTP SETTING NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS; @@ -2482,8 +2452,6 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { int J, l; char *address = NULL; char *cidr = NULL; - //int num_gnbs = 0; - //int num_component_carriers = 0; int j,k = 0; int32_t gnb_id = 0; From 7731f5bd2d853d84620ac308645fd3ee8fdbb259 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 25 Oct 2024 23:59:27 +0200 Subject: [PATCH 03/48] Introduce macros to get parameters in gnb_config.c * this commit introduces macro to reduce redundant code in gNB configuration --- common/config/config_paramdesc.h | 16 ++ openair2/GNB_APP/gnb_config.c | 345 ++++++++++--------------------- 2 files changed, 129 insertions(+), 232 deletions(-) diff --git a/common/config/config_paramdesc.h b/common/config/config_paramdesc.h index 7097991f18..6947f6531d 100644 --- a/common/config/config_paramdesc.h +++ b/common/config/config_paramdesc.h @@ -167,4 +167,20 @@ typedef struct paramlist_def { int numelt ; } paramlist_def_t; +/* Macros to get parameters with the config module API */ +#define GET_PARAMS(param_def, param_desc, prefix) \ + printf("Reading '%s' section from the config file\n", #param_def); \ + paramdef_t param_def[] = param_desc; \ + config_get(config_get_if(), param_def, sizeofArray(param_def), prefix); + +/* Macros to get params lists with the config module API */ +#define GET_PARAMS_LIST(param_list, param_def, param_desc, list_name, prefix, ...) \ + paramdef_t param_def[] = param_desc; \ + paramlist_def_t param_list = {list_name, NULL, 0}; \ + __VA_OPT__(checkedparam_t config_check_##param_def[] = __VA_ARGS__; \ + static_assert(sizeofArray(config_check_##param_def) == sizeofArray(param_def), \ + "param_def_t array and corresponding checkedparam_t array should have the same size"); \ + for (int i = 0; i < sizeofArray(param_def); ++i) param_def[i].chkPptr = &(config_check_##param_def[i]);) \ + config_getlist(config_get_if(), ¶m_list, param_def, sizeofArray(param_def), prefix); + #endif /* INCLUDE_CONFIG_PARAMDESC_H */ diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index a90ce5f90b..79e92d2a1d 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -796,13 +796,10 @@ static void verify_section_notset(configmodule_interface_t *cfg, char *aprefix, } void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) { - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs == 1, "need to have a " GNB_CONFIG_STRING_GNB_LIST " section, but %d found\n", num_gnbs); - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0}; - paramdef_t GNBParams[] = GNBPARAMS_DESC; - config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL, GNBPARAMS_CHECK); paramdef_t *gnbp = GNBParamList.paramarray[0]; if (NODE_IS_CU(node_type)) { @@ -847,9 +844,7 @@ void RCconfig_nr_prs(void) AssertFatal(RC.gNB != NULL, "gNB context is null, cannot complete PRS configuration\n"); - paramdef_t PRS_Params[] = PRS_PARAMS_DESC; - paramlist_def_t PRS_ParamList = {CONFIG_STRING_PRS_CONFIG,NULL,0}; - config_getlist(config_get_if(), &PRS_ParamList, PRS_Params, sizeofArray(PRS_Params), NULL); + GET_PARAMS_LIST(PRS_ParamList, PRS_Params, PRS_PARAMS_DESC, CONFIG_STRING_PRS_CONFIG, NULL); if (PRS_ParamList.numelt > 0) { for (j = 0; j < RC.nb_nr_L1_inst; j++) { @@ -968,14 +963,10 @@ void RCconfig_NR_L1(void) AssertFatal(RC.gNB[j] != NULL, "gNB L1 instance is null at index %d, cannot complete L1 configuration\n", j); // gNB params if (NFAPI_MODE != NFAPI_MODE_PNF) { - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0}; - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs > 0, "Failed to parse config file, no GNBs found in field %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS); - - paramdef_t GNBParams[] = GNBPARAMS_DESC; - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); int N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; int N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr; int XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr; @@ -996,9 +987,8 @@ void RCconfig_NR_L1(void) } // L1 params - paramdef_t L1_Params[] = L1PARAMS_DESC; - paramlist_def_t L1_ParamList = {CONFIG_STRING_L1_LIST, NULL, 0}; - config_getlist(config_get_if(), &L1_ParamList, L1_Params, sizeofArray(L1_Params), NULL); + GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL); + if (L1_ParamList.numelt > 0) { AssertFatal(*L1_ParamList.paramarray[j][L1_THREAD_POOL_SIZE].uptr == 2022, "thread_pool_size removed, please use --thread-pool\n"); @@ -1059,21 +1049,17 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf NR_ServingCellConfigCommon_t *scc = calloc_or_fail(1, sizeof(*scc)); uint64_t ssb_bitmap=0xff; prepare_scc(scc); - paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc); prepare_msgA_scc(scc); - paramdef_t MsgASCCsParams[] = MSGASCCPARAMS_DESC(scc); - paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0}; - paramlist_def_t MsgASCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0}; char aprefix[MAX_OPTNAME_SIZE*2 + 8]; sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - config_getlist(cfg, &SCCsParamList, NULL, 0, aprefix); - config_getlist(cfg, &MsgASCCsParamList, NULL, 0, aprefix); + GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); + GET_PARAMS_LIST(MsgASCCsParamList, MsgASCCsParams, MSGASCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); if (SCCsParamList.numelt > 0 || MsgASCCsParamList.numelt > 0) { sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); - config_get(cfg, SCCsParams, sizeofArray(SCCsParams), aprefix); - config_get(cfg, MsgASCCsParams, sizeofArray(MsgASCCsParams), aprefix); + GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix); + GET_PARAMS(MsgASCCsParams, MSGASCCPARAMS_DESC(scc), aprefix); // NR_TDD-UL-DL-ConfigCommon pattern2 (optional IE) // fetch params struct NR_TDD_UL_DL_Pattern p2; @@ -1165,15 +1151,14 @@ static NR_ServingCellConfig_t *get_scd_config(configmodule_interface_t *cfg) { NR_ServingCellConfig_t *scd = calloc(1, sizeof(*scd)); prepare_scd(scd); - paramdef_t SCDsParams[] = SCDPARAMS_DESC(scd); - paramlist_def_t SCDsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, NULL, 0}; char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - config_getlist(cfg, &SCDsParamList, NULL, 0, aprefix); + GET_PARAMS_LIST(SCDsParamList, SCDsParams, SCDPARAMS_DESC(scd), GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, aprefix); + if (SCDsParamList.numelt > 0) { sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0); - config_get(cfg, SCDsParams, sizeof(SCDsParams) / sizeof(paramdef_t), aprefix); + GET_PARAMS(SCDsParams, SCDPARAMS_DESC(scd), aprefix); const NR_BWP_UplinkDedicated_t *bwp_Dedicated = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated; const NR_PTRS_UplinkConfig_t *setup = bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup; @@ -1206,15 +1191,11 @@ static int read_du_cell_info(configmodule_interface_t *cfg, AssertFatal(max_cell_info == 1, "only one cell supported\n"); memset(info, 0, sizeof(*info)); - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; - config_get(cfg, GNBSParams, sizeof(GNBSParams) / sizeof(paramdef_t), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs == 1, "cannot configure DU: required config section \"gNBs\" missing\n"); - // Output a list of all eNBs. - config_getlist(cfg, &GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); // read the gNB-ID. The DU itself only needs the gNB-DU ID, but some (e.g., // E2 agent) need the gNB-ID as well if it is running in a separate process @@ -1227,16 +1208,9 @@ static int read_du_cell_info(configmodule_interface_t *cfg, *GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr); char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[0]", GNB_CONFIG_STRING_GNB_LIST); - paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK; - static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams), - "config_check_PLMNParams and PLMNParams should have the same size"); - for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I) - PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; - config_getlist(cfg, &PLMNParamList, PLMNParams, sizeof(PLMNParams) / sizeof(paramdef_t), aprefix); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); AssertFatal(PLMNParamList.numelt > 0, "need to have a PLMN in PLMN section\n"); AssertFatal(PLMNParamList.numelt == 1, "cannot have more than one PLMN\n"); @@ -1263,16 +1237,15 @@ static int read_du_cell_info(configmodule_interface_t *cfg, info->plmn.mnc_digit_length); info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr); - paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC; - paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0}; - checkedparam_t config_check_SNSSAIParams[] = SNSSAIPARAMS_CHECK; - static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams), - "config_check_SNSSAIParams and SNSSAIParams should have the same size"); - for (int J = 0; J < sizeofArray(SNSSAIParams); ++J) - SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]); + // SNSSAI char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; sprintf(snssaistr, "%s.[0].%s.[0]", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_PLMN_LIST); - config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr); + GET_PARAMS_LIST(SNSSAIParamList, + SNSSAIParams, + GNBSNSSAIPARAMS_DESC, + GNB_CONFIG_STRING_SNSSAI_LIST, + snssaistr, + SNSSAIPARAMS_CHECK); info->num_ssi = SNSSAIParamList.numelt; for (int s = 0; s < info->num_ssi; ++s) { info->nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; @@ -1459,33 +1432,16 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) { int j = 0; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0}; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - config_get(cfg, GNBSParams, sizeofArray(GNBSParams), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL, GNBPARAMS_CHECK); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs == 1, "Failed to parse config file: number of gnbs for gNB %s is %d != 1\n", GNB_CONFIG_STRING_ACTIVE_GNBS, num_gnbs); - paramdef_t GNBParams[] = GNBPARAMS_DESC; - /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_GNBParams[] = GNBPARAMS_CHECK; - static_assert(sizeofArray(config_check_GNBParams) == sizeofArray(GNBParams), - "config_check_GNBParams and GNBParams should have the same size"); - for (int i = 0; i < sizeofArray(GNBParams); ++i) - GNBParams[i].chkPptr = &(config_check_GNBParams[i]); - config_getlist(cfg, &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); - - paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC; - paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST, NULL, 0}; - /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_MacRLCParams[] = MACRLCPARAMS_CHECK; - static_assert(sizeofArray(config_check_MacRLCParams) == sizeofArray(MacRLC_Params), - "config_check_MacRLCParams and MacRLC_Params should have the same size"); - for (int i = 0; i < sizeofArray(MacRLC_Params); ++i) - MacRLC_Params[i].chkPptr = &(config_check_MacRLCParams[i]); - config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL); + // MAC / RLC + GET_PARAMS_LIST(MacRLC_ParamList, MacRLC_Params, MACRLCPARAMS_DESC, CONFIG_STRING_MACRLC_LIST, NULL, MACRLCPARAMS_CHECK); nr_mac_config_t config = {0}; config.pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; config.pdsch_AntennaPorts.N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr; @@ -1498,9 +1454,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.pdsch_AntennaPorts.XP, config.pusch_AntennaPorts); - paramdef_t RUParams[] = RUPARAMS_DESC; - paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST, NULL, 0}; - config_getlist(config_get_if(), &RUParamList, RUParams, sizeofArray(RUParams), NULL); + // RU + GET_PARAMS_LIST(RUParamList, RUParams, RUPARAMS_DESC, CONFIG_STRING_RU_LIST, NULL); int num_tx = 0; if (RUParamList.numelt > 0) { for (int i = 0; i < RUParamList.numelt; i++) @@ -1543,10 +1498,9 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.redcap = get_redcap_config(0); - paramdef_t Timers_Params[] = GNB_TIMERS_PARAMS_DESC; char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[0].%s", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_TIMERS_CONFIG); - config_get(config_get_if(), Timers_Params, sizeofArray(Timers_Params), aprefix); + sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_TIMERS_CONFIG); + GET_PARAMS(Timers_Params, GNB_TIMERS_PARAMS_DESC, aprefix); config.timer_config.sr_ProhibitTimer = *Timers_Params[GNB_TIMERS_SR_PROHIBIT_TIMER_IDX].iptr; config.timer_config.sr_TransMax = *Timers_Params[GNB_TIMERS_SR_TRANS_MAX_IDX].iptr; @@ -1912,10 +1866,12 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc char gnbpath[MAX_OPTNAME_SIZE + 8]; sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); - paramdef_t neighbour_list_params[] = GNB_NEIGHBOUR_LIST_PARAM_LIST; - paramlist_def_t neighbour_list_param_list = {GNB_CONFIG_STRING_NEIGHBOUR_LIST, NULL, 0}; + GET_PARAMS_LIST(neighbour_list_param_list, + neighbour_list_params, + GNB_NEIGHBOUR_LIST_PARAM_LIST, + GNB_CONFIG_STRING_NEIGHBOUR_LIST, + gnbpath); - config_getlist(config_get_if(), &neighbour_list_param_list, neighbour_list_params, sizeofArray(neighbour_list_params), gnbpath); if (neighbour_list_param_list.numelt < 1) return; @@ -1929,9 +1885,11 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc char neighbourpath[MAX_OPTNAME_SIZE + 8]; sprintf(neighbourpath, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); - paramdef_t NeighbourCellParams[] = GNBNEIGHBOURCELLPARAMS_DESC; - paramlist_def_t NeighbourCellParamList = {GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, NULL, 0}; - config_getlist(config_get_if(), &NeighbourCellParamList, NeighbourCellParams, sizeofArray(NeighbourCellParams), neighbourpath); + GET_PARAMS_LIST(NeighbourCellParamList, + NeighbourCellParams, + GNBNEIGHBOURCELLPARAMS_DESC, + GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, + neighbourpath); LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; @@ -1956,9 +1914,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, l, GNB_CONFIG_STRING_NEIGHBOUR_PLMN); - - paramdef_t NeighbourPlmn[] = GNBPLMNPARAMS_DESC; - config_get(config_get_if(), NeighbourPlmn, sizeofArray(NeighbourPlmn), neighbour_plmn_path); + GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; @@ -1989,8 +1945,8 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, MEASUREMENT_EVENTS_PERIODICAL); - paramdef_t Periodical_EventParams[] = MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC; - config_get(config_get_if(), Periodical_EventParams, sizeofArray(Periodical_EventParams), periodic_event_path); + GET_PARAMS(Periodical_EventParams, MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC, periodic_event_path); + if (*Periodical_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) { nr_per_event_t *periodic_event = (nr_per_event_t *)calloc(1, sizeof(nr_per_event_t)); periodic_event->includeBeamMeasurements = *Periodical_EventParams[MEASUREMENT_EVENTS_INCLUDE_BEAM_MEAS_IDX].i64ptr; @@ -2007,8 +1963,8 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, MEASUREMENT_EVENTS_A2); - paramdef_t A2_EventParams[] = MEASUREMENT_A2_GLOBALPARAMS_DESC; - config_get(config_get_if(), A2_EventParams, sizeofArray(A2_EventParams), a2_path); + GET_PARAMS(A2_EventParams, MEASUREMENT_A2_GLOBALPARAMS_DESC, a2_path); + if (*A2_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) { nr_a2_event_t *a2_event = (nr_a2_event_t *)calloc(1, sizeof(nr_a2_event_t)); a2_event->threshold_RSRP = *A2_EventParams[MEASUREMENT_EVENTS_A2_THRESHOLD_IDX].i64ptr; @@ -2017,9 +1973,8 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) measurementConfig->a2_event = a2_event; } // A3 Event Configuration - paramlist_def_t A3_EventList = {MEASUREMENT_EVENTS_A3, NULL, 0}; - paramdef_t A3_EventParams[] = MEASUREMENT_A3_GLOBALPARAMS_DESC; - config_getlist(config_get_if(), &A3_EventList, A3_EventParams, sizeofArray(A3_EventParams), measurement_path); + GET_PARAMS_LIST(A3_EventList, A3_EventParams, MEASUREMENT_A3_GLOBALPARAMS_DESC, MEASUREMENT_EVENTS_A3, measurement_path); + LOG_D(GNB_APP, "HO LOG: A3 Configuration Exists: %d\n", A3_EventList.numelt); if (A3_EventList.numelt < 1) @@ -2057,29 +2012,17 @@ gNB_RRC_INST *RCconfig_NRRRC() gNB_RRC_INST *rrc = calloc(1, sizeof(*rrc)); int num_gnbs = 0; - char aprefix[MAX_OPTNAME_SIZE*2 + 8]; int32_t gnb_id = 0; int k = 0; int i = 0; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - ////////// Identification parameters - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; - - ////////// Physical parameters - - /* get global parameters, defined outside any section in the config file */ - - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal (i < num_gnbs,"Failed to parse config file no %dth element in %s \n", i, GNB_CONFIG_STRING_ACTIVE_GNBS); AssertFatal(num_gnbs == 1, "required section \"gNBs\" not in config!\n"); if (num_gnbs > 0) { - - // Output a list of all gNBs. ////////// Identification parameters - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); if (GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr == NULL) { // Calculate a default gNB ID if (IS_SA_MODE(get_softmodem_params())) { @@ -2093,17 +2036,15 @@ gNB_RRC_INST *RCconfig_NRRRC() gnb_id = *(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr); } - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - LOG_D(GNB_APP, "NRRRC %d: Southbound Transport %s\n", i, *(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr)); rrc->node_type = get_node_type(); rrc->node_id = gnb_id; + if (NODE_IS_CU(rrc->node_type)) { - paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC; char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - sprintf(aprefix,"%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG); - config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix); + sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG); + GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n", k, rrc->node_id); rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr)); LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n", k, rrc->node_name); @@ -2136,9 +2077,6 @@ gNB_RRC_INST *RCconfig_NRRRC() gNB_RrcConfigurationReq nrrrc_config = {0}; for (k=0; k SIBs = fill_cu_sibs(GNBParamList.paramarray[i]); - paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; - - paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; - /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK; - static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams), - "config_check_PLMNParams and PLMNParams should have the same size"); - - for (int I = 0; I < sizeofArray(PLMNParams); ++I) - PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - nrrrc_config.tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr; AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr && !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr, @@ -2167,7 +2094,11 @@ gNB_RRC_INST *RCconfig_NRRRC() "to\n" " tracking_area_code = 1; // no string!!\n" " plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n"); - config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), gnbpath); + + // PLMN params + char gnbpath[MAX_OPTNAME_SIZE + 8]; + sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, gnbpath, PLMNPARAMS_CHECK); if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", @@ -2206,8 +2137,6 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { int gnb_id; int32_t my_int; const char* active_gnb[MAX_GNB]; - char *address = NULL; - char *cidr = NULL; // for no gcc warnings @@ -2219,13 +2148,7 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { char* gnb_ipv4_address_for_S1U = NULL; uint32_t gnb_port_for_S1U = 0; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; - - /* get global parameters, defined outside any section in the config file */ - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); - + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); AssertFatal (i0) { // Output a list of all gNBs. - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); if (GNBParamList.numelt > 0) { for (k = 0; k < GNBParamList.numelt; k++) { if (GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr == NULL) { @@ -2254,31 +2177,8 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { // search if in active list for (j=0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) { if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) { - paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; - paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; - paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC; - paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0}; - /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK; - static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams), - "config_check_PLMNParams and PLMNParams should have the same size"); - checkedparam_t config_check_SNSSAIParams [] = SNSSAIPARAMS_CHECK; - static_assert(sizeofArray(config_check_SNSSAIParams) == sizeofArray(SNSSAIParams), - "config_check_SNSSAIParams and SNSSAIParams should have the same size"); - for (int I = 0; I < sizeofArray(PLMNParams); ++I) - PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - for (int J = 0; J < sizeofArray(SNSSAIParams); ++J) - SNSSAIParams[J].chkPptr = &(config_check_SNSSAIParams[J]); - - paramdef_t NGParams[] = GNBNGPARAMS_DESC; - paramlist_def_t NGParamList = {GNB_CONFIG_STRING_AMF_IP_ADDRESS,NULL,0}; - - paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC; - paramdef_t NETParams[] = GNBNETPARAMS_DESC; char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); - NGAP_REGISTER_GNB_REQ (msg_p).gNB_id = gnb_id; if (strcmp(*(GNBParamList.paramarray[k][GNB_CELL_TYPE_IDX].strptr), "CELL_MACRO_GNB") == 0) { @@ -2302,7 +2202,9 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { "to\n" " tracking_area_code = 1; // no string!!\n" " plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n"); - config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix); + // PLMN params + sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", @@ -2311,9 +2213,14 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt; for (int l = 0; l < PLMNParamList.numelt; ++l) { - char snssaistr[MAX_OPTNAME_SIZE*2 + 8]; + char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l); - config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeofArray(SNSSAIParams), snssaistr); + GET_PARAMS_LIST(SNSSAIParamList, + SNSSAIParams, + GNBSNSSAIPARAMS_DESC, + GNB_CONFIG_STRING_SNSSAI_LIST, + snssaistr, + SNSSAIPARAMS_CHECK); NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; @@ -2334,9 +2241,8 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { (*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0xffffff); } } - sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); - config_getlist(config_get_if(), &NGParamList, NGParams, sizeofArray(NGParams), aprefix); - + sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); + GET_PARAMS_LIST(NGParamList, NGParams, GNBNGPARAMS_DESC, GNB_CONFIG_STRING_AMF_IP_ADDRESS, aprefix); NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0; for (int l = 0; l < NGParamList.numelt; l++) { @@ -2356,26 +2262,26 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS; NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS; if (IS_SA_MODE(get_softmodem_params())) { - sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG); - config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix); + sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG); + GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr); NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr); } - sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); // NETWORK_INTERFACES - config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix); + sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix); + if (NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr != NULL) { + char *cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr); + char *save = NULL; + char *address = strtok_r(cidr, "/", &save); + strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address); + LOG_I(GNB_APP, "Parsed IPv4 address for NG AMF: %s\n", address); + } - // NGAP_REGISTER_GNB_REQ (msg_p).enb_interface_name_for_NGU = strdup(enb_interface_name_for_NGU); - cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr); - char *save = NULL; - address = strtok_r(cidr, "/", &save); - NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv6 = 0; NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4 = 1; - - strcpy(NGAP_REGISTER_GNB_REQ (msg_p).gnb_ip_address.ipv4_address, address); - + break; } } @@ -2404,8 +2310,7 @@ void NRRCConfig(void) memset((void *)&RC, 0, sizeof(RC)); - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); // Set num of gNBs instances RC.nb_nr_inst = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; @@ -2455,18 +2360,13 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { int j,k = 0; int32_t gnb_id = 0; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - ////////// Identification parameters - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; /* get global parameters, defined outside any section in the config file */ - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); + NR_ServingCellConfigCommon_t *scc = calloc_or_fail(1, sizeof(*scc)); uint64_t ssb_bitmap=0xff; memset((void*)scc,0,sizeof(NR_ServingCellConfigCommon_t)); prepare_scc(scc); - paramdef_t SCCsParams[] = SCCPARAMS_DESC(scc); - paramlist_def_t SCCsParamList = {GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, NULL, 0}; AssertFatal(i < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt, "Failed to parse config file %s, %uth attribute %s \n", @@ -2474,7 +2374,7 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { if (GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt > 0) { // Output a list of all gNBs. - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); if (GNBParamList.numelt > 0) { for (k = 0; k < GNBParamList.numelt; k++) { @@ -2494,29 +2394,17 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { // search if in active list for (j = 0; j < GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; j++) { if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) { - paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; - paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK; - static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams), - "config_check_PLMNParams and PLMNParams should have the same size"); - for (int I = 0; I < sizeofArray(PLMNParams); ++I) - PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); + char aprefix[MAX_OPTNAME_SIZE * 80 + 8]; + sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); - paramdef_t X2Params[] = X2PARAMS_DESC; - paramlist_def_t X2ParamList = {ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS,NULL,0}; - paramdef_t SCTPParams[] = GNBSCTPPARAMS_DESC; - char* gnb_ipv4_address_for_NGU = NULL; - uint32_t gnb_port_for_NGU = 0; - char* gnb_ipv4_address_for_S1U = NULL; - uint32_t gnb_port_for_S1U = 0; + char* gnb_ipv4_address_for_NGU = NULL; + uint32_t gnb_port_for_NGU = 0; + char* gnb_ipv4_address_for_S1U = NULL; + uint32_t gnb_port_for_S1U = 0; - paramdef_t NETParams[] = GNBNETPARAMS_DESC; - /* TODO: fix the size - if set lower we have a crash (MAX_OPTNAME_SIZE was 64 when this code was written) */ - /* this is most probably a problem with the config module */ - char aprefix[MAX_OPTNAME_SIZE*80 + 8]; - sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); /* Some default/random parameters */ X2AP_REGISTER_ENB_REQ (msg_p).eNB_id = gnb_id; @@ -2530,7 +2418,6 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)); X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr; - config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix); if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", @@ -2548,11 +2435,10 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ(msg_p).mnc); sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - - config_getlist(config_get_if(), &SCCsParamList, NULL, 0, aprefix); + GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); if (SCCsParamList.numelt > 0) { - sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); - config_get(config_get_if(), SCCsParams, sizeofArray(SCCsParams), aprefix); + sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); + GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix); fix_scc(scc,ssb_bitmap); } X2AP_REGISTER_ENB_REQ (msg_p).num_cc = SCCsParamList.numelt; @@ -2573,7 +2459,8 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { } sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); - config_getlist(config_get_if(), &X2ParamList, X2Params, sizeofArray(X2Params), aprefix); + GET_PARAMS_LIST(X2ParamList, X2Params, X2PARAMS_DESC, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS, aprefix); + AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS, "value of X2ParamList.numelt %d must be lower than X2AP_MAX_NB_ENB_IP_ADDRESS %d value: reconsider to increase X2AP_MAX_NB_ENB_IP_ADDRESS\n", X2ParamList.numelt,X2AP_MAX_NB_ENB_IP_ADDRESS); @@ -2619,14 +2506,14 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { if (IS_SA_MODE(get_softmodem_params())) { sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG); - config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix); + GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr); X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr); } - sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); // NETWORK_INTERFACES - config_get(config_get_if(), NETParams, sizeofArray(NETParams), aprefix); + sprintf(aprefix, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix); X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr); //temp out @@ -2734,28 +2621,22 @@ int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_up ngran_node_t get_node_type(void) { - paramdef_t MacRLC_Params[] = MACRLCPARAMS_DESC; - paramlist_def_t MacRLC_ParamList = {CONFIG_STRING_MACRLC_LIST,NULL,0}; - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; - paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC; - paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0}; - - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); - + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); if (GNBParamList.numelt == 0) // We have no valid configuration, let's return a default return ngran_gNB; - config_getlist(config_get_if(), &MacRLC_ParamList, MacRLC_Params, sizeofArray(MacRLC_Params), NULL); - char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix); - for (int j = 0; j < MacRLC_ParamList.numelt; j++) { + // MAC/RLC params + GET_PARAMS_LIST(MacRLC_ParamList, MacRLC_Params, MACRLCPARAMS_DESC, CONFIG_STRING_MACRLC_LIST, NULL); + for (int j = 0; j < RC.nb_nr_macrlc_inst; j++) { if (strcmp(*(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_N_PREFERENCE_IDX].strptr), "f1") == 0) { return ngran_gNB_DU; // MACRLCs present in config: it must be a DU } } + // E1 params + char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; + sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS_LIST(GNBE1ParamList, GNBE1Params, GNBE1PARAMS_DESC, GNB_CONFIG_STRING_E1_PARAMETERS, aprefix); if (strcmp(*(GNBParamList.paramarray[0][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "f1") == 0) { if ( GNBE1ParamList.paramarray == NULL || GNBE1ParamList.numelt == 0 ) return ngran_gNB_CU; From 34fc1bb2540a2b7f7169e9e0f54619db62cc2fe3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sat, 26 Oct 2024 00:23:08 +0200 Subject: [PATCH 04/48] Set num_nssai to uint16_t in NGAP for consistency with other definitions --- openair2/COMMON/ngap_messages_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 9df2dfaeaa..ad988a6197 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -438,7 +438,7 @@ typedef struct { uint16_t mcc; uint16_t mnc; uint8_t mnc_digit_length; - uint8_t num_nssai; + uint16_t num_nssai; nssai_t s_nssai[8]; } ngap_plmn_t; From 2ee056bf4553aa2505d037a1467aa0f0bf7f6643 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 4 Apr 2025 16:35:58 +0200 Subject: [PATCH 05/48] Add definition for maximum number of slices according to 3GPP specs --- common/platform_constants.h | 2 ++ openair2/COMMON/f1ap_messages_types.h | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/common/platform_constants.h b/common/platform_constants.h index 2f54208306..3b59068a1f 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -80,6 +80,8 @@ #define NB_RAB_MAX 11 /* from LTE_maxDRB in LTE_asn_constant.h */ #define RAB_OFFSET 0x000F +#define MAX_NUM_SLICES 1024 + // RLC Entity #define RLC_TX_MAXSIZE 10000000 #define RLC_RX_MAXSIZE 10000000 diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 53740c1bde..14ad0b5dc7 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -25,6 +25,7 @@ #include #include #include "common/5g_platform_types.h" +#include "common/platform_constants.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -140,7 +141,7 @@ typedef struct f1ap_served_cell_info_t { // Number of slice support items (max 16, could be increased to as much as 1024) uint16_t num_ssi; - nssai_t nssai[16]; + nssai_t nssai[MAX_NUM_SLICES]; f1ap_mode_t mode; union { From c1f225abc13c58df2a2e6e6d7af6560d02139cbc Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 4 Apr 2025 16:36:40 +0200 Subject: [PATCH 06/48] Add set_snssai_config to replace redundant code in gnb_config.c --- openair2/GNB_APP/gnb_config.c | 56 +++++++++++++++-------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 79e92d2a1d..87c2a9bce7 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -98,6 +98,28 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1}; (element)->choice.setup = CALLOC(1, sizeof(*((element)->choice.setup))); \ } while (0) +static uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t k, uint8_t l) +{ + char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; + sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l); + GET_PARAMS_LIST(SNSSAIParamList, + SNSSAIParams, + GNBSNSSAIPARAMS_DESC, + GNB_CONFIG_STRING_SNSSAI_LIST, + snssaistr, + SNSSAIPARAMS_CHECK); + uint16_t num_ssi = SNSSAIParamList.numelt; + AssertFatal(num_ssi < max_num_ssi, "S-NSSAI size %d exceeds the max array size %d", num_ssi, max_num_ssi); + for (int s = 0; s < num_ssi; ++s) { + nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; + // SD is optional + // 0xffffff is "no SD", see 23.003 Sec 28.4.2 + nssai[s].sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr; + AssertFatal(nssai[s].sd <= 0xffffff, "SD cannot be bigger than 0xffffff, but is %d\n", nssai[s].sd); + } + return num_ssi; +} + /** * Allocate memory and initialize ServingCellConfigCommon struct members */ @@ -1238,20 +1260,7 @@ static int read_du_cell_info(configmodule_interface_t *cfg, info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr); // SNSSAI - char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(snssaistr, "%s.[0].%s.[0]", GNB_CONFIG_STRING_GNB_LIST, GNB_CONFIG_STRING_PLMN_LIST); - GET_PARAMS_LIST(SNSSAIParamList, - SNSSAIParams, - GNBSNSSAIPARAMS_DESC, - GNB_CONFIG_STRING_SNSSAI_LIST, - snssaistr, - SNSSAIPARAMS_CHECK); - info->num_ssi = SNSSAIParamList.numelt; - for (int s = 0; s < info->num_ssi; ++s) { - info->nssai[s].sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; - info->nssai[s].sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr; - AssertFatal(info->nssai[s].sd <= 0xffffff, "SD cannot be bigger than 0xffffff, but is %d\n", info->nssai[s].sd); - } + info->num_ssi = set_snssai_config(info->nssai, MAX_NUM_SLICES, 0, 0); return 1; } @@ -2213,15 +2222,6 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt; for (int l = 0; l < PLMNParamList.numelt; ++l) { - char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l); - GET_PARAMS_LIST(SNSSAIParamList, - SNSSAIParams, - GNBSNSSAIPARAMS_DESC, - GNB_CONFIG_STRING_SNSSAI_LIST, - snssaistr, - SNSSAIPARAMS_CHECK); - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; @@ -2231,15 +2231,7 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { "BAD MNC DIGIT LENGTH %d", NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length); - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = SNSSAIParamList.numelt; - for (int s = 0; s < SNSSAIParamList.numelt; ++s) { - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sst = - *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; - // SD is optional - // 0xffffff is "no SD", see 23.003 Sec 28.4.2 - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai[s].sd = - (*SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr & 0xffffff); - } + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = set_snssai_config(NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai, 8, k, l); } sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); GET_PARAMS_LIST(NGParamList, NGParams, GNBNGPARAMS_DESC, GNB_CONFIG_STRING_AMF_IP_ADDRESS, aprefix); From ac3f9f3e328a50316182e05d7aafd2c972f51fa9 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 6 Mar 2025 10:48:08 +0100 Subject: [PATCH 07/48] Introduce platform type plmn_id_t for consistency across the stack * F1AP, NGAP can now use the same struct type * this improves maintainability --- common/5g_platform_types.h | 6 +++ openair2/COMMON/f1ap_messages_types.h | 24 ++++------ openair2/COMMON/ngap_messages_types.h | 4 +- openair2/F1AP/lib/f1ap_interface_management.c | 12 ++--- openair2/F1AP/lib/f1ap_lib_common.c | 2 +- openair2/F1AP/lib/f1ap_lib_common.h | 4 +- openair2/F1AP/tests/f1ap_lib_test.c | 2 +- openair2/GNB_APP/gnb_config.c | 14 +++--- openair2/LAYER2/NR_MAC_gNB/config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 2 +- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 +- openair2/RRC/NR/nr_rrc_config.c | 2 +- openair2/RRC/NR/nr_rrc_config.h | 2 +- openair3/NGAP/ngap_gNB.c | 20 +++++---- openair3/NGAP/ngap_gNB_nas_procedures.c | 45 +++++++++---------- openair3/NGAP/ngap_gNB_nnsf.c | 8 ++-- 16 files changed, 75 insertions(+), 76 deletions(-) diff --git a/common/5g_platform_types.h b/common/5g_platform_types.h index 05fc2be28d..6f055e9305 100644 --- a/common/5g_platform_types.h +++ b/common/5g_platform_types.h @@ -24,6 +24,12 @@ #include +typedef struct plmn_id_s { + uint16_t mcc; + uint16_t mnc; + uint8_t mnc_digit_length; +} plmn_id_t; + typedef struct nssai_s { uint8_t sst; uint32_t sd; diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 14ad0b5dc7..45e5e55120 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -93,12 +93,6 @@ typedef struct f1ap_net_config_t { uint16_t DUport; } f1ap_net_config_t; -typedef struct f1ap_plmn_t { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_digit_length; -} f1ap_plmn_t; - typedef struct f1ap_cp_tnl_s { in_addr_t tl_address; // currently only IPv4 supported uint16_t port; @@ -130,7 +124,7 @@ typedef struct f1ap_tdd_info_t { typedef struct f1ap_served_cell_info_t { // NR CGI - f1ap_plmn_t plmn; + plmn_id_t plmn; uint64_t nr_cellid; // NR Global Cell Id // NR Physical Cell Ids @@ -193,7 +187,7 @@ typedef struct f1ap_sib_msg_t { } f1ap_sib_msg_t; typedef struct served_cells_to_activate_s { - f1ap_plmn_t plmn; + plmn_id_t plmn; // NR Global Cell Id uint64_t nr_cellid; /// NRPCI [int 0..1007] @@ -240,7 +234,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s { uint16_t num_cells_failed_to_be_activated; struct { // NR CGI - f1ap_plmn_t plmn; + plmn_id_t plmn; uint64_t nr_cellid; uint16_t cause; } cells_failed_to_be_activated[F1AP_MAX_NB_CELLS]; @@ -257,7 +251,7 @@ typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s { struct { uint32_t gNB_CU_ue_id; // NR CGI - f1ap_plmn_t ue_plmn; + plmn_id_t ue_plmn; uint64_t ue_nr_cellid; } dedicatedSIDeliveryNeededUEs[F1AP_MAX_NO_UE_ID]; } f1ap_gnb_cu_configuration_update_acknowledge_t; @@ -284,7 +278,7 @@ typedef struct f1ap_gnb_du_configuration_update_s { /// int cells_to_modify uint16_t num_cells_to_modify; struct { - f1ap_plmn_t old_plmn; + plmn_id_t old_plmn; uint64_t old_nr_cellid; // NR Global Cell Id f1ap_served_cell_info_t info; f1ap_gnb_du_system_info_t *sys_info; @@ -294,7 +288,7 @@ typedef struct f1ap_gnb_du_configuration_update_s { uint16_t num_cells_to_delete; struct { // NR CGI - f1ap_plmn_t plmn; + plmn_id_t plmn; uint64_t nr_cellid; // NR Global Cell Id } cell_to_delete[F1AP_MAX_NB_CELLS]; /// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1) @@ -334,7 +328,7 @@ typedef struct f1ap_dl_rrc_message_s { typedef struct f1ap_initial_ul_rrc_message_s { uint32_t gNB_DU_ue_id; - f1ap_plmn_t plmn; + plmn_id_t plmn; /// nr cell id uint64_t nr_cellid; /// crnti @@ -476,7 +470,7 @@ typedef struct f1ap_ue_context_setup_s { uint32_t gNB_CU_ue_id; uint32_t gNB_DU_ue_id; // SpCell Info - f1ap_plmn_t plmn; + plmn_id_t plmn; uint64_t nr_cellid; uint8_t servCellIndex; uint8_t *cellULConfigured; @@ -550,7 +544,7 @@ typedef struct f1ap_paging_ind_s { uint16_t ueidentityindexvalue; uint64_t fiveg_s_tmsi; uint8_t fiveg_s_tmsi_length; - f1ap_plmn_t plmn; + plmn_id_t plmn; uint64_t nr_cellid; uint8_t paging_drx; } f1ap_paging_ind_t; diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index ad988a6197..588d7c5cba 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -435,9 +435,7 @@ typedef enum ngap_paging_ind_present_s { } ngap_paging_ind_present_t; typedef struct { - uint16_t mcc; - uint16_t mnc; - uint8_t mnc_digit_length; + plmn_id_t plmn; uint16_t num_nssai; nssai_t s_nssai[8]; } ngap_plmn_t; diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index 5767a06d95..2ad4ab6467 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -1423,7 +1423,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura &served_cells_to_modify_item_ies->value.choice.Served_Cells_To_Modify_Item; F1AP_NRCGI_t *oldNRCGI = &served_cells_to_modify_item->oldNRCGI; - const f1ap_plmn_t *old_plmn = &msg->cell_to_modify[i].old_plmn; + const plmn_id_t *old_plmn = &msg->cell_to_modify[i].old_plmn; MCC_MNC_TO_PLMNID(old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length, &oldNRCGI->pLMN_Identity); NR_CELL_ID_TO_BIT_STRING(msg->cell_to_modify[i].old_nr_cellid, &oldNRCGI->nRCellIdentity); @@ -1449,7 +1449,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura F1AP_Served_Cells_To_Delete_Item_t *served_cells_to_delete_item = &served_cells_to_delete_item_ies->value.choice.Served_Cells_To_Delete_Item; F1AP_NRCGI_t *oldNRCGI = &served_cells_to_delete_item->oldNRCGI; - const f1ap_plmn_t *plmn = &msg->cell_to_delete[i].plmn; + const plmn_id_t *plmn = &msg->cell_to_delete[i].plmn; MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(oldNRCGI->pLMN_Identity)); NR_CELL_ID_TO_BIT_STRING(msg->cell_to_delete[i].nr_cellid, &(oldNRCGI->nRCellIdentity)); } @@ -1519,7 +1519,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du ->value.choice.Served_Cells_To_Modify_Item; /* Old NR CGI (M) */ F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; - f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn; + plmn_id_t *old_plmn = &out->cell_to_modify[i].old_plmn; PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length); /* Old NR CGI Cell ID */ BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid); @@ -1542,7 +1542,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du &((F1AP_Served_Cells_To_Delete_ItemIEs_t *)ie->value.choice.Served_Cells_To_Delete_List.list.array[i]) ->value.choice.Served_Cells_To_Delete_Item; F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; - f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn; + plmn_id_t *plmn = &out->cell_to_delete[i].plmn; /* Old NR CGI (M) */ PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); // NR cellID @@ -1833,7 +1833,7 @@ F1AP_F1AP_PDU_t *encode_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_ p1->cause.present = F1AP_Cause_PR_radioNetwork; p1->cause.choice.radioNetwork = msg->cells_failed_to_be_activated[i].cause; // NR CGI (M) - const f1ap_plmn_t *plmn = &msg->cells_failed_to_be_activated[i].plmn; + const plmn_id_t *plmn = &msg->cells_failed_to_be_activated[i].plmn; MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(p1->nRCGI.pLMN_Identity)); printf("plmn->mcc %d %d %d %ld \n", p1->nRCGI.pLMN_Identity.buf[0], p1->nRCGI.pLMN_Identity.buf[1], p1->nRCGI.pLMN_Identity.buf[2], p1->nRCGI.pLMN_Identity.size); @@ -1880,7 +1880,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, (F1AP_Cells_Failed_to_be_Activated_List_ItemIEs_t *)cell_fail_list->list.array[j]; const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item; // NR CGI (M) - f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn; + plmn_id_t *plmn = &out->cells_failed_to_be_activated[j].plmn; PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid); // Cause (M) diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index 3673fa3cc7..e32f7e6779 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -27,7 +27,7 @@ #include "common/utils/assertions.h" #include "common/utils/utils.h" -bool eq_f1ap_plmn(const f1ap_plmn_t *a, const f1ap_plmn_t *b) +bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b) { _F1_EQ_CHECK_INT(a->mcc, b->mcc); _F1_EQ_CHECK_INT(a->mnc, b->mnc); diff --git a/openair2/F1AP/lib/f1ap_lib_common.h b/openair2/F1AP/lib/f1ap_lib_common.h index 502200d9df..8a3ddfba4a 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.h +++ b/openair2/F1AP/lib/f1ap_lib_common.h @@ -26,6 +26,7 @@ #include #include #include "openair3/UTILS/conversions.h" +#include "common/5g_platform_types.h" #include "F1AP_Cause.h" #include "f1ap_messages_types.h" @@ -71,8 +72,7 @@ } \ } while (0) -struct f1ap_plmn_t; -bool eq_f1ap_plmn(const struct f1ap_plmn_t *a, const struct f1ap_plmn_t *b); +bool eq_f1ap_plmn(const plmn_id_t *a, const plmn_id_t *b); struct f1ap_served_cell_info_t; bool eq_f1ap_cell_info(const struct f1ap_served_cell_info_t *a, const struct f1ap_served_cell_info_t *b); struct f1ap_gnb_du_system_info_t; diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 29d4b625ed..aa770f47ea 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -80,7 +80,7 @@ static void f1ap_msg_free(F1AP_F1AP_PDU_t *pdu) */ static void test_initial_ul_rrc_message_transfer(void) { - f1ap_plmn_t plmn = { .mcc = 208, .mnc = 95, .mnc_digit_length = 2 }; + plmn_id_t plmn = {.mcc = 208, .mnc = 95, .mnc_digit_length = 2}; uint8_t rrc[] = "RRC Container"; uint8_t du2cu[] = "DU2CU Container"; f1ap_initial_ul_rrc_message_t orig = { diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 87c2a9bce7..6388a43d34 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2222,14 +2222,14 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt; for (int l = 0; l < PLMNParamList.numelt; ++l) { - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; NGAP_REGISTER_GNB_REQ (msg_p).default_drx = 0; - AssertFatal((NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 2) - || (NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length == 3), + AssertFatal((NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length == 2) + || (NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length == 3), "BAD MNC DIGIT LENGTH %d", - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].mnc_digit_length); + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length); NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = set_snssai_config(NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai, 8, k, l); } @@ -2549,7 +2549,7 @@ void wait_f1_setup_response(void) } NR_SCHED_UNLOCK(&mac->sched_lock); } -static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn) +static bool check_plmn_identity(const plmn_id_t *check_plmn, const plmn_id_t *plmn) { return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc; } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 26319a6049..90891919db 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -958,7 +958,7 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac, mac->mac_rrc.gnb_du_configuration_update(&update); } -void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const f1ap_plmn_t *plmn, uint64_t cellID, int tac) +void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac) { AssertFatal(IS_SA_MODE(get_softmodem_params()), "error: SIB1 only applicable for SA\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index c8b809a8cb..dad0eb570c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -54,7 +54,7 @@ void mac_top_init_gNB(ngran_node_t node_type, void nr_mac_send_f1_setup_req(void); void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *mac_config); -void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const f1ap_plmn_t *plmn, uint64_t cellID, int tac); +void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac); bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_sib_msg_t cu_sib[num_cu_sib]); bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index ca07d1555a..32943097ba 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -94,7 +94,7 @@ bool DURecvCb(protocol_ctxt_t *ctxt_pP, return true; } -static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn) +static bool check_plmn_identity(const plmn_id_t *check_plmn, const plmn_id_t *plmn) { return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc; } diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index d377b2aff3..8d99486c34 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -2463,7 +2463,7 @@ static bool is_ntn_band(int band) } NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, - const f1ap_plmn_t *plmn, + const plmn_id_t *plmn, uint64_t cellID, int tac, const nr_mac_config_t *mac_config) diff --git a/openair2/RRC/NR/nr_rrc_config.h b/openair2/RRC/NR/nr_rrc_config.h index d56db4b0cf..c4189dcb21 100644 --- a/openair2/RRC/NR/nr_rrc_config.h +++ b/openair2/RRC/NR/nr_rrc_config.h @@ -79,7 +79,7 @@ void free_MeasurementTimingConfiguration(struct NR_MeasurementTimingConfiguratio #define NR_MAX_SIB_LENGTH 2976 // 3GPP TS 38.331 section 5.2.1 NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, - const f1ap_plmn_t *plmn, + const plmn_id_t *plmn, uint64_t cellID, int tac, const nr_mac_config_t *mac_config); diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index de466daddf..488345261d 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -158,8 +158,8 @@ void ngap_gNB_handle_register_gNB(instance_t instance, ngap_register_gnb_req_t * DevCheck(new_instance->tac == ngap_register_gNB->tac, new_instance->tac, ngap_register_gNB->tac, 0); for (int i = 0; i < new_instance->num_plmn; i++) { - ngap_plmn_t *exist_plmn = &new_instance->plmn[i]; - ngap_plmn_t *new_plmn = &ngap_register_gNB->plmn[i]; + plmn_id_t *exist_plmn = &new_instance->plmn[i].plmn; + plmn_id_t *new_plmn = &ngap_register_gNB->plmn[i].plmn; DevCheck(exist_plmn->mcc == new_plmn->mcc, exist_plmn->mcc, new_plmn->mcc, 0); DevCheck(exist_plmn->mnc == new_plmn->mnc, exist_plmn->mnc, new_plmn->mnc, 0); DevCheck(exist_plmn->mnc_digit_length == new_plmn->mnc_digit_length, @@ -185,9 +185,9 @@ void ngap_gNB_handle_register_gNB(instance_t instance, ngap_register_gnb_req_t * sizeof(ngap_register_gNB->gnb_ip_address)); for (int i = 0; i < ngap_register_gNB->num_plmn; i++) { - new_instance->plmn[i].mcc = ngap_register_gNB->plmn[i].mcc; - new_instance->plmn[i].mnc = ngap_register_gNB->plmn[i].mnc; - new_instance->plmn[i].mnc_digit_length = ngap_register_gNB->plmn[i].mnc_digit_length; + new_instance->plmn[i].plmn.mcc = ngap_register_gNB->plmn[i].plmn.mcc; + new_instance->plmn[i].plmn.mnc = ngap_register_gNB->plmn[i].plmn.mnc; + new_instance->plmn[i].plmn.mnc_digit_length = ngap_register_gNB->plmn[i].plmn.mnc_digit_length; new_instance->plmn[i].num_nssai = ngap_register_gNB->plmn[i].num_nssai; memcpy(&new_instance->plmn[i].s_nssai, &ngap_register_gNB->plmn[i].s_nssai, sizeof(ngap_register_gNB->plmn[i].s_nssai)); @@ -421,9 +421,10 @@ static int ngap_gNB_generate_ng_setup_request( ie->value.present = NGAP_NGSetupRequestIEs__value_PR_GlobalRANNodeID; ie->value.choice.GlobalRANNodeID.present = NGAP_GlobalRANNodeID_PR_globalGNB_ID; ie->value.choice.GlobalRANNodeID.choice.globalGNB_ID = CALLOC(1, sizeof(struct NGAP_GlobalGNB_ID)); - MCC_MNC_TO_PLMNID(instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[0]].mcc, - instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[0]].mnc, - instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[0]].mnc_digit_length, + plmn_id_t *plmn_id = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[0]].plmn; + MCC_MNC_TO_PLMNID(plmn_id->mcc, + plmn_id->mnc, + plmn_id->mnc_digit_length, &(ie->value.choice.GlobalRANNodeID.choice.globalGNB_ID->pLMNIdentity)); ie->value.choice.GlobalRANNodeID.choice.globalGNB_ID->gNB_ID.present = NGAP_GNB_ID_PR_gNB_ID; MACRO_GNB_ID_TO_BIT_STRING(instance_p->gNB_id, @@ -458,7 +459,8 @@ static int ngap_gNB_generate_ng_setup_request( for (int i = 0; i < ngap_amf_data_p->broadcast_plmn_num; ++i) { plmn = (NGAP_BroadcastPLMNItem_t *)calloc(1, sizeof(NGAP_BroadcastPLMNItem_t)); ngap_plmn_t *plmn_req = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]]; - MCC_MNC_TO_TBCD(plmn_req->mcc, plmn_req->mnc, plmn_req->mnc_digit_length, &plmn->pLMNIdentity); + plmn_id_t *plmn_id = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]].plmn; + MCC_MNC_TO_TBCD(plmn_id->mcc, plmn_id->mnc, plmn_id->mnc_digit_length, &plmn->pLMNIdentity); for (int si = 0; si < plmn_req->num_nssai; si++) { ssi = (NGAP_SliceSupportItem_t *)calloc(1, sizeof(NGAP_SliceSupportItem_t)); diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 83c004fc74..a86ba83442 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -123,15 +123,14 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf amf_desc_p = ngap_gNB_nnsf_select_amf_by_amf_setid(instance_p, UEfirstReq->establishment_cause, UEfirstReq->selected_plmn_identity, UEfirstReq->ue_identity.s_tmsi.amf_set_id); if (amf_desc_p) { - NGAP_INFO( - "UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", - UEfirstReq->gNB_ue_ngap_id, - amf_desc_p->amf_name, - amf_desc_p->assoc_id, - UEfirstReq->ue_identity.s_tmsi.amf_set_id, - UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].mnc); + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through S-TMSI AMFSI %d and selected PLMN Identity index %d MCC %d MNC %d\n", + UEfirstReq->gNB_ue_ngap_id, + amf_desc_p->amf_name, + amf_desc_p->assoc_id, + UEfirstReq->ue_identity.s_tmsi.amf_set_id, + UEfirstReq->selected_plmn_identity, + instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, + instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); } } } @@ -148,8 +147,8 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf amf_desc_p->amf_name, amf_desc_p->assoc_id, UEfirstReq->selected_plmn_identity, - instance_p->plmn[UEfirstReq->selected_plmn_identity].mcc, - instance_p->plmn[UEfirstReq->selected_plmn_identity].mnc); + instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mcc, + instance_p->plmn[UEfirstReq->selected_plmn_identity].plmn.mnc); } } @@ -222,16 +221,16 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf MACRO_GNB_ID_TO_CELL_IDENTITY(instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(instance_p->plmn[ue_desc_p->selected_plmn_identity].mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].mnc_digit_length, + MCC_MNC_TO_TBCD(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, + instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, + instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* Set TAI */ INT24_TO_OCTET_STRING(instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(instance_p->plmn[ue_desc_p->selected_plmn_identity].mcc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].mnc, - instance_p->plmn[ue_desc_p->selected_plmn_identity].mnc_digit_length, + MCC_MNC_TO_PLMNID(instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mcc, + instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc, + instance_p->plmn[ue_desc_p->selected_plmn_identity].plmn.mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } @@ -454,16 +453,16 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_ MACRO_GNB_ID_TO_CELL_IDENTITY(ngap_gNB_instance_p->gNB_id, 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - MCC_MNC_TO_TBCD(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mnc_digit_length, + MCC_MNC_TO_TBCD(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, + ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, + ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* Set TAI */ INT24_TO_OCTET_STRING(ngap_gNB_instance_p->tac, &userinfo_nr_p->tAI.tAC); - MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mcc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mnc, - ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].mnc_digit_length, + MCC_MNC_TO_PLMNID(ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mcc, + ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc, + ngap_gNB_instance_p->plmn[ue_context_p->selected_plmn_identity].plmn.mnc_digit_length, &userinfo_nr_p->tAI.pLMNIdentity); } if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) { diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index a04474669c..e9f23c6401 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -135,8 +135,8 @@ ngap_gNB_nnsf_select_amf_by_plmn_id(ngap_gNB_instance_t *instance_p, /* Looking for served GUAMI PLMN Identity selected matching the one provided by the UE */ STAILQ_FOREACH(guami_p, &amf_data_p->served_guami, next) { STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].mnc)) { + if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) + && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { break; } } @@ -207,8 +207,8 @@ ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t *instance_p, struct plmn_identity_s *served_plmn_p = NULL; STAILQ_FOREACH(served_plmn_p, &guami_p->served_plmns, next) { - if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].mcc) - && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].mnc)) { + if ((served_plmn_p->mcc == instance_p->plmn[selected_plmn_identity].plmn.mcc) + && (served_plmn_p->mnc == instance_p->plmn[selected_plmn_identity].plmn.mnc)) { break; } } From 1cdd684e244a68c64cf9966410410b6ac52635d8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sat, 26 Oct 2024 11:18:08 +0200 Subject: [PATCH 08/48] Use plmn_id_t in RRC struct --- executables/nr-softmodem.c | 6 +++--- openair2/COMMON/rrc_messages_types.h | 4 +--- openair2/GNB_APP/gnb_config.c | 13 ++++++------- openair2/RRC/NR/rrc_gNB.c | 12 ++++++------ openair2/RRC/NR/rrc_gNB_NGAP.c | 16 ++++++++-------- openair2/RRC/NR/rrc_gNB_cuup.c | 6 +++--- openair2/RRC/NR/rrc_gNB_du.c | 9 ++++----- openair2/RRC/NR/rrc_gNB_mobility.c | 4 +--- 8 files changed, 32 insertions(+), 38 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 4f9ae49c42..a8ab55087a 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -520,9 +520,9 @@ static void initialize_agent(ngran_node_t node_type, e2_agent_args_t oai_args) const gNB_RRC_INST* rrc = RC.nrrrc[0]; assert(rrc != NULL && "rrc cannot be NULL"); - const int mcc = rrc->configuration.mcc[0]; - const int mnc = rrc->configuration.mnc[0]; - const int mnc_digit_len = rrc->configuration.mnc_digit_length[0]; + const int mcc = rrc->configuration.plmn[0].mcc; + const int mnc = rrc->configuration.plmn[0].mnc; + const int mnc_digit_len = rrc->configuration.plmn[0].mnc_digit_length; // const ngran_node_t node_type = rrc->node_type; int nb_id = 0; int cu_du_id = 0; diff --git a/openair2/COMMON/rrc_messages_types.h b/openair2/COMMON/rrc_messages_types.h index 2446bbe4b3..5d32c96074 100644 --- a/openair2/COMMON/rrc_messages_types.h +++ b/openair2/COMMON/rrc_messages_types.h @@ -416,9 +416,7 @@ typedef struct NbIoTRrcConfigurationReq_s { // gNB: GNB_APP -> RRC messages typedef struct NRRrcConfigurationReq_s { uint32_t tac; - uint16_t mcc[PLMN_LIST_MAX_SIZE]; - uint16_t mnc[PLMN_LIST_MAX_SIZE]; - uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE]; + plmn_id_t plmn[PLMN_LIST_MAX_SIZE]; uint8_t num_plmn; bool um_on_default_drb; diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 6388a43d34..ca9e286fc0 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2116,13 +2116,12 @@ gNB_RRC_INST *RCconfig_NRRRC() nrrrc_config.num_plmn = PLMNParamList.numelt; for (int l = 0; l < PLMNParamList.numelt; ++l) { - - nrrrc_config.mcc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - nrrrc_config.mnc[l] = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - nrrrc_config.mnc_digit_length[l] = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; - AssertFatal((nrrrc_config.mnc_digit_length[l] == 2) || - (nrrrc_config.mnc_digit_length[l] == 3),"BAD MNC DIGIT LENGTH %d", - nrrrc_config.mnc_digit_length[l]); + nrrrc_config.plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + nrrrc_config.plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; + nrrrc_config.plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; + AssertFatal((nrrrc_config.plmn[l].mnc_digit_length == 2) || (nrrrc_config.plmn[l].mnc_digit_length == 3), + "BAD MNC DIGIT LENGTH %d", + nrrrc_config.plmn[l].mnc_digit_length); } nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr; LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled"); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b93e08e79f..f3686cfc1e 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2894,9 +2894,9 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, f1ap_ue_context_setup_t ue_context_setup_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.mcc[0], - .plmn.mnc = rrc->configuration.mnc[0], - .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .plmn.mcc = rrc->configuration.plmn[0].mcc, + .plmn.mnc = rrc->configuration.plmn[0].mnc, + .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, .nr_cellid = rrc->nr_cellid, .servCellId = 0, /* TODO: correct value? */ .srbs_to_be_setup_length = nb_srb, @@ -2938,9 +2938,9 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, f1ap_ue_context_modif_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.mcc[0], - .plmn.mnc = rrc->configuration.mnc[0], - .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .plmn.mcc = rrc->configuration.plmn[0].mcc, + .plmn.mnc = rrc->configuration.plmn[0].mnc, + .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, .nr_cellid = rrc->nr_cellid, .servCellId = 0, /* TODO: correct value? */ .drbs_to_be_setup_length = n_drbs, diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 846889f841..fadbea4825 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1454,18 +1454,18 @@ int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance) for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) { LOG_I(NR_RRC,"[gNB %ld] In NGAP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc, NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, NGAP_PAGING_IND(msg_p).tac[tai_size]); - - for (uint8_t j = 0; j < RC.nrrrc[instance]->configuration.num_plmn; j++) { - if (RC.nrrrc[instance]->configuration.mcc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc - && RC.nrrrc[instance]->configuration.mnc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc - && RC.nrrrc[instance]->configuration.tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) { + gNB_RrcConfigurationReq *req = &RC.nrrrc[instance]->configuration; + for (uint8_t j = 0; j < req->num_plmn; j++) { + plmn_id_t *plmn = &req->plmn[j]; + if (plmn->mcc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc + && plmn->mnc == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc && req->tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) { for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { AssertFatal(false, "to be implemented properly\n"); if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) { MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_PAGING_IND); - F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.mcc[0]; - F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.mnc[0]; - F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.mnc_digit_length[0]; + F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.plmn[0].mcc; + F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.plmn[0].mnc; + F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.plmn[0].mnc_digit_length; F1AP_PAGING_IND (m).nr_cellid = RC.nrrrc[j]->nr_cellid; F1AP_PAGING_IND (m).ueidentityindexvalue = (uint16_t)(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi%1024); F1AP_PAGING_IND (m).fiveg_s_tmsi = NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi; diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index c065299824..1e3df71822 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -263,13 +263,13 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t * for (int i = 0; i < req->supported_plmns; i++) { const PLMN_ID_t *id = &req->plmn[i].id; - if (rrc->configuration.mcc[i] != id->mcc || rrc->configuration.mnc[i] != id->mnc) { + if (rrc->configuration.plmn[i].mcc != id->mcc || rrc->configuration.plmn[i].mnc != id->mnc) { LOG_E(NR_RRC, "PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n", id->mcc, id->mnc, - rrc->configuration.mcc[i], - rrc->configuration.mnc[i]); + rrc->configuration.plmn[i].mcc, + rrc->configuration.plmn[i].mnc); e1ap_cause_t cause = { .type = E1AP_CAUSE_RADIO_NETWORK, .value = E1AP_RADIO_CAUSE_OTHER}; e1ap_setup_failure(assoc_id, req->transac_id, cause); return -1; diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index f34ca13e6c..3df1109778 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -99,8 +99,7 @@ static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell { const gNB_RrcConfigurationReq *conf = &rrc->configuration; return conf->num_plmn == 1 // F1 supports only one - && conf->mcc[0] == info->plmn.mcc - && conf->mnc[0] == info->plmn.mnc; + && conf->plmn[0].mcc == info->plmn.mcc && conf->plmn[0].mnc == info->plmn.mnc; } static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t **mib, NR_SIB1_t **sib1) @@ -309,9 +308,9 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) if (!rrc_gNB_plmn_matches(rrc, cell_info)) { LOG_E(NR_RRC, "PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n", - rrc->configuration.mcc[0], - rrc->configuration.mnc_digit_length[0], - rrc->configuration.mnc[0], + rrc->configuration.plmn[0].mcc, + rrc->configuration.plmn[0].mnc_digit_length, + rrc->configuration.plmn[0].mnc, cell_info->plmn.mcc, cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index db1c4bb904..be12f2e562 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -227,9 +227,7 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ f1ap_ue_context_modif_req_t ue_context_modif_req = { .gNB_CU_ue_id = ue->rrc_ue_id, .gNB_DU_ue_id = ue_data.secondary_ue, - .plmn.mcc = rrc->configuration.mcc[0], - .plmn.mnc = rrc->configuration.mnc[0], - .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], + .plmn = rrc->configuration.plmn[0], .nr_cellid = rrc->nr_cellid, // TODO target cell ID .servCellId = 0, // TODO: correct value? .ReconfigComplOutcome = RRCreconf_success, From 2e7fa8e8b1523db1ee8926bb6ae79747f0f98093 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sat, 26 Oct 2024 12:00:05 +0200 Subject: [PATCH 09/48] New function to set PLMN in gNB config * reduce redundant code repeated in multiple places in the file --- openair2/GNB_APP/gnb_config.c | 104 +++++++++++++--------------------- 1 file changed, 39 insertions(+), 65 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index ca9e286fc0..dd96cb8a74 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -120,6 +120,23 @@ static uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t return num_ssi; } +static uint8_t set_plmn_config(plmn_id_t *p, uint8_t idx) +{ + char gnbpath[MAX_OPTNAME_SIZE * 2 + 8]; + snprintf(gnbpath, sizeof(gnbpath), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, idx); + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, gnbpath, PLMNPARAMS_CHECK); + uint8_t num_plmn = PLMNParamList.numelt; + AssertFatal(num_plmn >= 1 && num_plmn <= 6, "The number of PLMN IDs must be in [1,6], but is %d\n", num_plmn); + for (int l = 0; l < num_plmn; ++l) { + plmn_id_t *plmn = &p[l]; + plmn->mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + plmn->mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; + plmn->mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; + AssertFatal((plmn->mnc_digit_length == 2) || (plmn->mnc_digit_length == 3), "BAD MNC DIGIT LENGTH %d", plmn->mnc_digit_length); + } + return num_plmn; +} + /** * Allocate memory and initialize ServingCellConfigCommon struct members */ @@ -1229,13 +1246,6 @@ static int read_du_cell_info(configmodule_interface_t *cfg, GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0], *GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr); - char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - /* map parameter checking array instances to parameter definition array instances */ - snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); - AssertFatal(PLMNParamList.numelt > 0, "need to have a PLMN in PLMN section\n"); - AssertFatal(PLMNParamList.numelt == 1, "cannot have more than one PLMN\n"); - // if fronthaul is F1, require gNB_DU_ID, else use gNB_ID if (separate_du) { AssertFatal(config_isparamset(GNBParamList.paramarray[0], GNB_GNB_DU_ID_IDX), "%s is not defined in configuration file\n", GNB_CONFIG_STRING_GNB_DU_ID); @@ -1251,12 +1261,11 @@ static int read_du_cell_info(configmodule_interface_t *cfg, info->tac = malloc(sizeof(*info->tac)); AssertFatal(info->tac != NULL, "out of memory\n"); *info->tac = *GNBParamList.paramarray[0][GNB_TRACKING_AREA_CODE_IDX].uptr; - info->plmn.mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - info->plmn.mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - info->plmn.mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr; - AssertFatal((info->plmn.mnc_digit_length == 2) || (info->plmn.mnc_digit_length == 3), - "BAD MNC DIGIT LENGTH %d", - info->plmn.mnc_digit_length); + + // PLMN + plmn_id_t p[PLMN_LIST_MAX_SIZE] = {0}; + set_plmn_config(p, 0); + info->plmn = p[0]; info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr); // SNSSAI @@ -2104,25 +2113,7 @@ gNB_RRC_INST *RCconfig_NRRRC() " tracking_area_code = 1; // no string!!\n" " plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n"); - // PLMN params - char gnbpath[MAX_OPTNAME_SIZE + 8]; - sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); - GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, gnbpath, PLMNPARAMS_CHECK); - - if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) - AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", - PLMNParamList.numelt); - - nrrrc_config.num_plmn = PLMNParamList.numelt; - - for (int l = 0; l < PLMNParamList.numelt; ++l) { - nrrrc_config.plmn[l].mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - nrrrc_config.plmn[l].mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - nrrrc_config.plmn[l].mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; - AssertFatal((nrrrc_config.plmn[l].mnc_digit_length == 2) || (nrrrc_config.plmn[l].mnc_digit_length == 3), - "BAD MNC DIGIT LENGTH %d", - nrrrc_config.plmn[l].mnc_digit_length); - } + nrrrc_config.num_plmn = set_plmn_config(nrrrc_config.plmn, k); nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr; LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled"); nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr; @@ -2210,28 +2201,16 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { "to\n" " tracking_area_code = 1; // no string!!\n" " plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } )\n"); - // PLMN params - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); - - if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) - AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", - PLMNParamList.numelt); - - NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = PLMNParamList.numelt; - - for (int l = 0; l < PLMNParamList.numelt; ++l) { - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mcc = *PLMNParamList.paramarray[l][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc = *PLMNParamList.paramarray[l][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length = *PLMNParamList.paramarray[l][GNB_MNC_DIGIT_LENGTH].u8ptr; - NGAP_REGISTER_GNB_REQ (msg_p).default_drx = 0; - AssertFatal((NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length == 2) - || (NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length == 3), - "BAD MNC DIGIT LENGTH %d", - NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn.mnc_digit_length); - + // PLMN + plmn_id_t p[PLMN_LIST_MAX_SIZE] = {0}; + NGAP_REGISTER_GNB_REQ(msg_p).num_plmn = set_plmn_config(p, 0); + for (int l = 0; l < NGAP_REGISTER_GNB_REQ(msg_p).num_plmn; ++l) { + NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].plmn = p[l]; + // SNSSAI NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].num_nssai = set_snssai_config(NGAP_REGISTER_GNB_REQ(msg_p).plmn[l].s_nssai, 8, k, l); } + NGAP_REGISTER_GNB_REQ(msg_p).default_drx = 0; + // NG sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); GET_PARAMS_LIST(NGParamList, NGParams, GNBNGPARAMS_DESC, GNB_CONFIG_STRING_AMF_IP_ADDRESS, aprefix); NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0; @@ -2387,10 +2366,6 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[j], *(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)) == 0) { /* map parameter checking array instances to parameter definition array instances */ - char aprefix[MAX_OPTNAME_SIZE * 80 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); - GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); - char* gnb_ipv4_address_for_NGU = NULL; uint32_t gnb_port_for_NGU = 0; char* gnb_ipv4_address_for_S1U = NULL; @@ -2410,21 +2385,20 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ (msg_p).eNB_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)); X2AP_REGISTER_ENB_REQ (msg_p).tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr; - if (PLMNParamList.numelt < 1 || PLMNParamList.numelt > 6) - AssertFatal(0, "The number of PLMN IDs must be in [1,6], but is %d\n", - PLMNParamList.numelt); - - if (PLMNParamList.numelt > 1) + // PLMN + plmn_id_t p[PLMN_LIST_MAX_SIZE]; + uint8_t num_plmn = set_plmn_config(p, k); + if (num_plmn > 1) LOG_W(X2AP, "X2AP currently handles only one PLMN, ignoring the others!\n"); - - X2AP_REGISTER_ENB_REQ (msg_p).mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - X2AP_REGISTER_ENB_REQ (msg_p).mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr; - X2AP_REGISTER_ENB_REQ (msg_p).mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr; + X2AP_REGISTER_ENB_REQ(msg_p).mcc = p[0].mcc; + X2AP_REGISTER_ENB_REQ(msg_p).mnc = p[0].mnc; + X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length = p[0].mnc_digit_length; AssertFatal(X2AP_REGISTER_ENB_REQ(msg_p).mnc_digit_length == 3 || X2AP_REGISTER_ENB_REQ(msg_p).mnc < 100, "MNC %d cannot be encoded in two digits as requested (change mnc_digit_length to 3)\n", X2AP_REGISTER_ENB_REQ(msg_p).mnc); + char aprefix[MAX_OPTNAME_SIZE * 80 + 8]; sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); if (SCCsParamList.numelt > 0) { From 7c0dc930871ded58afc13023c59e8f0d900f2b3b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Sat, 26 Oct 2024 12:51:10 +0200 Subject: [PATCH 10/48] Add function to set antenna ports in gNB config * reduce redundant code --- openair2/GNB_APP/gnb_config.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index dd96cb8a74..650fbdc847 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -993,6 +993,13 @@ static int get_prb_blacklist(uint8_t instance, uint16_t *prbbl) return num_prbbl; } +static void set_antenna_ports(paramlist_def_t *p, int *N1, int *N2, int *XP) +{ + *N1 = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; + *N2 = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr; + *XP = *p->paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr; +} + void RCconfig_NR_L1(void) { LOG_I(NR_PHY, "Initializing NR L1: RC.nb_nr_L1_inst = %d\n", RC.nb_nr_L1_inst); @@ -1006,9 +1013,6 @@ void RCconfig_NR_L1(void) int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs > 0, "Failed to parse config file, no GNBs found in field %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS); GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); - int N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; - int N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr; - int XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr; // PRB Blacklist uint16_t prbbl[MAX_BWP_SIZE] = {0}; @@ -1020,9 +1024,7 @@ void RCconfig_NR_L1(void) } // Antenna ports - gNB->ap_N1 = N1; - gNB->ap_N2 = N2; - gNB->ap_XP = XP; + set_antenna_ports(&GNBParamList, &gNB->ap_N1, &gNB->ap_N2, &gNB->ap_XP); } // L1 params @@ -1461,9 +1463,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) // MAC / RLC GET_PARAMS_LIST(MacRLC_ParamList, MacRLC_Params, MACRLCPARAMS_DESC, CONFIG_STRING_MACRLC_LIST, NULL, MACRLCPARAMS_CHECK); nr_mac_config_t config = {0}; - config.pdsch_AntennaPorts.N1 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N1_IDX].iptr; - config.pdsch_AntennaPorts.N2 = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_N2_IDX].iptr; - config.pdsch_AntennaPorts.XP = *GNBParamList.paramarray[0][GNB_PDSCH_ANTENNAPORTS_XP_IDX].iptr; + nr_pdsch_AntennaPorts_t *p = &config.pdsch_AntennaPorts; + set_antenna_ports(&GNBParamList, &p->N1, &p->N2, &p->XP); config.pusch_AntennaPorts = *GNBParamList.paramarray[0][GNB_PUSCH_ANTENNAPORTS_IDX].iptr; LOG_I(GNB_APP, "pdsch_AntennaPorts N1 %d N2 %d XP %d pusch_AntennaPorts %d\n", From 1893974d1dbacce5bd9d5b8d280406742a0bc5d5 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 22 Nov 2024 15:24:14 +0100 Subject: [PATCH 11/48] Set defint64val in long conf params --- openair2/GNB_APP/RRC_nr_paramsvalues.h | 42 +++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/openair2/GNB_APP/RRC_nr_paramsvalues.h b/openair2/GNB_APP/RRC_nr_paramsvalues.h index 10af856770..c7b74be8b0 100644 --- a/openair2/GNB_APP/RRC_nr_paramsvalues.h +++ b/openair2/GNB_APP/RRC_nr_paramsvalues.h @@ -224,7 +224,7 @@ {GNB_CONFIG_STRING_PRACHMSG1FDM,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FDM,.defint64val=NR_RACH_ConfigGeneric__msg1_FDM_one,TYPE_INT64,0/*72*/},\ {GNB_CONFIG_STRING_PRACHMSG1FREQUENCYSTART,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.msg1_FrequencyStart,.defint64val=0,TYPE_INT64,0/*73*/},\ {GNB_CONFIG_STRING_ZEROCORRELATIONZONECONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.zeroCorrelationZoneConfig,.defint64val=13,TYPE_INT64,0/*74*/},\ -{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,.defintval=-118,TYPE_INT64,0/*75*/},\ +{GNB_CONFIG_STRING_PREAMBLERECEIVEDTARGETPOWER,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleReceivedTargetPower,.defint64val=-118,TYPE_INT64,0/*75*/},\ {GNB_CONFIG_STRING_PREAMBLETRANSMAX,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.preambleTransMax,.defint64val=NR_RACH_ConfigGeneric__preambleTransMax_n10,TYPE_INT64,0/*76*/},\ {GNB_CONFIG_STRING_POWERRAMPINGSTEP,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.powerRampingStep,.defint64val=NR_RACH_ConfigGeneric__powerRampingStep_dB2,TYPE_INT64,0/*77*/},\ {GNB_CONFIG_STRING_RARESPONSEWINDOW,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow,.defint64val=NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20,TYPE_INT64,0/*78*/},\ @@ -234,15 +234,15 @@ {GNB_CONFIG_STRING_RSRPTHRESHOLDSSB,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rsrp_ThresholdSSB,.defint64val=19,TYPE_INT64,0/*82*/},\ {GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR,NULL,0,.uptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.present,.defuintval=NR_RACH_ConfigCommon__prach_RootSequenceIndex_PR_l139,TYPE_UINT,0/*83*/},\ {GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->prach_RootSequenceIndex.choice.l139,.defint64val=0,TYPE_INT64,0/*84*/},\ -{GNB_CONFIG_STRING_RESTRICTEDSETCONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig,.defintval=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet,TYPE_INT64,0/*85*/}, \ -{GNB_CONFIG_STRING_MSG3TRANSFPREC,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder,.defintval=1,TYPE_INT64,0/*86*/}, \ +{GNB_CONFIG_STRING_RESTRICTEDSETCONFIG,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->restrictedSetConfig,.defint64val=NR_RACH_ConfigCommon__restrictedSetConfig_unrestrictedSet,TYPE_INT64,0/*85*/}, \ +{GNB_CONFIG_STRING_MSG3TRANSFPREC,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg3_transformPrecoder,.defint64val=1,TYPE_INT64,0/*86*/}, \ {GNB_CONFIG_STRING_MSG3DELTAPREABMLE, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->msg3_DeltaPreamble,.defint64val=1,TYPE_INT64,0},\ {GNB_CONFIG_STRING_P0NOMINALWITHGRANT, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->p0_NominalWithGrant,.defint64val=1,TYPE_INT64,0},\ {GNB_CONFIG_STRING_PUCCHGROUPHOPPING, NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_GroupHopping,.defint64val=NR_PUCCH_ConfigCommon__pucch_GroupHopping_neither,TYPE_INT64,0},\ {GNB_CONFIG_STRING_HOPPINGID, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->hoppingId,.defint64val=40,TYPE_INT64,0},\ {GNB_CONFIG_STRING_P0NOMINAL, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->p0_nominal,.defint64val=1,TYPE_INT64,0},\ {GNB_CONFIG_STRING_PUCCHRES, NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->pucch_ConfigCommon->choice.setup->pucch_ResourceCommon,.defint64val=0,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_SSBPOSITIONSINBURST,NULL,0,.u64ptr=&ssb_bitmap,.defintval=0xff,TYPE_UINT64,0}, \ +{GNB_CONFIG_STRING_SSBPOSITIONSINBURST,NULL,0,.u64ptr=&ssb_bitmap,.defint64val=0xff,TYPE_UINT64,0}, \ {GNB_CONFIG_STRING_REFERENCESUBCARRIERSPACING,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing,.defint64val=NR_SubcarrierSpacing_kHz30,TYPE_INT64,0},\ {GNB_CONFIG_STRING_DLULTRANSMISSIONPERIODICITY,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.dl_UL_TransmissionPeriodicity,.defint64val=NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms0p5,TYPE_INT64,0},\ {GNB_CONFIG_STRING_NROFDOWNLINKSLOTS,NULL,0,.i64ptr=&scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots,.defint64val=7,TYPE_INT64,0},\ @@ -259,7 +259,7 @@ {GNB_CONFIG_STRING_EPHEMERIS_VELOCITY_VZ,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ephemerisInfo_r17->choice.positionVelocity_r17->velocityVZ_r17,.defint64val=LONG_MAX,TYPE_INT64,0}, \ {GNB_CONFIG_STRING_TA_COMMON,NULL,0,.i64ptr=&scc->ext2->ntn_Config_r17->ta_Info_r17->ta_Common_r17,.defint64val=-1,TYPE_INT64,0}, \ {GNB_CONFIG_STRING_TA_COMMONDRIFT,NULL,0,.i64ptr=scc->ext2->ntn_Config_r17->ta_Info_r17->ta_CommonDrift_r17,.defint64val=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing,.defintval=-1,TYPE_INT64,0}} +{GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->msg1_SubcarrierSpacing,.defint64val=-1,TYPE_INT64,0}} #define SCC_PATTERN2_STRING_CONFIG "pattern2" @@ -323,20 +323,20 @@ /*-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ #define MSGASCCPARAMS_DESC(scc) { \ -{GNB_CONFIG_STRING_MSGBRESPONSEWINDOW_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16,.defintval=-1,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MSGARSRPTHRESHOLD_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_RSRP_Threshold_r16,.defintval=19,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MSGAMCS_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_MCS_r16,.defintval=2,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_NROFSLOTSMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofSlotsMsgA_PUSCH_r16,.defintval=1,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_NROFMSGAPOPERSLOT_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_PerSlot_r16,.defintval=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_PerSlot_r16_one,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MSGAPUSCHTIMEDOMAINOFFSET_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_PUSCH_TimeDomainOffset_r16,.defintval=0,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_STARTSYMBOLANDLENGTHMSGA_PO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->startSymbolAndLengthMsgA_PO_r16,.defintval=38,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MAPPINGTYPEMSGAPUSCH_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->mappingTypeMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_GUARDBANDMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->guardBandMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_FREQUENCYSTARTMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->frequencyStartMsgA_PUSCH_r16,.defintval=0,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_NROFPRBSPERMSGAPO_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofPRBs_PerMsgA_PO_r16,.defintval=8,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_NROFMSGAPOFDM_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_FDM_r16,.defintval=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_FDM_r16_one,TYPE_INT64,0}, \ -{GNB_CONFIG_STRING_MSGAPUSCHNROFPORTS_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_DMRS_Config_r16.msgA_PUSCH_NrofPorts_r16,.defintval=1,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_NROFDMRSSEQUENCES_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofDMRS_Sequences_r16,.defintval=1,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MSGATRANSFORMPRECODER_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_TransformPrecoder_r16,.defintval=NR_MsgA_PUSCH_Config_r16__msgA_TransformPrecoder_r16_disabled,TYPE_INT64,0},\ -{GNB_CONFIG_STRING_MSGACBPREAMBLESPERSHAREDRO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_CB_PreamblesPerSSB_PerSharedRO_r16,.defintval=1,TYPE_INT64,0}} +{GNB_CONFIG_STRING_MSGBRESPONSEWINDOW_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16,.defint64val=-1,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MSGARSRPTHRESHOLD_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_RSRP_Threshold_r16,.defint64val=19,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MSGAMCS_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_MCS_r16,.defint64val=2,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_NROFSLOTSMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofSlotsMsgA_PUSCH_r16,.defint64val=1,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_NROFMSGAPOPERSLOT_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_PerSlot_r16,.defint64val=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_PerSlot_r16_one,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MSGAPUSCHTIMEDOMAINOFFSET_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_PUSCH_TimeDomainOffset_r16,.defint64val=0,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_STARTSYMBOLANDLENGTHMSGA_PO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->startSymbolAndLengthMsgA_PO_r16,.defint64val=38,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MAPPINGTYPEMSGAPUSCH_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->mappingTypeMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_GUARDBANDMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->guardBandMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0}, \ +{GNB_CONFIG_STRING_FREQUENCYSTARTMSGAPUSCH_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->frequencyStartMsgA_PUSCH_r16,.defint64val=0,TYPE_INT64,0}, \ +{GNB_CONFIG_STRING_NROFPRBSPERMSGAPO_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofPRBs_PerMsgA_PO_r16,.defint64val=8,TYPE_INT64,0}, \ +{GNB_CONFIG_STRING_NROFMSGAPOFDM_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofMsgA_PO_FDM_r16,.defint64val=NR_MsgA_PUSCH_Resource_r16__nrofMsgA_PO_FDM_r16_one,TYPE_INT64,0}, \ +{GNB_CONFIG_STRING_MSGAPUSCHNROFPORTS_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->msgA_DMRS_Config_r16.msgA_PUSCH_NrofPorts_r16,.defint64val=1,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_NROFDMRSSEQUENCES_R16,NULL,0,.i64ptr=&scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16->nrofDMRS_Sequences_r16,.defint64val=1,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MSGATRANSFORMPRECODER_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->msgA_PUSCH_Config_r16->msgA_TransformPrecoder_r16,.defint64val=NR_MsgA_PUSCH_Config_r16__msgA_TransformPrecoder_r16_disabled,TYPE_INT64,0},\ +{GNB_CONFIG_STRING_MSGACBPREAMBLESPERSHAREDRO_R16,NULL,0,.i64ptr=scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup->rach_ConfigCommonTwoStepRA_r16.msgA_CB_PreamblesPerSSB_PerSharedRO_r16,.defint64val=1,TYPE_INT64,0}} #endif From 54990c2bc12aa50315a1995e4f268ee309785792 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 15:45:58 +0100 Subject: [PATCH 12/48] Refactor includes in executables/nr-gnb.c * used IWYU tools + manual review * output from IWYU: The full include-list for /code/executables/nr-gnb.c: /#include // for dump_nr_I0_... /#include // lines 39-39 /#include // for threadCreate /#include // for SEEK_SET /#include // for dump_pdsch_... /#include // for dump_pusch_... /#include // for pthread_join /#include // for int64_t /#include // for NULL, fclose /#include // for memset /#include // for clock_gettime /#include // for sleep, size_t /#include "NR_PHY_INTERFACE/NR_IF_Module.h" // for NR_UL_IND_t /#include "PHY/INIT/nr_phy_init.h" // for init_DLSCH_... /#include "PHY/MODULATION/nr_modulation.h" // for apply_nr_ro... /#include "PHY/NR_TRANSPORT/nr_transport_proto.h" // for reset_activ... /#include "PHY/TOOLS/tools_defs.h" // for c16_t /#include "PHY/defs_RU.h" // for RU_t, proce... /#include "PHY/defs_common.h" // for wait_sync /#include "PHY/defs_gNB.h" // for PHY_VARS_gNB /#include "PHY/defs_nr_common.h" // for NR_DL_FRAME... /#include "PHY/impl_defs_nr.h" // for NR_MIXED_SLOT /#include "SCHED_NR/fapi_nr_l1.h" // for nr_schedule... /#include "SCHED_NR/phy_frame_config_nr.h" // for nr_slot_select /#include "SCHED_NR/sched_nr.h" // for L1_nr_prach... /#include "T.h" // for T3, T_PUT_p... /#include "assertions.h" // for AssertFatal /#include "common/ran_context.h" // for RAN_CONTEXT_t /#include "common/utils/LOG/log.h" // for NR_PHY, LOG_D /#include "executables/softmodem-common.h" // for get_softmod... /#include "nfapi/oai_integration/vendor_ext.h" // for NFAPI_MODE /#include "nfapi_nr_interface_scf.h" // for nfapi_nr_co... /#include "notified_fifo.h" // for initNotifie... /#include "thread-pool.h" // for abortTpool /#include "time_meas.h" // for print_meas_log /#include "utils.h" // for calloc_or_fail --- executables/nr-gnb.c | 71 +++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 4766481364..74a95c2794 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -31,54 +31,45 @@ */ #define _GNU_SOURCE -#include +#undef MALLOC //there are two conflicting definitions, so we better make sure we don't use it at all -#include "assertions.h" -#include -#include - -#include "PHY/types.h" - +#include // for SEEK_SET +#include // for pthread_join +#include +#include +#include +#include +#include +#include "common/utils/LOG/log.h" +#include "common/utils/system.h" +#include "PHY/NR_ESTIMATION/nr_ul_estimation.h" +#include "openair1/PHY/NR_TRANSPORT/nr_dlsch.h" +#include "openair1/PHY/NR_TRANSPORT/nr_ulsch.h" +#include "NR_PHY_INTERFACE/NR_IF_Module.h" #include "PHY/INIT/nr_phy_init.h" - +#include "PHY/MODULATION/nr_modulation.h" +#include "PHY/NR_TRANSPORT/nr_transport_proto.h" +#include "PHY/TOOLS/tools_defs.h" +#include "PHY/defs_RU.h" +#include "PHY/defs_common.h" #include "PHY/defs_gNB.h" +#include "PHY/defs_nr_common.h" +#include "PHY/impl_defs_nr.h" +#include "SCHED_NR/fapi_nr_l1.h" +#include "SCHED_NR/phy_frame_config_nr.h" #include "SCHED_NR/sched_nr.h" -#include "SCHED_NR/fapi_nr_l1.h" -#include "PHY/NR_TRANSPORT/nr_transport_proto.h" -#include "PHY/MODULATION/nr_modulation.h" -#include "PHY/NR_TRANSPORT/nr_dlsch.h" -#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" -#include "LAYER2/NR_MAC_gNB/mac_proto.h" - -#include "radio/COMMON/common_lib.h" -#include "PHY/LTE_TRANSPORT/if4_tools.h" - -#include "PHY/phy_extern.h" - +#include "assertions.h" #include "common/ran_context.h" -#include "RRC/LTE/rrc_extern.h" -#include "PHY_INTERFACE/phy_interface.h" #include "common/utils/LOG/log.h" -#include "UTIL/OTG/otg_tx.h" -#include "UTIL/OTG/otg_externs.h" -#include "common/utils/LOG/vcd_signal_dumper.h" -#include "UTIL/OPT/opt.h" -#include "gnb_paramdef.h" - -#include - -#include "T.h" -#include "nfapi/oai_integration/vendor_ext.h" #include "executables/softmodem-common.h" -#include -#include -#include -#include +#include "nfapi/oai_integration/vendor_ext.h" +#include "nfapi_nr_interface_scf.h" +#include "notified_fifo.h" +#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h" +#include "thread-pool.h" +#include "time_meas.h" +#include "utils.h" -// #define USRP_DEBUG 1 -#include "executables/thread-common.h" - -//#define TICK_TO_US(ts) (ts.diff) #define TICK_TO_US(ts) (ts.trials==0?0:ts.diff/ts.trials) #define L1STATSSTRLEN 16384 static void rx_func(processingData_L1_t *param); From 33ad0f917e060384ae2124338d33a85ad455ed45 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 15:49:10 +0100 Subject: [PATCH 13/48] Cleanup obsolete commented out code in gnb_config.h --- openair2/GNB_APP/gnb_config.h | 36 ----------------------------------- 1 file changed, 36 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.h b/openair2/GNB_APP/gnb_config.h index f9d23ccba4..200400144b 100644 --- a/openair2/GNB_APP/gnb_config.h +++ b/openair2/GNB_APP/gnb_config.h @@ -46,51 +46,15 @@ }\ } while (0); -/** @defgroup _enb_app ENB APP - * @ingroup _oai2 - * @{ - */ - // Hard to find a defined value for max enb... #define MAX_GNB 16 -/* -typedef struct mme_ip_address_s { - unsigned ipv4:1; - unsigned ipv6:1; - unsigned active:1; - char *ipv4_address; - char *ipv6_address; -} mme_ip_address_t; - -typedef struct ru_config_s { - // indicates if local or remote rf is used (1 == LOCAL) - unsigned local_rf:1; - // indicates if UDP socket is used - unsigned udp:1; - // indicates if RAW socket is used - unsigned raw:1; - char *ru_if_name; - char *local_address; - char *remote_address; - uint16_t local_port; - uint16_t remote_port; - uint8_t udpif4p5; - uint8_t rawif4p5; - uint8_t rawif5_mobipass; - uint8_t if_compress; -} ru_config_t; -*/ - void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type); extern void RCconfig_nr_prs(void); extern void RCconfig_NR_L1(void); extern void RCconfig_nr_macrlc(configmodule_interface_t *cfg); extern void NRRCConfig(void); -//void enb_config_display(void); -//void ru_config_display(void); - gNB_RRC_INST *RCconfig_NRRRC(); int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i); int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i); From 65e9ad7fdffe0a3cc3691c0934e1be21ddbb39f2 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 17:27:27 +0100 Subject: [PATCH 14/48] Move get_node_type after init_gNB --- executables/nr-softmodem.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index a8ab55087a..084a2a8aae 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -599,8 +599,6 @@ int main( int argc, char **argv ) { char *pckg = strdup(OAI_PACKAGE_VERSION); LOG_I(HW, "Version: %s\n", pckg); - // don't create if node doesn't connect to RRC/S1/GTP - const ngran_node_t node_type = get_node_type(); // Init RAN context if (!(CONFIG_ISFLAGSET(CONFIG_ABORT))) NRRCConfig(); @@ -615,6 +613,9 @@ int main( int argc, char **argv ) { RCconfig_nr_prs(); } + // don't create if node doesn't connect to RRC/S1/GTP + const ngran_node_t node_type = get_node_type(); + if (NFAPI_MODE != NFAPI_MODE_PNF) { int ret = create_gNB_tasks(node_type, uniqCfg); AssertFatal(ret == 0, "cannot create ITTI tasks\n"); From bf6dff025bc971aaad718ce6fe33039f719b9678 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 17:31:02 +0100 Subject: [PATCH 15/48] Cleanup obsolete code in gNB_app_task --- openair2/GNB_APP/gnb_app.c | 44 -------------------------------------- 1 file changed, 44 deletions(-) diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index 2162d9998e..e90a83d3bc 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -181,43 +181,6 @@ void *gNB_app_task(void *args_p) case NGAP_REGISTER_GNB_CNF: LOG_I(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name, NGAP_REGISTER_GNB_CNF(msg_p).nb_amf); -/* - DevAssert(register_gnb_pending > 0); - register_gnb_pending--; - - // Check if at least gNB is registered with one AMF - if (NGAP_REGISTER_GNB_CNF(msg_p).nb_amf > 0) { - registered_gnb++; - } - - // Check if all register gNB requests have been processed - if (register_gnb_pending == 0) { - if (registered_gnb == gnb_nb) { - // If all gNB are registered, start L2L1 task - MessageDef *msg_init_p; - - msg_init_p = itti_alloc_new_message (TASK_GNB_APP, 0, INITIALIZE_MESSAGE); - itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p); - - } else { - uint32_t not_associated = gnb_nb - registered_gnb; - - LOG_W(GNB_APP, " %d gNB %s not associated with a AMF, retrying registration in %d seconds ...\n", - not_associated, not_associated > 1 ? "are" : "is", GNB_REGISTER_RETRY_DELAY); - - // Restart the gNB registration process in GNB_REGISTER_RETRY_DELAY seconds - if (timer_setup (GNB_REGISTER_RETRY_DELAY, 0, TASK_GNB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT, - NULL, &gnb_register_retry_timer_id) < 0) { - LOG_E(GNB_APP, " Can not start gNB register retry timer, use \"sleep\" instead!\n"); - - sleep(GNB_REGISTER_RETRY_DELAY); - // Restart the registration process - registered_gnb = 0; - register_gnb_pending = gNB_app_register (gnb_id_start, gnb_id_end);//, gnb_properties_p); - } - } - } -*/ break; case F1AP_SETUP_RESP: @@ -247,13 +210,6 @@ void *gNB_app_task(void *args_p) case TIMER_HAS_EXPIRED: LOG_I(GNB_APP, " Received %s: timer_id %ld\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id); - - //if (TIMER_HAS_EXPIRED (msg_p).timer_id == gnb_register_retry_timer_id) { - /* Restart the registration process */ - // registered_gnb = 0; - // register_gnb_pending = gNB_app_register(gnb_id_start, gnb_id_end);//, gnb_properties_p); - //} - break; default: From e6da64b1a347f16fd2ed9a604fa87ac3c6dc486d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 17:32:21 +0100 Subject: [PATCH 16/48] Refactor RCconfig_NR_NG * use macros from config module * cleanup irrelevant code --- openair2/GNB_APP/gnb_config.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 650fbdc847..78e88b9dc8 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2131,18 +2131,11 @@ gNB_RRC_INST *RCconfig_NRRRC() return rrc; } -int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) { - +int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) +{ int j,k = 0; int gnb_id; - int32_t my_int; - const char* active_gnb[MAX_GNB]; - // for no gcc warnings - - (void) my_int; - - memset((char*)active_gnb,0,MAX_GNB* sizeof(char*)); char* gnb_ipv4_address_for_NGU = NULL; uint32_t gnb_port_for_NGU = 0; char* gnb_ipv4_address_for_S1U = NULL; From 7ee6feac429d2c2ba9262723a1759290f6138d3e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 16 Dec 2024 19:06:57 +0100 Subject: [PATCH 17/48] Use config module macros in openair2/E1AP/e1ap_setup.c --- openair2/E1AP/e1ap_setup.c | 53 ++++++++++++++------------------------ 1 file changed, 19 insertions(+), 34 deletions(-) diff --git a/openair2/E1AP/e1ap_setup.c b/openair2/E1AP/e1ap_setup.c index b1654a1788..f00088324d 100644 --- a/openair2/E1AP/e1ap_setup.c +++ b/openair2/E1AP/e1ap_setup.c @@ -36,19 +36,18 @@ static void get_NGU_S1U_addr(char **addr, uint16_t *port) uint32_t gnb_port_for_NGU = 0; char *gnb_ipv4_address_for_S1U = NULL; uint32_t gnb_port_for_S1U = 0; - char gtpupath[MAX_OPTNAME_SIZE * 2 + 8]; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramdef_t NETParams[] = GNBNETPARAMS_DESC; - LOG_I(GTPU, "Configuring GTPu\n"); - - /* get number of active eNodeBs */ - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); + // get gNB params + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs > 0, "Failed to parse config file no active gNodeBs in %s \n", GNB_CONFIG_STRING_ACTIVE_GNBS); + // Config GTPu + char gtpupath[MAX_OPTNAME_SIZE * 2 + 8]; + LOG_I(GTPU, "Configuring GTPu\n"); sprintf(gtpupath, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); - config_get(config_get_if(), NETParams, sizeofArray(NETParams), gtpupath); + GET_PARAMS(NETParams, GNBNETPARAMS_DESC, gtpupath); + char *address; if (NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr != NULL) { LOG_I(GTPU, "SA mode \n"); @@ -84,15 +83,14 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity) if (!msgConfig) return NULL; - paramdef_t GNBSParams[] = GNBSPARAMS_DESC; - paramdef_t GNBParams[] = GNBPARAMS_DESC; - paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST, NULL, 0}; - config_get(config_get_if(), GNBSParams, sizeofArray(GNBSParams), NULL); - char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + GET_PARAMS(GNBSParams, GNBSPARAMS_DESC, NULL); int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; AssertFatal(num_gnbs == 1, "Support only one gNB per process\n"); - config_getlist(config_get_if(), &GNBParamList, GNBParams, sizeofArray(GNBParams), NULL); + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); + + char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; + sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + paramdef_t *gnbParms = GNBParamList.paramarray[0]; e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req; @@ -104,17 +102,8 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity) // Only 5GC supported e1Setup->cn_support = cn_support_5GC; - paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; - paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; - /* map parameter checking array instances to parameter definition array instances */ - checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK; - static_assert(sizeofArray(config_check_PLMNParams) == sizeofArray(PLMNParams), - "config_check_PLMNParams and PLMNParams should have the same size"); - - for (int I = 0; I < sizeofArray(PLMNParams); ++I) - PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]); - - config_getlist(config_get_if(), &PLMNParamList, PLMNParams, sizeofArray(PLMNParams), aprefix); + // get and config PLMN params + GET_PARAMS_LIST(PLMNParamList, PLMNParams, GNBPLMNPARAMS_DESC, GNB_CONFIG_STRING_PLMN_LIST, aprefix, PLMNPARAMS_CHECK); int numPLMNs = PLMNParamList.numelt; e1Setup->supported_plmns = numPLMNs; @@ -123,14 +112,12 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity) e1Setup->plmn[I].id.mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr; e1Setup->plmn[I].id.mnc_digit_length = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].uptr; + // get and config SNSSAI params char snssaistr[MAX_OPTNAME_SIZE*2 + 8]; sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_PLMN_LIST, I); - paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0}; - paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC; - config_getlist(config_get_if(), &SNSSAIParamList, SNSSAIParams, sizeof(SNSSAIParams) / sizeof(paramdef_t), snssaistr); + GET_PARAMS_LIST(SNSSAIParamList, SNSSAIParams, GNBSNSSAIPARAMS_DESC, GNB_CONFIG_STRING_SNSSAI_LIST, snssaistr); e1Setup->plmn[I].supported_slices = SNSSAIParamList.numelt; - e1Setup->plmn[I].slice = calloc(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice)); - AssertFatal(e1Setup->plmn[I].slice != NULL, "out of memory\n"); + e1Setup->plmn[I].slice = calloc_or_fail(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice)); for (int s = 0; s < SNSSAIParamList.numelt; ++s) { e1ap_nssai_t *slice = &e1Setup->plmn[I].slice[s]; slice->sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr; @@ -150,9 +137,7 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity) E1AP_REGISTER_REQ(msgConfig).gnb_id = gnb_id; if (entity != NULL) { - paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0}; - paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC; - config_getlist(config_get_if(), &GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix); + GET_PARAMS_LIST(GNBE1ParamList, GNBE1Params, GNBE1PARAMS_DESC, GNB_CONFIG_STRING_E1_PARAMETERS, aprefix); paramdef_t *e1Parms = GNBE1ParamList.paramarray[0]; strcpy(e1ap_nc->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr)); e1ap_nc->CUCP_e1_ip_address.ipv4 = 1; From a48e64f6f88fc643a82378b0c7f8d400cfb73246 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 10 Apr 2025 19:14:42 +0200 Subject: [PATCH 18/48] Adopt snprintf across the code in openair2/GNB_APP/gnb_config.c Replaced `sprintf` with `snprintf` in gnb_config.c to enhance memory safety by preventing potential buffer overflows. `sprintf` can cause buffer overflows by not checking the destination buffer size. In contrast, `snprintf` allows specifying a maximum buffer size, ensuring no overflow occurs by limiting the number of characters written, including the null terminator. --- openair2/GNB_APP/gnb_config.c | 82 ++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 78e88b9dc8..b63c5df130 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -101,7 +101,7 @@ static int DEFRUTPCORES[] = {-1,-1,-1,-1}; static uint16_t set_snssai_config(nssai_t *nssai, const int max_num_ssi, uint8_t k, uint8_t l) { char snssaistr[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l); + snprintf(snssaistr, sizeof(snssaistr), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_PLMN_LIST, l); GET_PARAMS_LIST(SNSSAIParamList, SNSSAIParams, GNBSNSSAIPARAMS_DESC, @@ -819,7 +819,7 @@ void fix_scd(NR_ServingCellConfig_t *scd) { static void verify_gnb_param_notset(paramdef_t *params, int paramidx, const char *paramname) { char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); AssertFatal(!config_isparamset(params, paramidx), "Option \"%s." GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON ".%s\" is not allowed in this config, please remove it\n", @@ -1093,12 +1093,12 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf prepare_msgA_scc(scc); char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); GET_PARAMS_LIST(MsgASCCsParamList, MsgASCCsParams, MSGASCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); if (SCCsParamList.numelt > 0 || MsgASCCsParamList.numelt > 0) { - sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST,0,GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix); GET_PARAMS(MsgASCCsParams, MSGASCCPARAMS_DESC(scc), aprefix); // NR_TDD-UL-DL-ConfigCommon pattern2 (optional IE) @@ -1106,7 +1106,14 @@ static NR_ServingCellConfigCommon_t *get_scc_config(configmodule_interface_t *cf struct NR_TDD_UL_DL_Pattern p2; paramdef_t pattern2Params[] = SCC_PATTERN2_PARAMS_DESC(p2); char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%i].%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0, SCC_PATTERN2_STRING_CONFIG); + snprintf(aprefix, + sizeof(aprefix), + "%s.[%i].%s.[%i].%s", + GNB_CONFIG_STRING_GNB_LIST, + 0, + GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, + 0, + SCC_PATTERN2_STRING_CONFIG); config_get(config_get_if(), pattern2Params, sizeofArray(pattern2Params), aprefix); // check validity bool is_pattern2 = false; @@ -1198,7 +1205,7 @@ static NR_ServingCellConfig_t *get_scd_config(configmodule_interface_t *cfg) GET_PARAMS_LIST(SCDsParamList, SCDsParams, SCDPARAMS_DESC(scd), GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, aprefix); if (SCDsParamList.numelt > 0) { - sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGDEDICATED, 0); GET_PARAMS(SCDsParams, SCDPARAMS_DESC(scd), aprefix); const NR_BWP_UplinkDedicated_t *bwp_Dedicated = scd->uplinkConfig->uplinkBWP_ToAddModList->list.array[0]->bwp_Dedicated; const NR_PTRS_UplinkConfig_t *setup = @@ -1396,7 +1403,7 @@ static nr_redcap_config_t *get_redcap_config(int gnb_idx) { paramdef_t RedCap_Params[] = GNB_REDCAP_PARAMS_DESC; char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_REDCAP); + snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_REDCAP); int ret = config_get(config_get_if(), RedCap_Params, sizeofArray(RedCap_Params), aprefix); if (ret <= 0) { @@ -1518,7 +1525,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.redcap = get_redcap_config(0); char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_TIMERS_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_TIMERS_CONFIG); GET_PARAMS(Timers_Params, GNB_TIMERS_PARAMS_DESC, aprefix); config.timer_config.sr_ProhibitTimer = *Timers_Params[GNB_TIMERS_SR_PROHIBIT_TIMER_IDX].iptr; @@ -1883,7 +1890,7 @@ static seq_arr_t *fill_cu_sibs(paramdef_t *GNBparamarray) static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) { char gnbpath[MAX_OPTNAME_SIZE + 8]; - sprintf(gnbpath, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); + snprintf(gnbpath, sizeof(gnbpath), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx); GET_PARAMS_LIST(neighbour_list_param_list, neighbour_list_params, @@ -1903,7 +1910,7 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; char neighbourpath[MAX_OPTNAME_SIZE + 8]; - sprintf(neighbourpath, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); + snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); GET_PARAMS_LIST(NeighbourCellParamList, NeighbourCellParams, GNBNEIGHBOURCELLPARAMS_DESC, @@ -1927,12 +1934,13 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; char neighbour_plmn_path[CONFIG_MAXOPTLENGTH]; - sprintf(neighbour_plmn_path, - "%s.%s.[%i].%s", - neighbourpath, - GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, - l, - GNB_CONFIG_STRING_NEIGHBOUR_PLMN); + snprintf(neighbour_plmn_path, + sizeof(neighbour_plmn_path), + "%s.%s.[%i].%s", + neighbourpath, + GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, + l, + GNB_CONFIG_STRING_NEIGHBOUR_PLMN); GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; @@ -1953,17 +1961,18 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) { char measurement_path[MAX_OPTNAME_SIZE + 8]; - sprintf(measurement_path, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION); + snprintf(measurement_path, sizeof(measurement_path), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION); nr_measurement_configuration_t *measurementConfig = &rrc->measurementConfiguration; // Periodical Event Configuration char periodic_event_path[MAX_OPTNAME_SIZE + 8]; - sprintf(periodic_event_path, - "%s.[%i].%s.%s", - GNB_CONFIG_STRING_GNB_LIST, - gnb_idx, - GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, - MEASUREMENT_EVENTS_PERIODICAL); + snprintf(periodic_event_path, + sizeof(periodic_event_path), + "%s.[%i].%s.%s", + GNB_CONFIG_STRING_GNB_LIST, + gnb_idx, + GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, + MEASUREMENT_EVENTS_PERIODICAL); GET_PARAMS(Periodical_EventParams, MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC, periodic_event_path); if (*Periodical_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) { @@ -1976,12 +1985,7 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) // A2 Event Configuration char a2_path[MAX_OPTNAME_SIZE + 8]; - sprintf(a2_path, - "%s.[%i].%s.%s", - GNB_CONFIG_STRING_GNB_LIST, - gnb_idx, - GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, - MEASUREMENT_EVENTS_A2); + snprintf(a2_path, sizeof(a2_path), "%s.[%i].%s.%s", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_MEASUREMENT_CONFIGURATION, MEASUREMENT_EVENTS_A2); GET_PARAMS(A2_EventParams, MEASUREMENT_A2_GLOBALPARAMS_DESC, a2_path); if (*A2_EventParams[MEASUREMENT_EVENTS_ENABLE_IDX].i64ptr) { @@ -2062,7 +2066,7 @@ gNB_RRC_INST *RCconfig_NRRRC() if (NODE_IS_CU(rrc->node_type)) { char aprefix[MAX_OPTNAME_SIZE*2 + 8]; - sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, i, GNB_CONFIG_STRING_SCTP_CONFIG); GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n", k, rrc->node_id); rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr)); @@ -2205,7 +2209,7 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) } NGAP_REGISTER_GNB_REQ(msg_p).default_drx = 0; // NG - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); GET_PARAMS_LIST(NGParamList, NGParams, GNBNGPARAMS_DESC, GNB_CONFIG_STRING_AMF_IP_ADDRESS, aprefix); NGAP_REGISTER_GNB_REQ (msg_p).nb_amf = 0; @@ -2226,14 +2230,14 @@ int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i) NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = SCTP_OUT_STREAMS; NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS; if (IS_SA_MODE(get_softmodem_params())) { - sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG); GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); NGAP_REGISTER_GNB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr); NGAP_REGISTER_GNB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr); } // NETWORK_INTERFACES - sprintf(aprefix, "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%d].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix); if (NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr != NULL) { char *cidr = *(NETParams[GNB_IPV4_ADDRESS_FOR_NG_AMF_IDX].strptr); @@ -2393,10 +2397,10 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ(msg_p).mnc); char aprefix[MAX_OPTNAME_SIZE * 80 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); GET_PARAMS_LIST(SCCsParamList, SCCsParams, SCCPARAMS_DESC(scc), GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, aprefix); if (SCCsParamList.numelt > 0) { - sprintf(aprefix, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_SERVINGCELLCONFIGCOMMON, 0); GET_PARAMS(SCCsParams, SCCPARAMS_DESC(scc), aprefix); fix_scc(scc,ssb_bitmap); } @@ -2417,7 +2421,7 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ (msg_p).num_cc); } - sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, k); GET_PARAMS_LIST(X2ParamList, X2Params, X2PARAMS_DESC, ENB_CONFIG_STRING_TARGET_ENB_X2_IP_ADDRESS, aprefix); AssertFatal(X2ParamList.numelt <= X2AP_MAX_NB_ENB_IP_ADDRESS, @@ -2464,14 +2468,14 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = SCTP_IN_STREAMS; if (IS_SA_MODE(get_softmodem_params())) { - sprintf(aprefix,"%s.[%i].%s",GNB_CONFIG_STRING_GNB_LIST,k,GNB_CONFIG_STRING_SCTP_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_SCTP_CONFIG); GET_PARAMS(SCTPParams, GNBSCTPPARAMS_DESC, aprefix); X2AP_REGISTER_ENB_REQ (msg_p).sctp_in_streams = (uint16_t)*(SCTPParams[GNB_SCTP_INSTREAMS_IDX].uptr); X2AP_REGISTER_ENB_REQ (msg_p).sctp_out_streams = (uint16_t)*(SCTPParams[GNB_SCTP_OUTSTREAMS_IDX].uptr); } // NETWORK_INTERFACES - sprintf(aprefix, "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); + snprintf(aprefix, sizeof(aprefix), "%s.[%i].%s", GNB_CONFIG_STRING_GNB_LIST, k, GNB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG); GET_PARAMS(NETParams, GNBNETPARAMS_DESC, aprefix); X2AP_REGISTER_ENB_REQ (msg_p).enb_port_for_X2C = (uint32_t)*(NETParams[GNB_PORT_FOR_X2C_IDX].uptr); @@ -2594,7 +2598,7 @@ ngran_node_t get_node_type(void) // E1 params char aprefix[MAX_OPTNAME_SIZE * 2 + 8]; - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); + snprintf(aprefix, sizeof(aprefix), "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); GET_PARAMS_LIST(GNBE1ParamList, GNBE1Params, GNBE1PARAMS_DESC, GNB_CONFIG_STRING_E1_PARAMETERS, aprefix); if (strcmp(*(GNBParamList.paramarray[0][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "f1") == 0) { if ( GNBE1ParamList.paramarray == NULL || GNBE1ParamList.numelt == 0 ) From 9e787a0ba2e3e7da4e5960f5d15503e2545ef292 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Fri, 22 Nov 2024 18:22:58 +0000 Subject: [PATCH 19/48] Bugfix for number of PRBs in PUCCH format 2 --- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 11 ++++++++++- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h | 4 +++- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 8 ++++++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c | 8 ++++++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 44c6673f2f..503040e7e6 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4305,12 +4305,21 @@ int get_f3_dmrs_symbols(NR_PUCCH_Resource_t *pucchres, NR_PUCCH_Config_t *pucch_ uint16_t compute_pucch_prb_size(uint8_t format, uint8_t nr_prbs, - uint16_t O_uci, + uint16_t O_csi, + uint16_t O_ack, + uint8_t O_sr, NR_PUCCH_MaxCodeRate_t *maxCodeRate, uint8_t Qm, uint8_t n_symb, uint8_t n_re_ctrl) { + // TODO: Consider also the case where there is a HARQ-ACK in response to a PDSCH reception without a corresponding PDCCH + // as described in the 3GPP TS 38.213 - Section 9.2.5.2 + if (O_csi > 0 && O_ack == 0) { + return nr_prbs; + } + + int O_uci = O_csi + O_ack + O_sr; int O_crc = compute_pucch_crc_size(O_uci); int O_tot = O_uci + O_crc; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h index 8e0e57d3a6..8df27ad16e 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h @@ -254,7 +254,9 @@ uint8_t get_pusch_nb_antenna_ports(NR_PUSCH_Config_t *pusch_Config, uint16_t compute_pucch_prb_size(uint8_t format, uint8_t nr_prbs, - uint16_t O_uci, + uint16_t O_csi, + uint16_t O_ack, + uint8_t O_sr, NR_PUCCH_MaxCodeRate_t *maxCodeRate, uint8_t Qm, uint8_t n_symb, diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 572202d044..8cd85e6160 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -1633,7 +1633,9 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, pucch_pdu->dmrs_scrambling_id = id0 != NULL ? *id0 : mac->physCellId; pucch_pdu->prb_size = compute_pucch_prb_size(2, pucchres->format.choice.format2->nrofPRBs, - n_uci, + pucch->n_csi, + pucch->n_harq, + pucch->n_sr, pucch_Config->format2->choice.setup->maxCodeRate, 2, pucchres->format.choice.format2->nrofSymbols, @@ -1666,7 +1668,9 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac, } pucch_pdu->prb_size = compute_pucch_prb_size(3, pucchres->format.choice.format3->nrofPRBs, - n_uci, + pucch->n_csi, + pucch->n_harq, + pucch->n_sr, pucch_Config->format3->choice.setup->maxCodeRate, 2 - pucch_pdu->pi_2bpsk, pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 4e292b916b..cf71c794b6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -1023,7 +1023,9 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, pucch_pdu->dmrs_scrambling_id = id0 ? *id0 : *scc->physCellId; pucch_pdu->prb_size = compute_pucch_prb_size(2, pucchres->format.choice.format2->nrofPRBs, - O_uci + O_sr, + O_csi, + O_ack, + O_sr, pucch_Config->format2->choice.setup->maxCodeRate, 2, pucchres->format.choice.format2->nrofSymbols, @@ -1047,7 +1049,9 @@ void nr_configure_pucch(nfapi_nr_pucch_pdu_t *pucch_pdu, int f3_dmrs_symbols = get_f3_dmrs_symbols(pucchres, pucch_Config); pucch_pdu->prb_size = compute_pucch_prb_size(3, pucchres->format.choice.format3->nrofPRBs, - O_uci + O_sr, + O_csi, + O_ack, + O_sr, pucch_Config->format3->choice.setup->maxCodeRate, 2 - pucch_pdu->pi_2bpsk, pucchres->format.choice.format3->nrofSymbols - f3_dmrs_symbols, From 2c164336bcb8d336d054cadb0c12ddc0bc0f80de Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 15:14:16 +0100 Subject: [PATCH 20/48] gNB changes in RRC- Enable SSB-SINR based CSI reporting 3GPP 38.331 release 16 specifies that If the field reportQuantity-r16 is present, UE shall ignore reportQuantity (without suffix). reportQuantity-r16 configures SSB based SINR as the reporting quantity. set do_SINR = 1; in gNB params part of the config file to enable SSB based SINR reporting instead of the default RSRP based. --- openair2/GNB_APP/gnb_config.c | 5 ++++- openair2/GNB_APP/gnb_paramdef.h | 5 +++++ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 1 + openair2/RRC/NR/nr_rrc_config.c | 24 +++++++++++++++++++++--- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index cbb46f0132..f5fb224365 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -822,6 +822,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_gnb_param_notset(gnbp, GNB_DISABLE_HARQ_IDX, GNB_CONFIG_STRING_DISABLE_HARQ); verify_gnb_param_notset(gnbp, GNB_NUM_DL_HARQ_IDX, GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES); verify_gnb_param_notset(gnbp, GNB_NUM_UL_HARQ_IDX, GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES); + verify_gnb_param_notset(gnbp, GNB_DO_SINR_IDX, GNB_CONFIG_STRING_DOSINR); // check for some general sections verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST); @@ -1519,6 +1520,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) LOG_I(GNB_APP, "SIB1 TDA %d\n", config.sib1_tda); config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr; config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr; + config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr; config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr; config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr; config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0; @@ -1529,9 +1531,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) if (config.disable_harq) LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n"); LOG_I(GNB_APP, - "CSI-RS %d, SRS %d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", + "CSI-RS %d, SRS %d, SINR:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n", config.do_CSIRS, config.do_SRS, + config.do_SINR, config.force_256qam_off ? "force off" : "may be on", config.use_deltaMCS ? "on" : "off", config.maxMIMO_layers, diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index c76b6bc143..99eb8847af 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -141,6 +141,7 @@ typedef enum { #define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels" #define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs" #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" +#define GNB_CONFIG_STRING_DOSINR "do_SINR" #define GNB_CONFIG_HLP_STRING_ENABLE_SDAP "enable the SDAP layer\n" #define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support" @@ -154,6 +155,7 @@ typedef enum { #define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1" #define GNB_CONFIG_HLP_CU_SIBS "List of CU generated SIBs to be transmitted" #define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted" +#define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB" /*-----------------------------------------------------------------------------------------------------------------------------------------*/ /* cell configuration parameters */ @@ -201,6 +203,7 @@ typedef enum { GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ +{GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ } // clang-format on @@ -244,6 +247,7 @@ typedef enum { #define GNB_UESS_AGG_LEVEL_LIST_IDX 36 #define GNB_CU_SIBS_IDX 37 #define GNB_DU_SIBS_IDX 38 +#define GNB_DO_SINR_IDX 39 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32} @@ -289,6 +293,7 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3a01ecfbfb..513e62b5ac 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -179,6 +179,7 @@ typedef struct nr_mac_config_t { int32_t *bw_list; int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; nr_redcap_config_t *redcap; + bool do_SINR; } nr_mac_config_t; typedef struct NR_preamble_ue { diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index d377b2aff3..0391ed282f 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -1934,7 +1934,8 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, int rep_id, int uid, int curr_bwp, - int num_antenna_ports) + int num_antenna_ports, + bool do_sinr) { int resource_id = -1; for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) { @@ -1968,6 +1969,14 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig, } else { csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP; csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0; + if (do_sinr) { + csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none; + csirep->reportQuantity.choice.none = (NULL_t)0; + csirep->ext2 = calloc(1, sizeof(*csirep->ext2)); + csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16)); + csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16; + csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0; + } } csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled; csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled)); @@ -3298,7 +3307,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, NR_PUCCH_CSI_Resource_t *pucchrsrp = calloc(1, sizeof(*pucchrsrp)); pucchrsrp->uplinkBandwidthPartId = bwp_id; pucchrsrp->pucch_Resource = pucch_Resource; - config_rsrp_meas_report(csi_MeasConfig, scc, pucchrsrp, configuration->do_CSIRS, bwp_id + 10, uid, curr_bwp, pdsch_AntennaPorts); + config_rsrp_meas_report(csi_MeasConfig, + scc, + pucchrsrp, + configuration->do_CSIRS, + bwp_id + 10, + uid, + curr_bwp, + pdsch_AntennaPorts, + configuration->do_SINR); } fill_harq_IEs(SpCellConfig->spCellConfigDedicated, configuration->num_dlharq, configuration->num_ulharq); @@ -3811,7 +3828,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC bwp->bwp_Id + 10, uid, curr_bwp, - dl_antenna_ports); + dl_antenna_ports, + configuration->do_SINR); } secondaryCellGroup->spCellConfig->spCellConfigDedicated->sCellDeactivationTimer = NULL; secondaryCellGroup->spCellConfig->spCellConfigDedicated->crossCarrierSchedulingConfig = NULL; From 61778f3d5599e6e1ec9091e2b37eb885eac4230a Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 15:57:02 +0100 Subject: [PATCH 21/48] gNB changes- Compute bitlen in case of SSB-SINR compute SINR bitlen according to 38.212 table 6.3.1.1.2-6A --- openair2/LAYER2/NR_MAC_COMMON/nr_mac.h | 7 +- openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c | 105 ++++++++++++------ 2 files changed, 73 insertions(+), 39 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h index 007976a1a5..68182ab9ec 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h @@ -517,7 +517,9 @@ typedef struct { uint8_t cri_ssbri_bitlen; uint8_t rsrp_bitlen; uint8_t diff_rsrp_bitlen; -} L1_RSRP_bitlen_t; + uint8_t sinr_bitlen; + uint8_t diff_sinr_bitlen; +} L1_Meas_bitlen_t; typedef struct{ uint8_t ri_restriction; @@ -535,13 +537,14 @@ typedef struct{ typedef struct nr_csi_report { NR_CSI_ReportConfigId_t reportConfigId; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type; + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16; long periodicity; uint16_t offset; long **SSB_Index_list; long **CSI_Index_list; // uint8_t nb_of_nzp_csi_report; uint8_t nb_of_csi_ssb_report; - L1_RSRP_bitlen_t CSI_report_bitlen; + L1_Meas_bitlen_t CSI_report_bitlen; CSI_Meas_bitlen_t csi_meas_bitlen; int codebook_mode; int N1; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c index 44c6673f2f..57ab38c0ef 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c @@ -4427,7 +4427,10 @@ static uint8_t number_of_bits_set(uint8_t buf) return nb_of_bits_set; } -static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, uint8_t nb_resources, nr_csi_report_t *csi_report) +static void compute_rsrp_or_sinr_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, + uint8_t nb_resources, + nr_csi_report_t *csi_report, + bool is_RSRP_configured) { if (NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled == csi_reportconfig->groupBasedBeamReporting.present) { if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) @@ -4445,13 +4448,20 @@ static void compute_rsrp_bitlen(const NR_CSI_ReportConfig_t *csi_reportconfig, u csi_report->CSI_report_bitlen.nb_ssbri_cri = 2; if (nb_resources) { - csi_report->CSI_report_bitlen.cri_ssbri_bitlen =ceil(log2 (nb_resources)); - csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP - csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.cri_ssbri_bitlen = ceil(log2 (nb_resources)); + if (is_RSRP_configured) { + csi_report->CSI_report_bitlen.rsrp_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6: CRI, SSBRI, and RSRP + } else { + csi_report->CSI_report_bitlen.sinr_bitlen = 7; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR + csi_report->CSI_report_bitlen.diff_sinr_bitlen = 4; // From spec 38.212 Table 6.3.1.1.2-6A: CRI, SSBRI, and SINR + } } else { csi_report->CSI_report_bitlen.cri_ssbri_bitlen = 0; csi_report->CSI_report_bitlen.rsrp_bitlen = 0; csi_report->CSI_report_bitlen.diff_rsrp_bitlen = 0; + csi_report->CSI_report_bitlen.sinr_bitlen = 0; + csi_report->CSI_report_bitlen.diff_sinr_bitlen = 0; } } @@ -4878,9 +4888,13 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report reportQuantity_type = csi_reportconfig->reportQuantity.present; csi_report->reportQuantity_type = reportQuantity_type; csi_report->reportConfigId = csi_reportconfig->reportConfigId; + csi_report->reportQuantity_type_r16 = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING; + if (csi_reportconfig->ext2 != NULL && csi_reportconfig->ext2->reportQuantity_r16) + csi_report->reportQuantity_type_r16 = csi_reportconfig->ext2->reportQuantity_r16->present; // setting the CSI or SSB index list - if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type) { + if (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP == csi_report->reportQuantity_type + || NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16 == csi_report->reportQuantity_type_r16) { for (int csi_idx = 0; csi_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_idx++) { if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_idx]->csi_SSB_ResourceSetId == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){ @@ -4891,8 +4905,7 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report break; } } - } - else { + } else { if (resourceType == NR_CSI_ResourceConfig__resourceType_periodic) { AssertFatal(csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList != NULL, "Wrong settings! Report quantity requires CSI-RS but csi_MeasConfig->nzp_CSI_RS_ResourceSetToAddModList is NULL\n"); @@ -4911,33 +4924,46 @@ void compute_csi_bitlen(const NR_CSI_MeasConfig_t *csi_MeasConfig, nr_csi_report } LOG_D(NR_MAC,"nb_resources %d\n",nb_resources); // computation of bit length depending on the report type - switch(reportQuantity_type){ - case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): - compute_rsrp_bitlen(csi_reportconfig, nb_resources, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): - csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); - csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); - compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); - break; - default: - AssertFatal(1==0,"Not yet supported CSI report quantity type"); + if (csi_report->reportQuantity_type_r16 != NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING) { + switch (csi_report->reportQuantity_type_r16) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false); + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, false); + break; + default: + AssertFatal(1 == 0, "Not yet supported CSI report quantity type"); + } + } else { + switch (reportQuantity_type) { + case (NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP): + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP): + compute_rsrp_or_sinr_bitlen(csi_reportconfig, nb_resources, csi_report, true); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + case (NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI): + csi_report->csi_meas_bitlen.cri_bitlen = ceil(log2(nb_resources)); + csi_report->csi_meas_bitlen.ri_restriction = compute_ri_bitlen(csi_reportconfig, csi_report); + compute_li_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_cqi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + compute_pmi_bitlen(csi_reportconfig, csi_report->csi_meas_bitlen.ri_restriction, csi_report); + break; + default: + AssertFatal(1 == 0, "Not yet supported CSI report quantity type"); + } } } } @@ -4946,11 +4972,16 @@ uint16_t nr_get_csi_bitlen(nr_csi_report_t *csi_report) { uint16_t csi_bitlen = 0; uint16_t max_bitlen = 0; - L1_RSRP_bitlen_t *CSI_report_bitlen = NULL; + L1_Meas_bitlen_t *CSI_report_bitlen = NULL; CSI_Meas_bitlen_t *csi_meas_bitlen = NULL; - if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP || - csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) { + if (csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16 + || csi_report->reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16) { + CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements + csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + CSI_report_bitlen->sinr_bitlen + + (CSI_report_bitlen->diff_sinr_bitlen * (CSI_report_bitlen->nb_ssbri_cri - 1))); + } else if (csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP + || csi_report->reportQuantity_type == NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) { CSI_report_bitlen = &(csi_report->CSI_report_bitlen); // This might need to be moodif for Aperiodic CSI-RS measurements csi_bitlen += ((CSI_report_bitlen->cri_ssbri_bitlen * CSI_report_bitlen->nb_ssbri_cri) + CSI_report_bitlen->rsrp_bitlen +(CSI_report_bitlen->diff_rsrp_bitlen * From 6e371b9e4813bcbe4dcd8eaf9a2f124c76e2933d Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 17:17:53 +0100 Subject: [PATCH 22/48] UE changes in PHY- Enable SSB based SINR measurement --- .../nfapi/public_inc/fapi_nr_ue_interface.h | 2 ++ openair1/PHY/INIT/nr_init_ue.c | 4 ++- openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h | 10 +++---- .../PHY/NR_UE_ESTIMATION/nr_ue_measurements.c | 27 +++++++++++-------- .../PHY/NR_UE_TRANSPORT/nr_initial_sync.c | 3 ++- openair1/PHY/defs_nr_UE.h | 1 + openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 1 + openair2/LAYER2/NR_MAC_UE/mac_defs.h | 1 + openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c | 6 +++-- 9 files changed, 35 insertions(+), 20 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h index a5d6087856..140ed130a4 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h @@ -129,6 +129,8 @@ typedef struct { short rsrp_dBm; long arfcn; rlm_t radiolink_monitoring; // -1 no monitoring, 0 out_of_sync, 1 in_sync + // SINR value times 10 as reporting granularity is 0.5 + float sinr_dB; } fapi_nr_ssb_pdu_t; typedef struct { diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c index 9f8a463ec7..f4f0f7e50e 100644 --- a/openair1/PHY/INIT/nr_init_ue.c +++ b/openair1/PHY/INIT/nr_init_ue.c @@ -180,8 +180,10 @@ int init_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB) AssertFatal( nb_connected_gNB <= NUMBER_OF_CONNECTED_gNB_MAX, "n_connected_gNB is too large" ); // init phy_vars_ue - for (int i = 0; i < fp->Lmax; i++) + for (int i = 0; i < fp->Lmax; i++) { ue->measurements.ssb_rsrp_dBm[i] = INT_MIN; + ue->measurements.ssb_sinr_dB[i] = INT_MIN; + } for (int i = 0; i < 4; i++) { ue->rx_gain_max[i] = 135; diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h index 835876d4bf..da6fd31eb5 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_estimation.h @@ -111,11 +111,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, uint32_t pdsch_est_size, int32_t dl_ch_estimates[][pdsch_est_size]); -int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, - const UE_nr_rxtx_proc_t *proc, - const c16_t rxdataF[][fp->samples_per_slot_wCP], - int symbol_offset, - int ssb_start_subcarrier); +uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, + const UE_nr_rxtx_proc_t *proc, + const c16_t rxdataF[][fp->samples_per_slot_wCP], + int symbol_offset, + int ssb_start_subcarrier); void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, uint8_t gNB_index, diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c index 0fb94f93f3..b6aeba7f76 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_ue_measurements.c @@ -172,11 +172,11 @@ void nr_ue_measurements(PHY_VARS_NR_UE *ue, // This function calculates: // - SS reference signal received digital power in dB/RE -int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, - const UE_nr_rxtx_proc_t *proc, - const c16_t rxdataF[][fp->samples_per_slot_wCP], - int symbol_offset, - int ssb_start_subcarrier) +uint32_t nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, + const UE_nr_rxtx_proc_t *proc, + const c16_t rxdataF[][fp->samples_per_slot_wCP], + int symbol_offset, + int ssb_start_subcarrier) { int k_start = 56; int k_end = 183; @@ -209,9 +209,7 @@ int nr_ue_calculate_ssb_rsrp(const NR_DL_FRAME_PARMS *fp, LOG_D(PHY, "In %s: RSRP/nb_re: %d nb_re :%d\n", __FUNCTION__, rsrp, nb_re); - int rsrp_db_per_re = 10 * log10(rsrp); - - return rsrp_db_per_re; + return rsrp; } // This function implements: @@ -234,7 +232,8 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, if (fp->half_frame_bit) symbol_offset += (fp->slots_per_frame >> 1) * fp->symbols_per_slot; - int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier); + uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(fp, proc, rxdataF, symbol_offset, fp->ssb_start_subcarrier); + float rsrp_db_per_re = 10 * log10(rsrp_avg); openair0_config_t *cfg0 = &openair0_cfg[0]; @@ -242,12 +241,18 @@ void nr_ue_ssb_rsrp_measurements(PHY_VARS_NR_UE *ue, - ((int)cfg0->rx_gain[0] - (int)cfg0->rx_gain_offset[0]) - dB_fixed(fp->ofdm_symbol_size); + // to obtain non-integer dB value with a resoluion of 0.5dB + uint32_t signal_pwr = rsrp_avg > ue->measurements.n0_power_avg ? rsrp_avg - ue->measurements.n0_power_avg : 0; + int SNRtimes10 = dB_fixed_x10(signal_pwr) - dB_fixed_x10(ue->measurements.n0_power_avg); + ue->measurements.ssb_sinr_dB[ssb_index] = SNRtimes10 / 10.0; + LOG_D(PHY, - "[UE %d] ssb %d SS-RSRP: %d dBm/RE (%d dB/RE)\n", + "[UE %d] ssb %d SS-RSRP: %d dBm/RE (%f dB/RE), SS-SINR: %f dB\n", ue->Mod_id, ssb_index, ue->measurements.ssb_rsrp_dBm[ssb_index], - rsrp_db_per_re); + rsrp_db_per_re, + ue->measurements.ssb_sinr_dB[ssb_index]); } // This function computes the received noise power diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c index dc634584f6..422e8d6484 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_initial_sync.c @@ -285,7 +285,8 @@ void nr_scan_ssb(void *arg) &ssbInfo->pbchResult, rxdataF); // start pbch detection at first symbol after pss if (ssbInfo->syncRes.cell_detected) { - int rsrp_db_per_re = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC); + uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, ssbInfo->proc, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC); + int rsrp_db_per_re = 10 * log10(rsrp_avg); ssbInfo->adjust_rxgain = TARGET_RX_POWER - rsrp_db_per_re; LOG_I(PHY, "pbch rx ok. rsrp:%d dB/RE, adjust_rxgain:%d dB\n", rsrp_db_per_re, ssbInfo->adjust_rxgain); } diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h index a617784e64..f724861e2d 100644 --- a/openair1/PHY/defs_nr_UE.h +++ b/openair1/PHY/defs_nr_UE.h @@ -140,6 +140,7 @@ typedef struct { uint32_t rsrp[7]; short rsrp_dBm[7]; int ssb_rsrp_dBm[64]; + float ssb_sinr_dB[64]; // common measurements //! estimated noise power (linear) unsigned int n0_power[NB_ANTENNAS_RX]; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d427e9721c..64ee69679a 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -175,6 +175,7 @@ void nr_fill_rx_indication(fapi_nr_rx_indication_t *rx_ind, rx->ssb_pdu.cell_id = frame_parms->Nid_cell; rx->ssb_pdu.ssb_start_subcarrier = frame_parms->ssb_start_subcarrier; rx->ssb_pdu.rsrp_dBm = ue->measurements.ssb_rsrp_dBm[frame_parms->ssb_index]; + rx->ssb_pdu.sinr_dB = ue->measurements.ssb_sinr_dB[frame_parms->ssb_index]; rx->ssb_pdu.arfcn = get_ssb_arfcn(frame_parms); rx->ssb_pdu.radiolink_monitoring = RLM_in_sync; // TODO to be removed from here rx->ssb_pdu.decoded_pdu = true; diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h index 3241235bd3..526e68892c 100644 --- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h +++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h @@ -417,6 +417,7 @@ typedef struct { uint32_t ssb_index; /// SSB RSRP in dBm short ssb_rsrp_dBm; + float_t ssb_sinr_dB; } NR_SSB_meas_t; typedef enum ta_type { diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c index dfb0a0d942..0d0829181e 100644 --- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c +++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c @@ -1133,10 +1133,11 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac, return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci); } -static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm) +static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm, float_t sinr_dB) { mac->ssb_measurements.ssb_index = ssb_index; mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm; + mac->ssb_measurements.ssb_sinr_dB = sinr_dB; } // L2 Abstraction Layer @@ -1272,7 +1273,8 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio if(rx_indication_body.ssb_pdu.decoded_pdu) { handle_ssb_meas(mac, rx_indication_body.ssb_pdu.ssb_index, - rx_indication_body.ssb_pdu.rsrp_dBm); + rx_indication_body.ssb_pdu.rsrp_dBm, + rx_indication_body.ssb_pdu.sinr_dB); ret_mask |= (handle_bcch_bch(mac, dl_info->cc_id, dl_info->gNB_index, From 516a61881678c120a8553ddf96f1e13d41ccee4e Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 19:17:42 +0100 Subject: [PATCH 23/48] UE changes- Generate SSB based SINR CSI report --- openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c | 158 ++++++++++++++++--- 1 file changed, 138 insertions(+), 20 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 572202d044..f61b6c4514 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c @@ -2643,6 +2643,111 @@ int nr_get_csi_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCC return num_csi; } +// Referred - Table 10.1.16.1-1 in 38.133 V16.7.0. +static uint8_t get_sinr_index(float sinr) +{ + int index = sinr * 2 + 47; + if (sinr >= 40) + index = 127; + if (sinr < -23) + index = 0; + + return index; +} + +// Reffered Table 10.1.16.1-2 in 38.133 V16.7.0. Differential value is reported. +static uint8_t get_sinr_diff_index(float best_sinr, float current_sinr) +{ + int diff = best_sinr - current_sinr; + if (diff >= 15) + return 15; + else if (diff <= 0) + return 0; + else + return diff; +} + +static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac, + struct NR_CSI_ReportConfig *csi_reportconfig, + NR_CSI_ResourceConfigId_t csi_ResourceConfigId, + NR_CSI_MeasConfig_t *csi_MeasConfig) +{ + int nb_ssb = 0; // nb of ssb in the resource + int nb_meas = 0; // nb of ssb to report measurements on + int bits = 0; + uint32_t temp_payload = 0; + + for (int csi_resourceidx = 0; csi_resourceidx < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_resourceidx++) { + struct NR_CSI_ResourceConfig *csi_resourceconfig = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_resourceidx]; + if (csi_resourceconfig->csi_ResourceConfigId == csi_ResourceConfigId) { + if (csi_reportconfig->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled) { + if (csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS != NULL) + nb_meas = *(csi_reportconfig->groupBasedBeamReporting.choice.disabled->nrofReportedRS) + 1; + else + nb_meas = 1; + } else + nb_meas = 2; + + struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource; + for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) { + if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId + == *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) { + SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList; + /// only one SSB resource set from spec 38.331 IE CSI-ResourceConfig + nb_ssb = SSB_resource.list.count; + break; + } + } + + AssertFatal(nb_ssb > 0, "No SSB found in the resource set\n"); + AssertFatal(nb_meas == 1, "PHY currently reports only the strongest SSB to MAC. Can't report more than 1 RSRP\n"); + int ssbri_bits = ceil(log2(nb_ssb)); + + int ssb_index[nb_meas]; // the array contains index and RSRP of each SSB to be reported (nb_meas highest RSRPs) + float ssb_sinr[nb_meas]; + + // TODO replace the following 2 lines with a function to order the nb_meas highest SSB RSRPs + for (int i = 0; i < nb_ssb; i++) { + ssb_index[i] = -1;//Invalid index + if (*SSB_resource.list.array[i] == mac->mib_ssb) { + ssb_index[0] = i; + break; + } + } + AssertFatal(ssb_index[0] >= 0, "Couldn't find corresponding SSB in csi_SSB_ResourceList\n"); + ssb_sinr[0] = mac->ssb_measurements.ssb_sinr_dB; + + uint8_t ssbi; + + // TS38.212 v16.5.0: Table 6.3.1.1.2-8A + if (ssbri_bits > 0) { + ssbi = ssb_index[0]; + temp_payload = reverse_bits(ssbi, ssbri_bits); + bits += ssbri_bits; + } + + uint8_t sinr_idx = get_sinr_index(ssb_sinr[0]); + temp_payload |= (reverse_bits(sinr_idx, 7) << bits); + bits += 7; // 7 bits for highest SINR + + // from the second SSB, differential report + for (int i = 1; i < nb_meas; i++) { + ssbi = ssb_index[i]; + temp_payload = reverse_bits(ssbi, ssbri_bits); + bits += ssbri_bits; + + sinr_idx = get_sinr_diff_index(ssb_sinr[0], ssb_sinr[i]); + temp_payload |= (reverse_bits(sinr_idx, 4) << bits); + bits += 4; // 7 bits for highest SINR + } + break; // resource found + } + } + AssertFatal(bits <= 32, "Not supporting CSI report with more than 32 bits\n"); + csi_payload_t csi = {.part1_payload = temp_payload, .p1_bits = bits, csi.p2_bits = 0}; + return csi; +} + csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, int csi_report_id, CSI_mapping_t mapping_type, @@ -2652,26 +2757,39 @@ csi_payload_t nr_get_csi_payload(NR_UE_MAC_INST_t *mac, csi_payload_t csi = {0}; struct NR_CSI_ReportConfig *csi_reportconfig = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[csi_report_id]; NR_CSI_ResourceConfigId_t csi_ResourceConfigId = csi_reportconfig->resourcesForChannelMeasurement; - switch(csi_reportconfig->reportQuantity.present) { - case NR_CSI_ReportConfig__reportQuantity_PR_none: - break; - case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - LOG_E(NR_MAC,"Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); - break; - default: - AssertFatal(1==0,"Invalid CSI report quantity type %d\n",csi_reportconfig->reportQuantity.present); + if (csi_reportconfig->ext2 && csi_reportconfig->ext2->reportQuantity_r16) { + switch (csi_reportconfig->ext2->reportQuantity_r16->present) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + csi = get_ssb_sinr_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + LOG_E(NR_MAC, "CSI Reporting of CSI-RS based SINR not yet available\n"); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity r16 type %d\n", csi_reportconfig->ext2->reportQuantity_r16->present); + } + } else { + switch (csi_reportconfig->reportQuantity.present) { + case NR_CSI_ReportConfig__reportQuantity_PR_none: + break; + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + csi = get_ssb_rsrp_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + csi = get_csirs_RI_PMI_CQI_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig, mapping_type); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + csi = get_csirs_RSRP_payload(mac, csi_reportconfig, csi_ResourceConfigId, csi_MeasConfig); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + LOG_E(NR_MAC, "Measurement report %d based on CSI-RS is not available\n", csi_reportconfig->reportQuantity.present); + break; + default: + AssertFatal(1 == 0, "Invalid CSI report quantity type %d\n", csi_reportconfig->reportQuantity.present); + } } return csi; } From 1666dced3eb0f9e5f5f2eb81dbfbc779938ecdb9 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Thu, 13 Feb 2025 21:45:40 +0100 Subject: [PATCH 24/48] gNB changes- Extract SSB-SINR from received CSI report --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c | 212 ++++++++++++------ openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 + 2 files changed, 148 insertions(+), 66 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c index 2b5cc97ffe..ddb5ba9ead 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c @@ -429,6 +429,78 @@ static uint8_t pickandreverse_bits(uint8_t *payload, uint16_t bitlen, uint8_t st return rev_bits; } +static void evaluate_sinr_report(gNB_MAC_INST *nrmac, + NR_UE_info_t *UE, + NR_UE_sched_ctrl_t *sched_ctrl, + uint8_t csi_report_id, + uint8_t *payload, + int *cumul_bits, + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16) +{ + /*! As per the spec 38.212 and table: 6.3.1.1.2-12 in a single UCI sequence we can have multiple CSI_report + * the number of CSI_report will depend on number of CSI resource sets that are configured in CSI-ResourceConfig RRC IE + * From spec 38.331 from the IE CSI-ResourceConfig for SSB RSRP reporting we can configure only one resource set + * From spec 38.214 section 5.2.1.2 For periodic and semi-persistent CSI Resource Settings, the number of CSI-RS Resource Sets + * configured is limited to S=1 + */ + + /** from 38.214 sec 5.2.1.4.2 + - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'disabled', the UE is + not required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in + a single report nrofReportedRS (higher layer configured) different CRI or SSBRI for each report setting + + - if the UE is configured with the higher layer parameter groupBasedBeamReporting set to 'enabled', the UE is not + required to update measurements for more than 64 CSI-RS and/or SSB resources, and the UE shall report in a + single reporting instance two different CRI or SSBRI for each report setting, where CSI-RS and/or SSB + resources can be received simultaneously by the UE either with a single spatial domain receive filter, or with + multiple simultaneous spatial domain receive filter + */ + + nr_csi_report_t *csi_report = &UE->csi_report_template[csi_report_id]; + RSRP_report_t *sinr_report; + long **index_list; + switch (reportQuantity_type_r16) { + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16: + sinr_report = &sched_ctrl->CSI_report.ssb_rsrp_report; + index_list = csi_report->SSB_Index_list; + break; + case NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16: + sinr_report = &sched_ctrl->CSI_report.csirs_rsrp_report; + index_list = csi_report->CSI_Index_list; + break; + default: + AssertFatal(false, "Invalid RSRP report type\n"); + } + + sinr_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri; + uint16_t curr_payload; + for (int i = 0; i < sinr_report->nr_reports; i++) { + int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen; + curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits); + sinr_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]); + LOG_D(MAC, "SSB/CSI-RS index = %d\n", sinr_report->resource_id[i]); + *cumul_bits += bitlen; + } + + curr_payload = pickandreverse_bits(payload, 7, *cumul_bits); + sinr_report->SINR_index[0] = curr_payload & 0x7f; + *cumul_bits += 7; + + csi_report->nb_of_csi_ssb_report++; + if (sinr_report->SINR_index[0] < 0 || sinr_report->SINR_index[0] > 127) { + LOG_E(NR_MAC, "UE %04x: reported SINR index %d invalid\n", UE->rnti, sinr_report->SINR_index[0]); + return; + } + + for (int i = 1; i < sinr_report->nr_reports; i++) { + curr_payload = pickandreverse_bits(payload, 4, *cumul_bits); + sinr_report->SINR_index[i] = curr_payload & 0x0f; + *cumul_bits += 4; + } + + LOG_D(MAC, "Reported SSB-SINR index = %d\n", sinr_report->SINR_index[0]); +} + static void evaluate_rsrp_report(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_UE_sched_ctrl_t *sched_ctrl, @@ -627,6 +699,8 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, uint8_t *payload = uci_pdu->csi_part1.csi_part1_payload; uint16_t bitlen = uci_pdu->csi_part1.csi_part1_bit_len; NR_CSI_ReportConfig__reportQuantity_PR reportQuantity_type = NR_CSI_ReportConfig__reportQuantity_PR_NOTHING; + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR reportQuantity_type_r16 = + NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_NOTHING; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; @@ -650,72 +724,78 @@ static void extract_pucch_csi_report(NR_CSI_MeasConfig_t *csi_MeasConfig, // verify if report with current id has been scheduled for this frame and slot if ((n_slots_frame*frame + slot - offset)%period == 0) { reportQuantity_type = csi_report->reportQuantity_type; - // phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP - if (get_softmodem_params()->phy_test - && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP - && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) - continue; - LOG_D(MAC,"SFN/SF:%d/%d reportQuantity type = %d\n",frame,slot,reportQuantity_type); - switch(reportQuantity_type) { - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: - evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: - evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); - beam_selection_procedures(nrmac, UE); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; - cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; - cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; - if(cri_bitlen) - evaluate_cri_report(payload,cri_bitlen,cumul_bits,sched_ctrl); - cumul_bits += cri_bitlen; - ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; - if(ri_bitlen) - r_index = evaluate_ri_report(payload,ri_bitlen,csi_report->csi_meas_bitlen.ri_restriction,cumul_bits,sched_ctrl); - cumul_bits += ri_bitlen; - li_bitlen = evaluate_li_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - cumul_bits += li_bitlen; - if (r_index != -1) - skip_zero_padding(&cumul_bits,csi_report,r_index,bitlen); - pmi_bitlen = evaluate_pmi_report(payload,csi_report,cumul_bits,r_index,sched_ctrl); - sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; - cumul_bits += pmi_bitlen; - evaluate_cqi_report(payload,csi_report,cumul_bits,r_index,UE,cqi_table); - break; - default: - AssertFatal(1==0, "Invalid or not supported CSI measurement report\n"); + reportQuantity_type_r16 = csi_report->reportQuantity_type_r16; + LOG_D(MAC, "SFN/SF:%d/%d reportQuantity type = %d, type_r16 = %d\n", frame, slot, reportQuantity_type, reportQuantity_type_r16); + if (reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_cri_SINR_r16 + || reportQuantity_type_r16 == NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16) { + evaluate_sinr_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type_r16); + } else { + // phy-test has hardcoded allocation, so no use to handle CSI reports except RSRP + if (get_softmodem_params()->phy_test + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP + && reportQuantity_type != NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP) + continue; + switch (reportQuantity_type) { + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP: + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP: + evaluate_rsrp_report(nrmac, UE, sched_ctrl, csi_report_id, payload, &cumul_bits, reportQuantity_type); + beam_selection_procedures(nrmac, UE); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; + cumul_bits += pmi_bitlen; + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI: + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report = true; + cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen; + if (cri_bitlen) + evaluate_cri_report(payload, cri_bitlen, cumul_bits, sched_ctrl); + cumul_bits += cri_bitlen; + ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen; + if (ri_bitlen) + r_index = evaluate_ri_report(payload, ri_bitlen, csi_report->csi_meas_bitlen.ri_restriction, cumul_bits, sched_ctrl); + cumul_bits += ri_bitlen; + li_bitlen = evaluate_li_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + cumul_bits += li_bitlen; + if (r_index != -1) + skip_zero_padding(&cumul_bits, csi_report, r_index, bitlen); + pmi_bitlen = evaluate_pmi_report(payload, csi_report, cumul_bits, r_index, sched_ctrl); + sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id = csi_report_id; + cumul_bits += pmi_bitlen; + evaluate_cqi_report(payload, csi_report, cumul_bits, r_index, UE, cqi_table); + break; + default: + AssertFatal(1 == 0, "Invalid or not supported CSI measurement report\n"); + } } } } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 513e62b5ac..0553464338 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -538,6 +538,8 @@ typedef struct RSRP_report { uint8_t nr_reports; uint8_t resource_id[MAX_NR_OF_REPORTED_RS]; int RSRP[MAX_NR_OF_REPORTED_RS]; + // SINR index according to tables 10.1.16.1-1, 10.1.16.1-2 + int SINR_index[MAX_NR_OF_REPORTED_RS]; } RSRP_report_t; struct CSI_Report { From bbcb31f64b8fcb65c498e2cd926396a1fe7a9c11 Mon Sep 17 00:00:00 2001 From: Raghavendra Dinavahi Date: Fri, 11 Apr 2025 14:50:16 +0200 Subject: [PATCH 25/48] Added description for do_SINR --- doc/MAC/mac-usage.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/MAC/mac-usage.md b/doc/MAC/mac-usage.md index e4d6ebc098..ae4f3a626b 100644 --- a/doc/MAC/mac-usage.md +++ b/doc/MAC/mac-usage.md @@ -250,6 +250,8 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. * `do_CSIRS` (default 0): flag whether to use channel-state information reference signal (CSI-RS) * `do_SRS` (default 0): flag whether to use sounding reference signal (SRS) +* `do_SINR` (default 0): flag whether to enable CSI reporting of SSB-SINR (introduced in rel16) + Default setting of CSI reporting quantity is SSB-RSRP. * `min_rxtxtime` (default 2): minimum feedback time for UE to respond to transmissions (k1 and k2 in 3GPP spec) * `ul_prbblacklist`: PRBs that should not be used for UL scheduling. Cf with @@ -272,6 +274,18 @@ configuration](../RRC/rrc-usage.md) as well for SIB configuration. - `du_sibs` (default `[]`): list of SIBs to transmit in the cell. Currently, SIB19 (for NTN) is supported. +| DL MIMO |`do_CSIRS`|`do_SINR`| CSI report Quantity | +| ---------------------------- | -------- | ------- | --------------------------------------------------| +| OFF (pdsch_AntennaPorts = 1) | 0 | 0 | SSB-RSRP | +| OFF (pdsch_AntennaPorts = 1) | 0 | 1 | SSB-SINR | +| OFF (pdsch_AntennaPorts = 1) | 1 | 0 | CSI-Reference signal RSRP | +| OFF (pdsch_AntennaPorts = 1) | 1 | 1 | CSI-Reference signal SINR (not supported yet) | +| ON (pdsch_AntennaPorts > 1) | 1 | 0 | cri-RI-PMI-CQI | + +DL-MIMO is configured using following parameters: +`pdsch_AntennaPorts_XP` , `pdsch_AntennaPorts_N1` , `pdsch_AntennaPorts_N2`, `maxMIMO_layers` +(see also [`RUNMODEM.md`](../RUNMODEM.md)) + ## ServingCellConfigCommon parameters The `gNBs` configuration section has a big structure `servingCellConfigCommon` From 5c4595e69954f5506ee9a01b3cea614da476a33c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 15 Apr 2025 18:34:47 +0200 Subject: [PATCH 26/48] Refactor 5GS registration result enc/dec functions * adopt byte_array * move enc/dec functions to Registration Accept library * simplify code * log result received in Registration Accept --- .../NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt | 1 - .../5GS/5GMM/IES/FGSRegistrationResult.c | 58 ------------------- .../5GS/5GMM/IES/FGSRegistrationResult.h | 55 ------------------ .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 38 ++++++++++-- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 14 +++-- openair3/NAS/NR_UE/nr_nas_msg.c | 8 ++- 6 files changed, 50 insertions(+), 124 deletions(-) delete mode 100644 openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c delete mode 100644 openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt index e865dd0046..40bfcbabcd 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/IES/CMakeLists.txt @@ -1,7 +1,6 @@ add_library(fgs_5gmm_ies_lib OBJECT FGSMobileIdentity.c FGSRegistrationType.c - FGSRegistrationResult.c FGMMCapability.c NrUESecurityCapability.c FGCNasMessageContainer.c diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c deleted file mode 100644 index 739cee7973..0000000000 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file FGSRegistrationResult.c - -\brief 5GS Registration result for registration request procedures -\author Yoshio INOUE, Masayuki HARADA -\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com -\date 2020 -\version 0.1 -*/ - -#include -#include -#include - -#include "TLVEncoder.h" -#include "TLVDecoder.h" -#include "FGSRegistrationResult.h" - -int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len) -{ - int decoded = 0; - uint16_t *buffer = &value; - fgsregistrationresult->registrationresult = *buffer & 0x7; - fgsregistrationresult->smsallowed = *buffer & 0x8; - decoded = decoded + 2; - return decoded; -} - -uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult) -{ - uint16_t bufferReturn; - uint16_t *buffer = &bufferReturn; - uint8_t encoded = 0; - *(buffer + encoded) = 0x00 | (fgsregistrationresult->smsallowed & 0x8) | (fgsregistrationresult->registrationresult & 0x7); - encoded = encoded + 2; - - return bufferReturn; -} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h b/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h deleted file mode 100644 index 04f45417b8..0000000000 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file FGSRegistrationResult.h - -\brief 5GS Registration result for registration request procedures -\author Yoshio INOUE, Masayuki HARADA -\email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com -\date 2020 -\version 0.1 -*/ - -#include -#include -#include - -#include "OctetString.h" - -#ifndef FGS_REGISTRATION_RESULT_H_ -#define FGS_REGISTRATION_RESULT_H_ -#define FGS_REGISTRATION_RESULT_3GPP 0b001 -#define FGS_REGISTRATION_RESULT_NON_3GPP 0b010 -#define FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP 0b011 - -typedef struct { - uint8_t iei; - uint8_t resultlength; - uint8_t spare: 4; - uint8_t smsallowed: 1; - uint8_t registrationresult: 3; -} FGSRegistrationResult; - -uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult); - -int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len); - -#endif /* FGS REGISTRATION RESULT_H_*/ diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index d92244a15f..dfcb1fce94 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -38,8 +38,36 @@ #include "RegistrationAccept.h" #include "assertions.h" #include "fgs_nas_utils.h" +#include "common/utils/utils.h" +#include "ds/byte_array.h" #define IEI_5G_GUTI 0x77 +#define FGS_REGISTRATION_RESULT_LEN 2 +#define REGISTRATION_ACCEPT_MIN_LEN FGS_REGISTRATION_RESULT_LEN // (5GS registration result) 2 octets + +/** @brief Decode 5GS registration result (9.11.3.6 3GPP TS 24.501) */ +static int decode_fgs_registration_result(registration_accept_msg *out, const byte_array_t buffer) +{ + if (buffer.len < FGS_REGISTRATION_RESULT_LEN) { + PRINT_NAS_ERROR("5GS registration result decoding failure: invalid buffer length\n"); + return -1; + } + out->result = buffer.buf[1] & 0x7; // skip length of contents octet + out->sms_allowed = buffer.buf[1] & 0x8; + return 2; // length 2 octets (no IEI) +} + +static int encode_fgs_registration_result(byte_array_t buffer, const registration_accept_msg *out) +{ + if (buffer.len < FGS_REGISTRATION_RESULT_LEN) { + PRINT_NAS_ERROR("5GS registration result encoding failure: invalid buffer length\n"); + return -1; + } + uint8_t *buf = buffer.buf; + buf[0] = 1; + buf[1] = 0x00 | (out->sms_allowed & 0x8) | (out->result & 0x7); + return 2; // encoded length 2 octets (no IEI) +} /** * @brief Allowed NSSAI from Registration Accept according to 3GPP TS 24.501 Table 8.2.7.1.1 @@ -105,8 +133,9 @@ int decode_registration_accept(registration_accept_msg *registration_accept, con int dec = 0; const uint8_t *end = buffer + len; - /* Decoding mandatory fields */ - if ((dec = decode_fgs_registration_result(®istration_accept->fgsregistrationresult, 0, *buffer, len)) < 0) + // 5GS registration result (Mandatory) + byte_array_t ba = {.buf = buffer, .len = len}; + if ((dec = decode_fgs_registration_result(registration_accept, ba)) < 0) return dec; buffer += dec; @@ -149,9 +178,8 @@ int encode_registration_accept(const registration_accept_msg *registration_accep int encoded = 0; LOG_FUNC_IN; - - *(buffer + encoded) = encode_fgs_registration_result(®istration_accept->fgsregistrationresult); - encoded = encoded + 2; + byte_array_t ba = {.buf = buffer, .len = len}; + encoded += encode_fgs_registration_result(ba, registration_accept); if (registration_accept->guti) { int mi_enc = encode_5gs_mobile_identity(registration_accept->guti, 0x77, buffer + encoded, len - encoded); diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 6abf1e70ca..5f444e95f9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -34,12 +34,17 @@ #include "SecurityHeaderType.h" #include "MessageType.h" -#include "FGSRegistrationResult.h" #include "FGSMobileIdentity.h" #ifndef REGISTRATION_ACCEPT_H_ #define REGISTRATION_ACCEPT_H_ +typedef enum { + FGS_REGISTRATION_RESULT_3GPP = 1, + FGS_REGISTRATION_RESULT_NON_3GPP = 2, + FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP = 3 +} fgs_registration_result_t; + // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; @@ -56,9 +61,10 @@ typedef struct { */ typedef struct registration_accept_msg_tag { - /* Mandatory fields */ - FGSRegistrationResult fgsregistrationresult; - /* Optional fields */ + // 5GS registration result (Mandatory) + fgs_registration_result_t result; + bool sms_allowed; + // 5G-GUTI (Optional) FGSMobileIdentity *guti; // Allowed NSSAI (O) nr_nas_msg_snssai_t nas_allowed_nssai[8]; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 941e0d7cdc..08003bbcba 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1438,7 +1438,6 @@ static void process_guti(Guti5GSMobileIdentity_t *guti, nr_ue_nas_t *nas) static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buffer, uint32_t msg_length) { - LOG_I(NAS, "[UE] Received REGISTRATION ACCEPT message\n"); registration_accept_msg msg = {0}; fgs_nas_message_security_header_t sp_header = {0}; const uint8_t *end = pdu_buffer + msg_length; @@ -1465,6 +1464,13 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff LOG_E(NAS, "Failed to decode NAS Registration Accept\n"); return; } + LOG_I(NAS, + "Received Registration Accept with result %s\n", + msg.result == FGS_REGISTRATION_RESULT_3GPP ? "3GPP" + : msg.result == FGS_REGISTRATION_RESULT_NON_3GPP ? "non-3PP" + : "3GPP and non-3GPP"); + LOG_I(NAS, "SMS %s in 5GS Registration Result\n", msg.sms_allowed ? "allowed" : "not allowed"); + pdu_buffer += decoded; // process GUTI if (msg.guti) { From 51661bd83ccffd8fa1d9f10c53c7a9968039139d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:18:00 +0100 Subject: [PATCH 27/48] Cleanup and other fixes to decode_registration_accept * adopt byte array * add check on minimum buffer length * improve comments * remove call to LOG utility functions * replace magic numbers with defines * refined includes --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 56 ++++++++++--------- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 13 +++-- openair3/NAS/NR_UE/nr_nas_msg.c | 3 +- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index dfcb1fce94..ed0de936f5 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -33,13 +33,11 @@ #include #include #include "conversions.h" -#include "TLVEncoder.h" -#include "TLVDecoder.h" #include "RegistrationAccept.h" -#include "assertions.h" #include "fgs_nas_utils.h" #include "common/utils/utils.h" #include "ds/byte_array.h" +#include "fgmm_lib.h" #define IEI_5G_GUTI 0x77 #define FGS_REGISTRATION_RESULT_LEN 2 @@ -128,56 +126,65 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) return decoded; } -int decode_registration_accept(registration_accept_msg *registration_accept, const uint8_t *buffer, uint32_t len) +size_t decode_registration_accept(registration_accept_msg *registration_accept, const byte_array_t buffer) { int dec = 0; - const uint8_t *end = buffer + len; + byte_array_t ba = buffer; // local copy of buffer + + if (ba.len < REGISTRATION_ACCEPT_MIN_LEN) { + PRINT_NAS_ERROR("Registration Accept decoding failed: invalid buffer length\n"); + return -1; + } // 5GS registration result (Mandatory) - byte_array_t ba = {.buf = buffer, .len = len}; if ((dec = decode_fgs_registration_result(registration_accept, ba)) < 0) - return dec; - buffer += dec; + return -1; + UPDATE_BYTE_ARRAY(ba, dec); - if (buffer < end && *buffer == IEI_5G_GUTI) { + // 5G-GUTI (Optional) + if (ba.len > 0 && ba.buf[0] == IEI_5G_GUTI) { registration_accept->guti = calloc_or_fail(1, sizeof(*registration_accept->guti)); - if ((dec = decode_5gs_mobile_identity(registration_accept->guti, IEI_5G_GUTI, buffer, end - buffer)) < 0) { + if ((dec = decode_5gs_mobile_identity(registration_accept->guti, IEI_5G_GUTI, ba.buf, ba.len)) < 0) { PRINT_NAS_ERROR("Failed to decode 5GS Mobile Identity in Registration Accept\n"); return -1; } - buffer += dec; + UPDATE_BYTE_ARRAY(ba, dec); } - // Allowed NSSAI (O) - /* Optional Presence IEs */ - while (buffer < end) { - const int iei = *buffer++; + // Decode other Optional IEs + while (ba.len > 0) { + uint8_t iei = ba.buf[0]; + UPDATE_BYTE_ARRAY(ba, 1); + switch (iei) { case 0x15: // allowed NSSAI - dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, buffer); - buffer += dec; + dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ba.buf); + UPDATE_BYTE_ARRAY(ba, dec); break; case 0x31: // configured NSSAI - dec = decode_nssai_ie(registration_accept->config_nssai, buffer); - buffer += dec; + dec = decode_nssai_ie(registration_accept->config_nssai, ba.buf); + UPDATE_BYTE_ARRAY(ba, dec); break; default: - dec = *buffer++; // content length + 1 byte (Length IE) - buffer += dec; + dec = ba.buf[0] + 1; // content length + 1 byte (Length IE) + UPDATE_BYTE_ARRAY(ba, dec); break; } } - return len; + if(ba.len != 0) { + PRINT_NAS_ERROR("Failed to decode registration accept: ba.len = %ld\n", ba.len); + return -1; + } + return buffer.len; } int encode_registration_accept(const registration_accept_msg *registration_accept, uint8_t *buffer, uint32_t len) { int encoded = 0; - LOG_FUNC_IN; byte_array_t ba = {.buf = buffer, .len = len}; encoded += encode_fgs_registration_result(ba, registration_accept); @@ -188,6 +195,5 @@ int encode_registration_accept(const registration_accept_msg *registration_accep encoded += mi_enc; } - // todo ,Encoding optional fields - LOG_FUNC_RETURN(encoded); + return encoded; } diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 5f444e95f9..8c044603de 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -35,6 +35,7 @@ #include "SecurityHeaderType.h" #include "MessageType.h" #include "FGSMobileIdentity.h" +#include "ds/byte_array.h" #ifndef REGISTRATION_ACCEPT_H_ #define REGISTRATION_ACCEPT_H_ @@ -45,6 +46,8 @@ typedef enum { FGS_REGISTRATION_RESULT_3GPP_AND_NON_3GPP = 3 } fgs_registration_result_t; +#define NAS_MAX_NUMBER_SLICES 8 + // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; @@ -66,13 +69,13 @@ typedef struct registration_accept_msg_tag { bool sms_allowed; // 5G-GUTI (Optional) FGSMobileIdentity *guti; - // Allowed NSSAI (O) - nr_nas_msg_snssai_t nas_allowed_nssai[8]; - // Configured NSSAI (O) - nr_nas_msg_snssai_t config_nssai[8]; + // Allowed NSSAI (Optional) + nr_nas_msg_snssai_t nas_allowed_nssai[NAS_MAX_NUMBER_SLICES]; + // Configured NSSAI (Optional) + nr_nas_msg_snssai_t config_nssai[NAS_MAX_NUMBER_SLICES]; } registration_accept_msg; -int decode_registration_accept(registration_accept_msg *registrationaccept, const uint8_t *buffer, uint32_t len); +size_t decode_registration_accept(registration_accept_msg *registrationaccept, const byte_array_t buffer); int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 08003bbcba..5ee233172c 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1460,7 +1460,8 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff } pdu_buffer += decoded; // plain payload - if ((decoded = decode_registration_accept(&msg, pdu_buffer, end - pdu_buffer)) < 0) { + const byte_array_t ba = {.buf = (uint8_t *)pdu_buffer, .len = end - pdu_buffer}; + if ((decoded = decode_registration_accept(&msg, ba)) < 0) { LOG_E(NAS, "Failed to decode NAS Registration Accept\n"); return; } From c6271a23e4b1e94997616e332199dee6207c059e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 15 Apr 2025 17:42:56 +0200 Subject: [PATCH 28/48] Add number of slices to decoding of NSSAI --- openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 7 ++++--- openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 2 ++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index ed0de936f5..d65d196701 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -70,7 +70,7 @@ static int encode_fgs_registration_result(byte_array_t buffer, const registratio /** * @brief Allowed NSSAI from Registration Accept according to 3GPP TS 24.501 Table 8.2.7.1.1 */ -static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) +static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint8_t *buf) { const int length = *buf; // Length of S-NSSAI IE contents (list of S-NSSAIs) const uint32_t decoded = length + 1; // Length IE (1 octet) @@ -123,6 +123,7 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) break; } } + *num_slices = nssai_cnt; return decoded; } @@ -159,12 +160,12 @@ size_t decode_registration_accept(registration_accept_msg *registration_accept, switch (iei) { case 0x15: // allowed NSSAI - dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ba.buf); + dec = decode_nssai_ie(registration_accept->nas_allowed_nssai, ®istration_accept->num_allowed_slices, ba.buf); UPDATE_BYTE_ARRAY(ba, dec); break; case 0x31: // configured NSSAI - dec = decode_nssai_ie(registration_accept->config_nssai, ba.buf); + dec = decode_nssai_ie(registration_accept->config_nssai, ®istration_accept->num_configured_slices, ba.buf); UPDATE_BYTE_ARRAY(ba, dec); break; diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 8c044603de..4c50de9384 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -71,8 +71,10 @@ typedef struct registration_accept_msg_tag { FGSMobileIdentity *guti; // Allowed NSSAI (Optional) nr_nas_msg_snssai_t nas_allowed_nssai[NAS_MAX_NUMBER_SLICES]; + uint8_t num_allowed_slices; // Configured NSSAI (Optional) nr_nas_msg_snssai_t config_nssai[NAS_MAX_NUMBER_SLICES]; + uint8_t num_configured_slices; } registration_accept_msg; size_t decode_registration_accept(registration_accept_msg *registrationaccept, const byte_array_t buffer); From 73b89726ad993f5accdfe9e60bb2ea94662076c6 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:24:27 +0100 Subject: [PATCH 29/48] Remove harcoded Slice Differentiator (SD) in NAS decode_nssai_ie and update the processing logic The SD stored in the allowed S-NSSAI list was hardcoded in the decoding function, however this IE is not mandatory but optional, therefore the check of the decoded message contents should take into account this and check the stored value against the one from the UICC only when the field is present. If no SD was received, consider the UICC SD a valid one. Also, add free function to Registration Accept library and adopt in stack to free NAS Registration Accept after use: heap memory is allocated for this message during decoding and shall be free after processing. --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 40 +++++++++++++++---- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 8 ++-- openair3/NAS/NR_UE/nr_nas_msg.c | 12 ++++-- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index d65d196701..f6b67edb11 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -79,7 +79,6 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint const uint8_t *end = buf + length; while (buf < end) { nr_nas_msg_snssai_t *item = nssai + nssai_cnt; - item->sd = 0xffffff; const int item_len = *buf++; // Length of S-NSSAI IE item switch (item_len) { case 1: @@ -89,31 +88,38 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, uint8_t *num_slices, uint case 2: item->sst = *buf++; - item->hplmn_sst = *buf++; + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; nssai_cnt++; break; case 4: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; nssai_cnt++; break; case 5: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; - item->hplmn_sst = *buf++; + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; nssai_cnt++; break; case 8: item->sst = *buf++; - item->sd = 0xffffff & ntoh_int24_buf(buf); + item->sd = malloc_or_fail(sizeof(*item->sd)); + *item->sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; - item->hplmn_sst = *buf++; - item->hplmn_sd = 0xffffff & ntoh_int24_buf(buf); + item->hplmn_sst = malloc_or_fail(sizeof(*item->hplmn_sst)); + *item->hplmn_sst = *buf++; + item->hplmn_sd = malloc_or_fail(sizeof(*item->hplmn_sd)); + *item->hplmn_sd = 0xffffff & ntoh_int24_buf(buf); buf += 3; nssai_cnt++; break; @@ -198,3 +204,21 @@ int encode_registration_accept(const registration_accept_msg *registration_accep return encoded; } + +/** Memory management of NAS Registration Accept */ + +static void free_nssai(nr_nas_msg_snssai_t *msg) +{ + free(msg->hplmn_sd); + free(msg->hplmn_sst); + free(msg->sd); +} + +void free_fgmm_registration_accept(registration_accept_msg *msg) +{ + free(msg->guti); + for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) { + free_nssai(&msg->nas_allowed_nssai[i]); + free_nssai(&msg->config_nssai[i]); + } +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index 4c50de9384..c373c067fa 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -51,9 +51,9 @@ typedef enum { // 9.11.3.37 of 3GPP TS 24.501 typedef struct { int sst; - int hplmn_sst; - int sd; - int hplmn_sd; + int *hplmn_sst; + int *sd; + int *hplmn_sd; } nr_nas_msg_snssai_t; /* @@ -81,4 +81,6 @@ size_t decode_registration_accept(registration_accept_msg *registrationaccept, c int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); +void free_fgmm_registration_accept(registration_accept_msg *msg); + #endif /* ! defined(REGISTRATION_ACCEPT_H_) */ diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 5ee233172c..55bad1c2eb 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1410,11 +1410,14 @@ static void request_default_pdusession(nr_ue_nas_t *nas) itti_send_msg_to_task(TASK_NAS_NRUE, nas->UE_id, message_p); } -static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[8], const nr_ue_nas_t *nas) +static int get_user_nssai_idx(const nr_nas_msg_snssai_t allowed_nssai[NAS_MAX_NUMBER_SLICES], const nr_ue_nas_t *nas) { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < NAS_MAX_NUMBER_SLICES; i++) { const nr_nas_msg_snssai_t *nssai = allowed_nssai + i; - if ((nas->uicc->nssai_sst == nssai->sst) && (nas->uicc->nssai_sd == nssai->sd)) + /* If it was received in Registration Accept, check the SD + in the stored Allowed N-SSAI, else, consider the SD valid */ + bool sd_match = !nssai->sd || (nas->uicc->nssai_sd == *nssai->sd); + if ((nas->uicc->nssai_sst == nssai->sst) && sd_match) return i; } return -1; @@ -1476,7 +1479,6 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff // process GUTI if (msg.guti) { process_guti(&msg.guti->guti, nas); - free(msg.guti); } else { LOG_W(NAS, "no GUTI in registration accept\n"); } @@ -1495,6 +1497,8 @@ static void handle_registration_accept(nr_ue_nas_t *nas, const uint8_t *pdu_buff } else { request_default_pdusession(nas); } + // Free local message after processing + free_fgmm_registration_accept(&msg); } /* 3GPP TS 24.008 10.5.7.3 GPRS Timer */ From 3fe601fa6b6c847e0e491b59375a5d275f4b09e4 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:26:42 +0100 Subject: [PATCH 30/48] Add equality check to NAS Registration Accept library --- .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.c | 77 +++++++++++++++++++ .../NR_UE/5GS/5GMM/MSG/RegistrationAccept.h | 2 + 2 files changed, 79 insertions(+) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index f6b67edb11..bc5c86f88e 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -205,6 +205,83 @@ int encode_registration_accept(const registration_accept_msg *registration_accep return encoded; } +/** Equality check for NAS Registration Accept */ + +bool eq_snssai(const nr_nas_msg_snssai_t *a, const nr_nas_msg_snssai_t *b) +{ + _NAS_EQ_CHECK_INT(a->sst, b->sst); + + if ((a->hplmn_sst && !b->hplmn_sst) || (!a->hplmn_sst && b->hplmn_sst)) + return false; + if (a->hplmn_sst && b->hplmn_sst) + _NAS_EQ_CHECK_INT(*a->hplmn_sst, *b->hplmn_sst); + + if ((a->sd && !b->sd) || (!a->sd && b->sd)) + return false; + if (a->sd && b->sd) + _NAS_EQ_CHECK_INT(*a->sd, *b->sd); + + if ((a->hplmn_sd && !b->hplmn_sd) || (!a->hplmn_sd && b->hplmn_sd)) + return false; + if (a->hplmn_sd && b->hplmn_sd) + _NAS_EQ_CHECK_INT(*a->hplmn_sd, *b->hplmn_sd); + + return true; +} + + +bool eq_fgmm_registration_accept(const registration_accept_msg *a, const registration_accept_msg *b) +{ + if (!a || !b) { + PRINT_NAS_ERROR("Null pointer in registration_accept_msg_eq\n"); + return false; + } + + // 5GS registration result (mandatory) + _NAS_EQ_CHECK_INT(a->result, b->result); + _NAS_EQ_CHECK_INT(a->sms_allowed, b->sms_allowed); + + // GUTI (optional) + if (a->guti && b->guti) { + _NAS_EQ_CHECK_INT(a->guti->guti.spare, b->guti->guti.spare); + _NAS_EQ_CHECK_INT(a->guti->guti.oddeven, b->guti->guti.oddeven); + _NAS_EQ_CHECK_INT(a->guti->guti.typeofidentity, b->guti->guti.typeofidentity); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit2, b->guti->guti.mccdigit2); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit1, b->guti->guti.mccdigit1); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit3, b->guti->guti.mncdigit3); + _NAS_EQ_CHECK_INT(a->guti->guti.mccdigit3, b->guti->guti.mccdigit3); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit2, b->guti->guti.mncdigit2); + _NAS_EQ_CHECK_INT(a->guti->guti.mncdigit1, b->guti->guti.mncdigit1); + _NAS_EQ_CHECK_INT(a->guti->guti.amfregionid, b->guti->guti.amfregionid); + _NAS_EQ_CHECK_INT(a->guti->guti.amfsetid, b->guti->guti.amfsetid); + _NAS_EQ_CHECK_INT(a->guti->guti.amfpointer, b->guti->guti.amfpointer); + _NAS_EQ_CHECK_INT(a->guti->guti.tmsi, b->guti->guti.tmsi); + } else if ((a->guti && !b->guti) || (!a->guti && b->guti)) { + PRINT_NAS_ERROR("NAS Equality Check failure: One of the two GUTIs is NULL\n"); + return false; + } + + _NAS_EQ_CHECK_INT(a->num_allowed_slices, b->num_allowed_slices); + _NAS_EQ_CHECK_INT(a->num_configured_slices, b->num_configured_slices); + + // Configured NSSAI (optional) + for (int i = 0; i < a->num_configured_slices; i++) { + if (!eq_snssai(&a->config_nssai[i], &b->config_nssai[i])) { + PRINT_NAS_ERROR("NAS Equality Check failure: Configured NSSAI\n"); + return false; + } + } + // Allowed NSSAI (optional) + for (int i = 0; i < a->num_allowed_slices; i++) { + if (!eq_snssai(&a->nas_allowed_nssai[i], &b->nas_allowed_nssai[i])) { + PRINT_NAS_ERROR("NAS Equality Check failure: Allowed NSSAI\n"); + return false; + } + } + + return true; +} + /** Memory management of NAS Registration Accept */ static void free_nssai(nr_nas_msg_snssai_t *msg) diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h index c373c067fa..42b02407d9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "SecurityHeaderType.h" #include "MessageType.h" @@ -81,6 +82,7 @@ size_t decode_registration_accept(registration_accept_msg *registrationaccept, c int encode_registration_accept(const registration_accept_msg *registrationaccept, uint8_t *buffer, uint32_t len); +bool eq_fgmm_registration_accept(const registration_accept_msg *a, const registration_accept_msg *b); void free_fgmm_registration_accept(registration_accept_msg *msg); #endif /* ! defined(REGISTRATION_ACCEPT_H_) */ From a19c7866006b83af081d755c15b8c9eca58bac57 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 7 Feb 2025 17:27:08 +0100 Subject: [PATCH 31/48] Add regression test for NAS Registration Accept decoding This test verifies that a NAS Registration Accept message, as received from the OAI CN5G, is correctly decoded and matches the expected output structure. It ensures that future changes to the NAS decoder do not break compatibility or correctness with existing decoding behavior. --- openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c | 61 +++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c index a73ee9b2be..2ccf78fa59 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -3,6 +3,7 @@ #include #include #include "common/utils/ds/byte_array.h" +#include "RegistrationAccept.h" #include "fgs_service_request.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" @@ -26,6 +27,65 @@ static bool eq_service_request(const fgs_service_request_msg_t *a, const fgs_ser return result; } +/** @brief Test regression of NAS Registration Accept decoding + * This test verifies that the NAS Registration Accept message + * is correctly decoded. It decodes a message as it received from + * the OAI CN5G and compares the output with the expected Registration Accept structure. + * The purpose of this regression test is to ensure that changes + * to the NAS decoder do not break the existing decoding behavior with OAI CN5G */ +static void test_regression_registration_accept(void) +{ + // Registration Accept message + registration_accept_msg orig = { + .guti = malloc_or_fail(sizeof(*orig.guti)), + .result = 0x01, + .nas_allowed_nssai[0].sst = 0x01, + .nas_allowed_nssai[1].sst = 0x02, + .nas_allowed_nssai[2].sst = 0x03, + .num_allowed_slices = 3, + .config_nssai[0].sst = 0x01, + .config_nssai[1].sst = 0x02, + .config_nssai[2].sst = 0x03, + .num_configured_slices = 3, + }; + + orig.guti->guti.typeofidentity = FGS_MOBILE_IDENTITY_5G_GUTI; + orig.guti->guti.amfpointer = 0x01; + orig.guti->guti.amfregionid = 0x02; + orig.guti->guti.amfsetid = 0x01; + orig.guti->guti.mccdigit1 = 0x00; + orig.guti->guti.mccdigit2 = 0x00; + orig.guti->guti.mccdigit3 = 0x01; + orig.guti->guti.mncdigit1 = 0x00; + orig.guti->guti.mncdigit2 = 0x01; + orig.guti->guti.mncdigit3 = 0x0F; + orig.guti->guti.tmsi = 0xb0207806; + orig.guti->guti.spare = 0b1111; + orig.guti->guti.oddeven = 0; + + // Encoded Registration Accept message from OAI CN5G + uint8_t cn5g_msg[] = {0x01, 0x01, // Registration Result + 0x77, 0x00, 0x0B, 0xF2, 0x00, 0xF1, 0x10, // 5G-GUTI + 0x02, 0x00, 0x41, 0xB0, 0x20, 0x78, 0x06, // 5G-GUTI + 0x15, 0x06, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03, // Allowed N-NSSAI + 0x31, 0x06, 0x01, 0x01, 0x01, 0x02, 0x01, 0x03}; // Configured N-NSSAI + + // Decode NAS Registration Accept + int encoded_length; + registration_accept_msg decoded = {0}; + byte_array_t ba = {.buf = cn5g_msg, .len = sizeof(cn5g_msg)}; + encoded_length = decode_registration_accept(&decoded, ba); + AssertFatal(encoded_length >= 0, "encode_fgs_service_request() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + bool ret = eq_fgmm_registration_accept(&orig, &decoded); + AssertFatal(ret, "Encoding mismatch!\n"); + + // Free dynamic allocated memory + free_fgmm_registration_accept(&orig); + free_fgmm_registration_accept(&decoded); +} + /** * @brief Test NAS Service Request enc/dec */ @@ -172,6 +232,7 @@ static void test_service_reject(void) int main() { + test_regression_registration_accept(); test_service_request(); test_service_accept(); test_service_reject(); From 5ac3f59d619d4e46a865d764fc22b8d49e195514 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 16 Apr 2025 12:59:13 +0000 Subject: [PATCH 32/48] NR UE: fix and improve PHY layer debugging --- openair1/PHY/MODULATION/slot_fep_nr.c | 18 ------- .../nr_dl_channel_estimation.c | 48 +++++++------------ .../NR_UE_TRANSPORT/nr_dlsch_demodulation.c | 39 ++++++++------- openair1/SCHED_NR_UE/phy_procedures_nr_ue.c | 7 +-- 4 files changed, 40 insertions(+), 72 deletions(-) diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 201101a39a..10d6ef87f4 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -28,13 +28,6 @@ #include "PHY/nr_phy_common/inc/nr_phy_common.h" #include -//#define DEBUG_FEP - -/*#ifdef LOG_I -#undef LOG_I -#define LOG_I(A,B...) printf(A) -#endif*/ - int nr_slot_fep(PHY_VARS_NR_UE *ue, const NR_DL_FRAME_PARMS *frame_parms, unsigned int slot, @@ -44,7 +37,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, uint32_t sample_offset, c16_t **rxdata) { - AssertFatal(symbol < frame_parms->symbols_per_slot, "slot_fep: symbol must be between 0 and %d\n", frame_parms->symbols_per_slot-1); AssertFatal(slot < frame_parms->slots_per_frame, "slot_fep: Ns must be between 0 and %d\n", frame_parms->slots_per_frame - 1); @@ -81,12 +73,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, // use OFDM symbol from within 1/8th of the CP to avoid ISI rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor); -#ifdef DEBUG_FEP - // if (ue->frame <100) - LOG_D(PHY,"slot_fep: slot %d, symbol %d, nb_prefix_samples %u, nb_prefix_samples0 %u, rx_offset %u energy %d\n", - Ns, symbol, nb_prefix_samples, nb_prefix_samples0, rx_offset, dB_fixed(signal_energy((int32_t *)&common_vars->rxdata[0][rx_offset],frame_parms->ofdm_symbol_size))); -#endif - for (unsigned char aa=0; aanb_antennas_rx; aa++) { int16_t *rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset]; @@ -129,10 +115,6 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, apply_nr_rotation_RX(frame_parms, rxdataF[aa], frame_parms->symbol_rotation[linktype], slot, N_RB, 0, symbol, 1); } -#ifdef DEBUG_FEP - printf("slot_fep: done\n"); -#endif - return 0; } diff --git a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c index b6161e0e27..cb7a2d3604 100644 --- a/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c +++ b/openair1/PHY/NR_UE_ESTIMATION/nr_dl_channel_estimation.c @@ -1081,7 +1081,6 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *dl_ch, unsigned short bwp_start_subcarrier, unsigned short nb_rb_pdsch, - int8_t delta, delay_t *delay, uint32_t *nvar) { @@ -1094,30 +1093,23 @@ void NFAPI_NR_DMRS_TYPE1_linear_interp(NR_DL_FRAME_PARMS *frame_parms, int nest_count = 0; uint64_t noise_amp2 = 0; - for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt++) { - if (pilot_cnt % 2 == 0) { - c16_t ch = c16mulShift(*pil, rxF[re_offset], 15); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - ch = c16maddShift(*pil, rxF[re_offset], ch, 15); - ch = c16Shift(ch, 1); - pil++; - re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; - for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { - dl_ls_est[k] = ch; - } - } - + for (int pilot_cnt = 0; pilot_cnt < 6 * nb_rb_pdsch; pilot_cnt += 2) { + c16_t ch_l = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", - pilot_cnt, - pil->r, - pil->i, - rxF[re_offset].r, - rxF[re_offset].i, - dl_ls_est[pilot_cnt << 1].r, - dl_ls_est[pilot_cnt << 1].i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_l.r, ch_l.i); #endif + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); +#ifdef DEBUG_PDSCH + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); +#endif + c16_t ch = c16addShift(ch_l, ch_r, 1); + pil++; + re_offset = (re_offset + 2) % frame_parms->ofdm_symbol_size; + for (int k = pilot_cnt << 1; k < (pilot_cnt << 1) + 4; k++) { + dl_ls_est[k] = ch; + } } c16_t ch_estimates_time[frame_parms->ofdm_symbol_size] __attribute__((aligned(32))); @@ -1247,8 +1239,6 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, c16_t *dl_ch, unsigned short bwp_start_subcarrier, unsigned short nb_rb_pdsch, - int8_t delta, - unsigned short p, delay_t *delay, uint32_t *nvar) { @@ -1270,7 +1260,7 @@ void NFAPI_NR_DMRS_TYPE2_linear_interp(NR_DL_FRAME_PARMS *frame_parms, re_offset = (re_offset + 1) % frame_parms->ofdm_symbol_size; c16_t ch_r = c16mulShift(*pil, rxF[re_offset], 15); #ifdef DEBUG_PDSCH - printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); + printf("pilot %3d: pil -> (%6d,%6d), rxF -> (%4d,%4d), ch -> (%4d,%4d) \n", pilot_cnt + 1, pil->r, pil->i, rxF[re_offset].r, rxF[re_offset].i, ch_r.r, ch_r.i); #endif c16_t ch = c16addShift(ch_l, ch_r, 1); for (int k = 3 * pilot_cnt; k < (3 * pilot_cnt) + 6; k++) { @@ -1427,9 +1417,8 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, #ifdef DEBUG_PDSCH printf( - "PDSCH Channel Estimation : gNB_id %d ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d " + "PDSCH Channel Estimation : ch_offset %d, symbol_offset %d OFDM size %d, Ncp=%d, Ns=%d, bwp_start_subcarrier=%d " "symbol %d\n", - gNB_id, ch_offset, symbol_offset, fp->ofdm_symbol_size, @@ -1467,7 +1456,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, dl_ch, bwp_start_subcarrier, nb_rb_pdsch, - delta, &delay, nvar); @@ -1478,8 +1466,6 @@ int nr_pdsch_channel_estimation(PHY_VARS_NR_UE *ue, dl_ch, bwp_start_subcarrier, nb_rb_pdsch, - delta, - p, &delay, nvar); diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c index 74543a250d..fddc2a7654 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_demodulation.c @@ -576,6 +576,25 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, *log2_maxh, ue->phy_cpu_stats.cpu_time_stats[DLSCH_CHANNEL_COMPENSATION_STATS].p_time / (cpuf * 1000.0)); } + // Please keep it: useful for debugging +#ifdef DEBUG_PDSCH_RX + char filename[50]; + + snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); + write_output(filename, "rxdataF0", &rxdataF[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); + + snprintf(filename, 50, "dl_ch_estimates0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); + write_output(filename, "dl_ch_estimates0", &dl_ch_estimates[0][symbol * frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size, 1, 1); + + snprintf(filename, 50, "rxdataF_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); + write_output(filename, "rxdataF_ext0", &rxdataF_ext[0][0], rx_size_symbol, 1, 1); + + snprintf(filename, 50, "dl_ch_estimates_ext0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); + write_output(filename, "dl_ch_estimates_ext0", &dl_ch_estimates_ext[0][0], rx_size_symbol, 1, 1); + + snprintf(filename, 50, "rxdataF_comp00_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); + write_output(filename, "rxdataF_comp00", &rxdataF_comp[0][0][symbol * rx_size_symbol], rx_size_symbol, 1, 1); +#endif } start_meas_nr_ue_phy(ue, DLSCH_MRC_MMSE_STATS); @@ -694,32 +713,12 @@ int nr_rx_pdsch(PHY_VARS_NR_UE *ue, rx_llr_layer_size, layer_llr); stop_meas_nr_ue_phy(ue, DLSCH_LAYER_DEMAPPING); - // Please keep it: useful for debugging -#ifdef DEBUG_PDSCH_RX - char filename[50]; - uint8_t aa = 0; - - snprintf(filename, 50, "rxdataF0_symb_%d_nr_slot_rx_%d.m", symbol, nr_slot_rx); - write_output(filename, "rxdataF0", &rxdataF[0][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1); - - snprintf(filename, 50, "dl_ch_estimates0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx); - write_output(filename, "dl_ch_estimates", &dl_ch_estimates[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->ofdm_symbol_size, 1, 1); - - snprintf(filename, 50, "rxdataF_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx); - write_output(filename, "rxdataF_ext", &rxdataF_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1); - - snprintf(filename, 50, "dl_ch_estimates_ext0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx); - write_output(filename, "dl_ch_estimates_ext00", &dl_ch_estimates_ext[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1); - - snprintf(filename, 50, "rxdataF_comp0%d_symb_%d_nr_slot_rx_%d.m", aa, symbol, nr_slot_rx); - write_output(filename, "rxdataF_comp00", &rxdataF_comp[aa][0], NR_SYMBOLS_PER_SLOT*frame_parms->N_RB_DL*NR_NB_SC_PER_RB, 1, 1); /* for (int i=0; i < 2; i++){ snprintf(filename, 50, "llr%d_symb_%d_nr_slot_rx_%d.m", i, symbol, nr_slot_rx); write_output(filename,"llr", &llr[i][0], (NR_SYMBOLS_PER_SLOT*nb_rb_pdsch*NR_NB_SC_PER_RB*dlsch1_harq->Qm) - 4*(nb_rb_pdsch*4*dlsch1_harq->Qm), 1, 0); } */ -#endif if (UEScopeHasTryLock(ue)) { metadata mt = {.frame = proc->frame_rx, .slot = proc->nr_slot_rx }; int total_valid_res = 0; diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d427e9721c..cf334c1478 100644 --- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c +++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c @@ -485,6 +485,7 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, c16_t rxdataF[][ue->frame_parms.samples_per_slot_wCP], int G) { + int frame_rx = proc->frame_rx; int nr_slot_rx = proc->nr_slot_rx; // We handle only one CW now @@ -496,9 +497,10 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, NR_DL_UE_HARQ_t *dlsch0_harq = &ue->dl_harq_processes[0][harq_pid]; LOG_D(PHY, - "[UE %d] nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask " + "[UE %d] frame_rx %d, nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask " "%x, Nl %d\n", ue->Mod_id, + frame_rx, nr_slot_rx, harq_pid, dlsch0_harq->status, @@ -558,10 +560,9 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue, nvar += nvar_tmp; #if 0 ///LOG_M: the channel estimation - int nr_frame_rx = proc->frame_rx; char filename[100]; for (uint8_t aarx=0; aarxframe_parms.nb_antennas_rx; aarx++) { - sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", nr_frame_rx, nr_slot_rx, m, nl, aarx); + sprintf(filename,"PDSCH_CHANNEL_frame%d_slot%d_sym%d_port%d_rx%d.m", frame_rx, nr_slot_rx, m, nl, aarx); int **dl_ch_estimates = ue->pdsch_vars[gNB_id]->dl_ch_estimates; LOG_M(filename,"channel_F",&dl_ch_estimates[nl*ue->frame_parms.nb_antennas_rx+aarx][ue->frame_parms.ofdm_symbol_size*m],ue->frame_parms.ofdm_symbol_size, 1, 1); } From 1ab8a58a2f7402e69f2b571b45b59c8672df8f0f Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 17 Feb 2025 13:12:48 +0100 Subject: [PATCH 33/48] Refactor TUN Interface Management and Move to SDAP Layer This commit refactors the TUN interface management by moving its creation and configuration from the PDCP layer to the SDAP layer for UE. Key changes include: - Introduced `tun_generate_ue_ifname` and `tun_destroy` functions for better TUN interface lifecycle management. - Added support for creating and destroying UE-specific TUN interfaces in SDAP. - Refactored `nr_pdcp_module_init` to remove TUN-related logic and moved it to SDAP. - Updated NAS and SDAP layers to handle PDU session-specific TUN interface creation and configuration. - Enhanced SDAP entity management to include TUN socket handling and thread lifecycle. - Updated NAS message handling to initialize default PDU session TUN interfaces in NOS1 mode. - Use a single SDAP thread function for gNB and UE - Allow noS1 mode also in SA on gNB These changes improve modularity by isolating TUN interface management within the SDAP layer, aligning with the 3GPP architecture, and simplifying the PDCP layer. Co-Authored-By: Robert Schmidt --- common/utils/tun_if.c | 28 ++- common/utils/tun_if.h | 15 ++ doc/SW_archi.md | 2 +- executables/nr-softmodem.c | 4 +- executables/nr-uesoftmodem.c | 25 +-- executables/softmodem-common.h | 4 + openair2/COMMON/as_message.h | 4 + openair2/COMMON/rrc_messages_def.h | 1 + openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 211 +--------------------- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 1 - openair2/RRC/NR_UE/main_ue.c | 2 + openair2/SDAP/nr_sdap/nr_sdap.c | 130 ++++++++++++- openair2/SDAP/nr_sdap/nr_sdap.h | 4 +- openair2/SDAP/nr_sdap/nr_sdap_entity.c | 26 ++- openair2/SDAP/nr_sdap/nr_sdap_entity.h | 7 + openair3/NAS/NR_UE/nr_nas_msg.c | 45 ++--- openair3/NAS/NR_UE/nr_nas_msg.h | 1 + 17 files changed, 238 insertions(+), 272 deletions(-) diff --git a/common/utils/tun_if.c b/common/utils/tun_if.c index 79fcc6a954..87bba5a513 100644 --- a/common/utils/tun_if.c +++ b/common/utils/tun_if.c @@ -38,7 +38,7 @@ int nas_sock_fd[MAX_MOBILES_PER_ENB * 2]; // Allocated for both LTE UE and NR UE. int nas_sock_mbms_fd; -static int tun_alloc(const char *dev) +int tun_alloc(const char *dev) { struct ifreq ifr; int fd, err; @@ -157,13 +157,14 @@ static bool setInterfaceParameter(int sock_fd, const char *ifn, int af, const ch return success; } -/* - * \brief bring interface up (up != 0) or down (up == 0) - */ + typedef enum { INTERFACE_DOWN, INTERFACE_UP } if_action_t; +/* +* \brief bring interface up (up != 0) or down (up == 0) +*/ static bool change_interface_state(int sock_fd, const char *ifn, if_action_t if_action) { - const char* action = if_action == INTERFACE_DOWN ? "DOWN" : "UP"; + const char *action = if_action == INTERFACE_DOWN ? "DOWN" : "UP"; struct ifreq ifr = {0}; strncpy(ifr.ifr_name, ifn, sizeof(ifr.ifr_name)); @@ -189,6 +190,7 @@ fail_interface_state: return false; } + bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) { AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n"); @@ -262,3 +264,19 @@ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id) { return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1); } + +int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id) +{ + char pdu_session_string[10]; + snprintf(pdu_session_string, sizeof(pdu_session_string), "p%d", pdu_session_id); + return snprintf(ifname, IFNAMSIZ, "%s%d%s", "oaitun_ue", instance_id + 1, pdu_session_id == -1 ? "" : pdu_session_string); +} + +void tun_destroy(const char *dev, int fd) { + if (change_interface_state(fd, dev, INTERFACE_DOWN) == 0) { + LOG_I(UTIL, "Interface %s is now down.\n", dev); + } else { + LOG_E(UTIL, "Could not bring interface %s down.\n", dev); + } + close(fd); +} diff --git a/common/utils/tun_if.h b/common/utils/tun_if.h index eafc5b3350..e73b4be94e 100644 --- a/common/utils/tun_if.h +++ b/common/utils/tun_if.h @@ -34,6 +34,7 @@ * \param[in] instance_id unique instance number */ int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id); +int tun_generate_ue_ifname(char *ifname, int instance_id, int pdu_session_id); /*! * \brief This function initializes the TUN interface @@ -73,4 +74,18 @@ bool tun_config(const char* ifname, const char *ipv4, const char *ipv6); */ void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4); +/*! + * \brief This function allocates a TUN interface + * \param[in] dev name of the interface + * \return file descriptor of the allocated interface + */ +int tun_alloc(const char *dev); + +/*! + * \brief This function destroys the TUN interface + * \param[in] dev name of the interface + * \param[in] fd file descriptor of the allocated interface + */ +void tun_destroy(const char *dev, int fd); + #endif /*TUN_IF_H_*/ diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 205da81b6b..da7f014fb7 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -329,7 +329,7 @@ To manage UE connections, `nr_pdcp_add_srbs()` is employed for adding UE SRBs in ## PDCP Tx flow -On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `enb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`. +On the Tx side (downlink in gNB), the entry functions `nr_pdcp_data_req_drb()` and `nr_pdcp_data_req_srb()` are called by the upper layer. The upper layer could be GTP or a PDCP internal thread like `gnb_tun_read_thread()`, which reads directly from the Linux socket if the 3GPP core implementation is skipped. The PDCP internals for `nr_pdcp_data_req_srb()` and `nr_pdcp_data_req_drb()` are thread-safe. Within these functions, the PDCP manager protects access to the SDU receiving function of PDCP (`recv_sdu()` callback, corresponding to `nr_pdcp_entity_recv_pdu()` for DRBs) using mutex. When necessary, the PDCP layer pushes this data to RLC by calling `rlc_data_req()`. ## PDCP Rx flow diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 4f9ae49c42..f72ef0d0d1 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -85,6 +85,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #include "utils.h" #include "x2ap_eNB.h" #include "openair1/SCHED_NR/sched_nr.h" +#include "openair2/SDAP/nr_sdap/nr_sdap.h" pthread_cond_t nfapi_sync_cond; pthread_mutex_t nfapi_sync_mutex; @@ -497,11 +498,8 @@ static void wait_nfapi_init(char *thread_name) } void init_pdcp(void) { - uint32_t pdcp_initmask = IS_SOFTMODEM_NOS1 ? ENB_NAS_USE_TUN_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT; - if (!NODE_IS_DU(get_node_type())) { nr_pdcp_layer_init(); - nr_pdcp_module_init(pdcp_initmask, 0); } } diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 931ffc3f31..6d3efc28cd 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -301,25 +301,10 @@ void init_openair0() static void init_pdcp(int ue_id) { - uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : LINK_ENB_PDCP_TO_GTPV1U_BIT; - - /*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) { - pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - }*/ - - // previous code was: - // if (IS_SOFTMODEM_NOKRNMOD) - // pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - // The kernel module (KRNMOD) has been removed from the project, so the 'if' - // was removed but the flag 'pdcp_initmask' was kept, as "no kernel module" - // was always set. further refactoring could take it out - pdcp_initmask = pdcp_initmask | UE_NAS_USE_TUN_BIT; - if (get_softmodem_params()->nsa && nr_rlc_module_init(0) != 0) { LOG_I(RLC, "Problem at RLC initiation \n"); } nr_pdcp_layer_init(); - nr_pdcp_module_init(pdcp_initmask, ue_id); } // Stupid function addition because UE itti messages queues definition is common with eNB @@ -449,6 +434,11 @@ int main(int argc, char **argv) } } + if (create_tasks_nrue(1) < 0) { + printf("cannot create ITTI tasks\n"); + exit(-1); // need a softer mode + } + int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1; uint16_t node_number = get_softmodem_params()->node_number; ue_id_g = (node_number == 0) ? 0 : node_number - 2; @@ -557,11 +547,6 @@ int main(int argc, char **argv) // wait for end of program printf("TYPE TO TERMINATE\n"); - if (create_tasks_nrue(1) < 0) { - printf("cannot create ITTI tasks\n"); - exit(-1); // need a softer mode - } - // Sleep a while before checking all parameters have been used // Some are used directly in external threads, asynchronously sleep(2); diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h index 348920868c..8bd3558ff1 100644 --- a/executables/softmodem-common.h +++ b/executables/softmodem-common.h @@ -144,6 +144,7 @@ extern "C" #define EMULATE_L1 softmodem_params.emulate_l1 #define CONTINUOUS_TX softmodem_params.continuous_tx #define SYNC_REF softmodem_params.sync_ref +#define DEFAULT_PDU_ID softmodem_params.default_pdu_session_id #define DEFAULT_RFCONFIG_FILE "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat"; @@ -188,6 +189,7 @@ extern int usrp_tx_thread; {"E" , CONFIG_HLP_TQFS, PARAMFLAG_BOOL, .iptr=&softmodem_params.threequarter_fs, .defintval=0, TYPE_INT, 0}, \ {"imscope" , CONFIG_HLP_IMSCOPE, PARAMFLAG_BOOL, .uptr=&enable_imscope, .defintval=0, TYPE_UINT, 0}, \ {"imscope-record" , CONFIG_HLP_IMSCOPE_RECORD,PARAMFLAG_BOOL, .uptr=&enable_imscope_record, .defintval=0, TYPE_UINT, 0}, \ + {"default_pdu_id", NULL, 0, .iptr=&DEFAULT_PDU_ID, .defintval=10, TYPE_INT, 0}, \ } // clang-format on @@ -234,6 +236,7 @@ extern int usrp_tx_thread; { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ } // clang-format on @@ -343,6 +346,7 @@ typedef struct { uint32_t sync_ref; int no_itti; int threequarter_fs; + int default_pdu_session_id; } softmodem_params_t; #define IS_SA_MODE(sM_params) (!(sM_params)->phy_test && !(sM_params)->do_ra && !(sM_params)->nsa) diff --git a/openair2/COMMON/as_message.h b/openair2/COMMON/as_message.h index 31d53d12fe..1fb59c6aa9 100644 --- a/openair2/COMMON/as_message.h +++ b/openair2/COMMON/as_message.h @@ -469,6 +469,10 @@ typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t; */ typedef ul_info_transfer_ind_t dl_info_transfer_ind_t; +typedef struct nas_nos1_msg_s { + int dummy; // This dummy element is to avoid CLANG warning: empty struct has size 0 in C, size 1 in C++ +} nas_nos1_msg_t; + typedef struct nas_pdu_session_req_s { int pdusession_id; int pdusession_type; diff --git a/openair2/COMMON/rrc_messages_def.h b/openair2/COMMON/rrc_messages_def.h index 841c44d612..67aadb2869 100644 --- a/openair2/COMMON/rrc_messages_def.h +++ b/openair2/COMMON/rrc_messages_def.h @@ -79,6 +79,7 @@ MESSAGE_DEF(NR_NAS_CONN_ESTABLISH_IND, MESSAGE_PRIORITY_MED, nas_establish_ind_t MESSAGE_DEF(NR_NAS_CONN_RELEASE_IND, MESSAGE_PRIORITY_MED, NRNasConnReleaseInd, nr_nas_conn_release_ind) MESSAGE_DEF(NAS_UPLINK_DATA_CNF, MESSAGE_PRIORITY_MED, ul_info_transfer_cnf_t, nas_ul_data_cnf) MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, dl_info_transfer_ind_t, nas_dl_data_ind) +MESSAGE_DEF(NAS_INIT_NOS1_IF, MESSAGE_PRIORITY_MED, nas_nos1_msg_t, nas_init_nos1_if) // xNB: realtime -> RRC messages MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index d8b706520e..94df409113 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -390,168 +390,6 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP, /* pdcp_data_ind thread - end */ /****************************************************************************/ -/****************************************************************************/ -/* hacks to be cleaned up at some point - begin */ -/****************************************************************************/ - -#include "LAYER2/MAC/mac_extern.h" - -static void reblock_tun_socket(void) -{ - extern int nas_sock_fd[]; - int f; - - f = fcntl(nas_sock_fd[0], F_GETFL, 0); - f &= ~(O_NONBLOCK); - if (fcntl(nas_sock_fd[0], F_SETFL, f) == -1) { - LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno)); - } -} - -static void *enb_tun_read_thread(void *_) -{ - extern int nas_sock_fd[]; - char rx_buf[NL_MAX_PAYLOAD]; - int len; - protocol_ctxt_t ctxt; - ue_id_t UEid; - - int rb_id = 1; - pthread_setname_np( pthread_self(),"enb_tun_read"); - - while (1) { - len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD); - if (len == -1) { - LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno)); - return NULL; - } - - LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); - - nr_pdcp_manager_lock(nr_pdcp_ue_manager); - const bool has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid); - nr_pdcp_manager_unlock(nr_pdcp_ue_manager); - - if (!has_ue) continue; - - ctxt.module_id = 0; - ctxt.enb_flag = 1; - ctxt.instance = 0; - ctxt.frame = 0; - ctxt.subframe = 0; - ctxt.eNB_index = 0; - ctxt.brOption = 0; - ctxt.rntiMaybeUEid = UEid; - - uint8_t qfi = 7; - bool rqi = 0; - int pdusession_id = 10; - - sdap_data_req(&ctxt, - UEid, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - len, - (unsigned char *)rx_buf, - PDCP_TRANSMISSION_MODE_DATA, - NULL, - NULL, - qfi, - rqi, - pdusession_id); - } - - return NULL; -} - -static void *ue_tun_read_thread(void *_) -{ - extern int nas_sock_fd[]; - char rx_buf[NL_MAX_PAYLOAD]; - int len; - protocol_ctxt_t ctxt; - ue_id_t UEid; - int has_ue; - - int rb_id = 1; - pthread_setname_np( pthread_self(),"ue_tun_read"); - while (1) { - len = read(nas_sock_fd[0], &rx_buf, NL_MAX_PAYLOAD); - if (len == -1) { - LOG_E(PDCP, "error: cannot read() from fd %d: errno %d, %s\n", nas_sock_fd[0], errno, strerror(errno)); - return NULL; /* exit thread */ - } - - LOG_D(PDCP, "%s(): nas_sock_fd read returns len %d\n", __func__, len); - - nr_pdcp_manager_lock(nr_pdcp_ue_manager); - has_ue = nr_pdcp_get_first_ue_id(nr_pdcp_ue_manager, &UEid); - nr_pdcp_manager_unlock(nr_pdcp_ue_manager); - - if (!has_ue) continue; - - ctxt.module_id = 0; - ctxt.enb_flag = 0; - ctxt.instance = 0; - ctxt.frame = 0; - ctxt.subframe = 0; - ctxt.eNB_index = 0; - ctxt.brOption = 0; - ctxt.rntiMaybeUEid = UEid; - - bool dc = SDAP_HDR_UL_DATA_PDU; - extern uint8_t nas_qfi; - extern uint8_t nas_pduid; - - sdap_data_req(&ctxt, - UEid, - SRB_FLAG_NO, - rb_id, - RLC_MUI_UNDEFINED, - RLC_SDU_CONFIRM_NO, - len, - (unsigned char *)rx_buf, - PDCP_TRANSMISSION_MODE_DATA, - NULL, - NULL, - nas_qfi, - dc, - nas_pduid); - } - - return NULL; -} - -static void start_pdcp_tun_enb(void) -{ - pthread_t t; - - reblock_tun_socket(); - - if (pthread_create(&t, NULL, enb_tun_read_thread, NULL) != 0) { - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } -} - -static void start_pdcp_tun_ue(void) -{ - pthread_t t; - - reblock_tun_socket(); - - if (pthread_create(&t, NULL, ue_tun_read_thread, NULL) != 0) { - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } -} - -/****************************************************************************/ -/* hacks to be cleaned up at some point - end */ -/****************************************************************************/ - int pdcp_fifo_flush_sdus(const protocol_ctxt_t *const ctxt_pP) { return 0; @@ -592,54 +430,7 @@ void nr_pdcp_layer_init(void) #include "nfapi/oai_integration/vendor_ext.h" #include "executables/lte-softmodem.h" #include "common/utils/tun_if.h" - -uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) -{ - /* hack: be sure to initialize only once */ - static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; - static int initialized = 0; - if (pthread_mutex_lock(&m) != 0) abort(); - if (initialized) { - abort(); - } - initialized = 1; - if (pthread_mutex_unlock(&m) != 0) abort(); - - pdcp_optmask = pdcp_optmask | _pdcp_optmask ; - - if (UE_NAS_USE_TUN) { - char *ifprefix = get_softmodem_params()->nsa ? "oaitun_nrue" : "oaitun_ue"; - int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) - ? MAX_MOBILES_PER_ENB - : 1; - int begx = (id == 0) ? 0 : id - 1; - int endx = (id == 0) ? num_if : id; - for (int i = begx; i < endx; i++) { - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, i); - tun_init(ifname, i); - } - if (IS_SOFTMODEM_NOS1) { - const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, id); - tun_config(ifname, ip, NULL); - set_qfi_pduid(7, 10); - } - LOG_I(PDCP, "UE pdcp will use tun interface\n"); - start_pdcp_tun_ue(); - } else if (ENB_NAS_USE_TUN) { - char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, ifprefix, id); - tun_init(ifname, id); - tun_config(ifname, "10.0.1.1", NULL); - LOG_I(PDCP, "ENB pdcp will use tun interface\n"); - start_pdcp_tun_enb(); - } - - return pdcp_optmask ; -} +#include "openair2/SDAP/nr_sdap/nr_sdap.h" static void deliver_sdu_drb(void *_ue, nr_pdcp_entity_t *entity, char *buf, int size, diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index a60cd869af..286d072019 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -35,7 +35,6 @@ struct NR_DRB_ToAddMod; struct NR_SRB_ToAddMod; void nr_pdcp_layer_init(void); -uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id); void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP, const srb_flag_t srb_flagP, diff --git a/openair2/RRC/NR_UE/main_ue.c b/openair2/RRC/NR_UE/main_ue.c index 0e51fe2779..e394fec299 100644 --- a/openair2/RRC/NR_UE/main_ue.c +++ b/openair2/RRC/NR_UE/main_ue.c @@ -62,6 +62,8 @@ void init_nsa_message(NR_UE_RRC_INST_t *rrc, char* reconfig_file, char* rbconfig msg_len = fread(buffer, 1, 1024, fd); fclose(fd); process_nsa_message(rrc, nr_RadioBearerConfigX_r15, buffer,msg_len); + MessageDef* ittiMsg = itti_alloc_new_message(TASK_RRC_NRUE, rrc->ue_id, NAS_INIT_NOS1_IF); + itti_send_msg_to_task(TASK_NAS_NRUE, rrc->ue_id, ittiMsg); } else LOG_D(NR_RRC, "In NSA mode \n"); diff --git a/openair2/SDAP/nr_sdap/nr_sdap.c b/openair2/SDAP/nr_sdap/nr_sdap.c index d1a82310e5..1fe8e925a7 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.c +++ b/openair2/SDAP/nr_sdap/nr_sdap.c @@ -20,13 +20,29 @@ */ #include "nr_sdap.h" +#include "assertions.h" +#include "utils.h" #include +#include #include #include "nr_sdap_entity.h" #include "common/utils/LOG/log.h" +#include "errno.h" +#include "rlc.h" +#include "tun_if.h" +#include "system.h" + +static void reblock_tun_socket(int fd) +{ + int f; + + f = fcntl(fd, F_GETFL, 0); + f &= ~(O_NONBLOCK); + if (fcntl(fd, F_SETFL, f) == -1) { + LOG_E(PDCP, "fcntl(F_SETFL) failed on fd %d: errno %d, %s\n", fd, errno, strerror(errno)); + } +} -uint8_t nas_qfi; -uint8_t nas_pduid; bool sdap_data_req(protocol_ctxt_t *ctxt_p, const ue_id_t ue_id, @@ -91,8 +107,110 @@ void sdap_data_ind(rb_id_t pdcp_entity, size); } -void set_qfi_pduid(uint8_t qfi, uint8_t pduid){ - nas_qfi = qfi; - nas_pduid = pduid; - return; +struct thread_args { + nr_sdap_entity_t *entity; + bool is_gnb; +}; +static void *sdap_tun_read_thread(void *arg) +{ + DevAssert(arg != NULL); + struct thread_args *ta = arg; + nr_sdap_entity_t *entity = ta->entity; + bool is_gnb = ta->is_gnb; + free(ta); + + char rx_buf[NL_MAX_PAYLOAD]; + int len; + reblock_tun_socket(entity->pdusession_sock); + + int rb_id = 1; + + while (!entity->stop_thread) { + len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD); + if (len == -1) { + LOG_E(PDCP, "could not read(): errno %d %s\n", errno, strerror(errno)); + return NULL; + } + + LOG_D(SDAP, "read data of size %d\n", len); + + protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id}; + + bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU; + + DevAssert(entity != NULL); + entity->tx_entity(entity, + &ctxt, + SRB_FLAG_NO, + rb_id, + RLC_MUI_UNDEFINED, + RLC_SDU_CONFIRM_NO, + len, + (unsigned char *)rx_buf, + PDCP_TRANSMISSION_MODE_DATA, + NULL, + NULL, + entity->qfi, + dc); + } + + return NULL; +} + +void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id); + DevAssert(entity != NULL); + char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb"; + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, ifprefix, ue_id - 1); + entity->pdusession_sock = tun_alloc(ifname); + tun_config(ifname, "10.0.1.1", NULL); + struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); + ta->entity = entity; + ta->is_gnb = true; + + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW); +} + +void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id); + DevAssert(entity != NULL); + entity->pdusession_sock = sock; + entity->stop_thread = false; + char thread_name[64]; + snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id); + struct thread_args *ta = calloc_or_fail(1, sizeof(*ta)); + ta->entity = entity; + ta->is_gnb = false; + threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW); +} + + +void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id) +{ + int default_pdu = get_softmodem_params()->default_pdu_session_id; + char ifname[IFNAMSIZ]; + tun_generate_ue_ifname(ifname, ue_id, pdu_session_id != default_pdu ? pdu_session_id : -1); + const int sock = tun_alloc(ifname); + tun_config(ifname, ipv4, ipv6); + if (ipv4) { + setup_ue_ipv4_route(ifname, ue_id, ipv4); + } + start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1 +} + +void remove_ue_ip_if(nr_sdap_entity_t *entity) +{ + DevAssert(entity != NULL); + // Stop the read thread + entity->stop_thread = true; + int ret = pthread_join(entity->pdusession_thread, NULL); + AssertFatal(ret == 0, "pthread_join() failed, errno: %d, %s\n", errno, strerror(errno)); + // Bring down the IP interface + int default_pdu = get_softmodem_params()->default_pdu_session_id; + char ifname[IFNAMSIZ]; + tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1); + tun_destroy(ifname, entity->pdusession_sock); } diff --git a/openair2/SDAP/nr_sdap/nr_sdap.h b/openair2/SDAP/nr_sdap/nr_sdap.h index ec2d7ad185..3877e58603 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap.h +++ b/openair2/SDAP/nr_sdap/nr_sdap.h @@ -61,6 +61,8 @@ void sdap_data_ind(rb_id_t pdcp_entity, char *buf, int size); -void set_qfi_pduid(uint8_t qfi, uint8_t pduid); +void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock); +void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id); +void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); #endif diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.c b/openair2/SDAP/nr_sdap/nr_sdap_entity.c index aae6b81540..aa6ee95b47 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.c +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.c @@ -31,6 +31,8 @@ #include "gtpv1_u_messages_types.h" #include "intertask_interface.h" #include "rlc.h" +#include "tun_if.h" +#include "nr_sdap.h" typedef struct { nr_sdap_entity_t *sdap_entity_llist; @@ -103,7 +105,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity, /* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */ int offset=0; bool ret = false; - /*Hardcode DRB ID given from upper layer (ue/enb_tun_read_thread rb_id), it will change if we have SDAP*/ + /*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/ rb_id_t sdap_drb_id = rb_id; int pdcp_ent_has_sdap = 0; @@ -321,8 +323,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity, * 5.2.2 Downlink * deliver the retrieved SDAP SDU to the upper layer. */ - extern int nas_sock_fd[]; - int len = write(nas_sock_fd[0], &buf[offset], size-offset); + int len = write(entity->pdusession_sock, &buf[offset], size - offset); LOG_D(SDAP, "RX Entity len : %d\n", len); LOG_D(SDAP, "RX Entity size : %d\n", size); LOG_D(SDAP, "RX Entity offset : %d\n", offset); @@ -513,6 +514,8 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del; sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map; + sdap_entity->pdusession_sock = -1; + if(is_defaultDRB) { sdap_entity->default_drb = drb_identity; LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb); @@ -523,6 +526,12 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb, sdap_entity->next_entity = sdap_info.sdap_entity_llist; sdap_info.sdap_entity_llist = sdap_entity; + + if (IS_SOFTMODEM_NOS1 && is_gnb) { + // In NOS1 mode, terminate SDAP for the first UE on the gNB. This allows injecting/receiving + // PDCP SDUs to/from the TUN interface. + start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id); + } return sdap_entity; } @@ -591,6 +600,9 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id) if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) { entityPrev->next_entity = entityPtr->next_entity; + if (entityPrev->pdusession_sock != -1) { + remove_ue_ip_if(entityPrev); + } free(entityPtr); LOG_D(SDAP, "Successfully deleted Entity.\n"); ret = true; @@ -674,3 +686,11 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in } } } + +void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id) +{ + nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pduid); + DevAssert(entity != NULL); + entity->qfi = qfi; + return; +} diff --git a/openair2/SDAP/nr_sdap/nr_sdap_entity.h b/openair2/SDAP/nr_sdap/nr_sdap_entity.h index bff1c49281..adfc48e663 100644 --- a/openair2/SDAP/nr_sdap/nr_sdap_entity.h +++ b/openair2/SDAP/nr_sdap/nr_sdap_entity.h @@ -81,6 +81,11 @@ typedef struct nr_sdap_entity_s { ue_id_t ue_id; rb_id_t default_drb; int pdusession_id; + int pdusession_sock; + pthread_t pdusession_thread; + bool stop_thread; + int qfi; + qfi2drb_t qfi2drb_table[SDAP_MAX_QFI]; void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx); @@ -212,4 +217,6 @@ bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config); */ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id); +void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id); +void remove_ue_ip_if(nr_sdap_entity_t *entity); #endif diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 941e0d7cdc..61df0fe098 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -64,6 +64,7 @@ #include "secu_defs.h" #include "utils.h" #include "openair2/SDAP/nr_sdap/nr_sdap.h" +#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "fgs_nas_utils.h" #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" @@ -1059,7 +1060,7 @@ static int capture_ipv6_addr(const uint8_t *addr, char *ip, size_t len) * @brief Process PDU Session Address in PDU Session Establishment Accept message * and configure the tun interface */ -static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg) +static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg, int instance_id, int pdu_session_id) { uint8_t *addr = msg->pdu_addr_ie.pdu_addr_oct; @@ -1067,18 +1068,13 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg case PDU_SESSION_TYPE_IPV4: { char ip[20]; capture_ipv4_addr(&addr[0], ip, sizeof(ip)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, ip, NULL); - setup_ue_ipv4_route(ifname, 0, ip); + create_ue_ip_if(ip, NULL, instance_id, pdu_session_id); } break; case PDU_SESSION_TYPE_IPV6: { char ipv6[40]; capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, NULL, ipv6); + create_ue_ip_if(NULL, ipv6, instance_id, pdu_session_id); } break; case PDU_SESSION_TYPE_IPV4V6: { @@ -1086,10 +1082,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); char ipv4[20]; capture_ipv4_addr(&addr[IPv6_INTERFACE_ID_LENGTH], ipv4, sizeof(ipv4)); - char ifname[IFNAMSIZ]; - tun_generate_ifname(ifname, "oaitun_ue", 0); - tun_config(ifname, ipv4, ipv6); - setup_ue_ipv4_route(ifname, 0, ipv4); + create_ue_ip_if(ipv4, ipv6, instance_id, pdu_session_id); } break; default: @@ -1101,7 +1094,7 @@ static void process_pdu_session_addr(pdu_session_establishment_accept_msg_t *msg /** * @brief Handle PDU Session Establishment Accept and process decoded message */ -static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length) +static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length, int instance) { pdu_session_establishment_accept_msg_t msg = {0}; int size = 0; @@ -1143,24 +1136,23 @@ static void handle_pdu_session_accept(uint8_t *pdu_buffer, uint32_t msg_length) LOG_E(NAS, "decode_pdu_session_establishment_accept_msg failure\n"); // process PDU Session - if (msg.pdu_addr_ie.pdu_length) - process_pdu_session_addr(&msg); + process_pdu_session_addr(&msg, instance, sm_header.pdu_session_id); else LOG_W(NAS, "Optional PDU Address IE was not provided\n"); - set_qfi_pduid(msg.qos_rules.rule->qfi, sm_header.pdu_session_id); + set_qfi(msg.qos_rules.rule->qfi, sm_header.pdu_session_id, instance); } /** * @brief Handle DL NAS Transport and process piggybacked 5GSM messages */ -static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length) +void handleDownlinkNASTransport(uint8_t * pdu_buffer, int pdu_length, int instance) { uint8_t msg_type = *(pdu_buffer + 16); if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n"); - handle_pdu_session_accept(pdu_buffer, msg_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, instance); } else { LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type); } @@ -1403,7 +1395,7 @@ static void send_nas_5gmm_ind(instance_t instance, const Guti5GSMobileIdentity_t static void request_default_pdusession(nr_ue_nas_t *nas) { MessageDef *message_p = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_PDU_SESSION_REQ); - NAS_PDU_SESSION_REQ(message_p).pdusession_id = 10; /* first or default pdu session */ + NAS_PDU_SESSION_REQ(message_p).pdusession_id = get_softmodem_params()->default_pdu_session_id; NAS_PDU_SESSION_REQ(message_p).pdusession_type = 0x91; // 0x91 = IPv4, 0x92 = IPv6, 0x93 = IPv4v6 NAS_PDU_SESSION_REQ(message_p).sst = nas->uicc->nssai_sst; NAS_PDU_SESSION_REQ(message_p).sd = nas->uicc->nssai_sd; @@ -1634,7 +1626,7 @@ void *nas_nrue(void *args_p) if (msg_type == FGS_REGISTRATION_ACCEPT) { handle_registration_accept(nas, pdu_buffer, pdu_length); } else if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) { - handle_pdu_session_accept(pdu_buffer, pdu_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id); } // Free NAS buffer memory after use (coming from RRC) @@ -1724,7 +1716,7 @@ void *nas_nrue(void *args_p) handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length); break; case FGS_DOWNLINK_NAS_TRANSPORT: - handleDownlinkNASTransport(pdu_buffer, pdu_length); + handleDownlinkNASTransport(pdu_buffer, pdu_length, nas->UE_id); break; case FGS_REGISTRATION_ACCEPT: handle_registration_accept(nas, pdu_buffer, pdu_length); @@ -1735,7 +1727,7 @@ void *nas_nrue(void *args_p) nas->fiveGMM_state = FGS_DEREGISTERED; break; case FGS_PDU_SESSION_ESTABLISHMENT_ACC: - handle_pdu_session_accept(pdu_buffer, pdu_length); + handle_pdu_session_accept(pdu_buffer, pdu_length, nas->UE_id); break; case FGS_PDU_SESSION_ESTABLISHMENT_REJ: LOG_E(NAS, "Received PDU Session Establishment reject\n"); @@ -1767,6 +1759,15 @@ void *nas_nrue(void *args_p) send_nas_uplink_data_req(nas, &initialNasMsg); } break; + case NAS_INIT_NOS1_IF: { + const int pdu_session_id = get_softmodem_params()->default_pdu_session_id; + const char *ip = !get_softmodem_params()->nsa ? "10.0.1.2" : "10.0.1.3"; + const int qfi = 7; + create_ue_ip_if(ip, NULL, nas->UE_id, pdu_session_id); + set_qfi(qfi, pdu_session_id, nas->UE_id); + break; + } + default: LOG_E(NAS, "[UE %ld] Received unexpected message %s\n", nas->UE_id, ITTI_MSG_NAME(msg_p)); break; diff --git a/openair3/NAS/NR_UE/nr_nas_msg.h b/openair3/NAS/NR_UE/nr_nas_msg.h index c4f1d04e28..40b4e64ac1 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.h +++ b/openair3/NAS/NR_UE/nr_nas_msg.h @@ -110,5 +110,6 @@ void generateServiceRequest(as_nas_info_t *initialNasMsg, nr_ue_nas_t *nas); void *nas_nrue_task(void *args_p); void *nas_nrue(void *args_p); void nas_init_nrue(int num_ues); +void nr_ue_create_ip_if(const char *ifnameprefix, const char *ipv4, const char *ipv6, int ue_id, int pdu_session_id); #endif /* __NR_NAS_MSG_SIM_H__*/ From 5f8aeaacc9eba56c560a222155f5ae1f99a15f63 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 16 Apr 2025 13:48:59 +0000 Subject: [PATCH 34/48] fix CI files for NTN LEO scenario --- .../gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf | 4 ++-- .../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf | 11 ----------- .../5g_rfsimulator_ntn_leo/docker-compose.yaml | 1 + 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf index fc591cd464..407723a909 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf @@ -51,7 +51,7 @@ gNBs = initialDLBWPsubcarrierSpacing = 0; #pdcch-ConfigCommon initialDLBWPcontrolResourceSetZero = 2; - initialDLBWPsearchSpaceZero = 0; + initialDLBWPsearchSpaceZero = 2; #uplinkConfigCommon #frequencyInfoUL @@ -151,7 +151,7 @@ gNBs = #ext2 #ntn_Config_r17 cellSpecificKoffset_r17 = 40; - ta-Common-r17 = 4634000; # 18.87 ms + ta-Common-r17 = 4628000; # 18.84 ms ta-CommonDrift-r17 = -230000; # -46 µs/s positionX-r17 = 0; positionY-r17 = -2166908; # -2816980.4 m diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf index 198ac12833..3e7dd08474 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn.conf @@ -235,15 +235,6 @@ RUs = ( } ); -THREAD_STRUCT = ( - { - #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT" - parallel_config = "PARALLEL_RU_L1_TRX_SPLIT"; - #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE" - worker_config = "WORKER_DISABLE"; - } -); - rfsimulator : { serveraddr = "server"; @@ -279,6 +270,4 @@ log_config : rlc_log_level ="info"; pdcp_log_level ="info"; rrc_log_level ="info"; - ngap_log_level ="debug"; - f1ap_log_level ="debug"; }; diff --git a/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml index 0cb382710e..3834e9aa57 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml +++ b/ci-scripts/yaml_files/5g_rfsimulator_ntn_leo/docker-compose.yaml @@ -117,6 +117,7 @@ services: --time-sync-I 0.1 --ntn-initial-time-drift -46 --autonomous-ta --initial-fo 57340 --cont-fo-comp 2 --log_config.global_log_options level,nocolor,time + --num-ul-actors 1 depends_on: - oai-gnb networks: From 1aa6aab12024895792afc6d55c1d5fb92d05da1b Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Wed, 16 Apr 2025 17:42:11 +0000 Subject: [PATCH 35/48] NR UE: in nr_slot_fep() perform FO compensation in local tmp_dft_in array instead of global rxdata array This avoids problems if nr_slot_fep() is called more than once for an OFDM symbol. --- executables/nr-ue.c | 2 +- openair1/PHY/MODULATION/slot_fep_nr.c | 18 +++++++++--------- openair1/PHY/nr_phy_common/inc/nr_phy_common.h | 2 +- openair1/PHY/nr_phy_common/src/nr_phy_common.c | 11 ++++++----- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/executables/nr-ue.c b/executables/nr-ue.c index f2716c099e..1218338eea 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -563,7 +563,7 @@ static void RU_write(nr_rxtx_thread_data_t *rxtxD, bool sl_tx_action) if (get_nrUE_params()->cont_fo_comp == 2) // different from LO frequency error compensation, Doppler UL pre-compensation has to be negative ul_freq_offset = -ul_freq_offset; for (int i = 0; i < fp->nb_antennas_tx; i++) - nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], writeBlockSize); + nr_fo_compensation(ul_freq_offset, fp->samples_per_subframe, writeTimestamp, txp[i], txp[i], writeBlockSize); } int tmp = openair0_write_reorder(&UE->rfdevice, writeTimestamp, txp, writeBlockSize, fp->nb_antennas_tx, flags); diff --git a/openair1/PHY/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 10d6ef87f4..17cd425fbd 100644 --- a/openair1/PHY/MODULATION/slot_fep_nr.c +++ b/openair1/PHY/MODULATION/slot_fep_nr.c @@ -60,7 +60,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, dft_size_idx_t dftsize = get_dft(frame_parms->ofdm_symbol_size); // This is for misalignment issues - int32_t tmp_dft_in[8192] __attribute__ ((aligned (32))); + c16_t tmp_dft_in[frame_parms->ofdm_symbol_size] __attribute__ ((aligned (32))); unsigned int rx_offset = frame_parms->get_samples_slot_timestamp(slot, frame_parms, 0); unsigned int abs_symbol = slot * frame_parms->symbols_per_slot + symbol; @@ -73,10 +73,10 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, // use OFDM symbol from within 1/8th of the CP to avoid ISI rx_offset -= (nb_prefix_samples / frame_parms->ofdm_offset_divisor); - for (unsigned char aa=0; aanb_antennas_rx; aa++) { - int16_t *rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset]; + rx_offset %= total_samples; - rx_offset %= total_samples; + for (unsigned char aa=0; aanb_antennas_rx; aa++) { + c16_t *rxdata_ptr = &rxdata[aa][rx_offset]; // This happens only during initial sync if (rx_offset + frame_parms->ofdm_symbol_size > total_samples) { @@ -87,17 +87,17 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, memcpy((void *)&tmp_dft_in[total_samples - rx_offset], (void *)&rxdata[aa][0], (frame_parms->ofdm_symbol_size - (total_samples - rx_offset)) * sizeof(int32_t)); - rxdata_ptr = (int16_t *)tmp_dft_in; + rxdata_ptr = tmp_dft_in; } else if ((rx_offset & 7) != 0) { // if input to dft is not 256-bit aligned memcpy((void *)&tmp_dft_in[0], (void *)&rxdata[aa][rx_offset], frame_parms->ofdm_symbol_size * sizeof(int32_t)); - - rxdata_ptr = (int16_t *)tmp_dft_in; + rxdata_ptr = tmp_dft_in; } if (ue && ue->cont_fo_comp) { start_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); - nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, (c16_t *)rxdata_ptr, frame_parms->ofdm_symbol_size); + nr_fo_compensation(ue->freq_offset, frame_parms->samples_per_subframe, rx_offset, rxdata_ptr, tmp_dft_in, frame_parms->ofdm_symbol_size); + rxdata_ptr = tmp_dft_in; stop_meas_nr_ue_phy(ue, RX_FO_COMPENSATION_STATS); } @@ -105,7 +105,7 @@ int nr_slot_fep(PHY_VARS_NR_UE *ue, start_meas_nr_ue_phy(ue, RX_DFT_STATS); dft(dftsize, - rxdata_ptr, + (int16_t *)rxdata_ptr, (int16_t *)&rxdataF[aa][frame_parms->ofdm_symbol_size*symbol], 1); diff --git a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h index 225388cb0d..94809ccb46 100644 --- a/openair1/PHY/nr_phy_common/inc/nr_phy_common.h +++ b/openair1/PHY/nr_phy_common/inc/nr_phy_common.h @@ -80,6 +80,6 @@ void nr_256qam_llr(int32_t *rxdataF_comp, int32_t *ch_mag, int32_t *ch_mag2, int void freq2time(uint16_t ofdm_symbol_size, int16_t *freq_signal, int16_t *time_signal); void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates_time, delay_t *delay); unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, int nb_rb); -void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size); +void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size); #endif diff --git a/openair1/PHY/nr_phy_common/src/nr_phy_common.c b/openair1/PHY/nr_phy_common/src/nr_phy_common.c index 700721e69f..5a950eba86 100644 --- a/openair1/PHY/nr_phy_common/src/nr_phy_common.c +++ b/openair1/PHY/nr_phy_common/src/nr_phy_common.c @@ -454,7 +454,7 @@ unsigned int nr_get_tx_amp(int power_dBm, int power_max_dBm, int total_nb_rb, in return (0); } -void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16_t *rxdata_ptr, int size) +void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, const c16_t *rxdata_in, c16_t *rxdata_out, int size) { const double phase_inc = -fo_Hz / (samples_per_ms * 1000); double phase = sample_offset * phase_inc; @@ -473,12 +473,13 @@ void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16 } const c16_t rot_vec = get_sin_cos(CHUNK * phase_inc); while (size > CHUNK) { - mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, CHUNK, 14); - rxdata_ptr += CHUNK; + mult_complex_vectors(rxdata_in, rot, rxdata_out, CHUNK, 14); rotate_cpx_vector(rot, &rot_vec, rot, CHUNK, 14); + rxdata_in += CHUNK; + rxdata_out += CHUNK; size -= CHUNK; } - mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14); + mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14); #else // This code path computes the complex rotation values for the complete OFDM symbol using get_sin_cos(). // This is more accurate, but also slower than the code path above. @@ -487,6 +488,6 @@ void nr_fo_compensation(double fo_Hz, int samples_per_ms, int sample_offset, c16 rot[i] = get_sin_cos(phase); phase += phase_inc; } - mult_complex_vectors(rxdata_ptr, rot, rxdata_ptr, size, 14); + mult_complex_vectors(rxdata_in, rot, rxdata_out, size, 14); #endif } From b99fcdf28970ee833151ccb599bfd9dcfc8b5435 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 17 Apr 2025 10:55:18 +0200 Subject: [PATCH 36/48] fix IP address The following error was appearing when running LTE UE: inet_pton(): cannot convert -64.-74.0.2 to IPv4 network address The allocated address by the core actually is 192.182.0.2. On my host "char" is signed, leading to the above error (192 and 182 are seen as signed). Let's force "ip_addr" unsigned and everyone is happy. --- openair3/NAS/UE/ESM/esm_ebr_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c index 7a8de459e7..cec4c268bd 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.c +++ b/openair3/NAS/UE/ESM/esm_ebr_context.c @@ -204,7 +204,7 @@ int esm_ebr_context_create( // etc case NET_PDN_TYPE_IPV4: { char ip[20]; - char *ip_addr = pdn->ip_addr; + unsigned char *ip_addr = (unsigned char *)pdn->ip_addr; snprintf(ip, sizeof(ip), "%d.%d.%d.%d", ip_addr[0], ip_addr[1], ip_addr[2], ip_addr[3]); const char *ifn = get_softmodem_params()->nsa ? "oaitun_nru" : "oaitun_ue"; char ifname[IFNAMSIZ]; From 570c1b5639b2164982b646e097feff5ed8250a52 Mon Sep 17 00:00:00 2001 From: alexjiao Date: Tue, 25 Mar 2025 17:21:35 +0800 Subject: [PATCH 37/48] Consider the ratio of PUSCH EPRE to DMRS EPRE when calculating PUSCH DMRS power scaling --- common/utils/nr/nr_common.c | 13 +++++++++++++ common/utils/nr/nr_common.h | 16 ++++++++++++++++ .../PHY/NR_ESTIMATION/nr_ul_channel_estimation.c | 7 ++++++- openair1/PHY/NR_REFSIG/nr_dmrs_rx.c | 5 ++++- openair1/PHY/NR_REFSIG/nr_refsig.h | 3 ++- openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c | 10 ++++++---- openair1/PHY/impl_defs_nr.h | 6 ------ 7 files changed, 47 insertions(+), 13 deletions(-) diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 69e095878f..30e8e6c32e 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -36,6 +36,7 @@ #include "common/utils/LOG/log.h" #include "nr_common.h" #include +#include #define C_SRS_NUMBER (64) #define B_SRS_NUMBER (4) @@ -1427,3 +1428,15 @@ frequency_range_t get_freq_range_from_band(uint16_t band) { return band <= 256 ? FR1 : FR2; } + +float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type) +{ + float beta_dmrs_pusch = 1.0; + if (num_cdm_groups_no_data == 2) { + beta_dmrs_pusch = powf(10.0, 3.0 / 20.0); + } else if (num_cdm_groups_no_data == 3) { + if (dmrs_type == pusch_dmrs_type2) + beta_dmrs_pusch = powf(10.0, 4.77 / 20.0); + } + return beta_dmrs_pusch; +} diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index fdb3cc7ffc..b28aca6dc9 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -123,6 +123,11 @@ typedef enum frequency_range_e { FR2 } frequency_range_t; +typedef enum { + pusch_dmrs_type1 = 0, + pusch_dmrs_type2 = 1 +} pusch_dmrs_type_t; + #define MAX_NUM_SLOTS_ALLOWED 80 // up to numerology 3 (120 KHz SCS) is supported enum slot_type { TDD_NR_DOWNLINK_SLOT, TDD_NR_UPLINK_SLOT, TDD_NR_MIXED_SLOT }; @@ -295,6 +300,17 @@ frequency_range_t get_freq_range_from_freq(uint64_t freq); frequency_range_t get_freq_range_from_arfcn(uint32_t arfcn); frequency_range_t get_freq_range_from_band(uint16_t band); +/** + * @brief Calculates the scaling factor for the ratio of PUSCH EPRE to DMRS EPRE. + * + * @param num_cdm_groups_no_data The number of CDM groups without data. + * @param dmrs_type The DMRS type. + * @return The calculated beta scaling factor for the ratio of PUSCH EPRE to DMRS EPRE. + * + * @note The values are derived from TS 38.214 Table 6.2.2-1. + */ +float get_beta_dmrs_pusch(int num_cdm_groups_no_data, pusch_dmrs_type_t dmrs_type); + #define CEILIDIV(a,b) ((a+b-1)/b) #define ROUNDIDIV(a,b) (((a<<1)+b)/(b<<1)) diff --git a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c index 5d318d6fd8..1f1e36ddef 100644 --- a/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c +++ b/openair1/PHY/NR_ESTIMATION/nr_ul_channel_estimation.c @@ -19,6 +19,7 @@ * contact@openairinterface.org */ +#include "nr_common.h" #include #include "nr_ul_estimation.h" @@ -480,6 +481,9 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, pusch_pdu->scid, Ns, symbol); + pusch_dmrs_type_t dmrs_type = pusch_pdu->dmrs_config_type == NFAPI_NR_DMRS_TYPE1 ? pusch_dmrs_type1 : pusch_dmrs_type2; + float beta_dmrs_pusch = get_beta_dmrs_pusch(pusch_pdu->num_dmrs_cdm_grps_no_data, dmrs_type); + int16_t dmrs_scaling = (1 / beta_dmrs_pusch) * (1 << 14); nr_pusch_dmrs_rx(gNB, Ns, gold, @@ -488,7 +492,8 @@ int nr_pusch_channel_estimation(PHY_VARS_gNB *gNB, 0, nb_rb_pusch, (pusch_pdu->bwp_start + pusch_pdu->rb_start) * NR_NB_SC_PER_RB, - pusch_pdu->dmrs_config_type); + pusch_pdu->dmrs_config_type, + dmrs_scaling); } else { // if transform precoding or SC-FDMA is enabled in Uplink // NR_SC_FDMA supports type1 DMRS so only 6 DMRS REs per RB possible const int index = get_index_for_dmrs_lowpapr_seq(nb_rb_pusch * (NR_NB_SC_PER_RB / 2)); diff --git a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c index 01b05071a2..e929fc5f3e 100644 --- a/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c +++ b/openair1/PHY/NR_REFSIG/nr_dmrs_rx.c @@ -34,6 +34,7 @@ //#define NR_PBCH_DMRS_LENGTH 144 //#define DEBUG_PUSCH +#include "PHY/TOOLS/tools_defs.h" #include "refsig_defs_ue.h" #include "PHY/defs_nr_UE.h" #include "nr_refsig.h" @@ -73,7 +74,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned char lp, unsigned short nb_pusch_rb, uint32_t re_offset, - uint8_t dmrs_type) + uint8_t dmrs_type, + int16_t dmrs_scaling) { typedef int array_of_w[2]; const array_of_w *wf = (dmrs_type == pusch_dmrs_type1) ? wf1 : wf2; @@ -91,6 +93,7 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, int i = k + dmrs_offset; int w = (wf[p - 1000][i & 1]) * (wt[p - 1000][lp]); output[k] = get_modulated(nr_gold_pusch, i, w == 1); + output[k] = c16mulRealShift(output[k], dmrs_scaling, 14); #ifdef DEBUG_PUSCH printf("nr_pusch_dmrs_rx dmrs config type %d port %d nb_pusch_rb %d\n", dmrs_type, p, nb_pusch_rb); printf("wf[%d] = %d wt[%d]= %d\n", i&1, wf[p-1000][i&1], lp, wt[p-1000][lp]); diff --git a/openair1/PHY/NR_REFSIG/nr_refsig.h b/openair1/PHY/NR_REFSIG/nr_refsig.h index b0cd9449f0..ceb9048d7f 100644 --- a/openair1/PHY/NR_REFSIG/nr_refsig.h +++ b/openair1/PHY/NR_REFSIG/nr_refsig.h @@ -36,7 +36,8 @@ int nr_pusch_dmrs_rx(PHY_VARS_gNB *gNB, unsigned char lp, unsigned short nb_pusch_rb, uint32_t re_offset, - uint8_t dmrs_type); + uint8_t dmrs_type, + int16_t dmrs_scaling); void nr_generate_csi_rs(const NR_DL_FRAME_PARMS *frame_parms, int32_t **dataF, diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index bd4ea90df8..956072fa95 100644 --- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c +++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c @@ -392,13 +392,15 @@ static void dmrs_amp_mult(const uint32_t dmrs_port, const c16_t *mod_dmrs, c16_t *mod_dmrs_out, const uint32_t n_dmrs, - const pusch_dmrs_type_t dmrs_type) + const pusch_dmrs_type_t dmrs_type, + const unsigned int num_cdm_groups_no_data) { + float beta_dmrs_pusch = get_beta_dmrs_pusch(num_cdm_groups_no_data, dmrs_type); /* short array that hold amplitude for k_prime = 0 and k_prime = 1 */ int32_t alpha_dmrs[2] __attribute((aligned(16))); for (int_fast8_t i = 0; i < sizeofArray(alpha_dmrs); i++) { const int32_t a = Wf[i] * Wt * AMP; - alpha_dmrs[i] = a; + alpha_dmrs[i] = a * beta_dmrs_pusch; } /* multiply amplitude with complex DMRS vector */ @@ -440,9 +442,9 @@ static void map_symbols(const nr_phy_pxsch_params_t p, c16_t mod_dmrs[ALNARS_16_4(n_dmrs)] __attribute((aligned(16))); if (p.transform_precoding == transformPrecoder_disabled) { nr_modulation(gold, n_dmrs * 2, DMRS_MOD_ORDER, (int16_t *)mod_dmrs); - dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type); + dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, mod_dmrs, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data); } else { - dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type); + dmrs_amp_mult(p.dmrs_port, p.Wt, p.Wf, dmrs_seq, mod_dmrs_amp, n_dmrs, p.dmrs_type, p.num_cdm_no_data); } } else if ((p.pdu_bit_map & PUSCH_PDU_BITMAP_PUSCH_PTRS) && ptrs_symbol) { AssertFatal(p.transform_precoding == transformPrecoder_disabled, "PTRS NOT SUPPORTED IF TRANSFORM PRECODING IS ENABLED\n"); diff --git a/openair1/PHY/impl_defs_nr.h b/openair1/PHY/impl_defs_nr.h index 123dbe162a..9db686d664 100644 --- a/openair1/PHY/impl_defs_nr.h +++ b/openair1/PHY/impl_defs_nr.h @@ -344,12 +344,6 @@ typedef enum { * DESCRIPTION : configuration for PUSCH * ************************************************************************/ - -typedef enum { - pusch_dmrs_type1 = 0, - pusch_dmrs_type2 = 1 -} pusch_dmrs_type_t; - typedef enum { txConfig_codebook = 1, txConfig_nonCodebook = 2 From 7cbedb15756e398137c825199cd988c7e3054a86 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 10 Oct 2024 17:48:01 +0200 Subject: [PATCH 38/48] time management module This commit introduces a time management module. See doc/time_management.md for details. --- CMakeLists.txt | 5 +- common/utils/CMakeLists.txt | 1 + common/utils/time_manager/CMakeLists.txt | 14 + .../utils/time_manager/tests/CMakeLists.txt | 11 + common/utils/time_manager/tests/test_auto.c | 285 ++++++++++++++++++ common/utils/time_manager/tests/test_manual.c | 175 +++++++++++ common/utils/time_manager/time_client.c | 231 ++++++++++++++ common/utils/time_manager/time_client.h | 36 +++ common/utils/time_manager/time_manager.c | 240 +++++++++++++++ common/utils/time_manager/time_manager.h | 46 +++ common/utils/time_manager/time_server.c | 251 +++++++++++++++ common/utils/time_manager/time_server.h | 40 +++ common/utils/time_manager/time_source.c | 264 ++++++++++++++++ common/utils/time_manager/time_source.h | 47 +++ doc/SW_archi.md | 2 +- doc/time_management.md | 284 +++++++++++++++++ executables/nr-cuup.c | 8 + executables/nr-ru.c | 5 + executables/nr-softmodem.c | 15 + executables/nr-ue.c | 15 +- executables/nr-uesoftmodem.c | 12 + openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 10 - openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 19 -- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h | 2 - .../LAYER2/nr_pdcp/nr_pdcp_timer_thread.c | 24 +- .../LAYER2/nr_pdcp/nr_pdcp_timer_thread.h | 3 +- openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c | 11 +- openair2/X2AP/x2ap_eNB.c | 2 +- openair2/X2AP/x2ap_eNB.h | 1 - openair2/X2AP/x2ap_timers.c | 3 +- 30 files changed, 1983 insertions(+), 79 deletions(-) create mode 100644 common/utils/time_manager/CMakeLists.txt create mode 100644 common/utils/time_manager/tests/CMakeLists.txt create mode 100644 common/utils/time_manager/tests/test_auto.c create mode 100644 common/utils/time_manager/tests/test_manual.c create mode 100644 common/utils/time_manager/time_client.c create mode 100644 common/utils/time_manager/time_client.h create mode 100644 common/utils/time_manager/time_manager.c create mode 100644 common/utils/time_manager/time_manager.h create mode 100644 common/utils/time_manager/time_server.c create mode 100644 common/utils/time_manager/time_server.h create mode 100644 common/utils/time_manager/time_source.c create mode 100644 common/utils/time_manager/time_source.h create mode 100644 doc/time_management.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 25bc56b79a..3a567fc3c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1835,6 +1835,7 @@ target_link_libraries(nr-softmodem PRIVATE ITTI ${NAS_UE_LIB} lte_rrc nr_rrc ngap s1ap L2_LTE_NR L2_NR MAC_NR_COMMON NFAPI_LIB NFAPI_VNF_LIB NFAPI_PNF_LIB NFAPI_USER_LIB SIMU x2ap f1ap m2ap m3ap e1ap shlib_loader + time_management -Wl,--end-group z dl) target_link_libraries(nr-softmodem PRIVATE pthread m CONFIG_LIB rt sctp) @@ -1867,6 +1868,7 @@ add_executable(nr-cuup target_link_libraries(nr-cuup PRIVATE CONFIG_LIB ITTI SCTP_CLIENT GTPV1U e1ap f1ap + time_management z sctp dl pthread shlib_loader ${T_LIB}) target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) if(E2_AGENT) @@ -1898,6 +1900,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE nr_rrc SECURITY UTIL HASHTABLE SCHED_RU_LIB SCHED_NR_UE_LIB PHY_COMMON PHY_NR_COMMON PHY_NR_UE NR_L2_UE MAC_NR_COMMON NFAPI_LIB ITTI SIMU shlib_loader + time_management -Wl,--end-group z dl) target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas) @@ -1993,7 +1996,7 @@ add_executable(nr_psbchsim ${PHY_INTERFACE_DIR}/queue_t.c ) target_link_libraries(nr_psbchsim PRIVATE - -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group + -Wl,--start-group ngap UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group m pthread ${T_LIB} ITTI dl shlib_loader physim_common ) target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) diff --git a/common/utils/CMakeLists.txt b/common/utils/CMakeLists.txt index b311d0542f..c3c7720628 100644 --- a/common/utils/CMakeLists.txt +++ b/common/utils/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(T) add_subdirectory(nr) add_subdirectory(LOG) add_subdirectory(threadPool) +add_subdirectory(time_manager) add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c) target_include_directories(utils PUBLIC .) target_link_libraries(utils PRIVATE ${T_LIB}) diff --git a/common/utils/time_manager/CMakeLists.txt b/common/utils/time_manager/CMakeLists.txt new file mode 100644 index 0000000000..3a197ae556 --- /dev/null +++ b/common/utils/time_manager/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(time_management STATIC + time_manager.c) + +add_library(time_management_core OBJECT + time_source.c + time_server.c + time_client.c) + +target_link_libraries(time_management PUBLIC time_management_core) +target_link_libraries(time_management_core PRIVATE ${T_LIB}) + +if(ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/common/utils/time_manager/tests/CMakeLists.txt b/common/utils/time_manager/tests/CMakeLists.txt new file mode 100644 index 0000000000..b3b57a67d4 --- /dev/null +++ b/common/utils/time_manager/tests/CMakeLists.txt @@ -0,0 +1,11 @@ +add_executable(test_time_manager_manual test_manual.c) +target_link_libraries(test_time_manager_manual time_management_core) +target_link_libraries(test_time_manager_manual LOG CONFIG_LIB) + +add_executable(test_time_manager_auto test_auto.c) +target_link_libraries(test_time_manager_auto time_management) +target_link_libraries(test_time_manager_auto LOG CONFIG_LIB) + +add_dependencies(tests test_time_manager_auto) +add_test(NAME time_management_tests + COMMAND ./test_time_manager_auto) diff --git a/common/utils/time_manager/tests/test_auto.c b/common/utils/time_manager/tests/test_auto.c new file mode 100644 index 0000000000..73bf27af88 --- /dev/null +++ b/common/utils/time_manager/tests/test_auto.c @@ -0,0 +1,285 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include +#include +#include + +#include "common/utils/time_manager/time_manager.h" +#include "common/utils/LOG/log.h" +#include "common/config/config_userapi.h" + +configmodule_interface_t *uniqCfg = NULL; + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + if (s != NULL) { + printf("%s:%d %s() Exiting OAI softmodem: %s\n", file, line, function, s); + } + if (assert) + abort(); + else + exit(1); +} + +int is_x2ap_enabled(void) +{ + /* we want x2ap ticks */ + return 1; +} + +static int rlc_tick_count = 0; +static int pdcp_tick_count = 0; +static int x2ap_tick_count = 0; + +void nr_rlc_ms_tick(void) +{ + rlc_tick_count++; +} + +void nr_pdcp_ms_tick(void) +{ + pdcp_tick_count++; +} + +void x2ap_ms_tick(void) +{ + x2ap_tick_count++; +} + +/* return 1 if ok, 0 if error */ +static int standalone_realtime(void) +{ + time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_REALTIME); + + sleep(1); + + time_manager_finish(); + + LOG_I(UTIL, + "standalone realtime: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n", + rlc_tick_count, + pdcp_tick_count, + x2ap_tick_count); + + /* let's accept 1% deviation from the 1000 counts we expect */ + return abs(rlc_tick_count-1000) < 10 + && abs(pdcp_tick_count - 1000) < 10 + && abs(x2ap_tick_count - 1000) < 10; +} + +/* return 1 if ok, 0 if error */ +static int standalone_iq_samples(void) +{ + time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_IQ_SAMPLES); + + /* let's pretend we have 2000 samples per second */ + for (int i = 0; i < 1000; i++) { + time_manager_iq_samples(1, 2000); + usleep(10); + time_manager_iq_samples(1, 2000); + usleep(10); + } + + time_manager_finish(); + + LOG_I(UTIL, + "standalone iq-samples: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n", + rlc_tick_count, + pdcp_tick_count, + x2ap_tick_count); + + /* exact count is required */ + return rlc_tick_count == 1000 + && pdcp_tick_count == 1000 + && x2ap_tick_count == 1000; +} + +/* return 1 if ok, 0 if error */ +static int client_server(char *program_name, bool iq_samples_time_source) +{ + LOG_I(UTIL, "client/server %s: launch sub-processes\n", iq_samples_time_source ? "iq-samples" : "realtime"); + + pid_t server; + pid_t client; + + /* start server */ + server = fork(); + DevAssert(server >= 0); + if (server == 0) { + /* run as server */ + if (iq_samples_time_source) + execl(program_name, program_name, "--time_management.mode", "server", "--time_management.time_source", "iq_samples", NULL); + else + execl(program_name, program_name, "--time_management.mode", "server", NULL); + exit(1); + } + + /* wait a little bit so that server is ready to accept clients + * (this is hackish) + */ + usleep(100); + + /* start client */ + client = fork(); + DevAssert(client >= 0); + if (client == 0) { + /* run as client */ + execl(program_name, program_name, "--time_management.mode", "client", NULL); + exit(1); + } + + /* wait for completion */ + int ret = 1; + + int status; + pid_t r = waitpid(server, &status, 0); + DevAssert(r == server); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + ret = 0; + + r = waitpid(client, &status, 0); + DevAssert(r == client); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + ret = 0; + + return ret; +} + +/* return 1 if ok, 0 if error */ +static int run_sub_client_server(bool iq_samples_time_source) +{ + /* second argument doesn't matter, overwritten by args of execl in client_server() */ + time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_REALTIME); + + if (iq_samples_time_source) { + /* 'iq_samples_time_source' is true only for server + * wait a bit for client to be there otherwise server + * may finish too early + */ + usleep(100); + + /* let's pretend we have 2000 samples per second */ + for (int i = 0; i < 1000; i++) { + time_manager_iq_samples(1, 2000); + usleep(10); + time_manager_iq_samples(1, 2000); + usleep(10); + } + } else { + sleep(1); + } + + time_manager_finish(); + + LOG_I(UTIL, "client/server: rlc ticks: %d pdcp ticks: %d x2ap ticks: %d\n", rlc_tick_count, pdcp_tick_count, x2ap_tick_count); + + if (iq_samples_time_source) + return rlc_tick_count == 1000 + && pdcp_tick_count == 1000 + && x2ap_tick_count == 1000; + else + /* let's accept 1% deviation from the 1000 counts we expect */ + return abs(rlc_tick_count-1000) < 10 + && abs(pdcp_tick_count - 1000) < 10 + && abs(x2ap_tick_count - 1000) < 10; +} + +int main(int argc, char **argv) +{ + if ((uniqCfg = load_configmodule(argc, argv, CONFIG_ENABLECMDLINEONLY)) == NULL) { + exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); + } + logInit(); + + /* for client/server tests, we use sub-processes with command line parameters */ + if (argc > 1) { + /* if there are command line parameters then it's a sub-process */ + rlc_tick_count = 0; + pdcp_tick_count = 0; + x2ap_tick_count = 0; + /* return value to the main test program + * let's do as for the shell: 0 means success and 1 means error + */ + /* we know we are in iq-samples time source mode if the last argument is "iq_samples" */ + int success = run_sub_client_server(!strcmp(argv[argc - 1], "iq_samples")) == 1; + return 1 - success; + } + + int err = 0; + + /* test standalone realtime */ + rlc_tick_count = 0; + pdcp_tick_count = 0; + x2ap_tick_count = 0; + int ret = standalone_realtime(); + if (ret == 1) + LOG_I(UTIL, "standalone realtime: OK\n"); + else { + LOG_E(UTIL, "standalone realtime: ERROR\n"); + err = 1; + } + + /* test standalone iq-samples */ + rlc_tick_count = 0; + pdcp_tick_count = 0; + x2ap_tick_count = 0; + ret = standalone_iq_samples(); + if (ret == 1) + LOG_I(UTIL, "standalone iq-samples: OK\n"); + else { + LOG_E(UTIL, "standalone iq-samples: ERROR\n"); + err = 1; + } + + /* client/server tests are not written in a robust way + * they may fail depending on realtime on the machine + * de-activate if needed (if CI fails) + */ + /* test client/server realtime */ + rlc_tick_count = 0; + pdcp_tick_count = 0; + x2ap_tick_count = 0; + ret = client_server(argv[0], false); + if (ret == 1) + LOG_I(UTIL, "client-server realtime: OK\n"); + else { + LOG_E(UTIL, "client-server realtime: ERROR\n"); + err = 1; + } + + /* test client/server iq-samples */ + rlc_tick_count = 0; + pdcp_tick_count = 0; + x2ap_tick_count = 0; + ret = client_server(argv[0], true); + if (ret == 1) + LOG_I(UTIL, "client-server iq-samples: OK\n"); + else { + LOG_E(UTIL, "client-server iq-samples: ERROR\n"); + err = 1; + } + + logTerm(); + + return err; +} diff --git a/common/utils/time_manager/tests/test_manual.c b/common/utils/time_manager/tests/test_manual.c new file mode 100644 index 0000000000..e0cc11873a --- /dev/null +++ b/common/utils/time_manager/tests/test_manual.c @@ -0,0 +1,175 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "../time_source.h" +#include "../time_server.h" +#include "../time_client.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "common/utils/system.h" +#include "common/utils/LOG/log.h" + +#include "common/config/config_userapi.h" + +configmodule_interface_t *uniqCfg = NULL; + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + printf("%s:%d:%s: %s\n", file, line, function, s); + fflush(stdout); + exit(1); +} + +_Atomic bool test_exit; + +static void *iq_generate_thread(void *ts) +{ + time_source_t *time_source = ts; + + while (!test_exit) { + printf("iq_generate_thread calls time_source_iq_add(time_source, 100, 10000)\n"); + time_source_iq_add(time_source, 100, 10000); + sleep(1); + } + + return NULL; +} + +#define STANDALONE 0 +#define SERVER 1 +#define CLIENT 2 + +static void usage(void) +{ + printf("options:\n"); + printf(" -client\n"); + printf(" run as client (default is standalone)\n"); + printf(" -server\n"); + printf(" run as server (default is standalone)\n"); + printf(" -ip \n"); + printf(" use this ip address for server\n"); + printf(" -port n-2) usage(); server_ip = v[++i]; continue; } + if (!strcmp(v[i], "-port")) { if (i>n-2) usage(); server_port = atoi(v[++i]); continue; } + if (!strcmp(v[i], "-realtime")) { time_source_type = TIME_SOURCE_REALTIME; continue; } + usage(); + } + + logInit(); + /* hack: set log to info (logInit doesn't do it because we don't call load_configmodule()) */ + for (int i = 0; i < MAX_LOG_COMPONENTS; i++) + g_log->log_component[i].level = OAILOG_INFO; + + if (mode != CLIENT) { + ts = new_time_source(time_source_type); + if (time_source_type == TIME_SOURCE_IQ_SAMPLES) { + void *ret = signal(SIGHUP, sig_handle); + DevAssert(ret != SIG_ERR); + threadCreate(&iq_thread, iq_generate_thread, ts, "iq samples generator", -1, SCHED_OAI); + } + } + + if (mode == SERVER) { + /* (void*)1 to check if callback data is passed correctly */ + server = new_time_server(server_ip, server_port, server_callback, (void *)1); + time_server_attach_time_source(server, ts); + } + + if (mode == CLIENT) { + /* (void*)2 to check if callback data is passed correctly */ + client = new_time_client(server_ip, server_port, client_callback, (void *)2); + } + + printf("main: press enter to quit\n"); + getchar(); + + test_exit = true; + + if (mode != CLIENT) + if (time_source_type == TIME_SOURCE_IQ_SAMPLES) { + (void)pthread_kill(iq_thread, SIGHUP); + int ret = pthread_join(iq_thread, NULL); + DevAssert(ret == 0); + } + + if (mode != CLIENT) { + free_time_source(ts); + } + + if (mode == SERVER) { + free_time_server(server); + } + + if (mode == CLIENT) { + free_time_client(client); + } + + logTerm(); + + return 0; +} diff --git a/common/utils/time_manager/time_client.c b/common/utils/time_manager/time_client.c new file mode 100644 index 0000000000..4cecf0e6c6 --- /dev/null +++ b/common/utils/time_manager/time_client.c @@ -0,0 +1,231 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "time_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/utils/assertions.h" +#include "common/utils/LOG/log.h" +#include "common/utils/system.h" + +typedef struct { + pthread_t thread_id; + int exit_fd; + struct sockaddr_in server_ip; + int server_port; + void (*callback)(void *); + void *callback_data; +} time_client_private_t; + +static int connect_to_server(time_client_private_t *time_client) +{ + int sock = -1; + int opts; + int r; + struct pollfd fds[2]; + + /* try forever (or exit requested) until we succeed */ + while (1) { + sock = socket(AF_INET, SOCK_STREAM, 0); + DevAssert(sock != -1); + int v = 1; + r = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + DevAssert(r == 0); + /* unblock socket */ + opts = fcntl(sock, F_GETFL); + DevAssert(opts >= 0); + opts |= O_NONBLOCK; + r = fcntl(sock, F_SETFL, opts); + DevAssert(r == 0); + if (connect(sock, (struct sockaddr *)&time_client->server_ip, sizeof(time_client->server_ip)) == 0) + break; + if (errno == EINPROGRESS) { + /* connection not completed yet, we need to wait */ + fds[0].fd = sock; + fds[0].events = POLLOUT; + fds[1].fd = time_client->exit_fd; + fds[1].events = POLLIN; + r = poll(fds, 2, -1); + DevAssert(r >= 0); + /* do we need to exit? */ + if (fds[1].revents) { + shutdown(sock, SHUT_RDWR); + close(sock); + sock = -1; + break; + } + /* check if connection is successful */ + if (fds[0].revents & POLLOUT) { + int so_error; + socklen_t so_error_len = sizeof(so_error); + r = getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); + DevAssert(r == 0 && so_error_len == sizeof(so_error)); + if (so_error == 0) + /* success */ + break; + } + } + /* connection failed, try again in 1s (or stop if exit requested) */ + close(sock); + sock = -1; + char server_address[256]; + const char *ret = inet_ntop(AF_INET, &time_client->server_ip.sin_addr, server_address, sizeof(server_address)); + DevAssert(ret != NULL); + LOG_W(UTIL, "time client: connection to %s:%d failed, try again in 1s\n", server_address, time_client->server_port); + /* sleep 1s (or exit requested) */ + fds[0].fd = time_client->exit_fd; + fds[0].events = POLLIN; + r = poll(fds, 1, 1000); + DevAssert(r >= 0); + /* exit requested? */ + if (fds[0].revents) { + shutdown(sock, SHUT_RDWR); + close(sock); + sock = -1; + break; + } + } + if (sock != -1) { + /* reblock socket */ + opts &= ~O_NONBLOCK; + r = fcntl(sock, F_SETFL, opts); + DevAssert(r == 0); + } + return sock; +} + +static void *time_client_thread(void *tc) +{ + time_client_private_t *time_client = tc; + int ret; + int socket = connect_to_server(time_client); + /* if socket is -1 at this point, it means that exit was requested */ + if (socket == -1) + return NULL; + + while (1) { + struct pollfd polls[2]; + /* polls[0] is for the socket */ + polls[0].fd = socket; + polls[0].events = POLLIN; + + /* polls[1] is for exit_fd */ + polls[1].fd = time_client->exit_fd; + polls[1].events = POLLIN; + + ret = poll(polls, 2, -1); + DevAssert(ret >= 0); + + /* whatever is in revents for exit_fd means exit */ + if (polls[1].revents) + break; + + /* is socket fine? */ + if (polls[0].revents & (POLLERR | POLLHUP)) { +reconnect: + /* socket not fine, reconnect */ + shutdown(socket, SHUT_RDWR); + close(socket); + socket = connect_to_server(time_client); + /* connect only fails if exit requested, we can safely 'continue' */ + continue; + } + + /* here we only accept POLLIN */ + DevAssert(polls[0].revents == POLLIN); + + /* get the ticks from server */ + uint8_t tick_count; + ret = read(socket, &tick_count, 1); + /* any error => reconnect */ + if (ret == -1) { + LOG_E(UTIL, "time client: error %s, reconnect\n", strerror(errno)); + goto reconnect; + } + /* if 0 is returned, it means socket has been closed by other end */ + if (ret == 0) { + LOG_E(UTIL, "time client: socket closed by other end, reconnect\n"); + goto reconnect; + } + DevAssert(ret == 1); + + /* call callback once for each tick */ + for (int i = 0; i < tick_count; i++) + time_client->callback(time_client->callback_data); + } + + shutdown(socket, SHUT_RDWR); + close(socket); + + return NULL; +} + +time_client_t *new_time_client(const char *server_ip, + int server_port, + void (*callback)(void *), + void *callback_data) +{ + time_client_private_t *tc; + int ret; + + tc = calloc(1, sizeof(*tc)); + DevAssert(tc != NULL); + + tc->exit_fd = eventfd(0, 0); + DevAssert(tc->exit_fd != -1); + + ret = inet_aton(server_ip, &tc->server_ip.sin_addr); + DevAssert(ret != 0); + tc->server_ip.sin_family = AF_INET; + tc->server_ip.sin_port = htons(server_port); + tc->server_port = server_port; + tc->callback = callback; + tc->callback_data = callback_data; + + threadCreate(&tc->thread_id, time_client_thread, tc, "time client", -1, SCHED_OAI); + + return tc; +} + +void free_time_client(time_client_t *tc) +{ + time_client_private_t *time_client = tc; + + uint64_t v = 1; + int ret = write(time_client->exit_fd, &v, 8); + DevAssert(ret == 8); + + ret = pthread_join(time_client->thread_id, NULL); + DevAssert(ret == 0); + + close(time_client->exit_fd); + free(time_client); +} diff --git a/common/utils/time_manager/time_client.h b/common/utils/time_manager/time_client.h new file mode 100644 index 0000000000..02905896a4 --- /dev/null +++ b/common/utils/time_manager/time_client.h @@ -0,0 +1,36 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_CLIENT +#define COMMON_UTIL_TIME_MANAGER_TIME_CLIENT + +/* opaque data type */ +typedef void time_client_t; + +time_client_t *new_time_client(const char *server_ip, + int server_port, + void (*callback)(void *), + void *callback_data); + +void free_time_client(time_client_t *time_client); + + +#endif /* COMMON_UTIL_TIME_MANAGER_TIME_CLIENT */ diff --git a/common/utils/time_manager/time_manager.c b/common/utils/time_manager/time_manager.c new file mode 100644 index 0000000000..cf8168de0b --- /dev/null +++ b/common/utils/time_manager/time_manager.c @@ -0,0 +1,240 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#define _GNU_SOURCE +#include + +#include "time_manager.h" + +#include "time_source.h" +#include "time_server.h" +#include "time_client.h" + +#include "common/config/config_userapi.h" +#include "common/utils/assertions.h" +#include "common/utils/LOG/log.h" + +/* global variables (some may be ununsed, depends on configuration) */ +static time_source_t *time_source = NULL; +static time_server_t *time_server = NULL; +static time_client_t *time_client = NULL; + +/* available tick functions in the executable + * found at startup time of the program using dlsym() + */ +static void (*pdcp_tick)(void) = NULL; +static void (*rlc_tick)(void) = NULL; +static void (*x2ap_tick)(void) = NULL; + +/* tick callback, called by time_source every 'millisecond' (can be + * actual millisecond or simulated millisecond) + */ +static void tick(void *unused) +{ + /* call x2ap_tick, pdcp_tick, rlc_tick (if they exist) */ + if (pdcp_tick != NULL) + pdcp_tick(); + + if (rlc_tick != NULL) + rlc_tick(); + + if (x2ap_tick != NULL) + x2ap_tick(); +} + +void time_manager_start(time_manager_client_t client_type, + time_manager_mode_t running_mode) +{ + time_source_type_t time_source_type = -1; + bool has_time_server = false; + bool has_time_client = false; + char *default_server_ip = "127.0.0.1"; + int default_server_port = 7374; + char *server_ip = NULL; + int server_port = -1; + + /* retrieve, if applicable, available tick functions in the program */ + if (client_type == TIME_MANAGER_GNB_MONOLITHIC + || client_type == TIME_MANAGER_GNB_CU + || client_type == TIME_MANAGER_UE) + pdcp_tick = dlsym(RTLD_DEFAULT, "nr_pdcp_ms_tick"); + + if (client_type == TIME_MANAGER_GNB_MONOLITHIC + || client_type == TIME_MANAGER_GNB_DU + || client_type == TIME_MANAGER_UE) + rlc_tick = dlsym(RTLD_DEFAULT, "nr_rlc_ms_tick"); + + /* let's also retrieve is_x2ap_enabled() with dlsym to not force the + * application to define it (this logic may be changed if wanted) + */ + int (*is_x2ap_enabled)(void) = dlsym(RTLD_DEFAULT, "is_x2ap_enabled"); + if ((client_type == TIME_MANAGER_GNB_MONOLITHIC + || client_type == TIME_MANAGER_GNB_CU) + && is_x2ap_enabled != NULL && is_x2ap_enabled()) + x2ap_tick = dlsym(RTLD_DEFAULT, "x2ap_ms_tick"); + + /* get default configuration */ + switch (client_type) { + case TIME_MANAGER_GNB_MONOLITHIC: + case TIME_MANAGER_GNB_DU: + case TIME_MANAGER_UE: + switch (running_mode) { + case TIME_MANAGER_REALTIME: + time_source_type = TIME_SOURCE_REALTIME; + break; + case TIME_MANAGER_IQ_SAMPLES: + time_source_type = TIME_SOURCE_IQ_SAMPLES; + break; + } + break; + case TIME_MANAGER_GNB_CU: + case TIME_MANAGER_SIMULATOR: + time_source_type = TIME_SOURCE_REALTIME; + break; + } + + /* get values from configuration */ + paramdef_t config_parameters[] = { + {"time_source", "time source", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {"mode", "time mode", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {"server_ip", "server ip", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {"server_port", "server port", 0, .iptr = NULL, .defintval = -1, TYPE_INT, 0}, + }; + int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management"); + if (ret >= 0) { +#define TIME_SOURCE_IDX 0 +#define MODE_IDX 1 +#define SERVER_IP_IDX 2 +#define SERVER_PORT_IDX 3 + char *param; + /* time source */ + if (config_parameters[TIME_SOURCE_IDX].strptr != NULL) + param = *config_parameters[TIME_SOURCE_IDX].strptr; + else + param = NULL; + if (param != NULL) { + if (!strcmp(param, "realtime")) { + time_source_type = TIME_SOURCE_REALTIME; + } else if (!strcmp(param, "iq_samples")) { + time_source_type = TIME_SOURCE_IQ_SAMPLES; + } else { + AssertFatal(0, "bad parameter 'time_source' in section 'time_management', unknown value \"%s\". Valid values are \"realtime\" and \"iq_samples\"\n", param); + } + } + + /* mode */ + if (config_parameters[MODE_IDX].strptr != NULL) + param = *config_parameters[MODE_IDX].strptr; + else + param = NULL; + if (param != NULL) { + if (!strcmp(param, "standalone")) { + has_time_server = false; + has_time_client = false; + } else if (!strcmp(param, "server")) { + has_time_server = true; + has_time_client = false; + } else if (!strcmp(param, "client")) { + has_time_server = false; + has_time_client = true; + } else { + AssertFatal(0, "bad parameter 'mode' in section 'time_management', unknown value \"%s\". Valid values are \"standalone\", \"server\" and \"client\"\n", param); + } + } + + /* server ip */ + if (config_parameters[SERVER_IP_IDX].strptr != NULL) + param = *config_parameters[SERVER_IP_IDX].strptr; + else + param = NULL; + if (param != NULL) { + server_ip = param; + } + + /* server port */ + int port = *config_parameters[SERVER_PORT_IDX].iptr; + if (port != -1) { + server_port = port; + } + } + + if (server_ip == NULL) + server_ip = default_server_ip; + + if (server_port == -1) + server_port = default_server_port; + + /* create entities, according to selected configuration */ + if (!has_time_client) { + time_source = new_time_source(time_source_type); + time_source_set_callback(time_source, tick, NULL); + } + + if (has_time_server) { + time_server = new_time_server(server_ip, server_port, tick, NULL); + time_server_attach_time_source(time_server, time_source); + } + + if (has_time_client) { + time_client = new_time_client(server_ip, server_port, tick, NULL); + } + + LOG_I(UTIL, + "time manager configuration: [time source: %s] [mode: %s] [server IP: %s} [server port: %d]%s\n", + (char *[]){"reatime", "iq_samples"}[time_source_type], + has_time_server ? "server" + : has_time_client ? "client" + : "standalone", + server_ip, + server_port, + has_time_server || has_time_client ? "" : " (server IP/port not used)"); + + LOG_I(UTIL, + "time manager: pdcp tick: %s, rlc tick: %s, x2ap tick: %s\n", + pdcp_tick == NULL ? "not activated" : "activated", + rlc_tick == NULL ? "not activated" : "activated", + x2ap_tick == NULL ? "not activated" : "activated"); +} + +void time_manager_iq_samples(uint64_t iq_samples_count, + uint64_t iq_samples_per_second) +{ + time_source_iq_add(time_source, iq_samples_count, iq_samples_per_second); +} + +void time_manager_finish(void) +{ + /* time source has to be shutdown first */ + if (time_source != NULL) { + free_time_source(time_source); + time_source = NULL; + } + + if (time_server != NULL) { + free_time_server(time_server); + time_server = NULL; + } + + if (time_client != NULL) { + free_time_client(time_client); + time_client = NULL; + } +} diff --git a/common/utils/time_manager/time_manager.h b/common/utils/time_manager/time_manager.h new file mode 100644 index 0000000000..d1ed4ed0e1 --- /dev/null +++ b/common/utils/time_manager/time_manager.h @@ -0,0 +1,46 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_MANAGER +#define COMMON_UTIL_TIME_MANAGER_TIME_MANAGER + +#include + +typedef enum { + TIME_MANAGER_GNB_MONOLITHIC, + TIME_MANAGER_GNB_CU, + TIME_MANAGER_GNB_DU, + TIME_MANAGER_UE, + TIME_MANAGER_SIMULATOR, +} time_manager_client_t; + +typedef enum { + TIME_MANAGER_REALTIME, + TIME_MANAGER_IQ_SAMPLES +} time_manager_mode_t; + +void time_manager_start(time_manager_client_t client_type, + time_manager_mode_t running_mode); +void time_manager_iq_samples(uint64_t iq_samples_count, + uint64_t iq_samples_per_second); +void time_manager_finish(void); + +#endif /* COMMON_UTIL_TIME_MANAGER_TIME_MANAGER */ diff --git a/common/utils/time_manager/time_server.c b/common/utils/time_manager/time_server.c new file mode 100644 index 0000000000..83b9e30fd2 --- /dev/null +++ b/common/utils/time_manager/time_server.c @@ -0,0 +1,251 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "time_server.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/utils/system.h" +#include "common/utils/LOG/log.h" + +typedef struct { + pthread_t thread_id; + _Atomic bool exit; + int server_socket; + int tick_fd; + void (*callback)(void *); + void *callback_data; +} time_server_private_t; + +static void *time_server_thread(void *ts) +{ + time_server_private_t *time_server = ts; + struct pollfd *polls = NULL; + int *socket_fds = NULL; + int client_count = 0; + + polls = calloc(2, sizeof(struct pollfd)); + DevAssert(polls != NULL); + + while (!time_server->exit) { + /* polls[0] is to receive ticks */ + polls[0].fd = time_server->tick_fd; + polls[0].events = POLLIN; + /* polls[1] is to accept connections from clients */ + polls[1].fd = time_server->server_socket; + polls[1].events = POLLIN; + + /* add clients */ + for (int i = 0; i < client_count; i++) { + polls[i + 2].fd = socket_fds[i]; + polls[i + 2].events = POLLIN; + } + + int ret = poll(polls, client_count + 2, -1); + DevAssert(ret >= 1 || (ret == -1 && errno == EINTR)); + + if (time_server->exit) + break; + + /* check tick */ + if (polls[0].revents) { + /* do not accept errors */ + DevAssert(polls[0].revents == POLLIN); + uint64_t ticks; + int ret = read(time_server->tick_fd, &ticks, 8); + DevAssert(ret == 8); + /* call the callback ticks time */ + for (int i = 0; i < ticks; i++) + time_server->callback(time_server->callback_data); + /* send ticks by blocks of 255 max (what fits in a uint8_t) */ + while (ticks) { + /* get min(ticks, 255) */ + uint8_t count = ticks < 255 ? ticks : 255; + /* send to all clients */ + for (int i = 0; i < client_count; i++) { + if (write(socket_fds[i], &count, 1) == 1) + continue; + + /* error writing - remove client */ + LOG_W(UTIL, "time server: client disconnects\n"); + shutdown(socket_fds[i], SHUT_RDWR); + close(socket_fds[i]); + client_count--; + i--; + if (client_count == 0) { + free(socket_fds); + socket_fds = NULL; + } else { + memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1)); + socket_fds = realloc(socket_fds, sizeof(int) * client_count); + } + polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); + DevAssert(polls != NULL); + } + ticks -= count; + } + } + + /* check new client */ + if (polls[1].revents) { + /* do not accept errors */ + DevAssert(polls[1].revents == POLLIN); + + int new_socket = accept(time_server->server_socket, NULL, NULL); + DevAssert(new_socket != -1); + + /* add client */ + client_count++; + socket_fds = realloc(socket_fds, sizeof(int) * client_count); + DevAssert(socket_fds != NULL); + socket_fds[client_count - 1] = new_socket; + polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); + DevAssert(polls != NULL); + continue; + } + + /* any event on a client socket is to be considered as an error */ + for (int i = 0; i < client_count; i++) { + if (polls[i + 2].revents == 0) + continue; + + LOG_W(UTIL, + "time server: error on client's socket, removing client (revents is %d, fd is %d i is %d)\n", + polls[i + 2].revents, + polls[i + 2].fd, + i); + shutdown(socket_fds[i], SHUT_RDWR); + close(socket_fds[i]); + client_count--; + i--; + if (client_count == 0) { + free(socket_fds); + socket_fds = NULL; + } else { + memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1)); + socket_fds = realloc(socket_fds, sizeof(int) * client_count); + DevAssert(socket_fds != NULL); + } + if (client_count) + memmove(&polls[i + 2 + 1], &polls[i + 2 + 2], sizeof(struct pollfd) * (client_count - i - 1)); + polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); + DevAssert(polls != NULL); + } + } + + /* close all clients' sockets */ + for (int i = 0; i < client_count; i++) { + shutdown(socket_fds[i], SHUT_RDWR); + close(socket_fds[i]); + } + + free(polls); + free(socket_fds); + + return NULL; +} + +time_server_t *new_time_server(const char *ip, + int port, + void (*callback)(void *), + void *callback_data) +{ + time_server_private_t *ts; + int ret; + + ts = calloc(1, sizeof(*ts)); + DevAssert(ts != NULL); + + ts->server_socket = socket(AF_INET, SOCK_STREAM, 0); + DevAssert(ts->server_socket != -1); + + int v = 1; + ret = setsockopt(ts->server_socket, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); + DevAssert(ret == 0); + v = 1; + ret = setsockopt(ts->server_socket, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + DevAssert(ret == 0); + ts->tick_fd = eventfd(0, 0); + DevAssert(ts->tick_fd != -1); + + struct sockaddr_in ip_addr; + ip_addr.sin_family = AF_INET; + ip_addr.sin_port = htons(port); + ret = inet_aton(ip, &ip_addr.sin_addr); + DevAssert(ret != 0); + ret = bind(ts->server_socket, (struct sockaddr *)&ip_addr, sizeof(ip_addr)); + DevAssert(ret == 0); + + ret = listen(ts->server_socket, 10); /* 10: arbitrary value */ + DevAssert(ret == 0); + + ts->callback = callback; + ts->callback_data = callback_data; + + threadCreate(&ts->thread_id, time_server_thread, ts, "time server", -1, SCHED_OAI); + return ts; +} + +void free_time_server(time_server_t *ts) +{ + time_server_private_t *time_server = ts; + + /* flag exit */ + time_server->exit = true; + + /* send a fake tick to wake up the server thread */ + uint64_t v = 1; + int ret = write(time_server->tick_fd, &v, 8); + DevAssert(ret == 8); + + /* wait for thread termination */ + void *retval; + ret = pthread_join(time_server->thread_id, &retval); + + /* free memory */ + shutdown(time_server->server_socket, SHUT_RDWR); + close(time_server->server_socket); + close(time_server->tick_fd); + free(time_server); +} + +static void time_server_tick_callback(void *ts) +{ + time_server_private_t *time_server = ts; + uint64_t v = 1; + int ret = write(time_server->tick_fd, &v, 8); + DevAssert(ret == 8); +} + +void time_server_attach_time_source(time_server_t *time_server, + time_source_t *time_source) +{ + time_source_set_callback(time_source, time_server_tick_callback, time_server); +} diff --git a/common/utils/time_manager/time_server.h b/common/utils/time_manager/time_server.h new file mode 100644 index 0000000000..b3f41b1941 --- /dev/null +++ b/common/utils/time_manager/time_server.h @@ -0,0 +1,40 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SERVER +#define COMMON_UTIL_TIME_MANAGER_TIME_SERVER + +#include "time_source.h" + +/* opaque data type */ +typedef void time_server_t; + +time_server_t *new_time_server(const char *ip, + int port, + void (*callback)(void *), + void *callback_data); +void free_time_server(time_server_t *time_server); + +void time_server_attach_time_source(time_server_t *time_server, + time_source_t *time_source); + +#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SERVER */ + diff --git a/common/utils/time_manager/time_source.c b/common/utils/time_manager/time_source.c new file mode 100644 index 0000000000..76a76bc655 --- /dev/null +++ b/common/utils/time_manager/time_source.c @@ -0,0 +1,264 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "time_source.h" + +#include +#include +#include +#include + +#include "common/utils/assertions.h" +#include "common/utils/system.h" + +typedef void (*callback_function_t)(void *callback_data); +typedef void * callback_data_t; + +typedef struct { + time_source_type_t type; + volatile callback_function_t callback; + volatile callback_data_t callback_data; + _Atomic bool exit; + void (*terminate)(void *this); + pthread_t thread_id; + pthread_mutex_t mutex; + pthread_cond_t cond; +} time_source_common_t; + +typedef struct { + time_source_common_t common; +} time_source_realtime_t; + +typedef struct { + time_source_common_t common; + volatile uint64_t iq_samples_count; + volatile uint64_t iq_samples_per_second; +} time_source_iq_t; + +static void init_mutex(time_source_common_t *t) +{ + int ret = pthread_mutex_init(&t->mutex, NULL); + DevAssert(ret == 0); +} + +static void init_cond(time_source_common_t *t) +{ + int ret = pthread_cond_init(&t->cond, NULL); + DevAssert(ret == 0); +} + +static void lock(time_source_common_t *t) +{ + int ret = pthread_mutex_lock(&t->mutex); + DevAssert(ret == 0); +} + +static void unlock(time_source_common_t *t) +{ + int ret = pthread_mutex_unlock(&t->mutex); + DevAssert(ret == 0); +} + +static void condwait(time_source_common_t *t) +{ + int ret = pthread_cond_wait(&t->cond, &t->mutex); + DevAssert(ret == 0); +} + +static void condsignal(time_source_common_t *t) +{ + int ret = pthread_cond_signal(&t->cond); + DevAssert(ret == 0); +} + +static void wait_thread_termination(time_source_common_t *t) +{ + void *retval; + int ret = pthread_join(t->thread_id, &retval); + DevAssert(ret == 0); +} + +static struct timespec next_ms(struct timespec t) +{ + /* go to next millisecond */ + t.tv_nsec += 1000000; + if (t.tv_nsec > 999999999) { + t.tv_nsec -= 1000000000; + t.tv_sec++; + } + + return t; +} + +static void *time_source_realtime_thread(void *ts) +{ + time_source_realtime_t *time_source = ts; + + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) + AssertFatal(0, "clock_gettime failed\n"); + + /* go to next millisecond */ + now = next_ms(now); + + while (!time_source->common.exit) { + /* sleep */ + if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &now, NULL) == -1) { + /* accept interruption by signals and then simply restart the sleep */ + if (errno == EINTR) + continue; + AssertFatal(0, "clock_nanosleep failed\n"); + } + + if (time_source->common.exit) + break; + + /* tick */ + lock(&time_source->common); + void (*callback)(void *callback_data) = time_source->common.callback; + void *callback_data = time_source->common.callback_data; + unlock(&time_source->common); + if (callback != NULL) + callback(callback_data); + + /* go to next millisecond */ + now = next_ms(now); + } + + return (void *)0; +} + +static void *time_source_iq_samples_thread(void *ts) +{ + time_source_iq_t *time_source = ts; + + while (!time_source->common.exit) { + /* wait until we have at least 1ms of IQ samples */ + lock(&time_source->common); + while (!time_source->common.exit + && (time_source->iq_samples_per_second == 0 + || time_source->iq_samples_count < time_source->iq_samples_per_second / 1000)) + condwait(&time_source->common); + time_source->iq_samples_count -= time_source->iq_samples_per_second / 1000; + unlock(&time_source->common); + + if (time_source->common.exit) + break; + + /* tick */ + lock(&time_source->common); + void (*callback)(void *callback_data) = time_source->common.callback; + void *callback_data = time_source->common.callback_data; + unlock(&time_source->common); + if (callback != NULL) + callback(callback_data); + } + + return (void *)0; +} + +static void time_source_iq_samples_terminate(void *ts) +{ + time_source_iq_t *time_source = ts; + condsignal(&time_source->common); +} + +time_source_t *new_time_source(time_source_type_t type) +{ + time_source_t *ret = NULL; + void *(*thread_function)(void *) = NULL; + void (*terminate_function)(void *) = NULL; + char *thread_function_name = NULL; + + switch (type) { + case TIME_SOURCE_REALTIME: { + time_source_realtime_t *ts = calloc(1, sizeof(*ts)); + DevAssert(ts != NULL); + thread_function = time_source_realtime_thread; + thread_function_name = "time source realtime"; + ret = ts; + break; + } + case TIME_SOURCE_IQ_SAMPLES: { + time_source_iq_t *ts = calloc(1, sizeof(*ts)); + DevAssert(ts != NULL); + thread_function = time_source_iq_samples_thread; + terminate_function = time_source_iq_samples_terminate; + thread_function_name = "time source iq samples"; + ret = ts; + break; + } + } + + time_source_common_t *c = ret; + c->type = type; + init_mutex(c); + init_cond(c); + c->terminate = terminate_function; + threadCreate(&c->thread_id, thread_function, c, thread_function_name, -1, SCHED_OAI); + + return ret; +} + +void free_time_source(time_source_t *ts) +{ + time_source_common_t *time_source = ts; + time_source->exit = true; + if (time_source->terminate != NULL) + time_source->terminate(time_source); + wait_thread_termination(time_source); + free(time_source); +} + +void time_source_set_callback(time_source_t *ts, + void (*callback)(void *), + void *callback_data) +{ + time_source_common_t *time_source = ts; + lock(time_source); + time_source->callback = callback; + time_source->callback_data = callback_data; + unlock(time_source); +} + +void time_source_iq_add(time_source_t *ts, + uint64_t iq_samples_count, + uint64_t iq_samples_per_second) +{ + if (ts == NULL) + return; + + time_source_iq_t *time_source = ts; + + if (time_source->common.type != TIME_SOURCE_IQ_SAMPLES) + return; + + lock(&time_source->common); + + time_source->iq_samples_count += iq_samples_count; + + if (time_source->iq_samples_per_second == 0) + time_source->iq_samples_per_second = iq_samples_per_second; + AssertFatal(time_source->iq_samples_per_second == iq_samples_per_second, "unsupported change of value 'IQ samples per second'\n"); + + condsignal(&time_source->common); + unlock(&time_source->common); +} diff --git a/common/utils/time_manager/time_source.h b/common/utils/time_manager/time_source.h new file mode 100644 index 0000000000..45b39d610f --- /dev/null +++ b/common/utils/time_manager/time_source.h @@ -0,0 +1,47 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SOURCE +#define COMMON_UTIL_TIME_MANAGER_TIME_SOURCE + +#include + +/* opaque data type */ +typedef void time_source_t; + +typedef enum { + TIME_SOURCE_REALTIME, + TIME_SOURCE_IQ_SAMPLES +} time_source_type_t; + +time_source_t *new_time_source(time_source_type_t type); + +void free_time_source(time_source_t *time_source); + +void time_source_set_callback(time_source_t *time_source, + void (*callback)(void *), + void *callback_data); + +void time_source_iq_add(time_source_t *time_source, + uint64_t iq_samples_count, + uint64_t iq_samples_per_second); + +#endif /* COMMON_UTIL_TIME_MANAGER_TIME_SOURCE */ diff --git a/doc/SW_archi.md b/doc/SW_archi.md index da7f014fb7..433a1ac3d1 100644 --- a/doc/SW_archi.md +++ b/doc/SW_archi.md @@ -298,7 +298,7 @@ Even, a future evolution could remove this global rlc layer: rlc can be only a l When adding a UE, external code have to call `add_rlc_srb()` and/or `add_rlc_drb()`, to remove it: `rrc_rlc_remove_ue()` Inside UE, channels called drd or srb can be created: ??? and deleted: rrc_rlc_config_req() -nr_rlc_tick() must be called periodically to manage the internal timers +nr_rlc_ms_tick() must be called periodically to manage the internal timers successful_delivery() and max_retx_reached(): in ??? trigger, the RLC sends a itti message to RRC: RLC_SDU_INDICATION (neutralized by #if 0 right now) diff --git a/doc/time_management.md b/doc/time_management.md new file mode 100644 index 0000000000..a3ea4d580c --- /dev/null +++ b/doc/time_management.md @@ -0,0 +1,284 @@ +# Time management module + +[[_TOC_]] + +## Introduction + +Several parts of the 4G/5G protocol stack keep track of time, for example +for timeout events (in RRC, PDCP, or RLC for example). + +The obvious simple way to deal with time is to use the computer's realtime +clock. This works well when we run the stack in realtime, with real +radio equipment. But in simulation the system may run faster or slower +than realtime, so we need another way to deal with time. A good solution +is then to base time on the current IQ data processed by the system. So time +becomes "IQ samples" based, not realtime. + +The system may be decomposed into various components (CU, DU, RU, various +UEs) running either in realtime or simulation. Time may be distributed +to all these components from only one time source for accurate execution +of the scenario, or each component may have its own time source, either +based on realtime or IQ samples. + +## Overall structure + +The time management module is made of three main parts. The first one +is the time source. It can either be realtime or "IQ samples" based. +In one running scenario of the system, there can be one or more time +sources (imagine one for the gNB, and one per each UE). There can also +be only one time source, shared between various users of the time +manager. + +The second part is the server. One server is attached to one time source +and receives a tick every millisecond (real or simulated) from the time +source. It distributes the tick to the various connected clients. + +And finally the last part is the client, which connects to a single server +and receives ticks from it. The client does not have a time source attached +to it. It gets the time from the server. + +It is possible for a program (monolithic gNB for example) to have only +a time source, without server or client. + +## Configuration + +To configure the time management module, add the following section in +the configuration file. + +``` +time_management = { + #valid time sources: realtime, iq_samples + time_source = realtime + + #valid modes: standalone, server, client + mode = standalone + + #set ip/port of server (for server mode, this is the address/port to bind to; + #for client mode, this is the address/port to connect to) + server_ip = "127.0.0.1" + server_port = 7374 +} +``` + +If not set in the configuration file, some default is applied, depending +on the program run. (See the function `time_manager_start()` for details.) + +It is also possible to pass configuration parameters on the command line. +For example add `--time_manager.time_source iq_samples` to the command line +to set the time source to `iq_samples`. The same syntax is applicable to the +other parameters. + +## Examples + +Here come some examples of configuration for typical use cases of OAI. + +### Monolithic gNB realtime + +This is a very simple example. The gNB runs in `standalone` mode with +a `realtime` time source. + +``` +time_management = { + time_source = realtime + mode = standalone +} +``` +### Monolithic gNB "IQ samples time" + +For this configuration, it's the same as the previous example, but the +time source is now `iq_samples`. + +``` +time_management = { + time_source = iq_samples + mode = standalone +} +``` +### RF simulator CU/DU "IQ samples time" + +Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU +runs on a machine with IP address 10.11.12.13. + +The DU has the time source and so is the server. The CU acts as a client. + +Here comes the configuration for the CU. + +``` +time_management = { + mode = client + server_ip = "10.11.12.13" + server_port = 7374 +} +``` +And here is the configuration for the DU. + +``` +time_management = { + time_source = iq_samples + mode = server + server_ip = "10.11.12.13" + server_port = 7374 +} +``` + +### RF simulator CU/DU "realtime" + +Let's suppose the CU runs on a machine with IP address 1.2.3.4 and the DU +runs on a machine with IP address 10.11.12.13. + +CU and DU can both run in standalone mode, with no exchange between them. +Any one of them can also acts as a server and the other one as a client. + +Let's suppose for this example that the CU and the DU run in client/server +mode. Let's set the CU as the time source and so as the server. The DU acts +as a client. + +Here comes the configuration for the CU. + +``` +time_management = { + time_source = realtime + mode = server + server_ip = "1.2.3.4" + server_port = 7374 +} +``` +And here is the configuration for the DU. + +``` +time_management = { + mode = client + server_ip = "1.2.3.4" + server_port = 7374 +} +``` + +Note that the time management module is flexible. It's possible to +configure more complex setups. For example the time source can be a gNB +and several UEs can be connected as client. + +One could also write a simple program acting as a time source and distributing +time to everyone (one or several gNB, several UEs). + +## Programming API + +Here comes the internal API of the time manager module. The (simpler) OAI +API is described afterwards. + +### Time source + +- opaque type: `time_source_t` +- create a time source: + ``` + time_source_t *new_time_source(time_source_type_t type) + ``` + where `type` is one of: + * `TIME_SOURCE_REALTIME` + * `TIME_SOURCE_IQ_SAMPLES` +- delete a time source: + ``` + void free_time_source(time_source_t *time_source) + ``` +- set millisecond callback: + ``` + void time_source_set_callback(time_source_t *time_source, + void (*callback)(void *), + void *callback_data) + ``` + where `callback` is a function that will be called for each millisecond using + the provided `callback_data` +- for IQ samples time management, the user of the time source must call + this function when it processes IQ samples: + ``` + void time_source_iq_add(time_source_t *time_source, + uint64_t iq_samples_count, + uint64_t iq_samples_per_second) + ``` + then the time source will generate a tick for each block for IQ samples + lasting one millisecond. (If you pass `iq_samples_count` lasting several + milliseconds then the time source will generate several ticks in a row, + one for each millisecond.) + +### Server + +- opaque tyoe: `time_server_t` +- create a server: + ``` + time_server_t *new_time_server(const char *ip, + int port, + void (*callback)(void *), + void *callback_data) + ``` + where ip/port is the IP adress and port the server will listen to + and `callback` is a function that will be called for each millisecond using + the provided `callback_data` +- delete a server: + ``` + void free_time_server(time_server_t *time_server) + ``` +- attach a time source: + ``` + void time_server_attach_time_source(time_server_t *time_server, + time_source_t *time_source) + ``` + +### Client + +- opaque type: `time_client_t` +- create a client: + ``` + time_client_t *new_time_client(const char *server_ip, + int server_port, + void (*callback)(void *), + void *callback_data) + ``` + the client will connect on given server ip/port + and use the `callback` with `callback_data` for each tick received +- delete a client: + ``` + void free_time_client(time_client_t *time_client) + ``` + +### Threading + +Each component (time source, server, client) runs its own thread which will +be the one calling the configured callback. Be careful of using proper +synchronization techniques in your callback to have correct behavior with +the other threads of the program. + +## OAI API + +OAI uses the time manager through a simplified API. All the code is contained +in `time_manager.c`, together with some global variables (so that there is no +need to pass objects around, to limit risks of misuse). + +Each program (for example: gnb, ue, cu, du) calls the `time_manager_start()` +function, passing the kind of program it is. Based on this type and the +configuration, `time_manager_start()` initializes what is needed. + +The function `time_manager_iq_samples()` is to be called by programs that +read IQ samples. It is called unconditionally. It may do nothing if the +configuration is to use realtime ticks and not IQ samples ticks. + +When the program exits, it calls `timer_manager_finish()` which in turns stops +the various threads created by `time_manager_start()` and releases all the +allocated data. + +Here comes the API. + +- init the time manager: + ``` + void time_manager_start(time_manager_client_t client_type, + time_manager_mode_t running_mode) + ``` + (for valid values of `client_type` and `running_mode` see in + `time_manager.h`) +- update IQ samples' based time manager: + ``` + void time_manager_iq_samples(uint64_t iq_samples_count, + uint64_t iq_samples_per_second) + ``` +- terminate the time manager: + ``` + void time_manager_finish(void) + ``` diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 238ee77275..4f5520d250 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -31,6 +31,7 @@ #include "openair2/F1AP/f1ap_ids.h" #include "openair2/GNB_APP/gnb_config.h" #include "nr_pdcp/nr_pdcp_oai_api.h" +#include "common/utils/time_manager/time_manager.h" RAN_CONTEXT_t RC; THREAD_STRUCT thread_struct; @@ -139,6 +140,11 @@ int main(int argc, char **argv) exit_fun("[SOFTMODEM] Error, configuration module init failed\n"); } logInit(); + + // start time manager with some reasonable default for the running mode + // (may be overwritten in configuration file or command line) + time_manager_start(TIME_MANAGER_GNB_CU, TIME_MANAGER_REALTIME); + // strdup to put the sring in the core file for post mortem identification LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION)); set_softmodem_sighandler(); @@ -177,6 +183,8 @@ int main(int argc, char **argv) printf("TYPE TO TERMINATE\n"); itti_wait_tasks_end(NULL); + time_manager_finish(); + logClean(); printf("Bye.\n"); return 0; diff --git a/executables/nr-ru.c b/executables/nr-ru.c index e665fd70bb..6187c9bc2e 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -47,6 +47,7 @@ #include "SCHED_NR/sched_nr.h" #include "common/utils/LOG/log.h" +#include "common/utils/time_manager/time_manager.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include @@ -1249,6 +1250,10 @@ void *ru_thread(void *param) slot++; } + // pretend we have 1 iq sample per slot + // and so slots_per_frame * 100 iq samples per second (1 frame being 10ms) + time_manager_iq_samples(1, fp->slots_per_frame * 100); + // synchronization on input FH interface, acquire signals/data and block LOG_D(PHY,"[RU_thread] read data: frame_rx = %d, tti_rx = %d\n", frame, slot); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index 98f89c881b..f0068a8d4b 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -28,6 +28,7 @@ #include "PHY/TOOLS/smbv.h" unsigned short config_frames[4] = {2,9,11,13}; #endif +#include "common/utils/time_manager/time_manager.h" #ifdef ENABLE_AERIAL #include "nfapi/oai_integration/aerial/fapi_nvIPC.h" #endif @@ -628,6 +629,18 @@ int main( int argc, char **argv ) { pthread_mutex_init(&sync_mutex, NULL); } + // start time manager with some reasonable default for the running mode + // (may be overwritten in configuration file or command line) + time_manager_start(NODE_IS_MONOLITHIC(node_type) ? TIME_MANAGER_GNB_MONOLITHIC + : NODE_IS_CU(node_type) ? TIME_MANAGER_GNB_CU + : TIME_MANAGER_GNB_DU, + // iq_samples time source for monolithic/du with rfsim, + // realtime time source for other cases + IS_SOFTMODEM_RFSIM + && (NODE_IS_MONOLITHIC(node_type) || NODE_IS_DU(node_type)) + ? TIME_MANAGER_IQ_SAMPLES + : TIME_MANAGER_REALTIME); + // start the main threads number_of_cards = 1; @@ -730,6 +743,8 @@ int main( int argc, char **argv ) { pthread_cond_destroy(&nfapi_sync_cond); pthread_mutex_destroy(&nfapi_sync_mutex); + time_manager_finish(); + free(pckg); logClean(); printf("Bye.\n"); diff --git a/executables/nr-ue.c b/executables/nr-ue.c index f2716c099e..2f531592b9 100644 --- a/executables/nr-ue.c +++ b/executables/nr-ue.c @@ -42,6 +42,7 @@ #include "common/utils/threadPool/notified_fifo.h" #include "position_interface.h" #include "nr_phy_common.h" +#include "common/utils/time_manager/time_manager.h" /* * NR SLOT PROCESSING SEQUENCE @@ -706,16 +707,6 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, process_msg_rcc_to_mac(msg); } while (msg); - if (IS_SOFTMODEM_NOS1 || IS_SA_MODE(get_softmodem_params())) { - /* send tick to RLC and PDCP every ms */ - if (proc->nr_slot_rx % fp->slots_per_subframe == 0) { - void nr_rlc_tick(int frame, int subframe); - void nr_pdcp_tick(int frame, int subframe); - nr_rlc_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe); - nr_pdcp_tick(proc->frame_rx, proc->nr_slot_rx / fp->slots_per_subframe); - } - } - if (UE->if_inst) UE->if_inst->slot_indication(UE->Mod_id, false); @@ -1095,6 +1086,10 @@ void *UE_thread(void *arg) absolute_slot++; TracyCFrameMark; + // pretend we have 1 iq sample per slot + // and so nb_slot_frame * 100 iq samples per second (1 frame being 10ms) + time_manager_iq_samples(1, nb_slot_frame * 100); + int slot_nr = absolute_slot % nb_slot_frame; nr_rxtx_thread_data_t curMsg = {0}; curMsg.UE=UE; diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 6d3efc28cd..fa5e5ca259 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -60,6 +60,7 @@ unsigned short config_frames[4] = {2,9,11,13}; #endif #include "common/utils/LOG/log.h" +#include "common/utils/time_manager/time_manager.h" #include "common/utils/LOG/vcd_signal_dumper.h" #include "UTIL/OPT/opt.h" @@ -461,6 +462,14 @@ int main(int argc, char **argv) if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test) sleep(3); + // start time manager with some reasonable default for the running mode + // (may be overwritten in configuration file or command line) + time_manager_start(TIME_MANAGER_UE, + // iq_samples time source for rfsim, + // realtime time source if not + IS_SOFTMODEM_RFSIM ? TIME_MANAGER_IQ_SAMPLES + : TIME_MANAGER_REALTIME); + if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) start_oai_nrue_threads(); @@ -586,6 +595,9 @@ int main(int argc, char **argv) } free_nrLDPC_coding_interface(&nrLDPC_coding_interface); + + time_manager_finish(); + free(pckg); return 0; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index e14004edc3..ab34ce551c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -177,16 +177,6 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo start_meas(&gNB->eNB_scheduler); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_gNB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN); - /* send tick to RLC, PDCP, and X2AP every ms */ - if ((slot & ((1 << *scc->ssbSubcarrierSpacing) - 1)) == 0) { - void nr_rlc_tick(int frame, int subframe); - void nr_pdcp_tick(int frame, int subframe); - nr_rlc_tick(frame, slot >> *scc->ssbSubcarrierSpacing); - nr_pdcp_tick(frame, slot >> *scc->ssbSubcarrierSpacing); - if (is_x2ap_enabled()) - x2ap_trigger(); - } - for (int CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) { int num_beams = 1; if(gNB->beam_info.beam_allocation) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 94df409113..c206d2d30f 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -74,11 +74,6 @@ static nr_pdcp_ue_manager_t *nr_pdcp_ue_manager; -/* TODO: handle time a bit more properly */ -static uint64_t nr_pdcp_current_time; -static int nr_pdcp_current_time_last_frame; -static int nr_pdcp_current_time_last_subframe; - /* necessary globals for OAI, not used internally */ hash_table_t *pdcp_coll_p; static uint64_t pdcp_optmask; @@ -422,9 +417,6 @@ void nr_pdcp_layer_init(void) nr_pdcp_e1_if_init(node_type == ngran_gNB_CUUP || node_type == ngran_gNB_CUCP); init_nr_pdcp_data_ind_queue(); nr_pdcp_init_timer_thread(nr_pdcp_ue_manager); - if (NODE_IS_CU(node_type)) { - nr_pdcp_init_tick_thread(); - } } #include "nfapi/oai_integration/vendor_ext.h" @@ -1052,17 +1044,6 @@ bool cu_f1u_data_req(protocol_ctxt_t *ctxt_pP, return ret; } -void nr_pdcp_tick(int frame, int subframe) -{ - if (frame != nr_pdcp_current_time_last_frame || - subframe != nr_pdcp_current_time_last_subframe) { - nr_pdcp_current_time_last_frame = frame; - nr_pdcp_current_time_last_subframe = subframe; - nr_pdcp_current_time++; - nr_pdcp_wakeup_timer_thread(nr_pdcp_current_time); - } -} - /* * For the SDAP API */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h index 286d072019..a77cc895e6 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h @@ -127,8 +127,6 @@ bool nr_pdcp_data_req_drb(protocol_ctxt_t *ctxt_pP, const uint32_t *const sourceL2Id, const uint32_t *const destinationL2Id); -void nr_pdcp_tick(int frame, int subframe); - nr_pdcp_ue_manager_t *nr_pdcp_sdap_get_ue_manager(); int nr_pdcp_get_num_ues(ue_id_t *ue_list, int len); diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c index 1c5e926fea..e63875a344 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.c @@ -70,26 +70,6 @@ static void *nr_pdcp_timer_thread(void *_nr_pdcp_ue_manager) return NULL; } -static void *nr_pdcp_tick_thread() { - pthread_setname_np(pthread_self(),"nr_pdcp_tick_thread"); - uint64_t curr_time = 0; - while (1) { - usleep(1000); - curr_time++; - nr_pdcp_wakeup_timer_thread(curr_time); - } - return NULL; -} - -void nr_pdcp_init_tick_thread() -{ - pthread_t t; - if (pthread_create(&t, NULL, nr_pdcp_tick_thread, NULL) != 0) { - LOG_E(PDCP, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } -} - void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager) { pthread_t t; @@ -100,10 +80,10 @@ void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager) } } -void nr_pdcp_wakeup_timer_thread(uint64_t time) +void nr_pdcp_ms_tick(void) { if (pthread_mutex_lock(&timer_thread_mutex)) abort(); - timer_thread_curtime = time; + timer_thread_curtime++; if (pthread_cond_broadcast(&timer_thread_cond)) abort(); if (pthread_mutex_unlock(&timer_thread_mutex)) abort(); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h index 552d5da279..90ff184d3d 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_timer_thread.h @@ -26,8 +26,7 @@ #include -void nr_pdcp_init_tick_thread(); void nr_pdcp_init_timer_thread(nr_pdcp_ue_manager_t *nr_pdcp_ue_manager); -void nr_pdcp_wakeup_timer_thread(uint64_t time); +void nr_pdcp_ms_tick(void); #endif /* _NR_PDCP_TIMER_THREAD_H_ */ diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c index 4b7202f6fd..b48b03847f 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c +++ b/openair2/LAYER2/nr_rlc/nr_rlc_oai_api.c @@ -50,8 +50,6 @@ static nr_rlc_ue_manager_t *nr_rlc_ue_manager; /* TODO: handle time a bit more properly */ static pthread_mutex_t nr_rlc_current_time_mutex = PTHREAD_MUTEX_INITIALIZER; static uint64_t nr_rlc_current_time; -static int nr_rlc_current_time_last_frame; -static int nr_rlc_current_time_last_subframe; void lock_nr_rlc_current_time(void) { @@ -956,15 +954,10 @@ void nr_rlc_test_trigger_reestablishment(int ue_id) nr_rlc_manager_unlock(nr_rlc_ue_manager); } -void nr_rlc_tick(int frame, int subframe) +void nr_rlc_ms_tick(void) { lock_nr_rlc_current_time(); - if (frame != nr_rlc_current_time_last_frame || - subframe != nr_rlc_current_time_last_subframe) { - nr_rlc_current_time_last_frame = frame; - nr_rlc_current_time_last_subframe = subframe; - nr_rlc_current_time++; - } + nr_rlc_current_time++; unlock_nr_rlc_current_time(); } diff --git a/openair2/X2AP/x2ap_eNB.c b/openair2/X2AP/x2ap_eNB.c index d0d2b03304..6bc37771e0 100644 --- a/openair2/X2AP/x2ap_eNB.c +++ b/openair2/X2AP/x2ap_eNB.c @@ -756,7 +756,7 @@ mutex_error: exit(1); } -void x2ap_trigger(void) +void x2ap_ms_tick(void) { MessageDef *msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_SUBFRAME_PROCESS); itti_send_msg_to_task(TASK_X2AP, 0, msg); diff --git a/openair2/X2AP/x2ap_eNB.h b/openair2/X2AP/x2ap_eNB.h index 0f83ca64af..afa6f11b8e 100644 --- a/openair2/X2AP/x2ap_eNB.h +++ b/openair2/X2AP/x2ap_eNB.h @@ -47,7 +47,6 @@ int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p, void *x2ap_task(void *arg); int is_x2ap_enabled(void); -void x2ap_trigger(void); #endif /* X2AP_H_ */ diff --git a/openair2/X2AP/x2ap_timers.c b/openair2/X2AP/x2ap_timers.c index ac619d5b0f..2e72aea408 100644 --- a/openair2/X2AP/x2ap_timers.c +++ b/openair2/X2AP/x2ap_timers.c @@ -52,7 +52,8 @@ void x2ap_check_timers(instance_t instance) int x2_ongoing; instance_p = x2ap_eNB_get_instance(instance); - DevAssert(instance_p != NULL); + if (instance_p == NULL) + return; t = &instance_p->timers; m = &instance_p->id_manager; From 59be08e3e69f9a61dedbc657f95d2c1febccceb2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 25 Mar 2025 15:22:22 +0100 Subject: [PATCH 39/48] add link to time management module to the main readme --- doc/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/README.md b/doc/README.md index cee2620f95..f1b0ba8284 100644 --- a/doc/README.md +++ b/doc/README.md @@ -108,6 +108,7 @@ Legacy unmaintained files: - The [shared object loader](../common/utils/DOC/loader.md) - The [threadpool](../common/utils/threadPool/thread-pool.md) used in L1 - The [LDPC implementation](../openair1/PHY/CODING/DOC/LDPCImplementation.md) is a shared library +- The [time management](time_management.md) module ## Radios From c9ad10f9f9fd75abdf200130c0606570ab471902 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 25 Mar 2025 15:27:29 +0100 Subject: [PATCH 40/48] remove ngap from linking It used to be necessary. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a567fc3c6..7c73f9a2a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1996,7 +1996,7 @@ add_executable(nr_psbchsim ${PHY_INTERFACE_DIR}/queue_t.c ) target_link_libraries(nr_psbchsim PRIVATE - -Wl,--start-group ngap UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group + -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON PHY_NR PHY_NR_UE SCHED_NR_LIB SCHED_NR_UE_LIB MAC_UE_NR MAC_NR_COMMON CONFIG_LIB L2_NR -lz -Wl,--end-group m pthread ${T_LIB} ITTI dl shlib_loader physim_common ) target_link_libraries(nr_psbchsim PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs) From b487c4deb2e6077157bd1171fea52ce9c28fb675 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 26 Mar 2025 10:32:06 +0100 Subject: [PATCH 41/48] restructure the code for retrieval of configuration parameters --- common/utils/time_manager/time_manager.c | 60 +++++++++++++++--------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/common/utils/time_manager/time_manager.c b/common/utils/time_manager/time_manager.c index cf8168de0b..a69ab503e8 100644 --- a/common/utils/time_manager/time_manager.c +++ b/common/utils/time_manager/time_manager.c @@ -60,6 +60,38 @@ static void tick(void *unused) x2ap_tick(); } +#define TIME_SOURCE "time_source" +#define MODE "mode" +#define SERVER_IP "server_ip" +#define SERVER_PORT "server_port" + +static paramdef_t config_parameters[] = { + {TIME_SOURCE, "time source", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {MODE, "time mode", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {SERVER_IP, "server ip", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, + {SERVER_PORT, "server port", 0, .iptr = NULL, .defintval = -1, TYPE_INT, 0}, +}; + +static char *get_param_str(char *name) +{ + int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name); + + char *param; + if (config_parameters[idx].strptr != NULL) + param = *config_parameters[idx].strptr; + else + param = NULL; + + return param; +} + +static int get_param_int(char *name) +{ + int idx = config_paramidx_fromname(config_parameters, sizeofArray(config_parameters), name); + + return *config_parameters[idx].iptr; +} + void time_manager_start(time_manager_client_t client_type, time_manager_mode_t running_mode) { @@ -112,24 +144,12 @@ void time_manager_start(time_manager_client_t client_type, } /* get values from configuration */ - paramdef_t config_parameters[] = { - {"time_source", "time source", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, - {"mode", "time mode", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, - {"server_ip", "server ip", 0, .strptr = NULL, .defstrval = NULL, TYPE_STRING, 0}, - {"server_port", "server port", 0, .iptr = NULL, .defintval = -1, TYPE_INT, 0}, - }; int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management"); if (ret >= 0) { -#define TIME_SOURCE_IDX 0 -#define MODE_IDX 1 -#define SERVER_IP_IDX 2 -#define SERVER_PORT_IDX 3 char *param; + /* time source */ - if (config_parameters[TIME_SOURCE_IDX].strptr != NULL) - param = *config_parameters[TIME_SOURCE_IDX].strptr; - else - param = NULL; + param = get_param_str(TIME_SOURCE); if (param != NULL) { if (!strcmp(param, "realtime")) { time_source_type = TIME_SOURCE_REALTIME; @@ -141,10 +161,7 @@ void time_manager_start(time_manager_client_t client_type, } /* mode */ - if (config_parameters[MODE_IDX].strptr != NULL) - param = *config_parameters[MODE_IDX].strptr; - else - param = NULL; + param = get_param_str(MODE); if (param != NULL) { if (!strcmp(param, "standalone")) { has_time_server = false; @@ -161,16 +178,13 @@ void time_manager_start(time_manager_client_t client_type, } /* server ip */ - if (config_parameters[SERVER_IP_IDX].strptr != NULL) - param = *config_parameters[SERVER_IP_IDX].strptr; - else - param = NULL; + param = get_param_str(SERVER_IP); if (param != NULL) { server_ip = param; } /* server port */ - int port = *config_parameters[SERVER_PORT_IDX].iptr; + int port = get_param_int(SERVER_PORT); if (port != -1) { server_port = port; } From 2f7eb6ebf9741b8c4fd6641b67cd88ea47ae8f17 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 26 Mar 2025 14:46:26 +0100 Subject: [PATCH 42/48] replace many DevAssert with AssertFatal for better user experience --- common/utils/time_manager/time_client.c | 31 ++++++++++---------- common/utils/time_manager/time_server.c | 38 ++++++++++++------------- common/utils/time_manager/time_source.c | 7 ++--- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/common/utils/time_manager/time_client.c b/common/utils/time_manager/time_client.c index 4cecf0e6c6..f587992fa8 100644 --- a/common/utils/time_manager/time_client.c +++ b/common/utils/time_manager/time_client.c @@ -55,16 +55,16 @@ static int connect_to_server(time_client_private_t *time_client) /* try forever (or exit requested) until we succeed */ while (1) { sock = socket(AF_INET, SOCK_STREAM, 0); - DevAssert(sock != -1); + AssertFatal(sock != -1, "socket() failed: %s\n", strerror(errno)); int v = 1; r = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); - DevAssert(r == 0); + AssertFatal(r == 0, "setsockopt() failed: %s\n", strerror(errno)); /* unblock socket */ opts = fcntl(sock, F_GETFL); - DevAssert(opts >= 0); + AssertFatal(opts >= 0, "fcntl() failed: %s\n", strerror(errno)); opts |= O_NONBLOCK; r = fcntl(sock, F_SETFL, opts); - DevAssert(r == 0); + AssertFatal(r == 0, "fctnl() failed: %s\n", strerror(errno)); if (connect(sock, (struct sockaddr *)&time_client->server_ip, sizeof(time_client->server_ip)) == 0) break; if (errno == EINPROGRESS) { @@ -74,7 +74,7 @@ static int connect_to_server(time_client_private_t *time_client) fds[1].fd = time_client->exit_fd; fds[1].events = POLLIN; r = poll(fds, 2, -1); - DevAssert(r >= 0); + AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno)); /* do we need to exit? */ if (fds[1].revents) { shutdown(sock, SHUT_RDWR); @@ -87,7 +87,9 @@ static int connect_to_server(time_client_private_t *time_client) int so_error; socklen_t so_error_len = sizeof(so_error); r = getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len); - DevAssert(r == 0 && so_error_len == sizeof(so_error)); + AssertFatal(r == 0 && so_error_len == sizeof(so_error), + "getsockopt() failed (r = %d) or so_error_len (= %d) is not %ld\n", + r, so_error_len, sizeof(so_error)); if (so_error == 0) /* success */ break; @@ -98,13 +100,13 @@ static int connect_to_server(time_client_private_t *time_client) sock = -1; char server_address[256]; const char *ret = inet_ntop(AF_INET, &time_client->server_ip.sin_addr, server_address, sizeof(server_address)); - DevAssert(ret != NULL); + AssertFatal(ret != NULL, "inet_ntop() failed: %s\n", strerror(errno)); LOG_W(UTIL, "time client: connection to %s:%d failed, try again in 1s\n", server_address, time_client->server_port); /* sleep 1s (or exit requested) */ fds[0].fd = time_client->exit_fd; fds[0].events = POLLIN; r = poll(fds, 1, 1000); - DevAssert(r >= 0); + AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno)); /* exit requested? */ if (fds[0].revents) { shutdown(sock, SHUT_RDWR); @@ -117,7 +119,7 @@ static int connect_to_server(time_client_private_t *time_client) /* reblock socket */ opts &= ~O_NONBLOCK; r = fcntl(sock, F_SETFL, opts); - DevAssert(r == 0); + AssertFatal(r == 0, "fcntl() failed: %s\n", strerror(errno)); } return sock; } @@ -142,7 +144,7 @@ static void *time_client_thread(void *tc) polls[1].events = POLLIN; ret = poll(polls, 2, -1); - DevAssert(ret >= 0); + AssertFatal(ret >= 0, "poll() failed: %s\n", strerror(errno)); /* whatever is in revents for exit_fd means exit */ if (polls[1].revents) @@ -160,7 +162,7 @@ reconnect: } /* here we only accept POLLIN */ - DevAssert(polls[0].revents == POLLIN); + AssertFatal(polls[0].revents == POLLIN, "poll() did not return expected POLLIN\n"); /* get the ticks from server */ uint8_t tick_count; @@ -196,14 +198,13 @@ time_client_t *new_time_client(const char *server_ip, time_client_private_t *tc; int ret; - tc = calloc(1, sizeof(*tc)); - DevAssert(tc != NULL); + tc = calloc_or_fail(1, sizeof(*tc)); tc->exit_fd = eventfd(0, 0); - DevAssert(tc->exit_fd != -1); + AssertFatal(tc->exit_fd != -1, "eventfd() failed: %s\n", strerror(errno)); ret = inet_aton(server_ip, &tc->server_ip.sin_addr); - DevAssert(ret != 0); + AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno)); tc->server_ip.sin_family = AF_INET; tc->server_ip.sin_port = htons(server_port); tc->server_port = server_port; diff --git a/common/utils/time_manager/time_server.c b/common/utils/time_manager/time_server.c index 83b9e30fd2..a1a95d8ebe 100644 --- a/common/utils/time_manager/time_server.c +++ b/common/utils/time_manager/time_server.c @@ -51,8 +51,7 @@ static void *time_server_thread(void *ts) int *socket_fds = NULL; int client_count = 0; - polls = calloc(2, sizeof(struct pollfd)); - DevAssert(polls != NULL); + polls = calloc_or_fail(2, sizeof(struct pollfd)); while (!time_server->exit) { /* polls[0] is to receive ticks */ @@ -69,7 +68,7 @@ static void *time_server_thread(void *ts) } int ret = poll(polls, client_count + 2, -1); - DevAssert(ret >= 1 || (ret == -1 && errno == EINTR)); + AssertFatal(ret >= 1 || (ret == -1 && errno == EINTR), "poll() failed\n"); if (time_server->exit) break; @@ -77,7 +76,7 @@ static void *time_server_thread(void *ts) /* check tick */ if (polls[0].revents) { /* do not accept errors */ - DevAssert(polls[0].revents == POLLIN); + AssertFatal(polls[0].revents == POLLIN, "poll() failed\n"); uint64_t ticks; int ret = read(time_server->tick_fd, &ticks, 8); DevAssert(ret == 8); @@ -107,7 +106,7 @@ static void *time_server_thread(void *ts) socket_fds = realloc(socket_fds, sizeof(int) * client_count); } polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); - DevAssert(polls != NULL); + AssertFatal(polls != NULL, "realloc() failed\n"); } ticks -= count; } @@ -116,18 +115,18 @@ static void *time_server_thread(void *ts) /* check new client */ if (polls[1].revents) { /* do not accept errors */ - DevAssert(polls[1].revents == POLLIN); + AssertFatal(polls[1].revents == POLLIN, "poll() failed\n"); int new_socket = accept(time_server->server_socket, NULL, NULL); - DevAssert(new_socket != -1); + AssertFatal(new_socket != -1, "accept() failed: %s\n", strerror(errno)); /* add client */ client_count++; socket_fds = realloc(socket_fds, sizeof(int) * client_count); - DevAssert(socket_fds != NULL); + AssertFatal(socket_fds != NULL, "realloc() failed\n"); socket_fds[client_count - 1] = new_socket; polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); - DevAssert(polls != NULL); + AssertFatal(polls != NULL, "realloc() failed\n"); continue; } @@ -151,12 +150,12 @@ static void *time_server_thread(void *ts) } else { memmove(&socket_fds[i + 1], &socket_fds[i + 2], sizeof(int) * (client_count - i - 1)); socket_fds = realloc(socket_fds, sizeof(int) * client_count); - DevAssert(socket_fds != NULL); + AssertFatal(socket_fds != NULL, "realloco() failed\n"); } if (client_count) memmove(&polls[i + 2 + 1], &polls[i + 2 + 2], sizeof(struct pollfd) * (client_count - i - 1)); polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); - DevAssert(polls != NULL); + AssertFatal(polls != NULL, "realloc() failed\n"); } } @@ -180,31 +179,30 @@ time_server_t *new_time_server(const char *ip, time_server_private_t *ts; int ret; - ts = calloc(1, sizeof(*ts)); - DevAssert(ts != NULL); + ts = calloc_or_fail(1, sizeof(*ts)); ts->server_socket = socket(AF_INET, SOCK_STREAM, 0); - DevAssert(ts->server_socket != -1); + AssertFatal(ts->server_socket != -1, "socket() failed: %s\n", strerror(errno)); int v = 1; ret = setsockopt(ts->server_socket, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v)); - DevAssert(ret == 0); + AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno)); v = 1; ret = setsockopt(ts->server_socket, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); - DevAssert(ret == 0); + AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno)); ts->tick_fd = eventfd(0, 0); - DevAssert(ts->tick_fd != -1); + AssertFatal(ts->tick_fd != -1, "eventfd() failed: %s\n", strerror(errno)); struct sockaddr_in ip_addr; ip_addr.sin_family = AF_INET; ip_addr.sin_port = htons(port); ret = inet_aton(ip, &ip_addr.sin_addr); - DevAssert(ret != 0); + AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno)); ret = bind(ts->server_socket, (struct sockaddr *)&ip_addr, sizeof(ip_addr)); - DevAssert(ret == 0); + AssertFatal(ret == 0, "bind() failed: %s\n", strerror(errno)); ret = listen(ts->server_socket, 10); /* 10: arbitrary value */ - DevAssert(ret == 0); + AssertFatal(ret == 0, "listen() failed: %s\n", strerror(errno)); ts->callback = callback; ts->callback_data = callback_data; diff --git a/common/utils/time_manager/time_source.c b/common/utils/time_manager/time_source.c index 76a76bc655..02a7ce0fa6 100644 --- a/common/utils/time_manager/time_source.c +++ b/common/utils/time_manager/time_source.c @@ -28,6 +28,7 @@ #include "common/utils/assertions.h" #include "common/utils/system.h" +#include "common/utils/utils.h" typedef void (*callback_function_t)(void *callback_data); typedef void * callback_data_t; @@ -190,16 +191,14 @@ time_source_t *new_time_source(time_source_type_t type) switch (type) { case TIME_SOURCE_REALTIME: { - time_source_realtime_t *ts = calloc(1, sizeof(*ts)); - DevAssert(ts != NULL); + time_source_realtime_t *ts = calloc_or_fail(1, sizeof(*ts)); thread_function = time_source_realtime_thread; thread_function_name = "time source realtime"; ret = ts; break; } case TIME_SOURCE_IQ_SAMPLES: { - time_source_iq_t *ts = calloc(1, sizeof(*ts)); - DevAssert(ts != NULL); + time_source_iq_t *ts = calloc_or_fail(1, sizeof(*ts)); thread_function = time_source_iq_samples_thread; terminate_function = time_source_iq_samples_terminate; thread_function_name = "time source iq samples"; From 4834d93006797f1c79bb905b01874cbd215a8b09 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 26 Mar 2025 15:34:34 +0100 Subject: [PATCH 43/48] fix typo --- doc/time_management.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/time_management.md b/doc/time_management.md index a3ea4d580c..79dbbcf372 100644 --- a/doc/time_management.md +++ b/doc/time_management.md @@ -201,7 +201,7 @@ API is described afterwards. ### Server -- opaque tyoe: `time_server_t` +- opaque type: `time_server_t` - create a server: ``` time_server_t *new_time_server(const char *ip, From b89b3abd13d07f667df77f9cee9359d97e9c84e2 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 27 Mar 2025 12:10:42 +0100 Subject: [PATCH 44/48] API change: new arguments to time_manager_start() --- common/utils/time_manager/tests/test_auto.c | 32 +++++--- common/utils/time_manager/time_manager.c | 87 +++++---------------- common/utils/time_manager/time_manager.h | 18 ++--- doc/time_management.md | 10 ++- executables/nr-cuup.c | 7 +- executables/nr-softmodem.c | 30 +++++-- executables/nr-uesoftmodem.c | 13 ++- 7 files changed, 93 insertions(+), 104 deletions(-) diff --git a/common/utils/time_manager/tests/test_auto.c b/common/utils/time_manager/tests/test_auto.c index 73bf27af88..817a518c4a 100644 --- a/common/utils/time_manager/tests/test_auto.c +++ b/common/utils/time_manager/tests/test_auto.c @@ -41,12 +41,6 @@ void exit_function(const char *file, const char *function, const int line, const exit(1); } -int is_x2ap_enabled(void) -{ - /* we want x2ap ticks */ - return 1; -} - static int rlc_tick_count = 0; static int pdcp_tick_count = 0; static int x2ap_tick_count = 0; @@ -69,7 +63,13 @@ void x2ap_ms_tick(void) /* return 1 if ok, 0 if error */ static int standalone_realtime(void) { - time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_REALTIME); + time_manager_tick_function_t tick_functions[] = { + nr_pdcp_ms_tick, + nr_rlc_ms_tick, + x2ap_ms_tick + }; + int tick_functions_count = sizeofArray(tick_functions); + time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME); sleep(1); @@ -90,7 +90,13 @@ static int standalone_realtime(void) /* return 1 if ok, 0 if error */ static int standalone_iq_samples(void) { - time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_IQ_SAMPLES); + time_manager_tick_function_t tick_functions[] = { + nr_pdcp_ms_tick, + nr_rlc_ms_tick, + x2ap_ms_tick + }; + int tick_functions_count = sizeofArray(tick_functions); + time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_IQ_SAMPLES); /* let's pretend we have 2000 samples per second */ for (int i = 0; i < 1000; i++) { @@ -168,8 +174,14 @@ static int client_server(char *program_name, bool iq_samples_time_source) /* return 1 if ok, 0 if error */ static int run_sub_client_server(bool iq_samples_time_source) { - /* second argument doesn't matter, overwritten by args of execl in client_server() */ - time_manager_start(TIME_MANAGER_GNB_MONOLITHIC, TIME_MANAGER_REALTIME); + time_manager_tick_function_t tick_functions[] = { + nr_pdcp_ms_tick, + nr_rlc_ms_tick, + x2ap_ms_tick + }; + int tick_functions_count = sizeofArray(tick_functions); + /* last argument doesn't matter, overwritten by args of execl in client_server() */ + time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME); if (iq_samples_time_source) { /* 'iq_samples_time_source' is true only for server diff --git a/common/utils/time_manager/time_manager.c b/common/utils/time_manager/time_manager.c index a69ab503e8..bad8e2ccc4 100644 --- a/common/utils/time_manager/time_manager.c +++ b/common/utils/time_manager/time_manager.c @@ -19,9 +19,6 @@ * contact@openairinterface.org */ -#define _GNU_SOURCE -#include - #include "time_manager.h" #include "time_source.h" @@ -37,27 +34,17 @@ static time_source_t *time_source = NULL; static time_server_t *time_server = NULL; static time_client_t *time_client = NULL; -/* available tick functions in the executable - * found at startup time of the program using dlsym() - */ -static void (*pdcp_tick)(void) = NULL; -static void (*rlc_tick)(void) = NULL; -static void (*x2ap_tick)(void) = NULL; +/* tick functions registered at initialization of the time manager */ +static time_manager_tick_function_t *tick_functions; +static int tick_functions_count; /* tick callback, called by time_source every 'millisecond' (can be * actual millisecond or simulated millisecond) */ static void tick(void *unused) { - /* call x2ap_tick, pdcp_tick, rlc_tick (if they exist) */ - if (pdcp_tick != NULL) - pdcp_tick(); - - if (rlc_tick != NULL) - rlc_tick(); - - if (x2ap_tick != NULL) - x2ap_tick(); + for (int i = 0; i < tick_functions_count; i++) + tick_functions[i](); } #define TIME_SOURCE "time_source" @@ -92,10 +79,10 @@ static int get_param_int(char *name) return *config_parameters[idx].iptr; } -void time_manager_start(time_manager_client_t client_type, - time_manager_mode_t running_mode) +void time_manager_start(time_manager_tick_function_t *_tick_functions, + int _tick_functions_count, + time_source_type_t time_source_type) { - time_source_type_t time_source_type = -1; bool has_time_server = false; bool has_time_client = false; char *default_server_ip = "127.0.0.1"; @@ -103,47 +90,11 @@ void time_manager_start(time_manager_client_t client_type, char *server_ip = NULL; int server_port = -1; - /* retrieve, if applicable, available tick functions in the program */ - if (client_type == TIME_MANAGER_GNB_MONOLITHIC - || client_type == TIME_MANAGER_GNB_CU - || client_type == TIME_MANAGER_UE) - pdcp_tick = dlsym(RTLD_DEFAULT, "nr_pdcp_ms_tick"); + tick_functions_count = _tick_functions_count; + tick_functions = calloc_or_fail(tick_functions_count, sizeof(*tick_functions)); + memcpy(tick_functions, _tick_functions, tick_functions_count * sizeof(*tick_functions)); - if (client_type == TIME_MANAGER_GNB_MONOLITHIC - || client_type == TIME_MANAGER_GNB_DU - || client_type == TIME_MANAGER_UE) - rlc_tick = dlsym(RTLD_DEFAULT, "nr_rlc_ms_tick"); - - /* let's also retrieve is_x2ap_enabled() with dlsym to not force the - * application to define it (this logic may be changed if wanted) - */ - int (*is_x2ap_enabled)(void) = dlsym(RTLD_DEFAULT, "is_x2ap_enabled"); - if ((client_type == TIME_MANAGER_GNB_MONOLITHIC - || client_type == TIME_MANAGER_GNB_CU) - && is_x2ap_enabled != NULL && is_x2ap_enabled()) - x2ap_tick = dlsym(RTLD_DEFAULT, "x2ap_ms_tick"); - - /* get default configuration */ - switch (client_type) { - case TIME_MANAGER_GNB_MONOLITHIC: - case TIME_MANAGER_GNB_DU: - case TIME_MANAGER_UE: - switch (running_mode) { - case TIME_MANAGER_REALTIME: - time_source_type = TIME_SOURCE_REALTIME; - break; - case TIME_MANAGER_IQ_SAMPLES: - time_source_type = TIME_SOURCE_IQ_SAMPLES; - break; - } - break; - case TIME_MANAGER_GNB_CU: - case TIME_MANAGER_SIMULATOR: - time_source_type = TIME_SOURCE_REALTIME; - break; - } - - /* get values from configuration */ + /* retrieve configuration */ int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management"); if (ret >= 0) { char *param; @@ -209,23 +160,19 @@ void time_manager_start(time_manager_client_t client_type, if (has_time_client) { time_client = new_time_client(server_ip, server_port, tick, NULL); + /* for the log below, there is no time source, we want to print 'server' as time source */ + time_source_type = 2; } LOG_I(UTIL, "time manager configuration: [time source: %s] [mode: %s] [server IP: %s} [server port: %d]%s\n", - (char *[]){"reatime", "iq_samples"}[time_source_type], + (char *[]){"reatime", "iq_samples", "server"}[time_source_type], has_time_server ? "server" : has_time_client ? "client" : "standalone", server_ip, server_port, has_time_server || has_time_client ? "" : " (server IP/port not used)"); - - LOG_I(UTIL, - "time manager: pdcp tick: %s, rlc tick: %s, x2ap tick: %s\n", - pdcp_tick == NULL ? "not activated" : "activated", - rlc_tick == NULL ? "not activated" : "activated", - x2ap_tick == NULL ? "not activated" : "activated"); } void time_manager_iq_samples(uint64_t iq_samples_count, @@ -251,4 +198,8 @@ void time_manager_finish(void) free_time_client(time_client); time_client = NULL; } + + free(tick_functions); + tick_functions = NULL; + tick_functions_count = 0; } diff --git a/common/utils/time_manager/time_manager.h b/common/utils/time_manager/time_manager.h index d1ed4ed0e1..23f4c6805f 100644 --- a/common/utils/time_manager/time_manager.h +++ b/common/utils/time_manager/time_manager.h @@ -24,21 +24,13 @@ #include -typedef enum { - TIME_MANAGER_GNB_MONOLITHIC, - TIME_MANAGER_GNB_CU, - TIME_MANAGER_GNB_DU, - TIME_MANAGER_UE, - TIME_MANAGER_SIMULATOR, -} time_manager_client_t; +#include "time_source.h" -typedef enum { - TIME_MANAGER_REALTIME, - TIME_MANAGER_IQ_SAMPLES -} time_manager_mode_t; +typedef void (*time_manager_tick_function_t)(void); -void time_manager_start(time_manager_client_t client_type, - time_manager_mode_t running_mode); +void time_manager_start(time_manager_tick_function_t *tick_functions, + int tick_functions_count, + time_source_type_t time_source); void time_manager_iq_samples(uint64_t iq_samples_count, uint64_t iq_samples_per_second); void time_manager_finish(void); diff --git a/doc/time_management.md b/doc/time_management.md index 79dbbcf372..c6424b3847 100644 --- a/doc/time_management.md +++ b/doc/time_management.md @@ -253,8 +253,9 @@ in `time_manager.c`, together with some global variables (so that there is no need to pass objects around, to limit risks of misuse). Each program (for example: gnb, ue, cu, du) calls the `time_manager_start()` -function, passing the kind of program it is. Based on this type and the -configuration, `time_manager_start()` initializes what is needed. +function, passing the callback functions to be called when a tick is generated +(several callbacks can be passed) and a default time source. Based on this, +`time_manager_start()` initializes what is needed. The function `time_manager_iq_samples()` is to be called by programs that read IQ samples. It is called unconditionally. It may do nothing if the @@ -268,8 +269,9 @@ Here comes the API. - init the time manager: ``` - void time_manager_start(time_manager_client_t client_type, - time_manager_mode_t running_mode) + void time_manager_start(time_manager_tick_function_t *tick_functions, + int tick_functions_count, + time_source_type_t time_source); ``` (for valid values of `client_type` and `running_mode` see in `time_manager.h`) diff --git a/executables/nr-cuup.c b/executables/nr-cuup.c index 4f5520d250..6467683cac 100644 --- a/executables/nr-cuup.c +++ b/executables/nr-cuup.c @@ -143,7 +143,12 @@ int main(int argc, char **argv) // start time manager with some reasonable default for the running mode // (may be overwritten in configuration file or command line) - time_manager_start(TIME_MANAGER_GNB_CU, TIME_MANAGER_REALTIME); + void nr_pdcp_ms_tick(void); + time_manager_tick_function_t tick_functions[] = { + nr_pdcp_ms_tick + }; + int tick_functions_count = 1; + time_manager_start(tick_functions, tick_functions_count, TIME_SOURCE_REALTIME); // strdup to put the sring in the core file for post mortem identification LOG_I(HW, "Version: %s\n", strdup(OAI_PACKAGE_VERSION)); diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index f0068a8d4b..24df549243 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -631,15 +631,35 @@ int main( int argc, char **argv ) { // start time manager with some reasonable default for the running mode // (may be overwritten in configuration file or command line) - time_manager_start(NODE_IS_MONOLITHIC(node_type) ? TIME_MANAGER_GNB_MONOLITHIC - : NODE_IS_CU(node_type) ? TIME_MANAGER_GNB_CU - : TIME_MANAGER_GNB_DU, + void nr_pdcp_ms_tick(void); + void x2ap_ms_tick(); + void nr_rlc_ms_tick(void); + time_manager_tick_function_t tick_functions[3]; + int tick_functions_count = 0; + if (NODE_IS_MONOLITHIC(node_type)) { + /* monolithic */ + tick_functions[tick_functions_count++] = nr_pdcp_ms_tick; + tick_functions[tick_functions_count++] = nr_rlc_ms_tick; + /* x2ap is enabled when in NSA mode */ + if (get_softmodem_params()->nsa) + tick_functions[tick_functions_count++] = x2ap_ms_tick; + } else if (NODE_IS_CU(node_type)) { + /* CU */ + tick_functions[tick_functions_count++] = nr_pdcp_ms_tick; + /* x2ap is enabled when in NSA mode */ + if (get_softmodem_params()->nsa) + tick_functions[tick_functions_count++] = x2ap_ms_tick; + } else { + /* DU */ + tick_functions[tick_functions_count++] = nr_rlc_ms_tick; + } + time_manager_start(tick_functions, tick_functions_count, // iq_samples time source for monolithic/du with rfsim, // realtime time source for other cases IS_SOFTMODEM_RFSIM && (NODE_IS_MONOLITHIC(node_type) || NODE_IS_DU(node_type)) - ? TIME_MANAGER_IQ_SAMPLES - : TIME_MANAGER_REALTIME); + ? TIME_SOURCE_IQ_SAMPLES + : TIME_SOURCE_REALTIME); // start the main threads number_of_cards = 1; diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index fa5e5ca259..0641a89ad9 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -464,11 +464,18 @@ int main(int argc, char **argv) // start time manager with some reasonable default for the running mode // (may be overwritten in configuration file or command line) - time_manager_start(TIME_MANAGER_UE, + void nr_pdcp_ms_tick(void); + void nr_rlc_ms_tick(void); + time_manager_tick_function_t tick_functions[] = { + nr_pdcp_ms_tick, + nr_rlc_ms_tick + }; + int tick_functions_count = 2; + time_manager_start(tick_functions, tick_functions_count, // iq_samples time source for rfsim, // realtime time source if not - IS_SOFTMODEM_RFSIM ? TIME_MANAGER_IQ_SAMPLES - : TIME_MANAGER_REALTIME); + IS_SOFTMODEM_RFSIM ? TIME_SOURCE_IQ_SAMPLES + : TIME_SOURCE_REALTIME); if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) start_oai_nrue_threads(); From ba2a0c4d1e9d2bfcb8b0233c047e746f21217352 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 18 Apr 2025 08:30:09 +0200 Subject: [PATCH 45/48] rejecting DRB addition if DRB field not present at setup in PDCP-Config --- openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c | 25 +++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index d8b706520e..7f6a7dd3ee 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -817,9 +817,15 @@ void add_drb(int is_gnb, nr_pdcp_ue_t *ue; int drb_id = s->drb_Identity; - int sn_size_ul = decode_sn_size_ul(*s->pdcp_Config->drb->pdcp_SN_SizeUL); - int sn_size_dl = decode_sn_size_dl(*s->pdcp_Config->drb->pdcp_SN_SizeDL); - int discard_timer = decode_discard_timer(*s->pdcp_Config->drb->discardTimer); + if (!s->pdcp_Config || !s->pdcp_Config->drb) { + LOG_E(PDCP, "DRB field mandatory present at setup. DRB %d not configured.\n", drb_id); + return; + } + + struct NR_PDCP_Config__drb *drb = s->pdcp_Config->drb; + int sn_size_ul = decode_sn_size_ul(*drb->pdcp_SN_SizeUL); + int sn_size_dl = decode_sn_size_dl(*drb->pdcp_SN_SizeDL); + int discard_timer = decode_discard_timer(*drb->discardTimer); int has_integrity; int has_ciphering; @@ -830,20 +836,18 @@ void add_drb(int is_gnb, t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering); } - if (s->pdcp_Config->drb != NULL - && s->pdcp_Config->drb->integrityProtection != NULL) + if (drb->integrityProtection != NULL) has_integrity = 1; else has_integrity = 0; - if (s->pdcp_Config->ext1 != NULL - && s->pdcp_Config->ext1->cipheringDisabled != NULL) + if (s->pdcp_Config->ext1 != NULL && s->pdcp_Config->ext1->cipheringDisabled != NULL) has_ciphering = 0; else has_ciphering = 1; if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) { - LOG_E(PDCP,"%s:%d:%s: fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n",__FILE__,__LINE__,__FUNCTION__); + LOG_E(PDCP, "fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n"); exit(-1); } @@ -857,7 +861,7 @@ void add_drb(int is_gnb, pdusession_id = s->cnAssociation->choice.eps_BearerIdentity; else { if (!s->cnAssociation->choice.sdap_Config) { - LOG_E(PDCP,"%s:%d:%s: fatal, sdap_Config is null",__FILE__,__LINE__,__FUNCTION__); + LOG_E(PDCP,"fatal, sdap_Config is null"); exit(-1); } pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session; @@ -870,8 +874,7 @@ void add_drb(int is_gnb, } /* TODO(?): accept different UL and DL SN sizes? */ if (sn_size_ul != sn_size_dl) { - LOG_E(PDCP, "%s:%d:%s: fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", - __FILE__, __LINE__, __FUNCTION__, sn_size_ul, sn_size_dl); + LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl); exit(1); } From a3ef5293fbd15d01934fd039b57902a44b74ccb1 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 15 Apr 2025 16:43:14 +0200 Subject: [PATCH 46/48] Add Delay Mechanism for Initial MIB/SIB Transmission in gNB Scheduler This commit introduces a delay mechanism for the first MIB/SIB transmission in the gNB scheduler to allow PRACH noise estimate to converge stabilize before first PRACH preamble reception. Key changes: - Added the `num_scheduled_prach_rx` variable to gNB_MAC_INST to keep track of total number scheduled of PRACH receptions. Using uint64_t type to avoid overflow. - Updated the `gNB_dlsch_ulsch_scheduler` function to conditionally schedule MIB/SIB transmissions if `num_scheduled_prach_rx` is at least 100. The value comes from OAIs implementation of PRACH noise estimate. --- common/platform_constants.h | 1 + openair1/SCHED/prach_procedures.c | 8 +++++--- openair1/SCHED_NR/nr_prach_procedures.c | 6 ++++-- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c | 16 +++++++++------- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 1 + openair2/LAYER2/NR_MAC_gNB/main.c | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 +- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/common/platform_constants.h b/common/platform_constants.h index 2f54208306..99d17708ae 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -93,5 +93,6 @@ #define RETURNerror (-1) #define DEFAULT_NAS_PATH "PWD" #define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE) +#define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100 #endif /* __PLATFORM_CONSTANTS_H__ */ diff --git a/openair1/SCHED/prach_procedures.c b/openair1/SCHED/prach_procedures.c index e4d4bff17e..968a94eeb0 100644 --- a/openair1/SCHED/prach_procedures.c +++ b/openair1/SCHED/prach_procedures.c @@ -120,7 +120,8 @@ void prach_procedures(PHY_VARS_eNB *eNB, */ if (eNB->frame_parms.prach_emtc_config_common.prach_ConfigInfo.prach_CElevel_enable[0] == 1) { - if ((eNB->prach_energy_counter == 100) && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) { + if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + && (max_preamble_energy[0] > eNB->measurements.prach_I0 + eNB->prach_DTX_threshold_emtc[0])) { eNB->UL_INFO.rach_ind_br.rach_indication_body.number_of_preambles++; eNB->preamble_list_br[ind].preamble_rel8.timing_advance = max_preamble_delay[ind]; // eNB->preamble_list_br[ind].preamble_rel8.preamble = max_preamble[ind]; @@ -142,7 +143,7 @@ void prach_procedures(PHY_VARS_eNB *eNB, } } */// ce_level } else { - if ((eNB->prach_energy_counter == 100) && + if ((eNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) && (max_preamble_energy[0] > eNB->measurements.prach_I0+eNB->prach_DTX_threshold)) { LOG_D(PHY,"[eNB %d/%d][RAPROC] Frame %d, subframe %d Initiating RA procedure with preamble %d, energy %d.%d dB, delay %d\n", eNB->Mod_id, @@ -186,7 +187,8 @@ void prach_procedures(PHY_VARS_eNB *eNB, if (frame==0) LOG_D(PHY,"prach_I0 = %d.%d dB\n",eNB->measurements.prach_I0/10,eNB->measurements.prach_I0%10); - if (eNB->prach_energy_counter < 100) eNB->prach_energy_counter++; + if (eNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + eNB->prach_energy_counter++; } } // else br_flag diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index ad4204bdee..5ee397aa11 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -145,7 +145,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac max_preamble_delay[0], gNB->prach_energy_counter); - if ((gNB->prach_energy_counter == 100) && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres) + if ((gNB->prach_energy_counter == NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + && (max_preamble_energy[0] > gNB->measurements.prach_I0 + gNB->prach_thres) && (rach_ind->number_of_pdus < MAX_NUM_NR_RX_RACH_PDUS)) { LOG_A(NR_PHY, "[RAPROC] %d.%d Initiating RA procedure with preamble %d, energy %d.%d dB (I0 %d, thres %d), delay %d start symbol " @@ -185,7 +186,8 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac } gNB->measurements.prach_I0 = ((gNB->measurements.prach_I0*900)>>10) + ((max_preamble_energy[0]*124)>>10); if (frame==0) LOG_I(PHY,"prach_I0 = %d.%d dB\n",gNB->measurements.prach_I0/10,gNB->measurements.prach_I0%10); - if (gNB->prach_energy_counter < 100) gNB->prach_energy_counter++; + if (gNB->prach_energy_counter < NUM_PRACH_RX_FOR_NOISE_ESTIMATE) + gNB->prach_energy_counter++; } //if prach_id>0 rach_ind->slot = prach_start_slot; } // for NUMBER_OF_NR_PRACH_OCCASION_MAX diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index e14004edc3..c842d5547f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c @@ -212,14 +212,16 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo nr_mac_update_timers(module_idP, frame, slot); - // This schedules MIB - schedule_nr_mib(module_idP, frame, slot, &sched_info->DL_req); + if (gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE || get_softmodem_params()->phy_test) { + // This schedules MIB + schedule_nr_mib(module_idP, frame, slot, &sched_info->DL_req); - // This schedules SIB1 - // SIB19 will be scheduled if ntn_Config_r17 is initialized - if (IS_SA_MODE(get_softmodem_params())) { - schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req); - schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req); + // This schedules SIB1 + // SIB19 will be scheduled if ntn_Config_r17 is initialized + if (IS_SA_MODE(get_softmodem_params())) { + schedule_nr_sib1(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req); + schedule_nr_other_sib(module_idP, frame, slot, &sched_info->DL_req, &sched_info->TX_req); + } } // This schedule PRACH if we are not in phy_test mode diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index 017dc3cd4f..cb27fa4ae3 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -430,6 +430,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) } } if(td_index == 0) { + gNB->num_scheduled_prach_rx++; AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus); diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 1d9bb3245d..acf0658e4c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -275,6 +275,7 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->common_channels[0].pre_ServingCellConfig = scd; RC.nrmac[i]->first_MIB = true; + RC.nrmac[i]->num_scheduled_prach_rx = 0; RC.nrmac[i]->common_channels[0].mib = get_new_MIB_NR(scc); RC.nrmac[i]->cset0_bwp_start = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index 3a01ecfbfb..edc7f3fa2a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -936,7 +936,7 @@ typedef struct gNB_MAC_INST_s { pthread_mutex_t sched_lock; mac_stats_t mac_stats; - + uint64_t num_scheduled_prach_rx; } gNB_MAC_INST; #endif /*__LAYER2_NR_MAC_GNB_H__ */ From 84b927297900ab581cd80a7c114f20cb5871e93b Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Thu, 10 Apr 2025 20:41:29 +0200 Subject: [PATCH 47/48] Disable PRACH delay workaround in NR UE Disable the PRACH workaround in NR UE. With the MIB/SIB delay implemented on the gNB there is no longer a need to delay first NR UE random access attempt. --- executables/nr-uesoftmodem.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c index 931ffc3f31..716d813117 100644 --- a/executables/nr-uesoftmodem.c +++ b/executables/nr-uesoftmodem.c @@ -467,10 +467,6 @@ int main(int argc, char **argv) get_channel_model_mode(uniqCfg); } - // Delay to allow the convergence of the IIR filter on PRACH noise measurements at gNB side - if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test) - sleep(3); - if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) start_oai_nrue_threads(); From 8f93424e53ebb6ac8c99250a857c50b271fa0480 Mon Sep 17 00:00:00 2001 From: Thomas Schlichter Date: Tue, 22 Apr 2025 15:47:41 +0200 Subject: [PATCH 48/48] Adapt NTN-LEO config after integration branch runs --- .../conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf index 407723a909..d08d900098 100644 --- a/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf +++ b/ci-scripts/conf_files/gnb.sa.band254.u0.25prb.rfsim.ntn-leo.conf @@ -151,7 +151,7 @@ gNBs = #ext2 #ntn_Config_r17 cellSpecificKoffset_r17 = 40; - ta-Common-r17 = 4628000; # 18.84 ms + ta-Common-r17 = 4627000; # 18.84 ms ta-CommonDrift-r17 = -230000; # -46 µs/s positionX-r17 = 0; positionY-r17 = -2166908; # -2816980.4 m