diff --git a/CMakeLists.txt b/CMakeLists.txt index 25bc56b79a..7c73f9a2a5 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) 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..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 @@ -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 = 4627000; # 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: 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/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/common/platform_constants.h b/common/platform_constants.h index 2f54208306..00c68bd5b8 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 @@ -93,5 +95,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/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/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 ef04daaad1..f98ce510a2 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -130,6 +130,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 }; @@ -302,6 +307,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/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..817a518c4a --- /dev/null +++ b/common/utils/time_manager/tests/test_auto.c @@ -0,0 +1,297 @@ +/* + * 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); +} + +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_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); + + 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_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++) { + 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) +{ + 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 + * 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..f587992fa8 --- /dev/null +++ b/common/utils/time_manager/time_client.c @@ -0,0 +1,232 @@ +/* + * 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); + AssertFatal(sock != -1, "socket() failed: %s\n", strerror(errno)); + int v = 1; + r = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + AssertFatal(r == 0, "setsockopt() failed: %s\n", strerror(errno)); + /* unblock socket */ + opts = fcntl(sock, F_GETFL); + AssertFatal(opts >= 0, "fcntl() failed: %s\n", strerror(errno)); + opts |= O_NONBLOCK; + r = fcntl(sock, F_SETFL, opts); + 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) { + /* 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); + AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno)); + /* 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); + 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; + } + } + /* 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)); + 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); + AssertFatal(r >= 0, "poll() failed: %s\n", strerror(errno)); + /* 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); + AssertFatal(r == 0, "fcntl() failed: %s\n", strerror(errno)); + } + 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); + AssertFatal(ret >= 0, "poll() failed: %s\n", strerror(errno)); + + /* 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 */ + AssertFatal(polls[0].revents == POLLIN, "poll() did not return expected POLLIN\n"); + + /* 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_or_fail(1, sizeof(*tc)); + + tc->exit_fd = eventfd(0, 0); + AssertFatal(tc->exit_fd != -1, "eventfd() failed: %s\n", strerror(errno)); + + ret = inet_aton(server_ip, &tc->server_ip.sin_addr); + 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; + 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..bad8e2ccc4 --- /dev/null +++ b/common/utils/time_manager/time_manager.c @@ -0,0 +1,205 @@ +/* + * 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_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; + +/* 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) +{ + for (int i = 0; i < tick_functions_count; i++) + tick_functions[i](); +} + +#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_tick_function_t *_tick_functions, + int _tick_functions_count, + time_source_type_t time_source_type) +{ + 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; + + 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)); + + /* retrieve configuration */ + int ret = config_get(config_get_if(), config_parameters, sizeofArray(config_parameters), "time_management"); + if (ret >= 0) { + char *param; + + /* time source */ + param = get_param_str(TIME_SOURCE); + 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 */ + param = get_param_str(MODE); + 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 */ + param = get_param_str(SERVER_IP); + if (param != NULL) { + server_ip = param; + } + + /* server port */ + int port = get_param_int(SERVER_PORT); + 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); + /* 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", "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)"); +} + +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; + } + + free(tick_functions); + tick_functions = NULL; + tick_functions_count = 0; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c b/common/utils/time_manager/time_manager.h similarity index 50% rename from openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c rename to common/utils/time_manager/time_manager.h index 739cee7973..23f4c6805f 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.c +++ b/common/utils/time_manager/time_manager.h @@ -19,40 +19,20 @@ * contact@openairinterface.org */ -/*! \file FGSRegistrationResult.c +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_MANAGER +#define COMMON_UTIL_TIME_MANAGER_TIME_MANAGER -\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" +#include "time_source.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; -} +typedef void (*time_manager_tick_function_t)(void); -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; +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); - return bufferReturn; -} +#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..a1a95d8ebe --- /dev/null +++ b/common/utils/time_manager/time_server.c @@ -0,0 +1,249 @@ +/* + * 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_or_fail(2, sizeof(struct pollfd)); + + 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); + AssertFatal(ret >= 1 || (ret == -1 && errno == EINTR), "poll() failed\n"); + + if (time_server->exit) + break; + + /* check tick */ + if (polls[0].revents) { + /* do not accept errors */ + AssertFatal(polls[0].revents == POLLIN, "poll() failed\n"); + 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)); + AssertFatal(polls != NULL, "realloc() failed\n"); + } + ticks -= count; + } + } + + /* check new client */ + if (polls[1].revents) { + /* do not accept errors */ + AssertFatal(polls[1].revents == POLLIN, "poll() failed\n"); + + int new_socket = accept(time_server->server_socket, NULL, NULL); + AssertFatal(new_socket != -1, "accept() failed: %s\n", strerror(errno)); + + /* add client */ + client_count++; + socket_fds = realloc(socket_fds, sizeof(int) * client_count); + AssertFatal(socket_fds != NULL, "realloc() failed\n"); + socket_fds[client_count - 1] = new_socket; + polls = realloc(polls, sizeof(struct pollfd) * (client_count + 2)); + AssertFatal(polls != NULL, "realloc() failed\n"); + 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); + 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)); + AssertFatal(polls != NULL, "realloc() failed\n"); + } + } + + /* 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_or_fail(1, sizeof(*ts)); + + ts->server_socket = socket(AF_INET, SOCK_STREAM, 0); + 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)); + AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno)); + v = 1; + ret = setsockopt(ts->server_socket, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + AssertFatal(ret == 0, "setsockopt() failed: %s\n", strerror(errno)); + ts->tick_fd = eventfd(0, 0); + 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); + AssertFatal(ret != 0, "inet_aton() failed: %s\n", strerror(errno)); + ret = bind(ts->server_socket, (struct sockaddr *)&ip_addr, sizeof(ip_addr)); + AssertFatal(ret == 0, "bind() failed: %s\n", strerror(errno)); + + ret = listen(ts->server_socket, 10); /* 10: arbitrary value */ + AssertFatal(ret == 0, "listen() failed: %s\n", strerror(errno)); + + 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..02a7ce0fa6 --- /dev/null +++ b/common/utils/time_manager/time_source.c @@ -0,0 +1,263 @@ +/* + * 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" +#include "common/utils/utils.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_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_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"; + 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/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h b/common/utils/time_manager/time_source.h similarity index 52% rename from openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h rename to common/utils/time_manager/time_source.h index 04f45417b8..45b39d610f 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/IES/FGSRegistrationResult.h +++ b/common/utils/time_manager/time_source.h @@ -19,37 +19,29 @@ * contact@openairinterface.org */ -/*! \file FGSRegistrationResult.h +#ifndef COMMON_UTIL_TIME_MANAGER_TIME_SOURCE +#define COMMON_UTIL_TIME_MANAGER_TIME_SOURCE -\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" +/* opaque data type */ +typedef void time_source_t; -#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 enum { + TIME_SOURCE_REALTIME, + TIME_SOURCE_IQ_SAMPLES +} time_source_type_t; -typedef struct { - uint8_t iei; - uint8_t resultlength; - uint8_t spare: 4; - uint8_t smsallowed: 1; - uint8_t registrationresult: 3; -} FGSRegistrationResult; +time_source_t *new_time_source(time_source_type_t type); -uint16_t encode_fgs_registration_result(const FGSRegistrationResult *fgsregistrationresult); +void free_time_source(time_source_t *time_source); -int decode_fgs_registration_result(FGSRegistrationResult *fgsregistrationresult, uint8_t iei, uint16_t value, uint32_t len); +void time_source_set_callback(time_source_t *time_source, + void (*callback)(void *), + void *callback_data); -#endif /* FGS REGISTRATION RESULT_H_*/ +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/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/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` 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 diff --git a/doc/SW_archi.md b/doc/SW_archi.md index 205da81b6b..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) @@ -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/doc/time_management.md b/doc/time_management.md new file mode 100644 index 0000000000..c6424b3847 --- /dev/null +++ b/doc/time_management.md @@ -0,0 +1,286 @@ +# 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 type: `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 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 +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_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`) +- 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..6467683cac 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,16 @@ 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) + 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)); set_softmodem_sighandler(); @@ -177,6 +188,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-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); 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 4f9ae49c42..24df549243 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 @@ -85,6 +86,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 +499,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); } } @@ -520,9 +519,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; @@ -599,8 +598,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 +612,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"); @@ -629,6 +629,38 @@ 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) + 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_SOURCE_IQ_SAMPLES + : TIME_SOURCE_REALTIME); + // start the main threads number_of_cards = 1; @@ -731,6 +763,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..1baf1e1b73 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 @@ -563,7 +564,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); @@ -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 931ffc3f31..229ebc7c19 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" @@ -301,25 +302,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 +435,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; @@ -467,9 +458,20 @@ 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); + // start time manager with some reasonable default for the running mode + // (may be overwritten in configuration file or command line) + 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_SOURCE_IQ_SAMPLES + : TIME_SOURCE_REALTIME); if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1) start_oai_nrue_threads(); @@ -557,11 +559,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); @@ -601,6 +598,9 @@ int main(int argc, char **argv) } free_nrLDPC_coding_interface(&nrLDPC_coding_interface); + + time_manager_finish(); + free(pckg); return 0; } 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/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/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){ 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/MODULATION/slot_fep_nr.c b/openair1/PHY/MODULATION/slot_fep_nr.c index 201101a39a..17cd425fbd 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); @@ -68,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; @@ -81,16 +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); -#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 + rx_offset %= total_samples; for (unsigned char aa=0; aanb_antennas_rx; aa++) { - int16_t *rxdata_ptr = (int16_t *)&rxdata[aa][rx_offset]; - - rx_offset %= total_samples; + c16_t *rxdata_ptr = &rxdata[aa][rx_offset]; // This happens only during initial sync if (rx_offset + frame_parms->ofdm_symbol_size > total_samples) { @@ -101,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); } @@ -119,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); @@ -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_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_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_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_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/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/NR_UE_TRANSPORT/nr_ulsch_ue.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_ue.c index be7a8101db..299eeb6c64 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/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/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 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 } 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/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c index d427e9721c..eef4dc2a41 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; @@ -485,6 +486,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 +498,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 +561,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); } 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/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 53740c1bde..45e5e55120 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. @@ -92,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; @@ -129,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 @@ -140,7 +135,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 { @@ -192,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] @@ -239,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]; @@ -256,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; @@ -283,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; @@ -293,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) @@ -333,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 @@ -475,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; @@ -549,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 9df2dfaeaa..588d7c5cba 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -435,10 +435,8 @@ 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; - uint8_t num_nssai; + plmn_id_t plmn; + uint16_t num_nssai; nssai_t s_nssai[8]; } ngap_plmn_t; 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/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/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; 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/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 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: diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index cbb46f0132..a43812ebdb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -98,6 +98,45 @@ 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]; + 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, + 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; +} + +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 */ @@ -780,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", @@ -796,13 +835,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)) { @@ -822,6 +858,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); @@ -847,9 +884,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++) { @@ -959,6 +994,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); @@ -968,17 +1010,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); - 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; + GET_PARAMS_LIST(GNBParamList, GNBParams, GNBPARAMS_DESC, GNB_CONFIG_STRING_GNB_LIST, NULL); // PRB Blacklist uint16_t prbbl[MAX_BWP_SIZE] = {0}; @@ -990,15 +1025,12 @@ 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 - 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,27 +1091,30 @@ 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); + 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); - config_get(cfg, SCCsParams, sizeofArray(SCCsParams), aprefix); - config_get(cfg, MsgASCCsParams, sizeofArray(MsgASCCsParams), aprefix); + 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) // fetch params 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; @@ -1165,15 +1200,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); + 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 = bwp_Dedicated->pusch_Config->choice.setup->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->phaseTrackingRS->choice.setup; @@ -1206,15 +1240,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 @@ -1226,20 +1256,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]; - 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); - 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); @@ -1255,30 +1271,15 @@ 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); - 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]); - 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); - 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); - } + // SNSSAI + info->num_ssi = set_snssai_config(info->nssai, MAX_NUM_SLICES, 0, 0); return 1; } @@ -1403,7 +1404,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) { @@ -1459,37 +1460,19 @@ 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; - 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", @@ -1498,9 +1481,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++) @@ -1519,6 +1501,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 +1512,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, @@ -1543,10 +1527,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); + 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; config.timer_config.sr_TransMax = *Timers_Params[GNB_TIMERS_SR_TRANS_MAX_IDX].iptr; @@ -1910,12 +1893,14 @@ 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); - 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; @@ -1928,10 +1913,12 @@ 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); - 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); + 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, + 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; @@ -1950,15 +1937,14 @@ 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); - - paramdef_t NeighbourPlmn[] = GNBPLMNPARAMS_DESC; - config_get(config_get_if(), NeighbourPlmn, sizeofArray(NeighbourPlmn), neighbour_plmn_path); + 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; neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; @@ -1978,19 +1964,20 @@ 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); - paramdef_t Periodical_EventParams[] = MEASUREMENT_PERIODICAL_GLOBALPARAMS_DESC; - config_get(config_get_if(), Periodical_EventParams, sizeofArray(Periodical_EventParams), periodic_event_path); + 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) { 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; @@ -2001,14 +1988,9 @@ 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); - paramdef_t A2_EventParams[] = MEASUREMENT_A2_GLOBALPARAMS_DESC; - config_get(config_get_if(), A2_EventParams, sizeofArray(A2_EventParams), a2_path); + 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) { 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 +1999,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 +2038,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 +2062,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); + 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)); LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n", k, rrc->node_name); @@ -2116,8 +2083,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) { @@ -2138,9 +2103,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, @@ -2169,23 +2120,8 @@ 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); - 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.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.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; @@ -2202,32 +2138,17 @@ 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]; - char *address = NULL; - char *cidr = NULL; - // 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; 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) { @@ -2256,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) { @@ -2304,108 +2202,57 @@ 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); - - 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) { - 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); - - 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).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), - "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); - } + // 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); } - sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); - config_getlist(config_get_if(), &NGParamList, NGParams, sizeofArray(NGParams), aprefix); - + NGAP_REGISTER_GNB_REQ(msg_p).default_drx = 0; + // NG + 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; 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; 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); + 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); } - 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); + 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); + 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; } } @@ -2434,8 +2281,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; @@ -2482,23 +2328,16 @@ 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; - 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", @@ -2506,7 +2345,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++) { @@ -2526,29 +2365,13 @@ 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* 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 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; - - 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; @@ -2562,29 +2385,26 @@ 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", - 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); - sprintf(aprefix, "%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0); - - config_getlist(config_get_if(), &SCCsParamList, NULL, 0, aprefix); + char aprefix[MAX_OPTNAME_SIZE * 80 + 8]; + 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); - config_get(config_get_if(), SCCsParams, sizeofArray(SCCsParams), aprefix); + 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); } X2AP_REGISTER_ENB_REQ (msg_p).num_cc = SCCsParamList.numelt; @@ -2604,8 +2424,9 @@ 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); - config_getlist(config_get_if(), &X2ParamList, X2Params, sizeofArray(X2Params), aprefix); + 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, "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); @@ -2650,15 +2471,15 @@ 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); - config_get(config_get_if(), SCTPParams, sizeofArray(SCTPParams), aprefix); + 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); } - 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); + 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); //temp out @@ -2702,7 +2523,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; } @@ -2766,28 +2587,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]; + 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 ) return ngran_gNB_CU; 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); 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_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..594992c1cb 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; @@ -4427,7 +4436,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 +4457,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 +4897,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 +4914,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 +4933,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 +4981,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 * 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/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/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c index 572202d044..2bb1e84342 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, @@ -2643,6 +2647,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 +2761,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; } 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/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c index e14004edc3..24bc3901ed 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) @@ -212,14 +202,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/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, 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/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/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..83802182e0 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 { @@ -537,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 { @@ -936,7 +939,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__ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index d8b706520e..4375692e9b 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; @@ -390,168 +385,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; @@ -584,62 +417,12 @@ 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" #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, @@ -817,9 +600,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 +619,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 +644,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 +657,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); } @@ -1261,17 +1047,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 a60cd869af..a77cc895e6 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, @@ -128,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/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, diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index d377b2aff3..3527958008 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)); @@ -2463,7 +2472,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) @@ -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; 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/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, 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/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; 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/MSG/RegistrationAccept.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c index d92244a15f..bc5c86f88e 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.c @@ -33,18 +33,44 @@ #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 +#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 */ -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) @@ -53,7 +79,6 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) 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: @@ -63,31 +88,38 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) 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; @@ -97,61 +129,71 @@ static int decode_nssai_ie(nr_nas_msg_snssai_t *nssai, const uint8_t *buf) break; } } + *num_slices = nssai_cnt; 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 - /* Decoding mandatory fields */ - if ((dec = decode_fgs_registration_result(®istration_accept->fgsregistrationresult, 0, *buffer, len)) < 0) - return dec; - buffer += dec; + if (ba.len < REGISTRATION_ACCEPT_MIN_LEN) { + PRINT_NAS_ERROR("Registration Accept decoding failed: invalid buffer length\n"); + return -1; + } - if (buffer < end && *buffer == IEI_5G_GUTI) { + // 5GS registration result (Mandatory) + if ((dec = decode_fgs_registration_result(registration_accept, ba)) < 0) + return -1; + UPDATE_BYTE_ARRAY(ba, dec); + + // 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, ®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, buffer); - buffer += dec; + dec = decode_nssai_ie(registration_accept->config_nssai, ®istration_accept->num_configured_slices, 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; - - *(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); @@ -160,6 +202,100 @@ int encode_registration_accept(const registration_accept_msg *registration_accep encoded += mi_enc; } - // todo ,Encoding optional fields - LOG_FUNC_RETURN(encoded); + 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) +{ + 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 6abf1e70ca..42b02407d9 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/RegistrationAccept.h @@ -31,21 +31,30 @@ #include #include #include +#include #include "SecurityHeaderType.h" #include "MessageType.h" -#include "FGSRegistrationResult.h" #include "FGSMobileIdentity.h" +#include "ds/byte_array.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; + +#define NAS_MAX_NUMBER_SLICES 8 + // 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; /* @@ -56,18 +65,24 @@ 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]; - // 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]; + 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; -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); +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_) */ 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(); diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 941e0d7cdc..8b127abf3e 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,18 +1395,21 @@ 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; 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; @@ -1438,7 +1433,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; @@ -1461,15 +1455,22 @@ 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; } + 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) { process_guti(&msg.guti->guti, nas); - free(msg.guti); } else { LOG_W(NAS, "no GUTI in registration accept\n"); } @@ -1488,6 +1489,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 */ @@ -1634,7 +1637,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 +1727,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 +1738,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 +1770,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__*/ 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]; 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; } }