diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a55506b59bf52332f6b3376e563e57e47668efd..ab6e988939780c1f9663715befd27f8524f7418d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -777,6 +777,8 @@ set(PHY_NRLDPC_CODINGIF add_library(dfts MODULE ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts.c ${OPENAIR1_DIR}/PHY/TOOLS/oai_dfts_neon.c) +add_library(crc_byte OBJECT ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c) + set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/dci_tools_common.c ${OPENAIR1_DIR}/PHY/LTE_TRANSPORT/lte_mcs.c @@ -802,7 +804,6 @@ set(PHY_SRC_COMMON ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte.c ${OPENAIR1_DIR}/PHY/CODING/ccoding_byte_lte.c ${OPENAIR1_DIR}/PHY/CODING/3gpplte_sse.c - ${OPENAIR1_DIR}/PHY/CODING/crc_byte.c ${PHY_TURBOIF} ${OPENAIR1_DIR}/PHY/CODING/lte_rate_matching.c ${OPENAIR1_DIR}/PHY/CODING/viterbi.c @@ -1019,9 +1020,11 @@ if (${SMBV}) endif (${SMBV}) add_library(PHY_COMMON ${PHY_SRC_COMMON}) -target_link_libraries(PHY_COMMON PRIVATE shlib_loader) +target_link_libraries(PHY_COMMON + PRIVATE shlib_loader asn1_lte_rrc_hdrs crc_byte + PUBLIC UTIL +) add_dependencies(PHY_COMMON dfts) -target_link_libraries(PHY_COMMON PRIVATE asn1_lte_rrc_hdrs PUBLIC UTIL) add_library(PHY ${PHY_SRC}) target_link_libraries(PHY PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs) @@ -1954,12 +1957,17 @@ target_link_libraries(smallblocktest PRIVATE add_executable(ldpctest - ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c - ) + ${OPENAIR1_DIR}/PHY/CODING/TESTBENCH/ldpctest.c + ${OPENAIR1_DIR}/PHY/CODING/nrLDPC_load.c +) target_link_libraries(ldpctest PRIVATE -Wl,--start-group UTIL SIMU PHY_COMMON PHY_NR_COMMON -Wl,--end-group - m pthread dl shlib_loader ${T_LIB} nr_coding_segment_utils - ) + m pthread dl shlib_loader ${T_LIB} + # link 'check_crc' to make it resolved in the LDPC coding libraries + # 'check_crc' is not used in ldpctest so it is not linked in the executable by default + # --whole-archive links 'check_crc' in the executable even though it is note used, see 'man ld' + -Wl,--whole-archive crc_byte -Wl,--no-whole-archive +) add_executable(nr_dlschsim ${OPENAIR1_DIR}/SIMULATION/NR_PHY/dlschsim.c @@ -2113,7 +2121,7 @@ if (${T_TRACER}) PHY_COMMON PHY PHY_UE PHY_NR PHY_NR_COMMON PHY_NR_UE PHY_RU L2 L2_LTE L2_NR L2_LTE_NR L2_UE NR_L2_UE L2_UE_LTE_NR MAC_NR_COMMON MAC_UE_NR ngap CN_UTILS GTPV1U SCTP_CLIENT MME_APP LIB_NAS_UE NB_IoT SIMU OPENAIR0_LIB - dfts config_internals nr_common) + dfts config_internals nr_common crc_byte) if (TARGET ${i}) add_dependencies(${i} generate_T) endif() diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml index 88f5079b685901bd46441df44a30a844741094ee..7a66ea6c34ea67324ee6375d832159305b2743bc 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run.xml @@ -45,7 +45,7 @@ <testCase id="090101"> <class>Initialize_eNB</class> <desc>Initialize gNB USRP</desc> - <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf --phy-test -q -U 787200 -T 106 -t 23 -D 130175 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> + <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.106prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 106 -t 23 -D 127 -m 28 -M 106 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> <rt_stats_cfg>datalog_rt_stats.default.yaml</rt_stats_cfg> <air_interface>NR</air_interface> <USRP_IPAddress>192.168.20.2</USRP_IPAddress> diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml index f81d747bfee9fec223603258483df9740e9a73e8..2f94fa986dea2e7c273408c6551a4ff034388b15 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_100_2x2.xml @@ -45,7 +45,7 @@ <testCase id="390101"> <class>Initialize_eNB</class> <desc>Initialize gNB USRP</desc> - <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 787200 -T 273 -t 23 -D 130175 -m 23 -M 273 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> + <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.273prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 273 -t 23 -D 127 -m 23 -M 273 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> <rt_stats_cfg>datalog_rt_stats.100.2x2.yaml</rt_stats_cfg> <air_interface>NR</air_interface> <USRP_IPAddress>192.168.20.2</USRP_IPAddress> diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml index 4b0fec92e29674ba62fb234fcffc1fa4d40981d1..77e47c66b48fc3546cb49bb77f655a3257ed3771 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_60.xml @@ -45,7 +45,7 @@ <testCase id="190101"> <class>Initialize_eNB</class> <desc>Initialize gNB USRP</desc> - <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test -q -U 787200 -T 162 -t 23 -D 130175 -m 23 -M 162 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> + <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> <rt_stats_cfg>datalog_rt_stats.1x1.60.yaml</rt_stats_cfg> <air_interface>NR</air_interface> <USRP_IPAddress>192.168.20.2</USRP_IPAddress> diff --git a/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml b/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml index f9e298127f010b4d0105a9d8411a864998d7c7f4..67e2316ea38789aba5c58a459ba20b1d19616b80 100644 --- a/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml +++ b/ci-scripts/xml_files/gnb_phytest_usrp_run_60_2x2.xml @@ -45,7 +45,7 @@ <testCase id="290101"> <class>Initialize_eNB</class> <desc>Initialize gNB USRP</desc> - <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test --gNBs.[0].pdsch_AntennaPorts_XP 2 --RUs.[0].nb_tx 2 --RUs.[0].nb_rx 2 -q -U 787200 -T 162 -t 23 -D 130175 -m 23 -M 162 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> + <Initialize_eNB_args>-O ci-scripts/conf_files/gnb.band78.162prb.usrpn300.phytest-dora.conf --phy-test --gNBs.[0].pdsch_AntennaPorts_XP 2 --RUs.[0].nb_tx 2 --RUs.[0].nb_rx 2 -q -U 768 -T 162 -t 23 -D 127 -m 23 -M 162 -l 2 --usrp-tx-thread-config 1 --log_config.global_log_options level,nocolor,time</Initialize_eNB_args> <rt_stats_cfg>datalog_rt_stats.60.2x2.yaml</rt_stats_cfg> <air_interface>NR</air_interface> <USRP_IPAddress>192.168.20.2</USRP_IPAddress> diff --git a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml index 6c3940d3065444b6357ec779fe636797ffc78456..5a55ade3c885d6fdc70e61a801b51446a108f2f3 100644 --- a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml @@ -9,6 +9,7 @@ services: environment: USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function + --security.drb_integrity yes volumes: - ../../conf_files/gnb-cucp.sa.f1.quectel.conf:/opt/oai-gnb/etc/gnb.conf # for performance reasons, we use host mode: in bridge mode, we have diff --git a/cmake_targets/autotests/test_case_list.xml b/cmake_targets/autotests/test_case_list.xml index 32876634c06bb945232ff7895e8754cdecc5ee51..80f18e98a7a000965756cae3c7f43ba98ed83b4c 100755 --- a/cmake_targets/autotests/test_case_list.xml +++ b/cmake_targets/autotests/test_case_list.xml @@ -168,7 +168,8 @@ (Test4: HARQ test 25% TP 4 rounds), (Test5: HARQ test 33% TP 3 rounds), (Test6: HARQ test 50% TP 2 rounds), - (Test7: 25 PRBs, 15 kHz SCS)</desc> + (Test7: 25 PRBs, 15 kHz SCS), + (Test8: 32 PRBs, 120 kHz SCS)</desc> <main_exec>nr_dlsim</main_exec> <main_exec_args>-n100 -R106 -b106 -s5 -n100 -R217 -b217 -s5 @@ -176,8 +177,9 @@ -n100 -s1 -S2 -t25 -n100 -s1 -S2 -t33 -n100 -s5 -S7 -t50 - -n100 -m0 -e0 -R25 -b25 -i 2 1 0</main_exec_args> - <tags>test1 test2 test3 test4 test5 test6 test7</tags> + -n100 -m0 -e0 -R25 -b25 -i 2 1 0 + -n100 -s5 -m3 -R32 -b32</main_exec_args> + <tags>test1 test2 test3 test4 test5 test6 test7 test8</tags> <search_expr_true>PDSCH test OK</search_expr_true> <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false> <nruns>3</nruns> @@ -400,9 +402,10 @@ (Test9: PUSCH Type B, 3 DMRS, 2 PTRS, 7 Interpolated Symbols), (Test10: PUSCH Type B, 3 DMRS, 2 PTRS, 3 Interpolated Symbols), (Test11: 25 PRBs, 15 kHz SCS), - (Test12: MCS 0, low SNR performance) - (Test13: MCS 28, 106 PRBs, Time shift 8) - (Test14: SRS, SNR 40 dB)</desc> + (Test12: 32 PRBs, 120 kHz SCS), + (Test13: MCS 0, low SNR performance) + (Test14: MCS 28, 106 PRBs, Time shift 8) + (Test15: SRS, SNR 40 dB)</desc> <main_exec>nr_ulsim</main_exec> <main_exec_args>-n100 -m9 -r106 -s5 -n100 -m16 -s10 @@ -415,10 +418,11 @@ -n100 -s5 -T 2,2 -U 1,2,1,1 -n100 -s5 -a4 -b8 -T 1,2 -U 1,3,1,1 -n100 -u0 -m0 -R25 -r25 -i 1,0 + -n100 -s5 -r32 -R32 -u3 -n100 -m0 -S -0.6 -i 1,0 -n100 -m 28 -R106 -r106 -t90 -s24 -S24 -d 8 -n100 -s40 -E 1</main_exec_args> - <tags>test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12 test13 test14</tags> + <tags>test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 test12 test13 test14 test15</tags> <search_expr_true>PUSCH test OK</search_expr_true> <search_expr_false>segmentation fault|assertion|exiting|fatal</search_expr_false> <nruns>3</nruns> diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 9b029657ad7704c3d83c9e4c96780a8a77a209e9..5bacbe9f385864cf0fc5381e684889c7fab3afa3 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -188,18 +188,20 @@ uint64_t reverse_bits(uint64_t in, int n_bits) return rev_bits; } -static const int tables_5_3_2[5][12] = { - {25, 52, 79, 106, 133, 160, 216, 270, -1, -1, -1, -1}, // 15 FR1 - {11, 24, 38, 51, 65, 78, 106, 133, 162, 217, 245, 273}, // 30 FR1 - {-1, 11, 18, 24, 31, 38, 51, 65, 79, 107, 121, 135}, // 60 FR1 - {66, 132, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 60 FR2 - {32, 66, 132, 264, -1, -1, -1, -1, -1, -1, -1, -1} // 120FR2 +#define NUM_BW_ENTRIES 15 + +static const int tables_5_3_2[5][NUM_BW_ENTRIES] = { + {25, 52, 79, 106, 133, 160, 188, 216, 242, 270, -1, -1, -1, -1, -1}, // 15 FR1 + {11, 24, 38, 51, 65, 78, 92, 106, 119, 133, 162, 189, 217, 245, 273}, // 30 FR1 + {-1, 11, 18, 24, 31, 38, 44, 51, 58, 65, 79, 93, 107, 121, 135}, // 60 FR1 + {66, 132, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}, // 60 FR2 + {32, 66, 132, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1} // 120FR2 }; int get_supported_band_index(int scs, frequency_range_t freq_range, int n_rbs) { int scs_index = scs + freq_range; - for (int i = 0; i < 12; i++) { + for (int i = 0; i < NUM_BW_ENTRIES; i++) { if(n_rbs == tables_5_3_2[scs_index][i]) return i; } @@ -209,7 +211,7 @@ int get_supported_band_index(int scs, frequency_range_t freq_range, int n_rbs) int get_smallest_supported_bandwidth_index(int scs, frequency_range_t frequency_range, int n_rbs) { int scs_index = scs + frequency_range; - for (int i = 0; i < 12; i++) { + for (int i = 0; i < NUM_BW_ENTRIES; i++) { if (n_rbs <= tables_5_3_2[scs_index][i]) return i; } @@ -422,10 +424,8 @@ void check_ssb_raster(uint64_t freq, int band, int scs) int get_supported_bw_mhz(frequency_range_t frequency_range, int bw_index) { if (frequency_range == FR1) { - int bandwidth_index_to_mhz[] = {5, 10, 15, 20, 25, 30, 40, 50, 60, 80, 90, 100}; - AssertFatal(bw_index >= 0 && bw_index <= sizeofArray(bandwidth_index_to_mhz), - "Bandwidth index %d is invalid\n", - bw_index); + int bandwidth_index_to_mhz[] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100}; + AssertFatal(bw_index >= 0 && bw_index <= sizeofArray(bandwidth_index_to_mhz), "Bandwidth index %d is invalid\n", bw_index); return bandwidth_index_to_mhz[bw_index]; } else { int bandwidth_index_to_mhz[] = {50, 100, 200, 400}; @@ -826,6 +826,18 @@ void get_samplerate_and_bw(int mu, *rx_bw = 50e6; } break; + case 242: // 45Mhz + case 188: // 35Mhz + if (threequarter_fs) { + *sample_rate = 46.08e6; + *samples_per_frame = 460800; + } else { + *sample_rate = 61.44e6; + *samples_per_frame = 614400; + } + *tx_bw = (n_rb == 242) ? 45e6 : 35e6; + *rx_bw = (n_rb == 242) ? 45e6 : 35e6; + break; case 216: if (threequarter_fs) { *sample_rate=46.08e6; @@ -926,6 +938,17 @@ void get_samplerate_and_bw(int mu, *rx_bw = 80e6; } break; + case 189: + if (threequarter_fs) { + *sample_rate = 92.16e6; + *samples_per_frame = 921600; + } else { + *sample_rate = 122.88e6; + *samples_per_frame = 1228800; + } + *tx_bw = 70e6; + *rx_bw = 70e6; + break; case 162 : if (threequarter_fs) { AssertFatal(1==0,"N_RB %d cannot use 3/4 sampling\n",n_rb); @@ -951,6 +974,20 @@ void get_samplerate_and_bw(int mu, } break; + + case 119: // 45Mhz + case 92: // 35Mhz + if (threequarter_fs) { + *sample_rate = 46.08e6; + *samples_per_frame = 460800; + } else { + *sample_rate = 61.44e6; + *samples_per_frame = 614400; + } + *tx_bw = (n_rb == 119) ? 45e6 : 35e6; + *rx_bw = (n_rb == 119) ? 45e6 : 35e6; + break; + case 106: if (threequarter_fs) { *sample_rate=46.08e6; diff --git a/common/utils/tun_if.c b/common/utils/tun_if.c index 4d0432599898a9491f97794d5e1b473c83f3eea0..79fcc6a9540a4acd7873ca7ff11499a2771d91d8 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(char *dev) +static int tun_alloc(const char *dev) { struct ifreq ifr; int fd, err; @@ -55,25 +55,27 @@ static int tun_alloc(char *dev) * IFF_NO_PI - Do not provide packet information */ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; - - if (*dev) - strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1); - + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1); if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) < 0) { close(fd); return err; } + // According to https://www.kernel.org/doc/Documentation/networking/tuntap.txt, TUNSETIFF performs string + // formatting on ifr_name. To ensure that the generated name is what we expect, check it here. + AssertFatal(strcmp(ifr.ifr_name, dev) == 0, "Failed to create tun interface, expected ifname %s, got %s\n", dev, ifr.ifr_name); + + err = fcntl(fd, F_SETFL, O_NONBLOCK); + if (err == -1) { + close(fd); + LOG_E(UTIL, "Error fcntl (%d:%s)\n", errno, strerror(errno)); + return err; + } - strcpy(dev, ifr.ifr_name); return fd; } -int tun_init_mbms(char *ifprefix, int id) +int tun_init_mbms(char *ifname) { - int ret; - char ifname[64]; - - sprintf(ifname, "%s%d", ifprefix, id); nas_sock_mbms_fd = tun_alloc(ifname); if (nas_sock_mbms_fd == -1) { @@ -82,48 +84,26 @@ int tun_init_mbms(char *ifprefix, int id) } LOG_D(UTIL, "Opened socket %s with fd %d\n", ifname, nas_sock_mbms_fd); - ret = fcntl(nas_sock_mbms_fd, F_SETFL, O_NONBLOCK); - - if (ret == -1) { - LOG_E(UTIL, "Error fcntl (%d:%s)\n", errno, strerror(errno)); - return 0; - } struct sockaddr_nl nas_src_addr = {0}; nas_src_addr.nl_family = AF_NETLINK; nas_src_addr.nl_pid = 1; nas_src_addr.nl_groups = 0; /* not in mcast groups */ - ret = bind(nas_sock_mbms_fd, (struct sockaddr *)&nas_src_addr, sizeof(nas_src_addr)); + bind(nas_sock_mbms_fd, (struct sockaddr *)&nas_src_addr, sizeof(nas_src_addr)); return 1; } -int tun_init(const char *ifprefix, int num_if, int id) +int tun_init(const char *ifname, int instance_id) { - int ret; - char ifname[64]; - - int begx = (id == 0) ? 0 : id - 1; - int endx = (id == 0) ? num_if : id; - for (int i = begx; i < endx; i++) { - sprintf(ifname, "%s%d", ifprefix, i + 1); - nas_sock_fd[i] = tun_alloc(ifname); - - if (nas_sock_fd[i] == -1) { - LOG_E(UTIL, "Error opening socket %s (%d:%s)\n", ifname, errno, strerror(errno)); - return 0; - } - - LOG_I(UTIL, "Opened socket %s with fd nas_sock_fd[%d]=%d\n", ifname, i, nas_sock_fd[i]); - ret = fcntl(nas_sock_fd[i], F_SETFL, O_NONBLOCK); - - if (ret == -1) { - LOG_E(UTIL, "Error fcntl (%d:%s)\n", errno, strerror(errno)); + nas_sock_fd[instance_id] = tun_alloc(ifname); - return 0; - } + if (nas_sock_fd[instance_id] == -1) { + LOG_E(UTIL, "Error opening socket %s (%d:%s)\n", ifname, errno, strerror(errno)); + return 0; } + LOG_I(UTIL, "Opened socket %s with fd nas_sock_fd[%d]=%d\n", ifname, instance_id, nas_sock_fd[instance_id]); return 1; } @@ -209,12 +189,8 @@ fail_interface_state: return false; } -// non blocking full configuration of the interface (address, and the two lest octets of the address) -bool tun_config(int interface_id, const char *ipv4, const char *ipv6, const char *ifpref) +bool tun_config(const char* ifname, const char *ipv4, const char *ipv6) { - char interfaceName[IFNAMSIZ]; - snprintf(interfaceName, sizeof(interfaceName), "%s%d", ifpref, interface_id); - AssertFatal(ipv4 != NULL || ipv6 != NULL, "need to have IP address, but none given\n"); int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); @@ -223,13 +199,16 @@ bool tun_config(int interface_id, const char *ipv4, const char *ipv6, const char return false; } - change_interface_state(sock_fd, interfaceName, INTERFACE_DOWN); + if (!change_interface_state(sock_fd, ifname, INTERFACE_DOWN)) { + close(sock_fd); + return false; + } bool success = true; if (ipv4 != NULL) - success = setInterfaceParameter(sock_fd, interfaceName, AF_INET, ipv4, SIOCSIFADDR); + success = setInterfaceParameter(sock_fd, ifname, AF_INET, ipv4, SIOCSIFADDR); // set the machine network mask for IPv4 if (success && ipv4 != NULL) - success = setInterfaceParameter(sock_fd, interfaceName, AF_INET, "255.255.255.0", SIOCSIFNETMASK); + success = setInterfaceParameter(sock_fd, ifname, AF_INET, "255.255.255.0", SIOCSIFNETMASK); if (ipv6 != NULL) { // for setting the IPv6 address, we need an IPv6 socket. For setting IPv4, @@ -240,27 +219,25 @@ bool tun_config(int interface_id, const char *ipv4, const char *ipv6, const char LOG_E(UTIL, "Failed creating socket for interface management: %d, %s\n", errno, strerror(errno)); success = false; } - success = success && setInterfaceParameter(sock_fd, interfaceName, AF_INET6, ipv6, SIOCSIFADDR); + success = success && setInterfaceParameter(sock_fd, ifname, AF_INET6, ipv6, SIOCSIFADDR); close(sock_fd); } if (success) - success = change_interface_state(sock_fd, interfaceName, INTERFACE_UP); + success = change_interface_state(sock_fd, ifname, INTERFACE_UP); if (success) - LOG_I(OIP, "Interface %s successfully configured, IPv4 %s, IPv6 %s\n", interfaceName, ipv4, ipv6); + LOG_I(OIP, "Interface %s successfully configured, IPv4 %s, IPv6 %s\n", ifname, ipv4, ipv6); else - LOG_E(OIP, "Interface %s couldn't be configured (IPv4 %s, IPv6 %s)\n", interfaceName, ipv4, ipv6); + LOG_E(OIP, "Interface %s couldn't be configured (IPv4 %s, IPv6 %s)\n", ifname, ipv4, ipv6); close(sock_fd); return success; } -void setup_ue_ipv4_route(int interface_id, const char *ipv4, const char *ifpref) +void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4) { - int table_id = interface_id - 1 + 10000; - char interfaceName[IFNAMSIZ]; - snprintf(interfaceName, sizeof(interfaceName), "%s%d", ifpref, interface_id); + int table_id = instance_id - 1 + 10000; char command_line[500]; int res = sprintf(command_line, @@ -271,7 +248,7 @@ void setup_ue_ipv4_route(int interface_id, const char *ipv4, const char *ifpref) table_id, ipv4, table_id, - interfaceName, + ifname, table_id); if (res < 0) { @@ -281,3 +258,7 @@ void setup_ue_ipv4_route(int interface_id, const char *ipv4, const char *ifpref) background_system(command_line); } +int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id) +{ + return snprintf(ifname, IFNAMSIZ, "%s%d", ifprefix, instance_id + 1); +} diff --git a/common/utils/tun_if.h b/common/utils/tun_if.h index 45ae34983f70409819562f80efd8b019a9eece41..eafc5b3350a4c3808f3b146ea15e74372859f576 100644 --- a/common/utils/tun_if.h +++ b/common/utils/tun_if.h @@ -23,28 +23,43 @@ #define TUN_IF_H_ #include <stdbool.h> +#include <net/if.h> -/* TODO: doc */ -int tun_init(const char *ifprefix, int num_if, int id); +/*! + * \brief This function generates the name of the interface based on the prefix and + * the instance id. + * + * \param[in,out] ifname name of the interface + * \param[in] ifprefix prefix of the interface + * \param[in] instance_id unique instance number + */ +int tun_generate_ifname(char *ifname, const char *ifprefix, int instance_id); -/* TODO: doc */ -int tun_init_mbms(char *ifsuffix, int id); +/*! + * \brief This function initializes the TUN interface + * \param[in] ifname name of the interface + * \param[in] instance_id unique instance number, used to save socket file descriptor + */ +int tun_init(const char *ifname, int instance_id); -/*! \fn int tun_config(char*, int, int) +/*! + * \brief This function initializes the TUN interface for MBMS + * \param[in] ifname name of the interface + */ +int tun_init_mbms(char *ifname); + +/*! * \brief This function initializes the nasmesh interface using the basic values, * basic address, network mask and broadcast address, as the default configured * ones - * \param[in] interface_id number of this interface, prepended after interface - * name + * \param[in] ifname name of the interface * \param[in] ipv4 IPv4 address of this interface as a string * \param[in] ipv6 IPv6 address of this interface as a string - * \param[in] ifprefix interface name prefix to which an interface number will - * be appended * \return true on success, otherwise false * \note * @ingroup _nas */ -bool tun_config(int interface_id, const char *ipv4, const char *ipv6, const char *ifprefix); +bool tun_config(const char* ifname, const char *ipv4, const char *ipv6); /*! * \brief Setup a IPv4 rule in table (interface_id - 1 + 10000) and route to @@ -52,12 +67,10 @@ bool tun_config(int interface_id, const char *ipv4, const char *ipv6, const char * net.ipv4.conf.all.rp_filter=2 (strict source filtering would filter out * responses of packets going out through interface to another IP address not * in same subnet). - * \param[in] interface_id number of this interface, prepended after interface - * name + * \param[in] ifname name of the interface + * \param[in] instance_id unique instance number, used to create the table * \param[in] ipv4 IPv4 address of the UE - * \param[in] ifprefix interface name prefix to which an interface number will - * be appended */ -void setup_ue_ipv4_route(int interface_id, const char *ipv4, const char *ifpref); +void setup_ue_ipv4_route(const char* ifname, int instance_id, const char *ipv4); #endif /*TUN_IF_H_*/ diff --git a/doc/NR_SA_Tutorial_OAI_multi_UE.md b/doc/NR_SA_Tutorial_OAI_multi_UE.md index f596b9cb958556fe32769f17a5a568fd935b2b4e..9b8e49ac1f8bd69adc3bb3603b4b928fbc828201 100644 --- a/doc/NR_SA_Tutorial_OAI_multi_UE.md +++ b/doc/NR_SA_Tutorial_OAI_multi_UE.md @@ -54,7 +54,7 @@ Important notes: sudo ./nr-uesoftmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --uicc0.imsi 001010000000001 --rfsimulator.options chanmod --rfsimulator.serveraddr 10.201.1.100 --telnetsrv --telnetsrv.listenport 9095 ``` -3. For the second UE, create the namespace ue2 (`-c1`), then execute shell inside (`-o1`, "open"): +3. For the second UE, create the namespace ue2 (`-c2`), then execute shell inside (`-o2`, "open"): ```bash sudo ./multi-ue.sh -c2 diff --git a/executables/nr-softmodem-common.h b/executables/nr-softmodem-common.h index b7fc5768458766747d5a478d1160c9d85be37efe..3ab6d1e73de3ce1729713add6852a7104f8706cb 100644 --- a/executables/nr-softmodem-common.h +++ b/executables/nr-softmodem-common.h @@ -64,8 +64,8 @@ #define CONFIG_HLP_DLBW_PHYTEST "Set the number of PRBs used for DLSCH in PHYTEST mode\n" #define CONFIG_HLP_ULBW_PHYTEST "Set the number of PRBs used for ULSCH in PHYTEST mode\n" #define CONFIG_HLP_PRB_SA "Set the number of PRBs for SA\n" -#define CONFIG_HLP_DLBM_PHYTEST "Bitmap for DLSCH slots (slot 0 starts at LSB)\n" -#define CONFIG_HLP_ULBM_PHYTEST "Bitmap for ULSCH slots (slot 0 starts at LSB)\n" +#define CONFIG_HLP_DLBM_PHYTEST "Bitmap for DLSCH slots in period (slot 0 starts at LSB)\n" +#define CONFIG_HLP_ULBM_PHYTEST "Bitmap for ULSCH slots in period (slot 0 starts at LSB)\n" #define CONFIG_HLP_SSC "Set the start subcarrier \n" #define CONFIG_HLP_TDD "Set hardware to TDD mode (default: FDD). Used only with -U (otherwise set in config file).\n" #define CONFIG_HLP_UE "Set the lte softmodem as a UE\n" diff --git a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h index 0c14fcebef17304b1e624ca5df2ac431521b0cd1..0325c8c242c3fe4d80f9b523732201860eb84aa0 100644 --- a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h +++ b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h @@ -57,7 +57,7 @@ typedef struct { typedef struct { uint8_t* buffer; - uint16_t length; + uint32_t length; } pnf_p7_rx_message_segment_t; typedef struct pnf_p7_rx_message pnf_p7_rx_message_t; diff --git a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h index 5e964f10faf39721e316ce997ee0e152c5871059..7403bd7169435524e07b410ad23beb8d37f0e04e 100644 --- a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h +++ b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h @@ -629,8 +629,8 @@ typedef struct nfapi_pnf_p7_config uint8_t checksum_enabled; /*! The maxium size of a P7 segement. If a message is large that this it - * will be segemented */ - uint16_t segment_size; + * will be segmented. Note: u32 to cover 4G and 5G */ + uint32_t segment_size; /*! The dummy subframe buffer structure that should be used in case there * are no 'valid' subframe messages */ diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c index 81de4d7acc67f67061fa1515a689401315bbae67..bdc1634ef5cde7566fd51d3cb387bd06c7955669 100644 --- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c +++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c @@ -602,18 +602,20 @@ int pnf_nr_p7_pack_and_send_p7_message(pnf_p7_t* pnf_p7, nfapi_nr_p7_message_hea uint8_t buffer[pnf_p7->_public.segment_size]; for (segment = 0; segment < segment_count; ++segment) { uint8_t last = 0; - uint16_t size = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + uint32_t size = pnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; if (segment + 1 == segment_count) { last = 1; size = (msg_body_len) - (seg_body_len * segment); } - uint16_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; + uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; // Update the header with the m and segement memcpy(&buffer[0], tx_buf, NFAPI_NR_P7_HEADER_LENGTH); // set the segment length + buffer[4] = (segment_size & 0xFF000000) >> 24; + buffer[5] = (segment_size & 0xFF0000) >> 16; buffer[6] = (segment_size & 0xFF00) >> 8; buffer[7] = (segment_size & 0xFF); @@ -2378,7 +2380,7 @@ void pnf_nr_handle_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, if (rx_msg->num_segments_received == rx_msg->num_segments_expected) { // send the buffer on uint16_t i = 0; - uint16_t length = 0; + uint32_t length = 0; for (i = 0; i < rx_msg->num_segments_expected; ++i) { length += rx_msg->segments[i].length - (i > 0 ? NFAPI_NR_P7_HEADER_LENGTH : 0); } @@ -2400,7 +2402,7 @@ void pnf_nr_handle_p7_message(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7, pnf_p7->reassemby_buffer_size = length; } - uint16_t offset = 0; + uint32_t offset = 0; for (i = 0; i < rx_msg->num_segments_expected; ++i) { if (i == 0) { memcpy(pnf_p7->reassemby_buffer, rx_msg->segments[i].buffer, rx_msg->segments[i].length); diff --git a/nfapi/open-nFAPI/vnf/inc/vnf_p7.h b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h index 3684997c22126e835ef49ec080501bc8552602bb..92623b41b8359206860629353644ad1a27c6a27a 100644 --- a/nfapi/open-nFAPI/vnf/inc/vnf_p7.h +++ b/nfapi/open-nFAPI/vnf/inc/vnf_p7.h @@ -27,7 +27,7 @@ typedef struct { uint8_t* buffer; - uint16_t length; + uint32_t length; } vnf_p7_rx_message_segment_t; typedef struct vnf_p7_rx_message vnf_p7_rx_message_t; diff --git a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h index 77f0358e40977b5d1062962cb19979419cb7d7a4..6fd7d733eb472527757527ec833e5b1d1e6e14ef 100644 --- a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h +++ b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h @@ -669,8 +669,8 @@ typedef struct nfapi_vnf_p7_config uint8_t checksum_enabled; /*! The maxium size of a P7 segement. If a message is large that this it - * will be segemented */ - uint16_t segment_size; + * will be segmented. Note: u32 to cover 4G and 5G. */ + uint32_t segment_size; uint16_t max_num_segments; /*! Configuration option for the p7 pack unpack functions*/ diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c index 0caebd213006158b9a4d562e086651bc5695d0c5..3d2975d03cacf51b3c26a24cad7c535e0a3554d3 100644 --- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c +++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c @@ -501,7 +501,7 @@ int vnf_nr_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_nr_p7_message_header_ // segmenting the transmit int msg_body_len = len - NFAPI_NR_P7_HEADER_LENGTH ; - int seg_body_len = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH ; + uint32_t seg_body_len = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH ; int segment_count = (msg_body_len / (seg_body_len)) + ((msg_body_len % seg_body_len) ? 1 : 0); int segment = 0; @@ -511,19 +511,21 @@ int vnf_nr_p7_pack_and_send_p7_msg(vnf_p7_t* vnf_p7, nfapi_nr_p7_message_header_ for(segment = 0; segment < segment_count; ++segment) { uint8_t last = 0; - uint16_t size = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; + uint32_t size = vnf_p7->_public.segment_size - NFAPI_NR_P7_HEADER_LENGTH; if(segment + 1 == segment_count) { last = 1; size = (msg_body_len) - (seg_body_len * segment); } - uint16_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; + uint32_t segment_size = size + NFAPI_NR_P7_HEADER_LENGTH; // Update the header with the m and segement memcpy(&tx_buffer[0], buffer, NFAPI_NR_P7_HEADER_LENGTH); // set the segment length + tx_buffer[4] = (segment_size & 0xFF000000) >> 24; + tx_buffer[5] = (segment_size & 0xFF0000) >> 16; tx_buffer[6] = (segment_size & 0xFF00) >> 8; tx_buffer[7] = (segment_size & 0xFF); diff --git a/openair1/PHY/CODING/CMakeLists.txt b/openair1/PHY/CODING/CMakeLists.txt index c469a2b2360a6704afc2e9299f3f4ce3ceb0a18f..e4e8d43a955a2faa92387a4b555e2f6a457294ce 100644 --- a/openair1/PHY/CODING/CMakeLists.txt +++ b/openair1/PHY/CODING/CMakeLists.txt @@ -13,28 +13,36 @@ add_library(ldpc_orig MODULE nrLDPC_encoder/ldpc_encoder.c ) set_target_properties(ldpc_orig PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_orig PRIVATE ldpc_gen_HEADERS) +target_link_libraries(ldpc_orig PRIVATE ldpc_segment ldpc_gen_HEADERS) add_library(ldpc_optim MODULE nrLDPC_decoder/nrLDPC_decoder.c nrLDPC_encoder/ldpc_encoder_optim.c ) set_target_properties(ldpc_optim PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_optim PRIVATE ldpc_gen_HEADERS) +target_link_libraries(ldpc_optim PRIVATE ldpc_segment ldpc_gen_HEADERS) add_library(ldpc_optim8seg MODULE nrLDPC_decoder/nrLDPC_decoder.c nrLDPC_encoder/ldpc_encoder_optim8seg.c ) set_target_properties(ldpc_optim8seg PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_optim8seg PRIVATE ldpc_gen_HEADERS) +target_link_libraries(ldpc_optim8seg PRIVATE ldpc_segment ldpc_gen_HEADERS) -add_library(ldpc_optim8segmulti MODULE +add_library(ldpc MODULE nrLDPC_decoder/nrLDPC_decoder.c nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) -set_target_properties(ldpc_optim8segmulti PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_optim8segmulti PRIVATE ldpc_gen_HEADERS) +set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) +target_link_libraries(ldpc PRIVATE ldpc_segment ldpc_gen_HEADERS) + +add_dependencies(ldpctest ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr-softmodem ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr-uesoftmodem ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr_ulsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr_ulschsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr_dlsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg) +add_dependencies(nr_dlschsim ldpc ldpc_orig ldpc_optim ldpc_optim8seg) add_custom_target(nrLDPC_decoder_kernels_CL COMMAND gcc nrLDPC_decoder/nrLDPC_decoder_CL.c -dD -DNRLDPC_KERNEL_SOURCE -E -o ${CMAKE_CURRENT_BINARY_DIR}/nrLDPC_decoder_kernels_CL.clc @@ -46,7 +54,7 @@ add_library(ldpc_cl MODULE nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) set_target_properties(ldpc_cl PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -target_link_libraries(ldpc_cl PRIVATE OpenCL) +target_link_libraries(ldpc_cl PRIVATE ldpc_segment OpenCL) add_dependencies(ldpc_cl nrLDPC_decoder_kernels_CL) ############################################## @@ -64,14 +72,24 @@ if (ENABLE_LDPC_CUDA) cuda_add_library(ldpc_cuda MODULE nrLDPC_decoder_LYC/nrLDPC_decoder_LYC.cu nrLDPC_encoder/ldpc_encoder_optim8segmulti.c + # The slot coding layer cannot be linked with + # target_link_libraries like above + # because of cuda_add_library + # which already uses target_link_libraries + nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c + nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c ) set_target_properties(ldpc_cuda PROPERTIES CUDA_SEPARABLE_COMPILATION ON) set_target_properties(ldpc_cuda PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) -endif() -add_dependencies(ldpctest ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) -if (ENABLE_LDPC_CUDA) add_dependencies(ldpctest ldpc_cuda) + add_dependencies(nr-softmodem ldpc_cuda) + add_dependencies(nr-uesoftmodem ldpc_cuda) + add_dependencies(nr_ulsim ldpc_cuda) + add_dependencies(nr_ulschsim ldpc_cuda) + add_dependencies(nr_dlsim ldpc_cuda) + add_dependencies(nr_dlschsim ldpc_cuda) endif() add_subdirectory(nrLDPC_coding) diff --git a/openair1/PHY/CODING/DOC/LDPCImplementation.md b/openair1/PHY/CODING/DOC/LDPCImplementation.md index cf5fb506c8591543a3ec5d7d53edd8d4dcf0c091..2880c45ecfd1f0feeddd0d9129d4ce78b0b2e27b 100644 --- a/openair1/PHY/CODING/DOC/LDPCImplementation.md +++ b/openair1/PHY/CODING/DOC/LDPCImplementation.md @@ -28,9 +28,6 @@ shlib_path libldpc.so `libldpc.so` has its decoder implemented in [nrLDPC_coding_segment_decoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c).\ Its encoder is implemented in [nrLDPC_coding_segment_encoder.c](file://../nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c). -*Note: The segment coding library `libldpc.so` is an adaptation layer between the slot coding interface and a segment coding library.* -*The segment coding library is `libldpc_optim8segmulti.so` by default but it can be chosen with option `--nrLDPC_coding_segment.segment_shlibversion` followed by the library version - like with `--loader.ldpc.shlibversion` in the slot coding case -* - loading `libldpc_t2.so` instead of `libldpc.so`: `make ldpc_t2` @@ -114,28 +111,29 @@ Libraries implementing the slotwise LDPC coding must be named `libldpc<_version> The interface of the library is defined in [nrLDPC_defs.h](file://../nrLDPC_defs.h). The code loading the LDPC library is in [nrLDPC_load.c](file://../nrLDPC_load.c), in function `load_nrLDPClib`, which must be called at init time. -*Note: LDPC segment coding libraries are not loaded directly by OAI but by the intermediate library `libldpc.so` which is implementing the LDPC slot coding interface using a LDPC segment coding library.* +LDPC segment coding libraries are not loaded directly by OAI but are statically linked in libraries implementing the LDPC slot coding interface using an adaptation layer between the slot coding interface and the segment coding interface. +This way, these libraries can be loaded to implement the slot coding interface as well as the segment coding interface in `ldpctest`. ### Selecting the LDPC library at run time -By default the function `int load_nrLDPClib(void)` looks for `libldpc_optim8segmulti.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: +By default the function `int load_nrLDPClib(void)` looks for `libldpc.so`, this default behavior can be changed using the oai loader configuration options in the configuration file or from the command line as shown below: #### Examples of ldpc shared lib selection when running nr softmodem's: -loading `libldpc_optim8seg.so` instead of `libldpc_optim8segmulti.so`: +loading `libldpc_optim8seg.so` instead of `libldpc.so`: ``` -./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _optim8seg +./nr-softmodem -O libconfig:gnb.band78.tm1.106PRB.usrpx300.conf:dbgl5 --loader.ldpc.shlibversion _optim8seg ....................... -[CONFIG] nrLDPC_coding_segment.segment_shlibversion set to default value "_optim8segmulti" -[LIBCONFIG] nrLDPC_coding_segment: 1/1 parameters successfully set, (0 to default value) -[CONFIG] segment_shlibversion set to _optim8seg from command line -[CONFIG] nrLDPC_coding_segment 1 options set from command line +[CONFIG] loader.ldpc.shlibversion set to default value "" +[LIBCONFIG] loader.ldpc: 2/2 parameters successfully set, (1 to default value) +[CONFIG] shlibversion set to _optim8seg from command line +[CONFIG] loader.ldpc 1 options set from command line [LOADER] library libldpc_optim8seg.so successfully loaded ........................ ``` -loading `libldpc_cl.so` instead of `libldpc_optim8segmulti.so`: +loading `libldpc_cl.so` instead of `libldpc.so`: `make ldpc_cl` @@ -161,7 +159,7 @@ Built target ldpc_cl At runtime, to successfully use hardware acceleration via OpenCL, you need to install vendor specific packages which deliver the required drivers and tools to make use of their GPU (Nvidia, Intel...) , fpga (Xilinx, Intel) or CPU (Intel, AMD, ARM...) through OpenCL. -`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --nrLDPC_coding_segment.segment_shlibversion _cl` +`./nr-softmodem -O libconfig:gnb.band78.sa.fr1.106PRB.usrpb210.conf:dbgl5 --rfsim --rfsimulator.serveraddr server --log_config.gtpu_log_level info --loader.ldpc.shlibversion _cl` ``` ------------------------------------------------ @@ -196,12 +194,12 @@ At runtime, to successfully use hardware acceleration via OpenCL, you need to in ----------------------------------------------------------------- ``` -`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --nrLDPC_coding_segment.segment_shlibversion _cl --log_config.hw_log_level info` +`./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim -O libconfig:/usr/local/oai/conf/nrue_sim.conf:dbgl5 --loader.ldpc.shlibversion _cl --log_config.hw_log_level info` ``` ............................................................ [CONFIG] segment_shlibversion set to _cl from command line -[CONFIG] nrLDPC_coding_segment 1 options set from command line +[CONFIG] loader.ldpc 1 options set from command line [LOADER] library libldpc_cl.so successfully loaded [HW] Platform 0, OpenCL profile FULL_PROFILE [HW] Platform 0, OpenCL version OpenCL 2.1 LINUX @@ -254,7 +252,7 @@ SNR0 -2.000000: [CONFIG] log_config: 16/16 parameters successfully set log init done [CONFIG] loader: 2/2 parameters successfully set -[CONFIG] loader.ldpc: 1/2 parameters successfully set +[CONFIG] loader.ldpc: 2/2 parameters successfully set [LOADER] library libldpc_cuda.so successfully loaded ................................... ``` diff --git a/openair1/PHY/CODING/TESTBENCH/ldpctest.c b/openair1/PHY/CODING/TESTBENCH/ldpctest.c index 71c2f1af27240345dc389037bd95b7219a663e06..0fa81f360bb01dbc30f7b9cbfe25979a6ac85287 100644 --- a/openair1/PHY/CODING/TESTBENCH/ldpctest.c +++ b/openair1/PHY/CODING/TESTBENCH/ldpctest.c @@ -403,7 +403,7 @@ int main(int argc, char *argv[]) { short block_length=8448; // decoder supports length: 1201 -> 1280, 2401 -> 2560 // default to check output inside ldpc, the NR version checks the outer CRC defined by 3GPP - char *ldpc_version = "_optim8segmulti"; + char *ldpc_version = ""; /* version of the ldpc decoder library to use (XXX suffix to use when loading libldpc_XXX.so */ short max_iterations=5; int n_segments=1; diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt index ed8de90594990105cf21c57d60af9704626f1827..f96a2cfacada2e46861ad82099a00e4016eee41e 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/CMakeLists.txt @@ -1,39 +1,10 @@ -add_library(nr_coding_segment_utils OBJECT - nrLDPC_load.c +add_library(ldpc_segment OBJECT nr_rate_matching.c -) - -add_library(nr_coding_segment_decoder OBJECT nrLDPC_coding_segment_decoder.c -) - -add_library(nr_coding_segment_encoder OBJECT nrLDPC_coding_segment_encoder.c ) #ensure that the T header files are generated before targets depending on them if (${T_TRACER}) - add_dependencies(nr_coding_segment_utils generate_T) - add_dependencies(nr_coding_segment_decoder generate_T) - add_dependencies(nr_coding_segment_encoder generate_T) + add_dependencies(ldpc_segment generate_T) endif (${T_TRACER}) - -add_library(ldpc MODULE) -target_link_libraries(ldpc PRIVATE - nr_coding_segment_decoder - nr_coding_segment_encoder - nr_coding_segment_utils -) -set_target_properties(ldpc PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) - -add_dependencies(nr-softmodem ldpc) -add_dependencies(nr-uesoftmodem ldpc) -add_dependencies(nr_ulsim ldpc) -add_dependencies(nr_ulschsim ldpc) -add_dependencies(nr_dlsim ldpc) -add_dependencies(nr_dlschsim ldpc) - -add_dependencies(ldpc ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) -if (ENABLE_LDPC_CUDA) - add_dependencies(ldpc ldpc_cuda) -endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c index 3d228da0089c441cae930af0a3c6d793856e056b..9b36197e45ee9ea22a04fbfe55f4d50d5d6e8cdf 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c @@ -120,9 +120,6 @@ typedef struct nrLDPC_decoding_parameters_s { time_stats_t *p_ts_ldpc_decode; } nrLDPC_decoding_parameters_t; -// Global var to limit the rework of the dirty legacy code -ldpc_interface_t ldpc_interface_segment; - static void nr_process_decode_segment(void *arg) { nrLDPC_decoding_parameters_t *rdata = (nrLDPC_decoding_parameters_t *)arg; @@ -219,7 +216,7 @@ static void nr_process_decode_segment(void *arg) ////////////////////////////////// pl =====> llrProcBuf ////////////////////////////////// int decodeIterations = - ldpc_interface_segment.LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); + LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode); if (decodeIterations <= p_decoderParms->numMaxIter) { memcpy(rdata->c, llrProcBuf, K >> 3); @@ -285,19 +282,11 @@ int nrLDPC_prepare_TB_decoding(nrLDPC_slot_decoding_parameters_t *nrLDPC_slot_de int32_t nrLDPC_coding_init(void) { - char *segment_shlibversion = NULL; - paramdef_t LoaderParams[] = { - {"segment_shlibversion", NULL, 0, .strptr = &segment_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL}}; - config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_segment"); - load_LDPClib(segment_shlibversion, &ldpc_interface_segment); - return 0; } int32_t nrLDPC_coding_shutdown(void) { - free_LDPClib(&ldpc_interface_segment); - return 0; } diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c index adf9dd6624109309b6a898893ef8ea2a5b0f8b3c..95141e88454a9873f0a90e18d8cdb4dddb23da83 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c @@ -73,7 +73,7 @@ static void ldpc8blocks_coding_segment(void *p) for (int r = 0; r < nrLDPC_TB_encoding_parameters->C; r++) c[r] = nrLDPC_TB_encoding_parameters->segments[r].c; start_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num * 8].ts_ldpc_encode); - ldpc_interface_segment.LDPCencoder(c, d, impp); + LDPCencoder(c, d, impp); stop_meas(&nrLDPC_TB_encoding_parameters->segments[impp->macro_num * 8].ts_ldpc_encode); // Compute where to place in output buffer that is concatenation of all segments diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c index a25b6d4b577fce675d058e1de1c01b97615dc459..46919e19834e80febbbc162eb83a3dd35daa0003 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nr_rate_matching.c @@ -380,24 +380,22 @@ int nr_rate_matching_ldpc(uint32_t Tbslbrm, uint8_t rvidx, uint32_t E) { - uint32_t Ncb, ind, k = 0, Nref, N; - if (C == 0) { - LOG_E(PHY, "nr_rate_matching: invalid parameters (C %d\n", C); + LOG_E(PHY, "nr_rate_matching: invalid parameter C %d\n", C); return -1; } - // Bit selection - N = (BG == 1) ? (66 * Z) : (50 * Z); - + //Bit selection + uint32_t N = (BG == 1) ? (66 * Z) : (50 * Z); + uint32_t Ncb; if (Tbslbrm == 0) Ncb = N; else { - Nref = 3 * Tbslbrm / (2 * C); // R_LBRM = 2/3 + uint32_t Nref = 3 * Tbslbrm / (2 * C); //R_LBRM = 2/3 Ncb = min(N, Nref); } - ind = (index_k0[BG - 1][rvidx] * Ncb / N) * Z; + uint32_t ind = (index_k0[BG - 1][rvidx] * Ncb / N) * Z; #ifdef RM_DEBUG printf("nr_rate_matching_ldpc: E %u, F %u, Foffset %u, k0 %u, Ncb %u, rvidx %d, Tbslbrm %u\n", @@ -430,6 +428,7 @@ int nr_rate_matching_ldpc(uint32_t Tbslbrm, if (ind >= Foffset && ind < (F + Foffset)) ind = F + Foffset; + uint32_t k = 0; if (ind < Foffset) { // case where we have some bits before the filler and the rest after memcpy((void *)e, (void *)(d + ind), Foffset - ind); @@ -476,28 +475,22 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm, uint32_t F, uint32_t Foffset) { - uint32_t Ncb, ind, k, Nref, N; - -#ifdef RM_DEBUG - int nulled = 0; -#endif - if (C == 0) { - LOG_E(PHY, "nr_rate_matching: invalid parameters (C %d\n", C); + LOG_E(PHY, "nr_rate_matching: invalid parameter C %d\n", C); return -1; } - // Bit selection - N = (BG == 1) ? (66 * Z) : (50 * Z); - + //Bit selection + uint32_t N = (BG == 1) ? (66 * Z) : (50 * Z); + uint32_t Ncb; if (Tbslbrm == 0) Ncb = N; else { - Nref = (3 * Tbslbrm / (2 * C)); // R_LBRM = 2/3 + uint32_t Nref = (3 * Tbslbrm / (2 * C)); //R_LBRM = 2/3 Ncb = min(N, Nref); } - ind = (index_k0[BG - 1][rvidx] * Ncb / N) * Z; + uint32_t ind = (index_k0[BG - 1][rvidx] * Ncb / N) * Z; if (Foffset > E) { LOG_E(PHY, "nr_rate_matching: invalid parameters (Foffset %d > E %d)\n", Foffset, E); return -1; @@ -521,8 +514,7 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm, if (clear == 1) memset(d, 0, Ncb * sizeof(int16_t)); - k = 0; - + uint32_t k = 0; if (ind < Foffset) for (; (ind < Foffset) && (k < E); ind++) { #ifdef RM_DEBUG @@ -566,6 +558,5 @@ int nr_rate_matching_ldpc_rx(uint32_t Tbslbrm, #endif } } - return 0; } diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt index f51eb9d8ca43c7dffa2fbcc5334eba71d705abe2..0325858389f2b07c58ee0c14f6be12a25b23bc1c 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/CMakeLists.txt @@ -10,6 +10,9 @@ if (ENABLE_LDPC_XDMA) add_library(ldpc_xdma MODULE nrLDPC_coding_xdma_offload.c nrLDPC_coding_xdma.c + ../nrLDPC_coding_segment/nr_rate_matching.c + ../nrLDPC_coding_segment/nrLDPC_coding_segment_encoder.c + ../../nrLDPC_encoder/ldpc_encoder_optim8segmulti.c ) target_include_directories(ldpc_xdma PRIVATE ../nrLDPC_coding_segment) @@ -18,10 +21,7 @@ if (ENABLE_LDPC_XDMA) add_dependencies(ldpc_xdma generate_T) endif (${T_TRACER}) - target_link_libraries(ldpc_xdma PRIVATE - nr_coding_segment_encoder - nr_coding_segment_utils - ) + target_link_libraries(ldpc_xdma PRIVATE ldpc_gen_HEADERS) set_target_properties(ldpc_xdma PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) add_dependencies(nr-softmodem ldpc_xdma) @@ -31,9 +31,4 @@ if (ENABLE_LDPC_XDMA) add_dependencies(nr_dlsim ldpc_xdma) add_dependencies(nr_dlschsim ldpc_xdma) - add_dependencies(ldpc_xdma ldpc_orig ldpc_optim ldpc_optim8seg ldpc_optim8segmulti) - if (ENABLE_LDPC_CUDA) - add_dependencies(ldpc_xdma ldpc_cuda) - endif() - endif() diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c index 5df0bd4406f82b65edc2c91f8f2850c9065bf95c..7960215ab7bb8ba76f081196f82eb9d4c2e375a1 100644 --- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c +++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c @@ -62,7 +62,6 @@ #include "PHY/CODING/nrLDPC_coding/nrLDPC_coding_interface.h" // Global var to limit the rework of the dirty legacy code -ldpc_interface_t ldpc_interface_segment; int num_threads_prepare_max = 0; char *user_device = NULL; char *enc_read_device = NULL; @@ -98,10 +97,8 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args); int32_t nrLDPC_coding_init(void) { - char *encoder_shlibversion = NULL; paramdef_t LoaderParams[] = { {"num_threads_prepare", NULL, 0, .iptr = &num_threads_prepare_max, .defintval = 0, TYPE_INT, 0, NULL}, - {"encoder_shlibversion", NULL, 0, .strptr = &encoder_shlibversion, .defstrval = "_optim8segmulti", TYPE_STRING, 0, NULL}, {"user_device", NULL, 0, .strptr = &user_device, .defstrval = DEVICE_NAME_DEFAULT_USER, TYPE_STRING, 0, NULL}, {"enc_read_device", NULL, 0, .strptr = &enc_read_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_READ, TYPE_STRING, 0, NULL}, {"enc_write_device", NULL, 0, .strptr = &enc_write_device, .defstrval = DEVICE_NAME_DEFAULT_ENC_WRITE, TYPE_STRING, 0, NULL}, @@ -110,13 +107,11 @@ int32_t nrLDPC_coding_init(void) config_get(config_get_if(), LoaderParams, sizeofArray(LoaderParams), "nrLDPC_coding_xdma"); AssertFatal(num_threads_prepare_max != 0, "nrLDPC_coding_xdma.num_threads_prepare was not provided"); - load_LDPClib(encoder_shlibversion, &ldpc_interface_segment); return 0; } int32_t nrLDPC_coding_shutdown(void) { - free_LDPClib(&ldpc_interface_segment); return 0; } diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_load.c b/openair1/PHY/CODING/nrLDPC_load.c similarity index 100% rename from openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_load.c rename to openair1/PHY/CODING/nrLDPC_load.c diff --git a/openair1/PHY/MODULATION/nr_modulation.c b/openair1/PHY/MODULATION/nr_modulation.c index e8b215acccaa9dd1333fdc700c83af1e4e71fb23..6fd4ea76b3ba206a147677f41695893a825297f2 100644 --- a/openair1/PHY/MODULATION/nr_modulation.c +++ b/openair1/PHY/MODULATION/nr_modulation.c @@ -517,7 +517,7 @@ void nr_layer_precoder_simd(const int n_layers, prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re; prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im; - const simde__m256i x = simde_mm256_loadu_epi32(&txdataF_res_mapped[nl][symbol][sc]); + const simde__m256i x = simde_mm256_loadu_si256(&txdataF_res_mapped[nl][symbol][sc]); // Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size const simde__m256i w_c = simde_mm256_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w @@ -561,7 +561,7 @@ void nr_layer_precoder_simd(const int n_layers, prec_weight.r = pmi_pdu->weights[nl][ant].precoder_weight_Re; prec_weight.i = pmi_pdu->weights[nl][ant].precoder_weight_Im; - const simde__m128i x = simde_mm_loadu_epi32(&txdataF_res_mapped[nl][symbol][sc]); + const simde__m128i x = simde_mm_loadu_si128(&txdataF_res_mapped[nl][symbol][sc]); // Rearrange precoding matrix weight to match complex multiplication and broadcast it to match SIMD size const simde__m128i w_c = simde_mm_set1_epi32(c16toI32(c16conj(prec_weight))); // broadcast conjugate of w diff --git a/openair1/PHY/TOOLS/tools_defs.h b/openair1/PHY/TOOLS/tools_defs.h index b456fab82b97eddc45bba14f5e0c1e1043097858..93b07a60de31f60e34fee98f1089c312b34f2aa9 100644 --- a/openair1/PHY/TOOLS/tools_defs.h +++ b/openair1/PHY/TOOLS/tools_defs.h @@ -401,8 +401,8 @@ static __attribute__((always_inline)) inline void mult_complex_vectors(const c16 int i; // do 8 multiplications at a time for (i = 0; i < size - 7; i += 8) { - const simde__m256i i1 = simde_mm256_loadu_epi32((simde__m256i *)(in1 + i)); - const simde__m256i i2 = simde_mm256_loadu_epi32((simde__m256i *)(in2 + i)); + const simde__m256i i1 = simde_mm256_loadu_si256((simde__m256i *)(in1 + i)); + const simde__m256i i2 = simde_mm256_loadu_si256((simde__m256i *)(in2 + i)); const simde__m256i i2swap = simde_mm256_shuffle_epi8(i2, complex_shuffle256); const simde__m256i i2conj = simde_mm256_sign_epi16(i2, conj256); const simde__m256i re = simde_mm256_madd_epi16(i1, i2conj); @@ -412,8 +412,8 @@ static __attribute__((always_inline)) inline void mult_complex_vectors(const c16 simde_mm256_blend_epi16(simde_mm256_srai_epi32(re, shift), simde_mm256_slli_epi32(im, 16 - shift), 0xAA)); } if (size - i > 4) { - const simde__m128i i1 = simde_mm_loadu_epi32((simde__m128i *)(in1 + i)); - const simde__m128i i2 = simde_mm_loadu_epi32((simde__m128i *)(in2 + i)); + const simde__m128i i1 = simde_mm_loadu_si128((simde__m128i *)(in1 + i)); + const simde__m128i i2 = simde_mm_loadu_si128((simde__m128i *)(in2 + i)); const simde__m128i i2swap = simde_mm_shuffle_epi8(i2, *(simde__m128i *)&complex_shuffle256); const simde__m128i i2conj = simde_mm_sign_epi16(i2, *(simde__m128i *)&conj256); const simde__m128i re = simde_mm_madd_epi16(i1, i2conj); diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index fc09f23bd645c91a05df21cb9727cf1727de9e64..ab3a044ac6c21612c5c47967e1ebfa943218acf5 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -125,7 +125,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { @@ -147,10 +147,9 @@ extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration /* specific dlsim DL preprocessor: uses rbStart/rbSize/mcs/nrOfLayers from command line of dlsim */ int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLayers = 1, g_pmi = 0; -void nr_dlsim_preprocessor(module_id_t module_id, - frame_t frame, - sub_frame_t slot) { +void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot) +{ NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0]; AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n"); NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl; @@ -326,7 +325,6 @@ int main(int argc, char **argv) gNB_MAC_INST *gNB_mac; NR_UE_MAC_INST_t *UE_mac; int cyclic_prefix_type = NFAPI_CP_NORMAL; - int run_initial_sync=0; int loglvl=OAILOG_WARNING; //float target_error_rate = 0.01; @@ -357,7 +355,7 @@ int main(int argc, char **argv) FILE *scg_fd=NULL; - while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -1) { + while ((c = getopt(argc, argv, "--:O:f:hA:p:f:g:i:n:s:S:t:v:x:y:z:o:H:M:N:F:GR:d:PI:L:a:b:e:m:w:T:U:q:X:Y:Z:")) != -1) { /* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */ /* with this opstring getopt returns 1 for non-option arguments, refer to 'man 3 getopt' */ @@ -537,11 +535,6 @@ int main(int argc, char **argv) gNBthreads[sizeof(gNBthreads)-1]=0; break; - case 'Y': - run_initial_sync=1; - //target_error_rate=0.1; - slot = 0; - break; case 'Z' : filename_csv = strdup(optarg); AssertFatal(filename_csv != NULL, "strdup() error: errno %d\n", errno); @@ -551,6 +544,10 @@ int main(int argc, char **argv) delay = atoi(optarg); break; + case 'H': + slot = atoi(optarg); + break; + default: case 'h': printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n", @@ -584,6 +581,7 @@ int main(int argc, char **argv) printf("-f raw file containing RRC configuration (generated by gNB)\n"); printf("-g Channel model: [A] TDLA30, [B] TDLB100, [C] TDLC300, e.g. -g A\n"); printf("-h This message\n"); + printf("-H Slot number\n"); printf("-i Change channel estimation technique. Arguments list: Frequency domain {0:Linear interpolation, 1:PRB based averaging}, Time domain {0:Estimates of last DMRS symbol, 1:Average of DMRS symbols}\n"); printf("-m Numerology\n"); printf("-n Number of frames to simulate\n"); @@ -606,13 +604,12 @@ int main(int argc, char **argv) printf("-T Enable PTRS, arguments list L_PTRS{0,1,2} K_PTRS{2,4}, e.g. -T 2 0 2 \n"); printf("-U Change DMRS Config, arguments list DMRS TYPE{0=A,1=B} DMRS AddPos{0:2} DMRS ConfType{1:2}, e.g. -U 3 0 2 1 \n"); printf("-X gNB thread pool configuration, n => no threads\n"); - printf("-Y Run initial sync in UE\n"); printf("-Z Output filename (.csv format) for stats\n"); exit (-1); break; } } - +printf("%d\n", slot); logInit(); set_glog(loglvl); /* initialize the sin table */ @@ -648,6 +645,11 @@ int main(int argc, char **argv) fill_scc_sim(scc, &ssb_bitmap, N_RB_DL, N_RB_DL, mu, mu); fix_scc(scc, ssb_bitmap); + frame_structure_t frame_structure = {0}; + frame_type_t frame_type = TDD; + config_frame_structure(mu, scc, get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon), frame_type, &frame_structure); + AssertFatal(is_dl_slot(slot, &frame_structure), "The slot selected is not DL. Can't run DLSIM\n"); + // TODO do a UECAP for phy-sim nr_pdsch_AntennaPorts_t pdsch_AntennaPorts = {0}; pdsch_AntennaPorts.N1 = n_tx > 1 ? n_tx >> 1 : 1; @@ -658,6 +660,7 @@ int main(int argc, char **argv) .minRXTXTIME = 6, .do_CSIRS = 0, .do_SRS = 0, + .maxMIMO_layers = g_nrOfLayers, .force_256qam_off = false, .timer_config.sr_ProhibitTimer = 0, .timer_config.sr_TransMax = 64, @@ -843,11 +846,7 @@ int main(int argc, char **argv) UE->nrLDPC_coding_interface = gNB->nrLDPC_coding_interface; UE->max_ldpc_iterations = max_ldpc_iterations; init_nr_ue_phy_cpu_stats(&UE->phy_cpu_stats); - - if (run_initial_sync==1) - UE->is_synchronized = 0; - else - UE->is_synchronized = 1; + UE->is_synchronized = 1; if (init_nr_ue_signal(UE, 1) != 0) { @@ -1048,15 +1047,13 @@ int main(int argc, char **argv) msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.bchPayload=0x001234; msgDataTx->ssb[0].ssb_pdu.ssb_pdu_rel15.SsbBlockIndex = 0; msgDataTx->gNB = gNB; - if (run_initial_sync) { - nr_common_signal_procedures(gNB,frame,slot,msgDataTx->ssb[0].ssb_pdu); - } else { - start_meas(&gNB->phy_proc_tx); - phy_procedures_gNB_TX(msgDataTx,frame,slot,1); - stop_meas(&gNB->phy_proc_tx); - } + + start_meas(&gNB->phy_proc_tx); + phy_procedures_gNB_TX(msgDataTx,frame,slot,1); + stop_meas(&gNB->phy_proc_tx); + int txdataF_offset = slot * frame_parms->samples_per_slot_wCP; - + if (n_trials==1) { LOG_M("txsigF0.m","txsF0=", &gNB->common_vars.txdataF[0][0][txdataF_offset +2 * frame_parms->ofdm_symbol_size], diff --git a/openair1/SIMULATION/NR_PHY/psbchsim.c b/openair1/SIMULATION/NR_PHY/psbchsim.c index d1f799334653de2463dc5442767b269246c8a74d..23803e133fa8f848691431a31803b63d3598039f 100644 --- a/openair1/SIMULATION/NR_PHY/psbchsim.c +++ b/openair1/SIMULATION/NR_PHY/psbchsim.c @@ -51,7 +51,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 301beb19f5adaaed52090e08fac914698df19019..4f07bbc7aacde03c1ba5621adb0592c5261aadc1 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -126,7 +126,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { @@ -626,6 +626,11 @@ int main(int argc, char *argv[]) fill_scc_sim(scc, &ssb_bitmap, N_RB_DL, N_RB_DL, mu, mu); fix_scc(scc,ssb_bitmap); + frame_structure_t frame_structure = {0}; + frame_type_t frame_type = TDD; + config_frame_structure(mu, scc, get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon), frame_type, &frame_structure); + AssertFatal(is_ul_slot(slot, &frame_structure), "The slot selected is not UL. Can't run ULSIM\n"); + // TODO do a UECAP for phy-sim const nr_mac_config_t conf = {.pdsch_AntennaPorts = {.N1 = 1, .N2 = 1, .XP = 1}, .pusch_AntennaPorts = n_rx, diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 7fed0969710c4c8727d599e2b7e4222cabd93d87..2f59cb62d6c527c2f49d21e6994dcd3eb6b2ddce 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -138,12 +138,6 @@ typedef enum BEARER_CONTEXT_STATUS_e { BEARER_RESUME, } BEARER_CONTEXT_STATUS_t; -typedef enum activity_notification_level_e { - ANL_DRB = 0, - ANL_PDU_SESSION, - ANL_UE, -} activity_notification_level_t; - typedef enum cell_group_id_e { MCG = 0, SCG, @@ -258,10 +252,16 @@ typedef struct e1ap_setup_fail_s { criticality_diagnostics_t *crit_diag; } e1ap_setup_fail_t; -typedef struct up_params_s { +typedef struct UP_TL_information_s { in_addr_t tlAddress; - long teId; - int cell_group_id; + int32_t teId; +} UP_TL_information_t; + +typedef struct up_params_s { + // Transport layer info + UP_TL_information_t tl_info; + // Cell Group ID (M) + cell_group_id_t cell_group_id; } up_params_t; /* IE SDAP Configuration (clause 9.3.1.39 of 3GPP TS 38.463) */ @@ -331,38 +331,63 @@ typedef struct qos_flow_level_qos_parameters_s { ngran_allocation_retention_priority_t alloc_reten_priority; // additional members should be added!! } qos_flow_level_qos_parameters_t; +// QoS Flow QoS Parameters List 9.3.1.25 typedef struct qos_flow_setup_e { long qfi; // qos flow identifier qos_flow_level_qos_parameters_t qos_params; } qos_flow_to_setup_t; -/* DRB To Setup List according to 3GPP TS 38.463 */ +// 9.3.1.60 QoS Flow Mapping Indication +typedef enum qos_flow_mapping_indication_e { + QF_UL = 0, + QF_DL, + QF_BOTH +} qos_flow_mapping_indication_t; + +typedef struct qos_flow_list_s { + long qfi; // qos flow identifier + qos_flow_mapping_indication_t *indication; +} qos_flow_list_t; + +/** + * DRB To Setup List according to 3GPP TS 38.463 + */ typedef struct DRB_nGRAN_to_setup_s { - /* DRB ID (clause 9.3.1.16) */ + // DRB ID (M) (clause 9.3.1.16) long id; - - /* SDAP Configuration (clause 9.3.1.39) */ + // SDAP Configuration (M) (clause 9.3.1.39) bearer_context_sdap_config_t sdap_config; - /* PDCP Configuration (clause 9.3.1.38) */ + // PDCP Configuration (M) (clause 9.3.1.38) bearer_context_pdcp_config_t pdcp_config; - - /* DRB Data Forwarding Information (clause 9.3.2.6) */ - /* Transport Layer Address (clause 9.3.2.4) */ - in_addr_t tlAddress; - /* GTP-TEID (clause 9.3.2.3) */ - int teId; - /* DL UP Transport Layer Information (clause 9.3.2.1) */ - int numDlUpParam; - up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; - - /* Cell Group Information (clause 9.3.1.11) */ + // DRB Inactivity Timer (O) + int *drb_inactivity_timer; + // Cell Group Information (M) (clause 9.3.1.11) int numCellGroups; cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; + // QoS Flows Information To Be Setup (M) (clause 9.3.1.25, 9.3.1.26) + int numQosFlow2Setup; + qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; +} DRB_nGRAN_to_setup_t; - /* DRB QoS Flows Parameters (clause 9.3.1.26) */ +/** + * DRB To Modify List according to 3GPP TS 38.463 + */ +typedef struct DRB_nGRAN_to_modify_s { + // DRB ID (M) (clause 9.3.1.16) + long id; + // SDAP Configuration (O) (clause 9.3.1.39) + bearer_context_sdap_config_t *sdap_config; + // PDCP Configuration (O) (clause 9.3.1.38) + bearer_context_pdcp_config_t *pdcp_config; + // PDCP SN Status Request (O) + bool pdcp_sn_status_requested; + // DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1) + int numDlUpParam; + up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; + // QoS Flows Information To Modify (O) (clause 9.3.1.25, 9.3.1.26) int numQosFlow2Setup; qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; -} DRB_nGRAN_to_setup_t, DRB_nGRAN_to_mod_t; +} DRB_nGRAN_to_mod_t; typedef enum e1ap_indication_e { SECURITY_REQUIRED = 0, @@ -377,48 +402,108 @@ typedef struct security_indication_s { long maxIPrate; } security_indication_t; -typedef struct UP_TL_information_s { - in_addr_t tlAddress; - int32_t teId; -} UP_TL_information_t; +// Security Information (9.3.1.10) +typedef struct security_information_s { + uint64_t cipheringAlgorithm; + uint64_t integrityProtectionAlgorithm; + char encryptionKey[E1AP_SECURITY_KEY_SIZE]; + char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE]; +} security_information_t; /** * PDU Session Resource To Setup List (clause 9.3.3.10) - * PDU Session Resource To Modify List (clause 9.3.3.11) -*/ + */ typedef struct pdu_session_to_setup_s { + // PDU Session ID (M) long sessionId; + // PDU Session Type (M) long sessionType; + // S-NSSAI (M) e1ap_nssai_t nssai; + // Security Indication (M) security_indication_t securityIndication; + // PDU Session Resource DL Aggregate Maximum Bit Rate (O) + long *dlAggregateMaxBitRate; + // NG UL UP Transport Layer Information (M) UP_TL_information_t UP_TL_information; - long numDRB2Setup; + // PDU Session Inactivity Timer (O) + int *inactivityTimer; + // DRB To Setup List (M) + int numDRB2Setup; + // DRB To Setup Item (1..<E1AP_MAX_NUM_DRBS>) + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; +} pdu_session_to_setup_t; + +/** + * PDU Session Resource To Modify List (clause 9.3.3.11) + */ +typedef struct pdu_session_to_mod_s { + // PDU Session ID (M) + long sessionId; + // Security Indication (O) + security_indication_t *securityIndication; + // NG UL UP Transport Layer Information (O) + UP_TL_information_t *UP_TL_information; + // DRB To Setup List (0..1) + int numDRB2Setup; + // DRB To Setup Item (1..<E1AP_MAX_NUM_DRBS>) DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; + // DRB To Modify List (0..1) long numDRB2Modify; + // DRB To Modify Item (1..<E1AP_MAX_NUM_DRBS>) DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; -} pdu_session_to_setup_t, pdu_session_to_mod_t; +} pdu_session_to_mod_t; /** * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 - * out of simplicity, this same struct is used for clause 9.2.2.4 - * i.e. Bearer Context Modification Request message */ typedef struct e1ap_bearer_setup_req_s { + // gNB-CU-CP UE E1AP ID (M) uint32_t gNB_cu_cp_ue_id; - uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only - uint64_t cipheringAlgorithm; - uint64_t integrityProtectionAlgorithm; - char encryptionKey[E1AP_SECURITY_KEY_SIZE]; - char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE]; - long ueDlAggMaxBitRate; + // Security Information (M) + security_information_t secInfo; + // UE DL Aggregate Maximum Bit Rate (M) + long ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + long *ueDlMaxIPBitRate; + // Serving PLMN (M) PLMN_ID_t servingPLMNid; + // Bearer Context Status Change (O) BEARER_CONTEXT_STATUS_t bearerContextStatus; - activity_notification_level_t activityNotificationLevel; + // UE Inactivity Timer (O) + int *inactivityTimerUE; + // NG-RAN PDU Session Resource To Setup List (M) int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; +} e1ap_bearer_setup_req_t; + +/** + * Bearer Context Modification Request, clause 9.2.2.4 of 3GPP TS 38.463 + */ +typedef struct e1ap_bearer_mod_req_s { + // gNB-CU-CP UE E1AP ID (M) + uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) + uint32_t gNB_cu_up_ue_id; + // Security Information (O) + security_information_t *secInfo; + // UE DL Aggregate Maximum Bit Rate (O) + uint32_t *ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + uint32_t *ueDlMaxIPBitRate; + // Bearer Context Status Change (O) + BEARER_CONTEXT_STATUS_t *bearerContextStatus; + // UE Inactivity Timer (O) + int *inactivityTimer; + // Data Discard Required (O) + bool dataDiscardRequired; + // NG-RAN PDU Session Resource To Setup List (O) + int numPDUSessions; + pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; + // NG-RAN PDU Session Resource To Modify List (O) int numPDUSessionsMod; pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; -} e1ap_bearer_setup_req_t, e1ap_bearer_mod_req_t; +} e1ap_bearer_mod_req_t; typedef struct e1ap_bearer_release_cmd_s { uint32_t gNB_cu_cp_ue_id; @@ -432,43 +517,61 @@ typedef struct e1ap_bearer_release_cplt_s { uint32_t gNB_cu_up_ue_id; } e1ap_bearer_release_cplt_t; -typedef struct qos_flow_setup_s { - long qfi; -} qos_flow_setup_t; - typedef struct DRB_nGRAN_setup_s { + // DRB ID (M) long id; int numUpParam; up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (M) int numQosFlowSetup; - qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_setup_t; +/* DRB Modified Item */ typedef struct DRB_nGRAN_modified_s { + // DRB ID (M) long id; + // UL UP Parameters (O) + int numUpParam; + up_params_t ul_UP_Params[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (O) + int numQosFlowSetup; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + // Old QoS Flow List (O) + int numOldQosFlow; + qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_modified_t; typedef struct DRB_nGRAN_failed_s { long id; - long cause_type; - long cause; + e1ap_cause_t cause; } DRB_nGRAN_failed_t; typedef struct pdu_session_setup_s { long id; - in_addr_t tlAddress; - long teId; + // Transport layer info + UP_TL_information_t tl_info; int numDRBSetup; DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; int numDRBFailed; DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS]; } pdu_session_setup_t; +/* PDU Session Resource Modified List (9.3.3.17) */ typedef struct pdu_session_modif_s { + // PDU Session ID (M) long id; - // setup as part of PDU session modification not supported yet + // Security Result (O) + e1ap_indication_t *integrityProtectionIndication; + e1ap_indication_t *confidentialityProtectionIndication; + // NG DL UP Transport Layer Information (O) + UP_TL_information_t *ng_DL_UP_TL_info; + // DRB Modified List (O) int numDRBModified; DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; + // DRB Setup List (O) + int numDRBSetup; + DRB_nGRAN_setup_t DRBnGRanSetupList[E1AP_MAX_NUM_DRBS]; } pdu_session_modif_t; typedef struct e1ap_bearer_setup_resp_s { @@ -479,8 +582,11 @@ typedef struct e1ap_bearer_setup_resp_s { } e1ap_bearer_setup_resp_t; typedef struct e1ap_bearer_modif_resp_s { + // gNB-CU-CP UE E1AP ID (M) uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) uint32_t gNB_cu_up_ue_id; + // NG-RAN PDU Session Resource Modified List (O) int numPDUSessionsMod; pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; } e1ap_bearer_modif_resp_t; diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 36c3ad4f76b1676524045b0994bf10e57fe9f7da..53740c1bde4e1d081ea7c1c7efa9e445c7fed55d 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -563,24 +563,25 @@ typedef enum F1AP_ResetType_e { F1AP_RESET_PART_OF_F1_INTERFACE } f1ap_ResetType_t; +typedef struct f1ap_ue_to_reset_t { + uint32_t *gNB_CU_ue_id; + uint32_t *gNB_DU_ue_id; +} f1ap_ue_to_reset_t; + typedef struct f1ap_reset_t { uint64_t transaction_id; f1ap_Cause_t cause; long cause_value; f1ap_ResetType_t reset_type; - struct { - uint32_t gNB_CU_ue_id; - uint32_t gNB_DU_ue_id; - } ue_to_reset[F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET]; + int num_ue_to_reset; + f1ap_ue_to_reset_t *ue_to_reset; // array of num_ue_to_reset elements } f1ap_reset_t; typedef struct f1ap_reset_ack_t { - uint64_t transaction_id; - struct { - uint32_t gNB_CU_ue_id; - uint32_t gNB_DU_ue_id; - } ue_to_reset[F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET]; - uint16_t criticality_diagnostics; + uint64_t transaction_id; + int num_ue_to_reset; + f1ap_ue_to_reset_t *ue_to_reset; // array of num_ue_to_reset elements + //uint16_t criticality_diagnostics; // not implemented as of now } f1ap_reset_ack_t; #endif /* F1AP_MESSAGES_TYPES_H_ */ diff --git a/openair2/E1AP/CMakeLists.txt b/openair2/E1AP/CMakeLists.txt index 5849a32fe56b88a133f15268d8c938284a755821..eb3bd0f5466d2f9c6fd7b62d1d38581b8e44b1b7 100644 --- a/openair2/E1AP/CMakeLists.txt +++ b/openair2/E1AP/CMakeLists.txt @@ -10,3 +10,7 @@ target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR}) if(ENABLE_TESTS) add_subdirectory(tests) endif() + +if(ENABLE_TESTS) + target_compile_definitions(e1ap PRIVATE E1AP_LOG_ERRORS) +endif() diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 95046cb65297866a45c71992c55b92c433ad2e50..0b5582ea3964355105e33a5ff9987b9858ac2ca4 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -219,6 +219,8 @@ int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst return -1; } free_e1ap_cuup_setup_response(&out); + + e1_reset(); // reset all UE contexts, if any: see 38.463 sec 8.2.3 return 0; } @@ -429,7 +431,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc BEARER CONTEXT MODIFICATION REQUEST */ -static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -451,6 +453,21 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = bearerCxt->gNB_cu_up_ue_id; + /* optional */ + /* Security Information */ + if (bearerCxt->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie); + ie->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie->value.choice.SecurityInformation.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie->value.choice.SecurityInformation.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = bearerCxt->secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, bearerCxt->secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, bearerCxt->secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, bearerCxt->secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + } /* optional */ /* c3. E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC3); @@ -473,7 +490,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); drb2Mod->dRB_ID = j->id; asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); - if (j->pdcp_config.pDCP_Reestablishment) { + if (j->pdcp_config && j->pdcp_config->pDCP_Reestablishment) { asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); } if (j->numDlUpParam > 0) { @@ -482,8 +499,8 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; asn1cCalloc(DL_UP_Param->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID); DL_UP_Param->cell_Group_ID = k->cell_group_id; } @@ -491,7 +508,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con } } /* c4. E1AP_ProtocolIE_ID_id_BearerContextStatusChange */ - if (bearerCxt->bearerContextStatus == BEARER_SUSPEND) { + if (bearerCxt->bearerContextStatus && *bearerCxt->bearerContextStatus == BEARER_SUSPEND) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC4); ieC4->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; ieC4->criticality = E1AP_Criticality_reject; @@ -606,6 +623,26 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; break; + case E1AP_ProtocolIE_ID_id_SecurityInformation: { + DevAssert(ie->criticality == E1AP_Criticality_reject); + DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation); + E1AP_SecurityInformation_t *sec = &ie->value.choice.SecurityInformation; + DevAssert(sec->uPSecuritykey.encryptionKey.size == E1AP_SECURITY_KEY_SIZE); + DevAssert(sec->uPSecuritykey.integrityProtectionKey == NULL + || sec->uPSecuritykey.integrityProtectionKey->size == E1AP_SECURITY_KEY_SIZE); + bearerCxt->secInfo = malloc_or_fail(sizeof(*bearerCxt->secInfo)); + bearerCxt->secInfo->cipheringAlgorithm = sec->securityAlgorithm.cipheringAlgorithm; + bearerCxt->secInfo->integrityProtectionAlgorithm = sec->securityAlgorithm.integrityProtectionAlgorithm == NULL + ? 0 + : *sec->securityAlgorithm.integrityProtectionAlgorithm; + memcpy(bearerCxt->secInfo->encryptionKey, sec->uPSecuritykey.encryptionKey.buf, E1AP_SECURITY_KEY_SIZE); + if (sec->securityAlgorithm.integrityProtectionAlgorithm == NULL) + memset(bearerCxt->secInfo->integrityProtectionKey, 0, E1AP_SECURITY_KEY_SIZE); + else + memcpy(bearerCxt->secInfo->integrityProtectionKey, sec->uPSecuritykey.integrityProtectionKey->buf, E1AP_SECURITY_KEY_SIZE); + break; + } + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); @@ -635,7 +672,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p if (drb2Mod->pDCP_Configuration != NULL && drb2Mod->pDCP_Configuration->pDCP_Reestablishment != NULL && *drb2Mod->pDCP_Configuration->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) { - drb->pdcp_config.pDCP_Reestablishment = true; + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + drb->pdcp_config->pDCP_Reestablishment = true; } if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */ E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; @@ -647,8 +685,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel); BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4( &dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress, - dl_up_param->tlAddress); - OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->teId); + dl_up_param->tl_info.tlAddress); + OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->tl_info.teId); } else { AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n"); } @@ -663,7 +701,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p /* Bearer Context Status Change */ DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); - bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; + bearerCxt->bearerContextStatus = malloc_or_fail(*bearerCxt->bearerContextStatus); + *bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; break; default: @@ -1129,7 +1168,7 @@ static void e1_task_handle_sctp_association_resp(E1_t type, if (getCxtE1(instance)->gtpInstF1U < 0) getCxtE1(instance)->gtpInstF1U = cuup_task_create_gtpu_instance_to_du(&IPaddr); if (getCxtE1(instance)->gtpInstF1U < 0) - LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener"); + LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener\n"); extern instance_t CUuniqInstance; CUuniqInstance = getCxtE1(instance)->gtpInstF1U; cuup_init_n3(instance); @@ -1152,7 +1191,7 @@ void cuup_init_n3(instance_t instance) legacyInstanceMapping = getCxtE1(instance)->gtpInstN3 = gtpv1Init(tmp); } if (getCxtE1(instance)->gtpInstN3 < 0) - LOG_E(E1AP, "Failed to create CUUP N3 UDP listener"); + LOG_E(E1AP, "Failed to create CUUP N3 UDP listener\n"); extern instance_t *N3GTPUInst; N3GTPUInst = &getCxtE1(instance)->gtpInstN3; } diff --git a/openair2/E1AP/lib/CMakeLists.txt b/openair2/E1AP/lib/CMakeLists.txt index 27bfbcc8a27f139cdab5529f384c8062931007a9..332986dffb3d8334dc73deae29d2df74875cc16d 100644 --- a/openair2/E1AP/lib/CMakeLists.txt +++ b/openair2/E1AP/lib/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(e1ap_lib OBJECT e1ap_bearer_context_management.c e1ap_interface_management.c + e1ap_lib_common.c ) target_link_libraries(e1ap_lib PRIVATE asn1_e1ap) diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 5e359512ed3ba5e7e1087b1040a5ff0e9db7646a..a8f68e70d6aaea86faaf75f83687e027d448c91f 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -37,9 +37,130 @@ #include "e1ap_bearer_context_management.h" #include "e1ap_lib_includes.h" -/* ==================================== - * E1AP Bearer Context Setup Request - * ==================================== */ +/** @brief Encode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static E1AP_SecurityIndication_t e1_encode_security_indication(const security_indication_t *in) +{ + E1AP_SecurityIndication_t out = {0}; + out.integrityProtectionIndication = in->integrityProtectionIndication; + out.confidentialityProtectionIndication = in->confidentialityProtectionIndication; + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + asn1cCalloc(out.maximumIPdatarate, ipDataRate); + ipDataRate->maxIPrate = in->maxIPrate; + } + return out; +} + +/** @brief Decode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static bool e1_decode_security_indication(security_indication_t *out, const E1AP_SecurityIndication_t *in) +{ + // Confidentiality Protection Indication (M) + out->confidentialityProtectionIndication = in->confidentialityProtectionIndication; + // Maximum Integrity Protected Data Rate (Conditional) + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + if (in->maximumIPdatarate) + out->maxIPrate = in->maximumIPdatarate->maxIPrate; + else { + PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n"); + return false; + } + } + return true; +} + +/** + * @brief Encode E1AP_SecurityInformation_t + */ +static E1AP_SecurityInformation_t e1_encode_security_info(const security_information_t *secInfo) +{ + E1AP_SecurityInformation_t ie = {0}; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + return ie; +} + +/** + * @brief Decode E1AP_SecurityInformation_t + */ +static bool e1_decode_security_info(security_information_t *out, const E1AP_SecurityInformation_t *in) +{ + out->cipheringAlgorithm = in->securityAlgorithm.cipheringAlgorithm; + memcpy(out->encryptionKey, in->uPSecuritykey.encryptionKey.buf, in->uPSecuritykey.encryptionKey.size); + if (in->securityAlgorithm.integrityProtectionAlgorithm) + out->integrityProtectionAlgorithm = *in->securityAlgorithm.integrityProtectionAlgorithm; + if (in->uPSecuritykey.integrityProtectionKey) { + E1AP_IntegrityProtectionKey_t *ipKey = in->uPSecuritykey.integrityProtectionKey; + memcpy(out->integrityProtectionKey, ipKey->buf, ipKey->size); + } + return true; +} + +/** + * @brief Encode E1AP_UP_TNL_Information_t + */ +static E1AP_UP_TNL_Information_t e1_encode_up_tnl_info(const UP_TL_information_t *in) +{ + E1AP_UP_TNL_Information_t out = {0}; + out.present = E1AP_UP_TNL_Information_PR_gTPTunnel; + asn1cCalloc(out.choice.gTPTunnel, gTPTunnel); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + return out; +} + +/** + * @brief Decode E1AP_UP_TNL_Information_t + */ +static bool e1_decode_up_tnl_info(UP_TL_information_t *out, const E1AP_UP_TNL_Information_t *in) +{ + /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ + // GTP Tunnel + struct E1AP_GTPTunnel *gTPTunnel = in->choice.gTPTunnel; + AssertFatal(gTPTunnel != NULL, "item->nG_UL_UP_TNL_Information.choice.gTPTunnel is a mandatory IE"); + _E1_EQ_CHECK_INT(in->present, E1AP_UP_TNL_Information_PR_gTPTunnel); + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, out->tlAddress); + // GTP-TEID + OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, out->teId); + return true; +} + +/** @brief Encode PDCP Configuration IE */ +static E1AP_PDCP_Configuration_t e1_encode_pdcp_config(const bearer_context_pdcp_config_t *in) +{ + E1AP_PDCP_Configuration_t out = {0}; + out.pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out.pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + asn1cCallocOne(out.discardTimer, in->discardTimer); + E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); + out.t_ReorderingTimer = roTimer; + roTimer->t_Reordering = in->reorderingTimer; + out.rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment) { + asn1cCallocOne(out.pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); + } + return out; +} + +/** @brief Decode PDCP Configuration IE */ +static bool e1_decode_pdcp_config(bearer_context_pdcp_config_t *out, const E1AP_PDCP_Configuration_t *in) +{ + out->pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out->pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + if (in->discardTimer) { + out->discardTimer = *in->discardTimer; + } + if (in->t_ReorderingTimer) { + out->reorderingTimer = in->t_ReorderingTimer->t_Reordering; + } + out->rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment && *in->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) + out->pDCP_Reestablishment = true; + return true; +} /** * @brief Equality check for bearer_context_pdcp_config_t @@ -55,6 +176,25 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c return true; } +/** @brief Encode SDAP Configuration IE */ +static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in) +{ + E1AP_SDAP_Configuration_t out = {0}; + out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + out.sDAP_Header_UL = in->sDAP_Header_UL; + out.sDAP_Header_DL = in->sDAP_Header_DL; + return out; +} + +/** @brief Decode SDAP Configuration IE */ +static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in) +{ + out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true; + out->sDAP_Header_UL = in->sDAP_Header_UL; + out->sDAP_Header_DL = in->sDAP_Header_DL; + return true; +} + /** * @brief Equality check for bearer_context_sdap_config_t */ @@ -66,6 +206,69 @@ static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_c return true; } +static E1AP_QoS_Flow_QoS_Parameter_Item_t e1_encode_qos_flow_to_setup(const qos_flow_to_setup_t *in) +{ + E1AP_QoS_Flow_QoS_Parameter_Item_t out = {0}; + out.qoS_Flow_Identifier = in->qfi; + // QoS Characteristics + const qos_characteristics_t *qos_char_in = &in->qos_params.qos_characteristics; + if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); + non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; + } else { // dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); + dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; + dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; + dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; + dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; + } + // QoS Retention Priority + const ngran_allocation_retention_priority_t *rent_priority_in = &in->qos_params.alloc_reten_priority; + E1AP_NGRANAllocationAndRetentionPriority_t *arp = &out.qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; + arp->priorityLevel = rent_priority_in->priority_level; + arp->pre_emptionCapability = rent_priority_in->preemption_capability; + arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + return out; +} + +bool e1_decode_qos_flow_to_setup(qos_flow_to_setup_t *out, const E1AP_QoS_Flow_QoS_Parameter_Item_t *in) +{ + // QoS Flow Identifier (M) + out->qfi = in->qoS_Flow_Identifier; + qos_characteristics_t *qos_char = &out->qos_params.qos_characteristics; + // QoS Flow Level QoS Parameters (M) + const E1AP_QoSFlowLevelQoSParameters_t *qosParams = &in->qoSFlowLevelQoSParameters; + const E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; + switch (qoS_Characteristics->present) { + case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: + qos_char->qos_type = NON_DYNAMIC; + qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; + break; + case E1AP_QoS_Characteristics_PR_dynamic_5QI: { + E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; + qos_char->qos_type = DYNAMIC; + qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel; + qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget; + qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar; + qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; + break; + } + default: + PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); + return false; + break; + } + // NG-RAN Allocation and Retention Priority (M) + ngran_allocation_retention_priority_t *rent_priority = &out->qos_params.alloc_reten_priority; + const E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; + rent_priority->priority_level = aRP->priorityLevel; + rent_priority->preemption_capability = aRP->pre_emptionCapability; + rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + return true; +} + /** * @brief Equality check for qos_flow_to_setup_t */ @@ -90,30 +293,66 @@ static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t return true; } +/** @brief S-NSSAI Encoding (3GPP TS 38.463 9.3.1.9) */ +static E1AP_SNSSAI_t e1_encode_snssai(const nssai_t *in) +{ + E1AP_SNSSAI_t out = {0}; + INT8_TO_OCTET_STRING(in->sst, &out.sST); + if (in->sd != 0xffffff) { + out.sD = malloc_or_fail(sizeof(*out.sD)); + INT24_TO_OCTET_STRING(in->sd, out.sD); + } + return out; +} + +/** @brief S-NSSAI Decoding (3GPP TS 38.463 9.3.1.9) */ +static bool e1_decode_snssai(e1ap_nssai_t *out, const E1AP_SNSSAI_t *in) +{ + // SST (M) + OCTET_STRING_TO_INT8(&in->sST, out->sst); + out->sd = 0xffffff; + // SD (O) + if (in->sD != NULL) + OCTET_STRING_TO_INT24(in->sD, out->sd); + return true; +} + /** - * @brief Equality check for DRB_nGRAN_to_setup_t + * @brief Decode E1AP_UP_Parameters_t */ -static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b) +static int decode_dl_up_parameters(up_params_t *dl_up_param, const E1AP_UP_Parameters_t *dl_up_paramList) { - bool result = true; - _E1_EQ_CHECK_LONG(a->id, b->id); - _E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups); - for (int i = 0; i < a->numCellGroups; i++) { - _E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]); + for (int k = 0; k < dl_up_paramList->list.count; k++) { + dl_up_param = dl_up_param + k; + E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; + // GTP tunnel + if (!e1_decode_up_tnl_info(&dl_up_param->tl_info, &dl_up_param_in->uP_TNL_Information)) { + PRINT_ERROR("GTP tunnel decoding failed\n"); + return -1; + } + // Cell group ID + dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID; } - _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); - for (int i = 0; i < a->numQosFlow2Setup; i++) { - result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + return dl_up_paramList->list.count; +} + +/** + * @brief Encode E1AP_UP_Parameters_t IE + */ +static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const up_params_t *in) +{ + E1AP_UP_Parameters_t out = {0}; + for (const up_params_t *k = in; k < in + numUpParam; k++) { + asn1cSequenceAdd(out.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); + ieC3_1_1_1->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); } - result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); - result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); - return result; + return out; } /** - * @brief Equality check for DRB_nGRAN_to_mod_t + * @brief Equality check for DRB_nGRAN_to_setup_t */ -static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b) { bool result = true; _E1_EQ_CHECK_LONG(a->id, b->id); @@ -125,127 +364,63 @@ static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t for (int i = 0; i < a->numQosFlow2Setup; i++) { result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); } - _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); - _E1_EQ_CHECK_INT(a->teId, b->teId); - _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); - for (int i = 0; i < a->numDlUpParam; i++) { - _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); - _E1_EQ_CHECK_LONG(a->DlUpParamList[i].teId, b->DlUpParamList[i].teId); - _E1_EQ_CHECK_INT(a->DlUpParamList[i].tlAddress, b->DlUpParamList[i].tlAddress); - } result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); return result; } -/* PDU Session To Setup Item */ +static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) +{ + free(msg->drb_inactivity_timer); +} +/** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in) { + // PDU Session ID (M) item->pDU_Session_ID = in->sessionId; + // PDU Session Type (M) item->pDU_Session_Type = in->sessionType; - // SNSSAI - INT8_TO_OCTET_STRING(in->nssai.sst, &item->sNSSAI.sST); - if (in->nssai.sd != 0xffffff) { - item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD)); - INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD); - } - // Security Indication - E1AP_SecurityIndication_t *siOut = &item->securityIndication; - const security_indication_t *siIn = &in->securityIndication; - siOut->integrityProtectionIndication = siIn->integrityProtectionIndication; - siOut->confidentialityProtectionIndication = siIn->confidentialityProtectionIndication; - if (siIn->integrityProtectionIndication != SECURITY_NOT_NEEDED) { - asn1cCalloc(siOut->maximumIPdatarate, ipDataRate); - ipDataRate->maxIPrate = siIn->maxIPrate; - } - // TNL Information - item->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(item->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - const UP_TL_information_t *UP_TL_information = &in->UP_TL_information; - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(UP_TL_information->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(UP_TL_information->teId, &gTPTunnel->gTP_TEID); - // DRB to setup + // S-NSSAI (M) + item->sNSSAI = e1_encode_snssai(&in->nssai); + // Security Indication (M) + item->securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item->nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB To Setup List (M) for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); + // DRB ID (M) ieC6_1_1->dRB_ID = j->id; - // SDAP Config - E1AP_SDAP_Configuration_t *sdap = &ieC6_1_1->sDAP_Configuration; - sdap->defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - sdap->sDAP_Header_UL = j->sdap_config.sDAP_Header_UL; - sdap->sDAP_Header_DL = j->sdap_config.sDAP_Header_DL; - // PDCP Config - E1AP_PDCP_Configuration_t *pdcp = &ieC6_1_1->pDCP_Configuration; - pdcp->pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL; - pdcp->pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL; - asn1cCallocOne(pdcp->discardTimer, j->pdcp_config.discardTimer); - E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); - pdcp->t_ReorderingTimer = roTimer; - roTimer->t_Reordering = j->pdcp_config.reorderingTimer; - pdcp->rLC_Mode = j->pdcp_config.rLC_Mode; - // Cell Group + // SDAP Configuration (M) + ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Configuration (M) + ieC6_1_1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1); ieC6_1_1_1->cell_Group_ID = *k; } - // QoS Flows + // QoS Flows Information To Be Setup (M) for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { - asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1); - ieC6_1_1_1->qoS_Flow_Identifier = k->qfi; - // QoS Characteristics - const qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics; - if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI - ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); - non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; - } else { // dynamic 5QI - ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); - dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; - dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; - dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; - dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; - } - // QoS Retention Priority - const ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *arp = &ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; - arp->priorityLevel = rent_priority_in->priority_level; - arp->pre_emptionCapability = rent_priority_in->preemption_capability; - arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2); + *ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k); } } return true; } +/** @brief Decode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1AP_PDU_Session_Resource_To_Setup_Item_t *item) { // PDU Session ID (M) out->sessionId = item->pDU_Session_ID; // PDU Session Type (M) out->sessionType = item->pDU_Session_Type; - /* S-NSSAI (M) */ - // SST (M) - OCTET_STRING_TO_INT8(&item->sNSSAI.sST, out->nssai.sst); - out->nssai.sd = 0xffffff; - // SD (O) - if (item->sNSSAI.sD != NULL) - OCTET_STRING_TO_INT24(item->sNSSAI.sD, out->nssai.sd); - /* Security Indication (M) */ - E1AP_SecurityIndication_t *securityIndication = &item->securityIndication; - // Integrity Protection Indication (M) - security_indication_t *sec = &out->securityIndication; - sec->integrityProtectionIndication = securityIndication->integrityProtectionIndication; - // Confidentiality Protection Indication (M) - sec->confidentialityProtectionIndication = securityIndication->confidentialityProtectionIndication; - // Maximum Integrity Protected Data Rate (Conditional) - if (sec->integrityProtectionIndication != SECURITY_NOT_NEEDED) { - if (securityIndication->maximumIPdatarate) - sec->maxIPrate = securityIndication->maximumIPdatarate->maxIPrate; - else { - PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n"); - return false; - } - } + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ // GTP Tunnel struct E1AP_GTPTunnel *gTPTunnel = item->nG_UL_UP_TNL_Information.choice.gTPTunnel; @@ -254,12 +429,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A return false; } _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); - // Transport Layer Address - UP_TL_information_t *UP_TL_information = &out->UP_TL_information; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UP_TL_information->tlAddress); - // GTP-TEID - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UP_TL_information->teId); - // DRB To Setup List ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN; _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); out->numDRB2Setup = drb2SetupList->list.count; @@ -269,23 +440,11 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; // DRB ID (M) drb->id = drb2Setup->dRB_ID; - // >SDAP Configuration (M) - E1AP_SDAP_Configuration_t *sdap = &drb2Setup->sDAP_Configuration; - drb->sdap_config.defaultDRB = sdap->defaultDRB == E1AP_DefaultDRB_true; - drb->sdap_config.sDAP_Header_UL = sdap->sDAP_Header_UL; - drb->sdap_config.sDAP_Header_DL = sdap->sDAP_Header_DL; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); // PDCP Configuration (M) - E1AP_PDCP_Configuration_t *pdcp = &drb2Setup->pDCP_Configuration; - drb->pdcp_config.pDCP_SN_Size_UL = pdcp->pDCP_SN_Size_UL; - drb->pdcp_config.pDCP_SN_Size_DL = pdcp->pDCP_SN_Size_DL; - if (pdcp->discardTimer) { - drb->pdcp_config.discardTimer = *pdcp->discardTimer; - } - if (pdcp->t_ReorderingTimer) { - drb->pdcp_config.reorderingTimer = pdcp->t_ReorderingTimer->t_Reordering; - } - drb->pdcp_config.rLC_Mode = pdcp->rLC_Mode; - // Cell Group Information (M) ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); drb->numCellGroups = cellGroupList->list.count; @@ -298,44 +457,50 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup; drb->numQosFlow2Setup = qos2SetupList->list.count; for (int k = 0; k < qos2SetupList->list.count; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k]; - // QoS Flow Identifier (M) - qos_flow->qfi = qos2Setup->qoS_Flow_Identifier; - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - // QoS Flow Level QoS Parameters (M) - E1AP_QoSFlowLevelQoSParameters_t *qosParams = &qos2Setup->qoSFlowLevelQoSParameters; - E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; - switch (qoS_Characteristics->present) { - case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: - qos_char->qos_type = NON_DYNAMIC; - qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; - break; - case E1AP_QoS_Characteristics_PR_dynamic_5QI: { - E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; - qos_char->qos_type = DYNAMIC; - qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel; - qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget; - qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar; - qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; - break; - } - default: - PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); - return false; - break; - } - // NG-RAN Allocation and Retention Priority (M) - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; - rent_priority->priority_level = aRP->priorityLevel; - rent_priority->preemption_capability = aRP->pre_emptionCapability; - rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); } } return true; } +/** @brief Deep copy DRB To Setup List Item (3GPP TS 38.463 9.3.3.2) */ +static DRB_nGRAN_to_setup_t cp_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) +{ + DRB_nGRAN_to_setup_t cp = {0}; + cp.id = msg->id; + cp.sdap_config = msg->sdap_config; + cp.pdcp_config = msg->pdcp_config; + cp.numCellGroups = msg->numCellGroups; + // Cell Group List + for (int k = 0; k < msg->numCellGroups; k++) { + cp.cellGroupList[k] = msg->cellGroupList[k]; + } + cp.numQosFlow2Setup = msg->numQosFlow2Setup; + // QoS Flow To Setup List + for (int k = 0; k < msg->numQosFlow2Setup; k++) { + cp.qosFlows[k].qfi = msg->qosFlows[k].qfi; + cp.qosFlows[k].qos_params = msg->qosFlows[k].qos_params; + } + return cp; +} + +/** @brief Free PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg) +{ + free(msg->dlAggregateMaxBitRate); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + +/** @brief Equality check for UP Transport Layer Information (3GPP TS 38.463 9.3.2.1)*/ +static bool eq_up_tl_info(const UP_TL_information_t *a, const UP_TL_information_t *b) +{ + _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); + _E1_EQ_CHECK_INT(a->teId, b->teId); + return true; +} + /** * @brief Equality check for PDU session item to modify/setup */ @@ -343,57 +508,21 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi { _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); _E1_EQ_CHECK_LONG(a->sessionType, b->sessionType); - _E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress); - _E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId); - _E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup); - if (a->numDRB2Setup != b->numDRB2Setup) - return false; + eq_up_tl_info(&a->UP_TL_information, &b->UP_TL_information); + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); for (int i = 0; i < a->numDRB2Setup; i++) if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) return false; - _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); - if (a->numDRB2Modify != b->numDRB2Modify) - return false; - for (int i = 0; i < a->numDRB2Modify; i++) - if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) - return false; + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(a->inactivityTimer, b->inactivityTimer); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, dlAggregateMaxBitRate, _E1_EQ_CHECK_LONG); return true; } -static bool cp_pdu_session_item(pdu_session_to_setup_t *cp, const pdu_session_to_setup_t *msg) -{ - // Copy basic fields - *cp = *msg; - // Copy DRB to Setup List - for (int j = 0; j < msg->numDRB2Setup; j++) { - cp->DRBnGRanList[j].id = msg->DRBnGRanList[j].id; - cp->DRBnGRanList[j].sdap_config = msg->DRBnGRanList[j].sdap_config; - cp->DRBnGRanList[j].pdcp_config = msg->DRBnGRanList[j].pdcp_config; - cp->DRBnGRanList[j].tlAddress = msg->DRBnGRanList[j].tlAddress; - cp->DRBnGRanList[j].teId = msg->DRBnGRanList[j].teId; - cp->DRBnGRanList[j].numDlUpParam = msg->DRBnGRanList[j].numDlUpParam; - // Copy DL UP Params List - for (int k = 0; k < msg->DRBnGRanList[j].numDlUpParam; k++) { - cp->DRBnGRanList[j].DlUpParamList[k] = msg->DRBnGRanList[j].DlUpParamList[k]; - } - cp->DRBnGRanList[j].numCellGroups = msg->DRBnGRanList[j].numCellGroups; - // Copy Cell Group List - for (int k = 0; k < msg->DRBnGRanList[j].numCellGroups; k++) { - cp->DRBnGRanList[j].cellGroupList[k] = msg->DRBnGRanList[j].cellGroupList[k]; - } - cp->DRBnGRanList[j].numQosFlow2Setup = msg->DRBnGRanList[j].numQosFlow2Setup; - // Copy QoS Flow To Setup List - for (int k = 0; k < msg->DRBnGRanList[j].numQosFlow2Setup; k++) { - cp->DRBnGRanList[j].qosFlows[k].qfi = msg->DRBnGRanList[j].qosFlows[k].qfi; - cp->DRBnGRanList[j].qosFlows[k].qos_params = msg->DRBnGRanList[j].qosFlows[k].qos_params; - } - } - // Copy DRB to Modify List - for (int j = 0; j < msg->numDRB2Modify; j++) { - cp->DRBnGRanModList[j] = msg->DRBnGRanModList[j]; - } - return true; -} +/* ==================================== + * E1AP Bearer Context Setup Request + * ==================================== */ /** * @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463) @@ -421,13 +550,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation; ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation; - E1AP_SecurityAlgorithm_t *securityAlgorithm = &ieC2->value.choice.SecurityInformation.securityAlgorithm; - E1AP_UPSecuritykey_t *uPSecuritykey = &ieC2->value.choice.SecurityInformation.uPSecuritykey; - securityAlgorithm->cipheringAlgorithm = msg->cipheringAlgorithm; - OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, msg->encryptionKey, E1AP_SECURITY_KEY_SIZE); - asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, msg->integrityProtectionAlgorithm); - asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); - OCTET_STRING_fromBuf(protKey, msg->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + ieC2->value.choice.SecurityInformation = e1_encode_security_info(&msg->secInfo); /* mandatory */ /* c3. UE DL Aggregate Maximum Bit Rate */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3); @@ -450,8 +573,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC5->criticality = E1AP_Criticality_reject; ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel; ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session; // TODO: Remove hard coding - /* mandatory */ - /* */ + // System (M) asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6); ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest; ieC6->criticality = E1AP_Criticality_reject; @@ -469,7 +591,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ for (int i = 0; i < msg->numPDUSessions; i++) { const pdu_session_to_setup_t *pdu_session = &msg->pduSession[i]; asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1); - e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session); + CHECK_E1AP_DEC(e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session)); } return pdu; } @@ -479,7 +601,8 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ */ void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg) { - // Do nothing + free(msg->inactivityTimerUE); + free(msg->ueDlMaxIPBitRate); } /** @@ -492,8 +615,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea // Check message type _E1_EQ_CHECK_INT(pdu->present,E1AP_E1AP_PDU_PR_initiatingMessage); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest); const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; @@ -519,17 +641,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea case E1AP_ProtocolIE_ID_id_SecurityInformation: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation); - E1AP_SecurityInformation_t *SecurityInformation = &ie->value.choice.SecurityInformation; - E1AP_SecurityAlgorithm_t *securityAlgorithm = &SecurityInformation->securityAlgorithm; - E1AP_EncryptionKey_t *encryptionKey = &SecurityInformation->uPSecuritykey.encryptionKey; - E1AP_IntegrityProtectionKey_t *integrityProtectionKey = SecurityInformation->uPSecuritykey.integrityProtectionKey; - - out->cipheringAlgorithm = securityAlgorithm->cipheringAlgorithm; - memcpy(out->encryptionKey, encryptionKey->buf, encryptionKey->size); - if (securityAlgorithm->integrityProtectionAlgorithm) - out->integrityProtectionAlgorithm = *securityAlgorithm->integrityProtectionAlgorithm; - if (integrityProtectionKey) - memcpy(out->integrityProtectionKey, integrityProtectionKey->buf, integrityProtectionKey->size); + CHECK_E1AP_DEC(e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation)); break; case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: @@ -545,12 +657,6 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea out->servingPLMNid.mnc_digit_length); break; - case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel: - _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - out->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel; - break; - case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest); E1AP_System_BearerContextSetupRequest_t *System_BearerContextSetupRequest = @@ -590,10 +696,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea for (int i = 0; i < pdu2SetupList->list.count; i++) { pdu_session_to_setup_t *pdu_session = out->pduSession + i; E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i]; - if (!e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)) { - PRINT_ERROR("Failed to decode PDU Session to setup item %d\n", i); - return false; - } + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)); } break; default: @@ -604,19 +707,35 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea return true; } -/** - * @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST - */ +/** @brief Deep copy PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +static pdu_session_to_setup_t cp_pdu_session_item(const pdu_session_to_setup_t *msg) +{ + pdu_session_to_setup_t cp = {0}; + // Copy basic fields + cp = *msg; + // Copy DRB to Setup List + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // Copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + _E1_CP_OPTIONAL_IE(&cp, msg, dlAggregateMaxBitRate); + return cp; +} + +/** @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST */ e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg) { e1ap_bearer_setup_req_t cp = {0}; // Copy basi fields cp = *msg; - strncpy(cp.encryptionKey, msg->encryptionKey, sizeof(cp.encryptionKey)); - strncpy(cp.integrityProtectionKey, msg->integrityProtectionKey, sizeof(cp.integrityProtectionKey)); + strncpy(cp.secInfo.encryptionKey, msg->secInfo.encryptionKey, sizeof(cp.secInfo.encryptionKey)); + strncpy(cp.secInfo.integrityProtectionKey, msg->secInfo.integrityProtectionKey, sizeof(cp.secInfo.integrityProtectionKey)); // Copy PDU Sessions for (int i = 0; i < msg->numPDUSessions; i++) - cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]); + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + // copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, ueDlMaxIPBitRate); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimerUE); return cp; } @@ -627,30 +746,28 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a { // Primitive data types _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); - _E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm); - _E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.cipheringAlgorithm, b->secInfo.cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.integrityProtectionAlgorithm, b->secInfo.integrityProtectionAlgorithm); _E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate); - _E1_EQ_CHECK_INT(a->activityNotificationLevel, b->activityNotificationLevel); _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); - _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); // PLMN _E1_EQ_CHECK_INT(a->servingPLMNid.mcc, b->servingPLMNid.mcc); _E1_EQ_CHECK_INT(a->servingPLMNid.mnc, b->servingPLMNid.mnc); _E1_EQ_CHECK_INT(a->servingPLMNid.mnc_digit_length, b->servingPLMNid.mnc_digit_length); // Security Keys - _E1_EQ_CHECK_STR(a->encryptionKey, b->encryptionKey); - _E1_EQ_CHECK_STR(a->integrityProtectionKey, b->integrityProtectionKey); + _E1_EQ_CHECK_STR(a->secInfo.encryptionKey, b->secInfo.encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo.integrityProtectionKey, b->secInfo.integrityProtectionKey); // PDU Sessions if (a->numPDUSessions != b->numPDUSessions) return false; for (int i = 0; i < a->numPDUSessions; i++) if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) return false; - if (a->numPDUSessionsMod != b->numPDUSessionsMod) - return false; - for (int i = 0; i < a->numPDUSessionsMod; i++) - if (!eq_pdu_session_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) - return false; + // Check optional IEs + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimerUE); + if (a->inactivityTimerUE && b->inactivityTimerUE) + _E1_EQ_CHECK_INT(a->inactivityTimerUE, b->inactivityTimerUE); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, ueDlMaxIPBitRate, _E1_EQ_CHECK_LONG); return true; } @@ -669,12 +786,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP pduSetup->id = in->pDU_Session_ID; pduSetup->numDRBSetup = in->dRB_Setup_List_NG_RAN.list.count; // NG DL UP Transport Layer Information (M) - E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information; - if (DL_UP_TNL_Info->choice.gTPTunnel) { - _E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tlAddress); - OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId); - } + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&pduSetup->tl_info, &in->nG_DL_UP_TNL_Information)); // DRB Setup List (1..<maxnoofDRBs>) for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) { DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j; @@ -682,32 +794,29 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP // DRB ID (M) drbSetup->id = drb->dRB_ID; // UL UP Parameters (M) - drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count; - for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) { - up_params_t *UL_UP_param = drbSetup->UpParamList + k; - // UP Parameters List (1..<maxnoofUPParameters>) - E1AP_UP_Parameters_Item_t *UL_UP_item = drb->uL_UP_Transport_Parameters.list.array[k]; - // UP Transport Layer Information (M) - DevAssert(UL_UP_item->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel); - // GTP Tunnel (M) - E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel; - AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n"); - if (gTPTunnel) { - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tlAddress); - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId); - } else { - } - // Cell Group ID (M) - UL_UP_param->cell_group_id = UL_UP_item->cell_Group_ID; + if ((drbSetup->numUpParam = decode_dl_up_parameters(drbSetup->UpParamList, &drb->uL_UP_Transport_Parameters)) < 0) { + PRINT_ERROR("UL UP Parameters decoding failed\n"); + return false; } // Flow Setup List (M) drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count; for (int q = 0; q < drb->flow_Setup_List.list.count; q++) { - qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q]; + qos_flow_list_t *qosflowSetup = &drbSetup->qosFlows[q]; E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q]; qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; } } + // DRB Failed to Setup List (O) + if (in->dRB_Failed_List_NG_RAN) { + for (int j = 0; j < in->dRB_Failed_List_NG_RAN->list.count; j++) { + DRB_nGRAN_failed_t *drbFailed = pduSetup->DRBnGRanFailedList + j; + E1AP_DRB_Failed_Item_NG_RAN_t *item = in->dRB_Failed_List_NG_RAN->list.array[j]; + // DRB ID (M) + drbFailed->id = item->dRB_ID; + // Cause (M) + drbFailed->cause = e1_decode_cause_ie(&item->cause); + } + } return true; } @@ -719,25 +828,16 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // PDU Session ID (M) item->pDU_Session_ID = in->id; // NG DL UP Transport Layer Information (M) - item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + item->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(&in->tl_info); // DRB Setup List (1..<maxnoofDRBs>) for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) { asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // UL UP Parameters (M) - for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) { - asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); - ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); - } + ieC3_1_1->uL_UP_Transport_Parameters = encode_dl_up_parameters(j->numUpParam, j->UpParamList); // Flow Setup List(M) - for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { + for (const qos_flow_list_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1); ieC3_1_1_1->qoS_Flow_Identifier = k->qfi; } @@ -751,24 +851,7 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // Cause (M) - ieC3_1_1->cause.present = j->cause_type; - switch (ieC3_1_1->cause.present) { - case E1AP_Cause_PR_radioNetwork: - ieC3_1_1->cause.choice.radioNetwork = j->cause; - break; - case E1AP_Cause_PR_transport: - ieC3_1_1->cause.choice.transport = j->cause; - break; - case E1AP_Cause_PR_protocol: - ieC3_1_1->cause.choice.protocol = j->cause; - break; - case E1AP_Cause_PR_misc: - ieC3_1_1->cause.choice.misc = j->cause; - break; - default: - PRINT_ERROR("DRB setup failure cause out of expected range\n"); - break; - } + ieC3_1_1->cause = e1_encode_cause_ie(&j->cause); } return true; } @@ -816,7 +899,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; for (const pdu_session_setup_t *i = in->pduSession; i < in->pduSession + in->numPDUSessions; i++) { asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1); - e1_encode_pdu_session_setup_item(ieC3_1, i); + CHECK_E1AP_DEC(e1_encode_pdu_session_setup_item(ieC3_1, i)); } return pdu; } @@ -828,8 +911,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be { // Check message type _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse); const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; @@ -862,7 +944,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse; _E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1); E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0]; - _E1_EQ_CHECK_INT(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); _E1_EQ_CHECK_INT(msgNGRAN->value.present, E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List); E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; @@ -870,7 +952,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be for (int i = 0; i < pduSetupList->list.count; i++) { pdu_session_setup_t *pduSetup = out->pduSession + i; E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i]; - e1_decode_pdu_session_setup_item(pduSetup, pdu_session); + CHECK_E1AP_DEC(e1_decode_pdu_session_setup_item(pduSetup, pdu_session)); } } break; @@ -938,8 +1020,7 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const pdu_session_setup_t *ps_a = &a->pduSession[i]; const pdu_session_setup_t *ps_b = &b->pduSession[i]; _E1_EQ_CHECK_LONG(ps_a->id, ps_b->id); - _E1_EQ_CHECK_INT(ps_a->tlAddress, ps_b->tlAddress); - _E1_EQ_CHECK_LONG(ps_a->teId, ps_b->teId); + eq_up_tl_info(&ps_a->tl_info, &ps_b->tl_info); _E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup); _E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed); // Check DRB Setup @@ -955,8 +1036,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const DRB_nGRAN_failed_t *drbf_a = &ps_a->DRBnGRanFailedList[j]; const DRB_nGRAN_failed_t *drbf_b = &ps_b->DRBnGRanFailedList[j]; _E1_EQ_CHECK_LONG(drbf_a->id, drbf_b->id); - _E1_EQ_CHECK_LONG(drbf_a->cause_type, drbf_b->cause_type); - _E1_EQ_CHECK_LONG(drbf_a->cause, drbf_b->cause); + _E1_EQ_CHECK_LONG(drbf_a->cause.type, drbf_b->cause.type); + _E1_EQ_CHECK_LONG(drbf_a->cause.value, drbf_b->cause.value); } } return true; @@ -969,3 +1050,633 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg) { // Do nothing (no dynamic allocation) } + +/* ============================================ + * E1AP Bearer Context Modification Request + * ============================================ */ + +/** @brief Encode PDU Session Item to modify */ +static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_item(const pdu_session_to_mod_t *in) +{ + E1AP_PDU_Session_Resource_To_Modify_Item_t out = {0}; + out.pDU_Session_ID = in->sessionId; + for (const DRB_nGRAN_to_mod_t *j = in->DRBnGRanModList; j < in->DRBnGRanModList + in->numDRB2Modify; j++) { + asn1cCalloc(out.dRB_To_Modify_List_NG_RAN, drb2Mod_List); + asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); + drb2Mod->dRB_ID = j->id; + // PDCP Config (O) + if (j->pdcp_config) { + asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); + *pDCP_Configuration = e1_encode_pdcp_config(j->pdcp_config); + } + // SDAP Config (O) + if (j->sdap_config) { + asn1cCalloc(drb2Mod->sDAP_Configuration, sDAP_Configuration); + *sDAP_Configuration = e1_encode_sdap_config(j->sdap_config); + } + // PDCP SN Status Request (O) + if (j->pdcp_sn_status_requested) { + asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request); + *pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested; + } + // DL UP TNL parameters (O) + if (j->numDlUpParam > 0) { + asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); + for (const up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) { + asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); + DL_UP_Param->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + DL_UP_Param->cell_Group_ID = k->cell_group_id; + } + } + // QoS Flows to setup (O) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cCalloc(drb2Mod->flow_Mapping_Information, flow_Mapping_Information); + asn1cSequenceAdd(flow_Mapping_Information->list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return out; +} + +/** @brief Common encoding for the NG-RAN System IE */ +static E1AP_NG_RAN_BearerContextModificationRequest_t *encode_ng_ran_to_mod(E1AP_BearerContextModificationRequestIEs_t *ie) +{ + ie->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest; + E1AP_System_BearerContextModificationRequest_t *reqIE = &ie->value.choice.System_BearerContextModificationRequest; + reqIE->present = E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest; + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list)); + reqIE->choice.nG_RAN_BearerContextModificationRequest = (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; + asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextModificationRequest_t, msgNGRAN); + return msgNGRAN; +} + +/** @brief Encode PDU Session Resource To Setup Modification List item */ +static E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t e1_encode_pdu_session_to_setup_mod_item(const pdu_session_to_setup_t *in) +{ + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t item = {0}; + // PDU Session ID (M) + item.pDU_Session_ID = in->sessionId; + // PDU Session Type (M) + item.pDU_Session_Type = in->sessionType; + // SNSSAI (M) + item.sNSSAI = e1_encode_snssai(&in->nssai); + // Security indication (M) + item.securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item.nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB to setup + for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { + asn1cSequenceAdd(item.dRB_To_Setup_Mod_List_NG_RAN.list, E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t, ie1); + // DRB ID (M) + ie1->dRB_ID = j->id; + // SDAP Config (M) + ie1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Config (M) + ie1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) + for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { + asn1cSequenceAdd(ie1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ie1_1); + ie1_1->cell_Group_ID = *k; + } + // QoS Flows Information To Be Setup (M) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cSequenceAdd(ie1->flow_Mapping_Information.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return item; +} + +/** + * @brief Encodes the E1 Bearer Modification Request message + */ +E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *in) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + // PDU Type + pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, msg); + msg->procedureCode = E1AP_ProcedureCode_id_bearerContextModification; + msg->criticality = E1AP_Criticality_reject; + msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest; + + E1AP_BearerContextModificationRequest_t *out = &msg->value.choice.BearerContextModificationRequest; + + // gNB-CU-CP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie1); + ie1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ie1->criticality = E1AP_Criticality_reject; + ie1->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ie1->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_cp_ue_id; + + // gNB-CU-UP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie2); + ie2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; + ie2->criticality = E1AP_Criticality_reject; + ie2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; + ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = in->gNB_cu_up_ue_id; + + // Security Information (O) + if (in->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie3); + ie3->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie3->criticality = E1AP_Criticality_reject; + ie3->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + ie3->value.choice.SecurityInformation = e1_encode_security_info(in->secInfo); + } + + // UE DL Aggregate Maximum Bit Rate (O) + if (in->ueDlAggMaxBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie4); + ie4->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate; + ie4->criticality = E1AP_Criticality_reject; + ie4->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlAggMaxBitRate, &ie4->value.choice.BitRate); + } + + // UE DL Maximum Integrity Protected Data Rate (O) + if (in->ueDlMaxIPBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie5); + ie5->id = E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate; + ie5->criticality = E1AP_Criticality_ignore; + ie5->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlMaxIPBitRate, &ie5->value.choice.BitRate); + } + + // Bearer Context Status Change (O) + if (in->bearerContextStatus && *in->bearerContextStatus == BEARER_SUSPEND) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie6); + ie6->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; + ie6->criticality = E1AP_Criticality_reject; + ie6->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange; + ie6->value.choice.BearerContextStatusChange = E1AP_BearerContextStatusChange_suspend; + } + + // UE Inactivity Timer (O) + if (in->inactivityTimer) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie7); + ie7->id = E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer; + ie7->criticality = E1AP_Criticality_ignore; + ie7->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_Inactivity_Timer; + ie7->value.choice.Inactivity_Timer = *in->inactivityTimer; + } + + // Data Discard Required (O) + if (in->dataDiscardRequired) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie9); + ie9->id = E1AP_ProtocolIE_ID_id_DataDiscardRequired; + ie9->criticality = E1AP_Criticality_ignore; + ie9->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_DataDiscardRequired; + ie9->value.choice.DataDiscardRequired = in->dataDiscardRequired; + } + + // NG-RAN PDU Session Resource To Setup List (O) + if (in->numPDUSessions) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, setupList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(setupList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List; + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + for (int i = 0; i < in->numPDUSessions; i++) { + const pdu_session_to_setup_t *pdu_session = &in->pduSession[i]; + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t, item); + *item = e1_encode_pdu_session_to_setup_mod_item(pdu_session); + } + } + + // NG-RAN PDU Session Resource To Modify List (O) + if (in->numPDUSessionsMod) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, modList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(modList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List; + E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + for (const pdu_session_to_mod_t *i = in->pduSessionMod; i < in->pduSessionMod + in->numPDUSessionsMod; i++) { + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Modify_Item_t, ieC3_1); + *ieC3_1 = e1_encode_pdu_session_to_mod_item(i); + } + } + return pdu; +} + +/** @brief Decode PDU Session Item to Setup (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_setup_mod_item(pdu_session_to_setup_t *out, + const E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *item) +{ + // PDU Session ID (M) + out->sessionId = item->pDU_Session_ID; + // PDU Session Type (M) + out->sessionType = item->pDU_Session_Type; + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); + /* NG UL UP Transport Layer Information (M) */ + _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ + const E1AP_DRB_To_Setup_Mod_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_Mod_List_NG_RAN; + _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); + out->numDRB2Setup = drb2SetupList->list.count; + _E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session + for (int j = 0; j < drb2SetupList->list.count; j++) { + DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j; + const E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; + // DRB ID (M) + drb->id = drb2Setup->dRB_ID; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); + // PDCP Configuration (M) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) + const E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; + _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); + drb->numCellGroups = cellGroupList->list.count; + for (int k = 0; k < cellGroupList->list.count; k++) { + const E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k]; + // Cell Group ID + drb->cellGroupList[k] = cg2Setup->cell_Group_ID; + } + // QoS Flows Information To Be Setup (M) + const E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** @brief Decode PDU Session Item to modify (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E1AP_PDU_Session_Resource_To_Modify_Item_t *in) +{ + // PDU Session ID + out->sessionId = in->pDU_Session_ID; + // DRB to modify list + E1AP_DRB_To_Modify_List_NG_RAN_t *drb2ModList = in->dRB_To_Modify_List_NG_RAN; + out->numDRB2Modify = drb2ModList->list.count; + for (int j = 0; j < drb2ModList->list.count; j++) { + DRB_nGRAN_to_mod_t *drb = out->DRBnGRanModList + j; + // DRB to modify item + E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j]; + drb->id = drb2Mod->dRB_ID; + // PDCP Config (O) + if (drb2Mod->pDCP_Configuration) { + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration)); + } + // SDAP Config (O) + if (drb2Mod->sDAP_Configuration) { + drb->sdap_config = malloc_or_fail(sizeof(*drb->sdap_config)); + CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration)); + } + // PDCP SN Status Request (O) + if (drb2Mod->pDCP_SN_Status_Request) { + drb->pdcp_sn_status_requested = true; + } + // DL UP TNL parameters (O) + if (drb2Mod->dL_UP_Parameters) { + E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; + if((drb->numDlUpParam = decode_dl_up_parameters(drb->DlUpParamList, dl_up_paramList)) < 0) { + PRINT_ERROR("Failed to decode DL UP TNL parameters\n"); + return false; + } + } + // QoS Flows Information To Be Setup (O) + E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = drb2Mod->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** + * @brief E1 Bearer Modification Request message decoding + */ +bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_mod_req_t *out) +{ + DevAssert(pdu != NULL); + // Validate message type + _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_initiatingMessage); + const E1AP_InitiatingMessage_t *im = pdu->choice.initiatingMessage; + _E1_EQ_CHECK_LONG(im->procedureCode, E1AP_ProcedureCode_id_bearerContextModification); + _E1_EQ_CHECK_INT(im->value.present, E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest); + + const E1AP_BearerContextModificationRequest_t *in = &im->value.choice.BearerContextModificationRequest; + E1AP_BearerContextModificationRequestIEs_t *ie = NULL; + + // Mandatory IEs + // gNB-CU-CP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true); + // gNB-CU-UP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true); + + // Loop through all IEs and extract + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); + out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID); + out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_SecurityInformation: + out->secInfo = malloc_or_fail(sizeof(*out->secInfo)); + CHECK_E1AP_DEC(e1_decode_security_info(out->secInfo, &ie->value.choice.SecurityInformation)); + break; + + case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: + out->ueDlAggMaxBitRate = malloc_or_fail(sizeof(*out->ueDlAggMaxBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlAggMaxBitRate); + break; + + case E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate: + out->ueDlMaxIPBitRate = malloc_or_fail(sizeof(*out->ueDlMaxIPBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlMaxIPBitRate); + break; + + case E1AP_ProtocolIE_ID_id_BearerContextStatusChange: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); + if (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) { + out->bearerContextStatus = malloc_or_fail(sizeof(*out->bearerContextStatus)); + *out->bearerContextStatus = BEARER_SUSPEND; + } + break; + + case E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer: + out->inactivityTimer = malloc_or_fail(sizeof(*out->inactivityTimer)); + *out->inactivityTimer = ie->value.choice.Inactivity_Timer; + break; + + case E1AP_ProtocolIE_ID_id_DataDiscardRequired: + out->dataDiscardRequired = ie->value.choice.DataDiscardRequired; + break; + + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: { + _E1_EQ_CHECK_INT(ie->value.present, + E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); + E1AP_System_BearerContextModificationRequest_t *modReq = &ie->value.choice.System_BearerContextModificationRequest; + DevAssert(ie->value.choice.System_BearerContextModificationRequest.choice.nG_RAN_BearerContextModificationRequest != NULL); + // System IE can contain either UTRAN or NG-RAN + switch (modReq->present) { + case E1AP_System_BearerContextModificationRequest_PR_NOTHING: + PRINT_ERROR("System Bearer Context Setup Request: no choice present\n"); + break; + case E1AP_System_BearerContextModificationRequest_PR_e_UTRAN_BearerContextModificationRequest: + PRINT_ERROR("UTRAN in E1 Setup Modification Request not supported\n"); + return false; + break; + case E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest: + // NG-RAN + AssertFatal(modReq->choice.nG_RAN_BearerContextModificationRequest != NULL, + "System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null"); + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P26_t *)modReq->choice.nG_RAN_BearerContextModificationRequest; + // loop through all items in the NG-RAN list (to setup, to modify, etc) + for (int i = 0; i < msgNGRAN_list->list.count; i++) { + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = msgNGRAN_list->list.array[i]; + switch (msgNGRAN->id) { + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List: + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List); + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List); + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *setupList = + &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + // PDU Session Resource To Modify List + out->numPDUSessions = setupList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < setupList->list.count; i++) { + pdu_session_to_setup_t *pdu_session = out->pduSession + i; + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *pdu2Setup = setupList->list.array[i]; + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_mod_item(pdu_session, pdu2Setup)); + } + break; + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List: + /* PDU Session Resource To Modify List (see 9.3.3.11 of TS 38.463) */ + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List); + E1AP_PDU_Session_Resource_To_Modify_List_t *modList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + out->numPDUSessionsMod = modList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < modList->list.count; i++) { + CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i])); + } + break; + default: + PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n"); + return false; + break; + } + } + + break; + default: + PRINT_ERROR("System Bearer Context Modification Request: No valid choice present.\n"); + break; + } + + break; + } + + default: + PRINT_ERROR("System Bearer Context Modification Request: this IE is not implemented (or) invalid IE detected\n"); + return false; + break; + } + } + + return true; +} + +/** @brief Deep copy for DRB Item to modify */ +static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + DRB_nGRAN_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + _E1_CP_OPTIONAL_IE(&cp, msg, sdap_config); + _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config); + return cp; +} + +/** @brief Deep copy for PDU Session Item to modify */ +static pdu_session_to_mod_t cp_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + pdu_session_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + // DRB to setup list + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // DRB to modify list + for (int j = 0; j < msg->numDRB2Modify; j++) + cp.DRBnGRanModList[j] = cp_drb_to_mod_item(&msg->DRBnGRanModList[j]); + _E1_CP_OPTIONAL_IE(&cp, msg, securityIndication); + _E1_CP_OPTIONAL_IE(&cp, msg, UP_TL_information); + return cp; +} + +/** @brief Deep copy for Bearer Context Modification Request */ +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + e1ap_bearer_mod_req_t cp = {0}; + // Shallow copy + cp = *msg; + // Deep copy for optional fields + _E1_CP_OPTIONAL_IE(&cp, msg, secInfo); + _E1_CP_OPTIONAL_IE(&cp, msg, bearerContextStatus); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + // Deep copy PDU sessions + for (int i = 0; i < msg->numPDUSessions; i++) + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]); + return cp; +} + +/** @brief Equality check for Security Indication IE (3GPP TS 38.463 9.3.1.23) */ +static bool eq_security_ind(security_indication_t *a, security_indication_t *b) +{ + _E1_EQ_CHECK_INT(a->confidentialityProtectionIndication, b->confidentialityProtectionIndication); + _E1_EQ_CHECK_INT(a->integrityProtectionIndication, b->integrityProtectionIndication); + _E1_EQ_CHECK_LONG(a->maxIPrate, b->maxIPrate); + return true; +} + +/** + * @brief Equality check for DRB_nGRAN_to_mod_t + */ +static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +{ + bool result = true; + _E1_EQ_CHECK_LONG(a->id, b->id); + _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); + for (int i = 0; i < a->numQosFlow2Setup; i++) { + result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + } + _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); + for (int i = 0; i < a->numDlUpParam; i++) { + _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); + eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info); + } + if (a->pdcp_config && b->pdcp_config) + result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config); + if (a->sdap_config && b->sdap_config) + result &= eq_sdap_config(a->sdap_config, b->sdap_config); + return result; +} + +/** @brief Equality check for PDU session item to modify */ +static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b) +{ + _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); + if (a->UP_TL_information && a->UP_TL_information) { + if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information)) + return false; + } + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); + for (int i = 0; i < a->numDRB2Setup; i++) { + if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) + return false; + } + _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); + for (int i = 0; i < a->numDRB2Modify; i++) { + if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) + return false; + } + if (a->securityIndication && b->securityIndication) { + eq_security_ind(a->securityIndication, b->securityIndication); + } + return true; +} + +/** + * @brief E1AP Bearer Modification Request equality check + */ +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b) +{ + // basic members + _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); + _E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id); + _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); + _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); + // Security Info + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, secInfo); + if (a->secInfo && b->secInfo) { + _E1_EQ_CHECK_LONG(a->secInfo->cipheringAlgorithm, b->secInfo->cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo->integrityProtectionAlgorithm, b->secInfo->integrityProtectionAlgorithm); + _E1_EQ_CHECK_STR(a->secInfo->encryptionKey, b->secInfo->encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo->integrityProtectionKey, b->secInfo->integrityProtectionKey); + } + // Bearer Context Status (O) + _E1_EQ_CHECK_OPTIONAL_IE(a, b, bearerContextStatus, _E1_EQ_CHECK_INT); + // Inactivity Timer (O) + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(*a->inactivityTimer, *b->inactivityTimer); + // Activity Notification Level (O) + // PDU Sessions + if (a->numPDUSessions != b->numPDUSessions) + return false; + for (int i = 0; i < a->numPDUSessions; i++) { + if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) + return false; + } + // Modified PDU Sessions + if (a->numPDUSessionsMod != b->numPDUSessionsMod) + return false; + for (int i = 0; i < a->numPDUSessionsMod; i++) { + if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) + return false; + } + return true; +} + +/* Free DRB to modify item */ +static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + free(msg->pdcp_config); + free(msg->sdap_config); +} + +/* Free PDU Session to modify item */ +void free_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + free(msg->securityIndication); + free(msg->UP_TL_information); + for (int i = 0; i < msg->numDRB2Modify; i++) + free_drb_to_mod_item(&msg->DRBnGRanModList[i]); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + +/** + * @brief E1AP Bearer Context Modification Request memory management + */ +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + free(msg->secInfo); + free(msg->ueDlAggMaxBitRate); + free(msg->ueDlMaxIPBitRate); + free(msg->bearerContextStatus); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numPDUSessions; i++) + free_pdu_session_to_setup_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + free_pdu_session_to_mod_item(&msg->pduSessionMod[i]); +} diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.h b/openair2/E1AP/lib/e1ap_bearer_context_management.h index 95e4cb0e159c93c964dd261a40a86a5af64c4f34..132c1857e1f45b45490ac9e03f32a2aef9b5dd73 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.h +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.h @@ -40,4 +40,10 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg); e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg); bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b); +struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool decode_E1_bearer_context_mod_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_mod_req_t *out); +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg); +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b); + #endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */ diff --git a/openair2/E1AP/lib/e1ap_interface_management.c b/openair2/E1AP/lib/e1ap_interface_management.c index 8f29ba07c5aff24bc6184b1185e3d516255beb86..681942f58b71bc6e2931659fb3b704aa58ef85a1 100644 --- a/openair2/E1AP/lib/e1ap_interface_management.c +++ b/openair2/E1AP/lib/e1ap_interface_management.c @@ -508,61 +508,6 @@ bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_re * GNB-CU-UP E1 SETUP FAILURE * ==================================== */ -static E1AP_Cause_t encode_e1ap_cause_ie(const e1ap_cause_t *cause) -{ - E1AP_Cause_t ie; - switch (cause->type) { - case E1AP_CAUSE_RADIO_NETWORK: - ie.present = E1AP_Cause_PR_radioNetwork; - ie.choice.radioNetwork = cause->value; - break; - case E1AP_CAUSE_TRANSPORT: - ie.present = E1AP_Cause_PR_transport; - ie.choice.transport = cause->value; - break; - case E1AP_CAUSE_PROTOCOL: - ie.present = E1AP_Cause_PR_protocol; - ie.choice.protocol = cause->value; - break; - case E1AP_CAUSE_MISC: - ie.present = E1AP_Cause_PR_misc; - ie.choice.misc = cause->value; - break; - default: - ie.present = E1AP_Cause_PR_NOTHING; - break; - } - return ie; -} - -static e1ap_cause_t decode_e1ap_cause_ie(const E1AP_Cause_t *ie) -{ - e1ap_cause_t cause; - // Decode the 'choice' field based on the 'present' value - switch (ie->present) { - case E1AP_Cause_PR_radioNetwork: - cause.value = ie->choice.radioNetwork; - cause.type = E1AP_CAUSE_RADIO_NETWORK; - break; - case E1AP_Cause_PR_transport: - cause.value = ie->choice.transport; - cause.type = E1AP_CAUSE_TRANSPORT; - break; - case E1AP_Cause_PR_protocol: - cause.value = ie->choice.protocol; - cause.type = E1AP_CAUSE_PROTOCOL; - break; - case E1AP_Cause_PR_misc: - cause.value = ie->choice.misc; - cause.type = E1AP_CAUSE_MISC; - break; - default: - cause.type = E1AP_CAUSE_NOTHING; - break; - } - return cause; -} - /** * @brief Encoder for GNB-CU-UP E1 Setup Failure * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463 @@ -588,7 +533,7 @@ E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg) ie2->id = E1AP_ProtocolIE_ID_id_Cause; ie2->criticality = E1AP_Criticality_ignore; ie2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause; - ie2->value.choice.Cause = encode_e1ap_cause_ie(&msg->cause); + ie2->value.choice.Cause = e1_encode_cause_ie(&msg->cause); // Time To Wait (O) if (msg->time_to_wait) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie3); @@ -630,7 +575,7 @@ bool decode_e1ap_cuup_setup_failure(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_fail_ case E1AP_ProtocolIE_ID_id_Cause: // Cause E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true); - out->cause = decode_e1ap_cause_ie(&ie->value.choice.Cause); + out->cause = e1_decode_cause_ie(&ie->value.choice.Cause); break; case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info: // Time To Wait (O) diff --git a/openair2/E1AP/lib/e1ap_lib_common.c b/openair2/E1AP/lib/e1ap_lib_common.c new file mode 100644 index 0000000000000000000000000000000000000000..02923b7cf7426aa4869c922c6e88094f24568d15 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_lib_common.c @@ -0,0 +1,81 @@ +/* + * 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 "e1ap_lib_common.h" +#include "e1ap_lib_includes.h" +#include "e1ap_messages_types.h" + +E1AP_Cause_t e1_encode_cause_ie(const e1ap_cause_t *cause) +{ + E1AP_Cause_t ie; + switch (cause->type) { + case E1AP_CAUSE_RADIO_NETWORK: + ie.present = E1AP_Cause_PR_radioNetwork; + ie.choice.radioNetwork = cause->value; + break; + case E1AP_CAUSE_TRANSPORT: + ie.present = E1AP_Cause_PR_transport; + ie.choice.transport = cause->value; + break; + case E1AP_CAUSE_PROTOCOL: + ie.present = E1AP_Cause_PR_protocol; + ie.choice.protocol = cause->value; + break; + case E1AP_CAUSE_MISC: + ie.present = E1AP_Cause_PR_misc; + ie.choice.misc = cause->value; + break; + default: + ie.present = E1AP_Cause_PR_NOTHING; + PRINT_ERROR("encode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return ie; +} + +e1ap_cause_t e1_decode_cause_ie(const E1AP_Cause_t *ie) +{ + e1ap_cause_t cause; + // Decode the 'choice' field based on the 'present' value + switch (ie->present) { + case E1AP_Cause_PR_radioNetwork: + cause.value = ie->choice.radioNetwork; + cause.type = E1AP_CAUSE_RADIO_NETWORK; + break; + case E1AP_Cause_PR_transport: + cause.value = ie->choice.transport; + cause.type = E1AP_CAUSE_TRANSPORT; + break; + case E1AP_Cause_PR_protocol: + cause.value = ie->choice.protocol; + cause.type = E1AP_CAUSE_PROTOCOL; + break; + case E1AP_Cause_PR_misc: + cause.value = ie->choice.misc; + cause.type = E1AP_CAUSE_MISC; + break; + default: + cause.type = E1AP_CAUSE_NOTHING; + PRINT_ERROR("decode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return cause; +} diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index f3c6b24da24af5c23228d1a0169215c23e8465e5..6fda2cd8ca3def23baca8ecc4f98a32786c71de9 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -26,13 +26,22 @@ #include <stdint.h> #include <stdio.h> #include "openair3/UTILS/conversions.h" +#include "e1ap_messages_types.h" -#ifdef ENABLE_TESTS +#ifdef E1AP_LOG_ERRORS #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__); #else #define PRINT_ERROR(...) // Do nothing #endif +#define CHECK_E1AP_DEC(exp) \ + do { \ + if (!(exp)) { \ + PRINT_ERROR("Failed executing " #exp " in %s() line %d\n", __func__, __LINE__); \ + return false; \ + } \ + } while (0) + #define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \ do { \ if (!(condition)) { \ @@ -66,4 +75,40 @@ } \ } while (0) +/* deep copy of optional E1AP IE */ +#define _E1_CP_OPTIONAL_IE(dest, src, field) \ + do { \ + if ((src)->field) { \ + (dest)->field = malloc_or_fail(sizeof(*(dest)->field)); \ + *(dest)->field = *(src)->field; \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_IE(a, b, field, EQ_MACRO) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + return false; /* One of the two is not allocated */ \ + } \ + if ((a)->field && (b)->field) { \ + EQ_MACRO(*(a)->field, *(b)->field) \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_PTR(a, b, field) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + PRINT_ERROR("%s:%d: optional IE '%s' not allocated: %p, %p\n", \ + __FILE__, \ + __LINE__, \ + #field, \ + (void *)(a)->field, \ + (void *)(b)->field); \ + return false; /* One of the two is not allocated */ \ + } \ + } while (0) + +struct E1AP_Cause; +struct E1AP_Cause e1_encode_cause_ie(const e1ap_cause_t *cause); +e1ap_cause_t e1_decode_cause_ie(const struct E1AP_Cause *ie); + #endif /* E1AP_LIB_COMMON_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 443d59e19eeeac228b3b7bafc02313336f145710..46d09f5aa9609880faff25d48c28ccc9054eaedc 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -48,6 +48,7 @@ #include "E1AP_System-BearerContextSetupRequest.h" #include "E1AP_MaximumIPdatarate.h" #include "E1AP_PDU-Session-Type.h" +#include "E1AP_Data-Forwarding-Information.h" // E1 Bearer Context Setup Response #include "E1AP_PDU-Session-Resource-Setup-Item.h" #include "E1AP_DRB-Setup-Item-NG-RAN.h" @@ -66,5 +67,11 @@ #include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-Item.h" #include "E1AP_GTPTLAs.h" #include "E1AP_GTPTLA-Item.h" +// E1 Bearer Context Modification Request +#include "E1AP_PDU-Session-Resource-To-Modify-Item.h" +#include "E1AP_DRB-To-Modify-List-NG-RAN.h" +#include "E1AP_DRB-To-Modify-Item-NG-RAN.h" +#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h" +#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h" #endif /* E1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 91eab080a92a961376020097793838486279327c..59e6f08e66f711965f53b197f067023cd6777fa4 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -70,6 +70,14 @@ static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu) ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu); } +static UP_TL_information_t create_up_tl_info(void) +{ + UP_TL_information_t tl_info; + tl_info.tlAddress = htonl(0xC0A90001); // 192.169.0.1 + tl_info.teId = 0x2345; + return tl_info; +} + /** * @brief Test E1AP Bearer Context Setup Request encoding/decoding */ @@ -77,7 +85,7 @@ static void test_bearer_context_setup_request(void) { bearer_context_pdcp_config_t pdcp = { .discardTimer = E1AP_DiscardTimer_ms10, - .pDCP_Reestablishment = E1AP_PDCP_Reestablishment_true, + .pDCP_Reestablishment = true, .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, .reorderingTimer = 10, @@ -107,14 +115,13 @@ static void test_bearer_context_setup_request(void) // Step 1: Initialize the E1AP Bearer Context Setup Request e1ap_bearer_setup_req_t orig = { .gNB_cu_cp_ue_id = 1234, - .cipheringAlgorithm = 0x01, - .integrityProtectionAlgorithm = 0x01, + .secInfo.cipheringAlgorithm = 0x01, + .secInfo.integrityProtectionAlgorithm = 0x01, .ueDlAggMaxBitRate = 1000000000, .bearerContextStatus = 0, .servingPLMNid.mcc = 001, .servingPLMNid.mnc = 01, .servingPLMNid.mnc_digit_length = 0x02, - .activityNotificationLevel = ANL_PDU_SESSION, .numPDUSessions = 1, .pduSession[0].sessionId = 1, .pduSession[0].sessionType = E1AP_PDU_Session_Type_ipv4, @@ -122,8 +129,7 @@ static void test_bearer_context_setup_request(void) .pduSession[0].nssai.sst = 0x01, .pduSession[0].securityIndication = security, .pduSession[0].numDRB2Setup = 1, - .pduSession[0].UP_TL_information.tlAddress = 167772161, - .pduSession[0].UP_TL_information.teId = 0x12345, + .pduSession[0].UP_TL_information = create_up_tl_info(), .pduSession[0].DRBnGRanList[0].id = 1, .pduSession[0].DRBnGRanList[0].sdap_config = sdap, .pduSession[0].DRBnGRanList[0].pdcp_config = pdcp, @@ -133,8 +139,8 @@ static void test_bearer_context_setup_request(void) .pduSession[0].DRBnGRanList[0].numQosFlow2Setup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0] = qos, }; - memset(orig.encryptionKey, 0xAB, sizeof(orig.encryptionKey)); - memset(orig.integrityProtectionKey, 0xCD, sizeof(orig.integrityProtectionKey)); + memset(orig.secInfo.encryptionKey, 0xAB, sizeof(orig.secInfo.encryptionKey)); + memset(orig.secInfo.integrityProtectionKey, 0xCD, sizeof(orig.secInfo.integrityProtectionKey)); // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig); // E1AP decode the encoded message @@ -172,8 +178,7 @@ static void test_bearer_context_setup_response(void) .gNB_cu_up_ue_id = 5678, .numPDUSessions = 1, .pduSession[0].id = 1, - .pduSession[0].tlAddress = 167772161, - .pduSession[0].teId = 0x12345, + .pduSession[0].tl_info = create_up_tl_info(), .pduSession[0].numDRBSetup = 1, .pduSession[0].numDRBFailed = 0, .pduSession[0].DRBnGRanList[0].id = 1, @@ -181,8 +186,7 @@ static void test_bearer_context_setup_response(void) .pduSession[0].DRBnGRanList[0].numQosFlowSetup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0].qfi = 1, .pduSession[0].DRBnGRanList[0].UpParamList[0].cell_group_id = MCG, - .pduSession[0].DRBnGRanList[0].UpParamList[0].teId = 0x34345, - .pduSession[0].DRBnGRanList[0].UpParamList[0].tlAddress = 167772161, + .pduSession[0].DRBnGRanList[0].UpParamList[0].tl_info = create_up_tl_info(), }; // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig); @@ -335,6 +339,120 @@ static void test_e1_cuup_setup_failure(void) free_e1ap_cuup_setup_failure(&orig); } +/** + * @brief Test E1AP Bearer Context Modification Request encoding/decoding + */ +static void test_bearer_context_modification_request(void) +{ + const bearer_context_sdap_config_t dummy_sdap_config = { + .defaultDRB = 0, + .sDAP_Header_DL = false, + .sDAP_Header_UL = false, + }; + + const bearer_context_pdcp_config_t dummy_pdcp_config = { + .discardTimer = E1AP_DiscardTimer_ms100, + .pDCP_Reestablishment = true, + .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, + .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, + .reorderingTimer = 5, + .rLC_Mode = E1AP_RLC_Mode_rlc_um_bidirectional, + }; + + const qos_flow_to_setup_t dummy_qos_flows = { + .qfi = 9, + .qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_may_trigger_pre_emption, + .qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_pre_emptable, + .qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_no_priority, + .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, + }; + + DRB_nGRAN_to_mod_t drb_to_mod = { + .numDlUpParam = 1, + .DlUpParamList[0].cell_group_id = MCG, + .DlUpParamList[0].tl_info = create_up_tl_info(), + .id = 1, + .pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)), + .pdcp_sn_status_requested = true, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + }; + *drb_to_mod.pdcp_config = dummy_pdcp_config; + + pdu_session_to_mod_t pdusession_mod_item = { + .sessionId = 1, + .numDRB2Modify = 1, + .DRBnGRanModList[0] = drb_to_mod, + }; + + DRB_nGRAN_to_setup_t drb_to_setup = { + .id = 1, + .cellGroupList[0] = MCG, + .numCellGroups = 1, + .pdcp_config = dummy_pdcp_config, + .sdap_config = dummy_sdap_config, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + .drb_inactivity_timer = malloc_or_fail(sizeof(*drb_to_setup.drb_inactivity_timer)), + }; + *drb_to_setup.drb_inactivity_timer = 500; + + pdu_session_to_setup_t pdusession_setup_item = { + .numDRB2Setup = 1, + .nssai.sd = 0x01, + .nssai.sst = 0x01, + .UP_TL_information.teId = 0x12345, + .UP_TL_information.tlAddress = 167772161, + .DRBnGRanList[0] = drb_to_setup, + }; + + // Initialize the Bearer Context Modification Request + e1ap_bearer_mod_req_t orig = { + .gNB_cu_cp_ue_id = 0x1234, + .gNB_cu_up_ue_id = 0x5678, + .bearerContextStatus = malloc_or_fail(sizeof(*orig.bearerContextStatus)), + .inactivityTimer = malloc_or_fail(sizeof(*orig.inactivityTimer)), + .numPDUSessions = 1, + .pduSession[0] = pdusession_setup_item, + .numPDUSessionsMod = 1, + .pduSessionMod[0] = pdusession_mod_item, + }; + *orig.bearerContextStatus = BEARER_SUSPEND; + *orig.inactivityTimer = 1000; + + // Encode the original message + E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_mod_request(&orig); + + // Decode the encoded message + E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc); + + // Free the encoded message + e1ap_msg_free(enc); + + // Decode the message into a new struct + e1ap_bearer_mod_req_t decoded = {0}; + AssertFatal(decode_E1_bearer_context_mod_request(dec, &decoded), "decode_E1_bearer_context_mod_request(): could not decode message\n"); + + // Free the decoded E1AP message + e1ap_msg_free(dec); + + // Compare the original and decoded structs + AssertFatal(eq_bearer_context_mod_request(&orig, &decoded), "eq_bearer_context_mod_request(): decoded message doesn't match\n"); + + // Free the memory for the decoded message + free_e1ap_context_mod_request(&decoded); + + // Deep copy the original message + e1ap_bearer_mod_req_t cp = cp_bearer_context_mod_request(&orig); + + // Verify the deep copy matches the original + AssertFatal(eq_bearer_context_mod_request(&orig, &cp), "eq_bearer_context_mod_request(): copied message doesn't match\n"); + + // Free the copied and original message + free_e1ap_context_mod_request(&cp); + free_e1ap_context_mod_request(&orig); +} + int main() { // E1 Bearer Context Setup @@ -344,5 +462,7 @@ int main() test_e1_cuup_setup_request(); test_e1_cuup_setup_response(); test_e1_cuup_setup_failure(); + // E1 Bearer Context Modification Request + test_bearer_context_modification_request(); return 0; } diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index 9e25aeb63e57edda0d27344e77cf3f1f5a84dbc2..e697649fb58e46bdf1117d00c61bf3a81c7b795e 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -36,11 +36,24 @@ #include "f1ap_cu_interface_management.h" #include "f1ap_default_values.h" #include "lib/f1ap_interface_management.h" -#include "lib/f1ap_lib_common.h" int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1 == 0, "Not implemented yet\n"); + DevAssert(pdu != NULL); + + f1ap_reset_ack_t ack = {0}; + /* Decode */ + if (!decode_f1ap_reset_ack(pdu, &ack)) { + LOG_E(F1AP, "cannot decode F1AP Reset acknowledgement\n"); + free_f1ap_reset_ack(&ack); + return -1; + } + /* Send to RRC (ITTI) */ + MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_RESET_ACK); + message_p->ittiMsgHeader.originInstance = assoc_id; + F1AP_RESET_ACK(message_p) = ack; /* "move" message into ITTI, RRC thread will free it */ + itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); + return 0; } int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack) @@ -48,6 +61,28 @@ int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack AssertFatal(1 == 0, "Not implemented yet\n"); } +void CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) +{ + uint8_t *buffer = NULL; + uint32_t len = 0; + + /* Encode F1 Reset */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_reset(reset); + if (pdu == NULL) { + LOG_E(F1AP, "failed to create asn.1 message for f1ap reset\n"); + return; + } + + /* encode ASN.1 PER */ + int encoded = f1ap_encode_pdu(pdu, &buffer, &len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + if (encoded <= 0) { + LOG_E(F1AP, "Failed to encode F1 reset\n"); + return; + } + f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); +} + /** * @brief F1AP Setup Request decoding (9.2.1.4 of 3GPP TS 38.473) and transfer to RRC */ diff --git a/openair2/F1AP/f1ap_cu_interface_management.h b/openair2/F1AP/f1ap_cu_interface_management.h index 9d0bf4a3915280ada3bacfc39bb60e79356160e1..fb39f1ca53231ce847753829f66ef5f916b90ddd 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.h +++ b/openair2/F1AP/f1ap_cu_interface_management.h @@ -36,6 +36,7 @@ /* * Reset */ +void CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset); int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack); diff --git a/openair2/F1AP/f1ap_cu_task.c b/openair2/F1AP/f1ap_cu_task.c index fa77f818ead41b3f540d63edfbfc6b7d6096f2f0..deb272776fd2284d5eb5a1a809d5babbd6c8aac3 100644 --- a/openair2/F1AP/f1ap_cu_task.c +++ b/openair2/F1AP/f1ap_cu_task.c @@ -35,6 +35,7 @@ #include "f1ap_cu_rrc_message_transfer.h" #include "f1ap_cu_ue_context_management.h" #include "lib/f1ap_rrc_message_transfer.h" +#include "lib/f1ap_interface_management.h" #include "f1ap_cu_paging.h" #include "f1ap_cu_task.h" #include <openair3/ocp-gtpu/gtp_itf.h> @@ -151,6 +152,11 @@ void *F1AP_CU_task(void *arg) { &received_msg->ittiMsg.sctp_data_ind); break; + case F1AP_RESET: + CU_send_RESET(assoc_id, &F1AP_RESET(received_msg)); + free_f1ap_reset(&F1AP_RESET(received_msg)); + break; + case F1AP_RESET_ACK: CU_send_RESET_ACKNOWLEDGE(assoc_id, &F1AP_RESET_ACK(received_msg)); break; diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index f12b104263e7851a8575733da3d49fd9eeacc068..7a892086b8180b1321820c5bbe65bb7ed2481ac4 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -35,7 +35,6 @@ #include "f1ap_itti_messaging.h" #include "f1ap_du_interface_management.h" #include "lib/f1ap_interface_management.h" -#include "lib/f1ap_lib_common.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" #include "assertions.h" @@ -118,35 +117,21 @@ int DU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, int DU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack) { - F1AP_F1AP_PDU_t pdu= {0}; - uint8_t *buffer; - uint32_t len; - /* Create */ - /* 0. pdu Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, successMsg); - successMsg->procedureCode = F1AP_ProcedureCode_id_Reset; - successMsg->criticality = F1AP_Criticality_reject; - successMsg->value.present = F1AP_SuccessfulOutcome__value_PR_ResetAcknowledge; - F1AP_ResetAcknowledge_t *f1ResetAcknowledge = &successMsg->value.choice.ResetAcknowledge; - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(f1ResetAcknowledge->protocolIEs.list, F1AP_ResetAcknowledgeIEs_t, ieC1); - ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = F1AP_Criticality_reject; - ieC1->value.present = F1AP_ResetAcknowledgeIEs__value_PR_TransactionID; - ieC1->value.choice.TransactionID = ack->transaction_id; - - /* TODO: (Optional) partialF1Interface, criticality diagnostics */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_reset_ack(ack); + if (!pdu) { + LOG_E(F1AP, "failed to create ASN.1 message for reset acknowledge\n"); + return -1; + } /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer; + uint32_t len; + int encoded = f1ap_encode_pdu(pdu, &buffer, &len); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + if (encoded <= 0) { LOG_E(F1AP, "Failed to encode F1ResetAcknowledge\n"); return -1; } - - /* send */ - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index 0d675a76e19d17447f73423a5a1fde28c849c42b..c231561eec68a2e105072414ecf190c1ca72a42c 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -35,6 +35,7 @@ #include "f1ap_du_ue_context_management.h" #include "f1ap_du_rrc_message_transfer.h" #include "lib/f1ap_rrc_message_transfer.h" +#include "lib/f1ap_interface_management.h" #include "f1ap_du_task.h" #include <openair3/ocp-gtpu/gtp_itf.h> @@ -150,6 +151,7 @@ void *F1AP_DU_task(void *arg) { case F1AP_RESET_ACK: DU_send_RESET_ACKNOWLEDGE(assoc_id, &F1AP_RESET_ACK(msg)); + free_f1ap_reset_ack(&F1AP_RESET_ACK(msg)); break; case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE: diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index 182f40952dc1ff129c358f545a8f5cb20c4c1bed..08f324a6188a48be99b45332231906261e8de28a 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -32,6 +32,341 @@ #include "f1ap_messages_types.h" #include "f1ap_lib_extern.h" +F1AP_UE_associatedLogicalF1_ConnectionItem_t encode_f1ap_ue_to_reset(const f1ap_ue_to_reset_t *to_reset) +{ + F1AP_UE_associatedLogicalF1_ConnectionItem_t conn_it = {0}; + + if (to_reset->gNB_CU_ue_id) + asn1cCallocOne(conn_it.gNB_CU_UE_F1AP_ID, *to_reset->gNB_CU_ue_id); + if (to_reset->gNB_DU_ue_id) + asn1cCallocOne(conn_it.gNB_DU_UE_F1AP_ID, *to_reset->gNB_DU_ue_id); + + return conn_it; +} + +f1ap_ue_to_reset_t decode_f1ap_ue_to_reset(const F1AP_UE_associatedLogicalF1_ConnectionItem_t *conn_it) +{ + f1ap_ue_to_reset_t to_reset = {0}; + if (conn_it->gNB_CU_UE_F1AP_ID) { + to_reset.gNB_CU_ue_id = malloc_or_fail(sizeof(*to_reset.gNB_CU_ue_id)); + *to_reset.gNB_CU_ue_id = *conn_it->gNB_CU_UE_F1AP_ID; + } + if (conn_it->gNB_DU_UE_F1AP_ID) { + to_reset.gNB_DU_ue_id = malloc_or_fail(sizeof(*to_reset.gNB_DU_ue_id)); + *to_reset.gNB_DU_ue_id = *conn_it->gNB_DU_UE_F1AP_ID; + } + return to_reset; +} + +void free_f1ap_ue_to_reset(const f1ap_ue_to_reset_t *to_reset) +{ + free(to_reset->gNB_CU_ue_id); + free(to_reset->gNB_DU_ue_id); +} + +bool eq_f1ap_ue_to_reset(const f1ap_ue_to_reset_t *a, const f1ap_ue_to_reset_t *b) +{ + if ((!a->gNB_CU_ue_id) ^ (!b->gNB_CU_ue_id)) + return false; + if (a->gNB_CU_ue_id) + _F1_EQ_CHECK_INT(*a->gNB_CU_ue_id, *b->gNB_CU_ue_id); + if ((!a->gNB_DU_ue_id) ^ (!b->gNB_DU_ue_id)) + return false; + if (a->gNB_DU_ue_id) + _F1_EQ_CHECK_INT(*a->gNB_DU_ue_id, *b->gNB_DU_ue_id); + return true; +} + +f1ap_ue_to_reset_t cp_f1ap_ue_to_reset(const f1ap_ue_to_reset_t *orig) +{ + f1ap_ue_to_reset_t cp = {0}; + if (orig->gNB_CU_ue_id) { + cp.gNB_CU_ue_id = malloc_or_fail(sizeof(*cp.gNB_CU_ue_id)); + *cp.gNB_CU_ue_id = *orig->gNB_CU_ue_id; + } + if (orig->gNB_DU_ue_id) { + cp.gNB_DU_ue_id = malloc_or_fail(sizeof(*cp.gNB_DU_ue_id)); + *cp.gNB_DU_ue_id = *orig->gNB_DU_ue_id; + } + return cp; +} + +/* @brief encode F1 Reset (9.2.1.1 in TS 38.473) */ +F1AP_F1AP_PDU_t *encode_f1ap_reset(const f1ap_reset_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = F1AP_ProcedureCode_id_Reset; + initMsg->criticality = F1AP_Criticality_reject; + initMsg->value.present = F1AP_InitiatingMessage__value_PR_Reset; + F1AP_Reset_t *reset = &initMsg->value.choice.Reset; + + /* (M) Transaction ID */ + asn1cSequenceAdd(reset->protocolIEs.list, F1AP_ResetIEs_t, ieC1); + ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = F1AP_Criticality_reject; + ieC1->value.present = F1AP_ResetIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transaction_id; + + /* (M) Cause */ + asn1cSequenceAdd(reset->protocolIEs.list, F1AP_ResetIEs_t, ieC2); + ieC2->id = F1AP_ProtocolIE_ID_id_Cause; + ieC2->criticality = F1AP_Criticality_ignore; + ieC2->value.present = F1AP_ResetIEs__value_PR_Cause; + ieC2->value.choice.Cause = encode_f1ap_cause(msg->cause, msg->cause_value); + + /* (M) Reset type */ + asn1cSequenceAdd(reset->protocolIEs.list, F1AP_ResetIEs_t, ieC3); + ieC3->id = F1AP_ProtocolIE_ID_id_ResetType; + ieC3->criticality = F1AP_Criticality_reject; + ieC3->value.present = F1AP_ResetIEs__value_PR_ResetType; + if (msg->reset_type == F1AP_RESET_ALL) { + ieC3->value.choice.ResetType.present = F1AP_ResetType_PR_f1_Interface; + ieC3->value.choice.ResetType.choice.f1_Interface = F1AP_ResetAll_reset_all; + AssertFatal(msg->num_ue_to_reset == 0, "cannot have F1AP_RESET_ALL and %d UEs to reset\n", msg->num_ue_to_reset); + } else if (msg->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE) { + F1AP_UE_associatedLogicalF1_ConnectionListRes_t *con_list = calloc_or_fail(1, sizeof(*con_list)); + ieC3->value.choice.ResetType.present = F1AP_ResetType_PR_partOfF1_Interface; + ieC3->value.choice.ResetType.choice.partOfF1_Interface = con_list; + AssertFatal(msg->num_ue_to_reset > 0, "at least one UE to reset required\n"); + for (int i = 0; i < msg->num_ue_to_reset; ++i) { + asn1cSequenceAdd(con_list->list, F1AP_UE_associatedLogicalF1_ConnectionItemRes_t, conn_it_res); + conn_it_res->id = F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionItem; + conn_it_res->criticality = F1AP_Criticality_reject; + conn_it_res->value.present = F1AP_UE_associatedLogicalF1_ConnectionItemRes__value_PR_UE_associatedLogicalF1_ConnectionItem; + conn_it_res->value.choice.UE_associatedLogicalF1_ConnectionItem = encode_f1ap_ue_to_reset(&msg->ue_to_reset[i]); + } + } else { + AssertFatal(false, "illegal reset_type %d\n", msg->reset_type); + } + + return pdu; +} + +/* @brief decode F1 Reset (9.2.1.1 in TS 38.473) */ +bool decode_f1ap_reset(const F1AP_F1AP_PDU_t *pdu, f1ap_reset_t *out) +{ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_initiatingMessage); + AssertError(pdu->choice.initiatingMessage != NULL, return false, "pdu->choice.initiatingMessage is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, F1AP_ProcedureCode_id_Reset); + _F1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, F1AP_InitiatingMessage__value_PR_Reset); + + /* Check presence of mandatory IEs */ + F1AP_Reset_t *in = &pdu->choice.initiatingMessage->value.choice.Reset; + F1AP_ResetIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_Cause, true); + F1AP_LIB_FIND_IE(F1AP_ResetIEs_t, ie, in, F1AP_ProtocolIE_ID_id_ResetType, true); + + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + // (M) Transaction ID + _F1_EQ_CHECK_INT(ie->value.present, F1AP_ResetIEs__value_PR_TransactionID); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_Cause: + // (M) Cause + _F1_EQ_CHECK_INT(ie->value.present, F1AP_ResetIEs__value_PR_Cause); + if (!decode_f1ap_cause(ie->value.choice.Cause, &out->cause, &out->cause_value)) { + PRINT_ERROR("could not decode F1AP Cause\n"); + return false; + } + break; + case F1AP_ProtocolIE_ID_id_ResetType: + // (M) Reset type + _F1_EQ_CHECK_INT(ie->value.present, F1AP_ResetIEs__value_PR_ResetType); + if (ie->value.choice.ResetType.present == F1AP_ResetType_PR_f1_Interface) { + out->reset_type = F1AP_RESET_ALL; + } else if (ie->value.choice.ResetType.present == F1AP_ResetType_PR_partOfF1_Interface) { + out->reset_type = F1AP_RESET_PART_OF_F1_INTERFACE; + const F1AP_UE_associatedLogicalF1_ConnectionListRes_t *con_list = ie->value.choice.ResetType.choice.partOfF1_Interface; + AssertError(con_list->list.count > 0, return false, "no UEs for partially reset F1 interface\n"); + out->num_ue_to_reset = con_list->list.count; + out->ue_to_reset = calloc_or_fail(out->num_ue_to_reset, sizeof(*out->ue_to_reset)); + for (int i = 0; i < out->num_ue_to_reset; ++i) { + const F1AP_UE_associatedLogicalF1_ConnectionItemRes_t *it_res = + (const F1AP_UE_associatedLogicalF1_ConnectionItemRes_t *)con_list->list.array[i]; + _F1_EQ_CHECK_LONG(it_res->id, F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionItem); + _F1_EQ_CHECK_INT(it_res->value.present, + F1AP_UE_associatedLogicalF1_ConnectionItemRes__value_PR_UE_associatedLogicalF1_ConnectionItem); + out->ue_to_reset[i] = decode_f1ap_ue_to_reset(&it_res->value.choice.UE_associatedLogicalF1_ConnectionItem); + } + } else { + PRINT_ERROR("unrecognized Reset type %d\n", ie->value.choice.ResetType.present); + return false; + } + } + } + return true; +} + +void free_f1ap_reset(f1ap_reset_t *msg) +{ + DevAssert(msg->reset_type == F1AP_RESET_ALL || msg->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE); + if (msg->reset_type == F1AP_RESET_ALL) { + DevAssert(msg->ue_to_reset == NULL); + return; /* nothing to be freed in this case */ + } + for (int i = 0; i < msg->num_ue_to_reset; ++i) + free_f1ap_ue_to_reset(&msg->ue_to_reset[i]); + free(msg->ue_to_reset); +} + +bool eq_f1ap_reset(const f1ap_reset_t *a, const f1ap_reset_t *b) +{ + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + _F1_EQ_CHECK_INT(a->cause, b->cause); + _F1_EQ_CHECK_LONG(a->cause_value, b->cause_value); + _F1_EQ_CHECK_INT(a->reset_type, b->reset_type); + if (a->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE) { + _F1_EQ_CHECK_INT(a->num_ue_to_reset, b->num_ue_to_reset); + for (int i = 0; i < a->num_ue_to_reset; ++i) + if (!eq_f1ap_ue_to_reset(&a->ue_to_reset[i], &b->ue_to_reset[i])) + return false; + } + return true; +} + +f1ap_reset_t cp_f1ap_reset(const f1ap_reset_t *orig) +{ + DevAssert(orig->reset_type == F1AP_RESET_ALL || orig->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE); + f1ap_reset_t cp = { + .transaction_id = orig->transaction_id, + .cause = orig->cause, + .cause_value = orig->cause_value, + .reset_type = orig->reset_type, + }; + if (orig->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE) { + DevAssert(orig->num_ue_to_reset > 0); + cp.num_ue_to_reset = orig->num_ue_to_reset; + cp.ue_to_reset = calloc_or_fail(cp.num_ue_to_reset, sizeof(*cp.ue_to_reset)); + for (int i = 0; i < cp.num_ue_to_reset; ++i) + cp.ue_to_reset[i] = cp_f1ap_ue_to_reset(&orig->ue_to_reset[i]); + } + return cp; +} + +/* @brief encode F1 Reset Ack (9.2.1.2 in TS 38.473) */ +struct F1AP_F1AP_PDU *encode_f1ap_reset_ack(const f1ap_reset_ack_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, so); + so->procedureCode = F1AP_ProcedureCode_id_Reset; + so->criticality = F1AP_Criticality_reject; + so->value.present = F1AP_SuccessfulOutcome__value_PR_ResetAcknowledge; + F1AP_ResetAcknowledge_t *reset_ack = &so->value.choice.ResetAcknowledge; + + /* (M) Transaction ID */ + asn1cSequenceAdd(reset_ack->protocolIEs.list, F1AP_ResetAcknowledgeIEs_t, ieC1); + ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = F1AP_Criticality_reject; + ieC1->value.present = F1AP_ResetAcknowledgeIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transaction_id; + + /* TODO criticality diagnostics */ + + /* 0:N UEs to reset */ + if (msg->num_ue_to_reset == 0) + return pdu; /* no UEs to encode */ + + asn1cSequenceAdd(reset_ack->protocolIEs.list, F1AP_ResetAcknowledgeIEs_t, ieC2); + ieC2->id = F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionListResAck; + ieC2->criticality = F1AP_Criticality_ignore; + ieC2->value.present = F1AP_ResetAcknowledgeIEs__value_PR_UE_associatedLogicalF1_ConnectionListResAck; + F1AP_UE_associatedLogicalF1_ConnectionListResAck_t *ue_to_reset = &ieC2->value.choice.UE_associatedLogicalF1_ConnectionListResAck; + for (int i = 0; i < msg->num_ue_to_reset; ++i) { + asn1cSequenceAdd(ue_to_reset->list, F1AP_UE_associatedLogicalF1_ConnectionItemResAck_t, conn_it_res); + conn_it_res->id = F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionItem; + conn_it_res->criticality = F1AP_Criticality_ignore; + conn_it_res->value.present = F1AP_UE_associatedLogicalF1_ConnectionItemResAck__value_PR_UE_associatedLogicalF1_ConnectionItem; + conn_it_res->value.choice.UE_associatedLogicalF1_ConnectionItem = encode_f1ap_ue_to_reset(&msg->ue_to_reset[i]); + } + return pdu; +} + +/* @brief decode F1 Reset Ack (9.2.1.2 in TS 38.473) */ +bool decode_f1ap_reset_ack(const struct F1AP_F1AP_PDU *pdu, f1ap_reset_ack_t *out) +{ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_successfulOutcome); + AssertError(pdu->choice.successfulOutcome != NULL, return false, "pdu->choice.initiatingMessage is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, F1AP_ProcedureCode_id_Reset); + _F1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, F1AP_SuccessfulOutcome__value_PR_ResetAcknowledge); + + /* Check presence of mandatory IEs */ + F1AP_ResetAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.ResetAcknowledge; + F1AP_ResetAcknowledgeIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_ResetAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + // (M) Transaction ID + _F1_EQ_CHECK_INT(ie->value.present, F1AP_ResetAcknowledgeIEs__value_PR_TransactionID); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionListResAck: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_ResetAcknowledgeIEs__value_PR_UE_associatedLogicalF1_ConnectionListResAck); + { + const F1AP_UE_associatedLogicalF1_ConnectionListResAck_t *conn_list = &ie->value.choice.UE_associatedLogicalF1_ConnectionListResAck; + AssertError(conn_list->list.count > 0, return false, "no UEs for partially reset F1 interface\n"); + out->num_ue_to_reset = conn_list->list.count; + out->ue_to_reset = calloc_or_fail(out->num_ue_to_reset, sizeof(*out->ue_to_reset)); + for (int i = 0; i < out->num_ue_to_reset; ++i) { + const F1AP_UE_associatedLogicalF1_ConnectionItemResAck_t *it_res = (const F1AP_UE_associatedLogicalF1_ConnectionItemResAck_t *)conn_list->list.array[i]; + _F1_EQ_CHECK_LONG(it_res->id, F1AP_ProtocolIE_ID_id_UE_associatedLogicalF1_ConnectionItem); + _F1_EQ_CHECK_INT(it_res->value.present, F1AP_UE_associatedLogicalF1_ConnectionItemResAck__value_PR_UE_associatedLogicalF1_ConnectionItem); + out->ue_to_reset[i] = decode_f1ap_ue_to_reset(&it_res->value.choice.UE_associatedLogicalF1_ConnectionItem); + } + } + break; + default: + AssertError(true, return false, "Reset Acknowledge: ProtocolIE id %ld not implemented, ignoring IE\n", ie->id); + break; + } + } + return true; +} + +void free_f1ap_reset_ack(f1ap_reset_ack_t *msg) +{ + for (int i = 0; i < msg->num_ue_to_reset; ++i) + free_f1ap_ue_to_reset(&msg->ue_to_reset[i]); + free(msg->ue_to_reset); +} + +bool eq_f1ap_reset_ack(const f1ap_reset_ack_t *a, const f1ap_reset_ack_t *b) +{ + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + _F1_EQ_CHECK_INT(a->num_ue_to_reset, b->num_ue_to_reset); + for (int i = 0; i < a->num_ue_to_reset; ++i) { + if (!eq_f1ap_ue_to_reset(&a->ue_to_reset[i], &b->ue_to_reset[i])) + return false; + } + return true; +} + +f1ap_reset_ack_t cp_f1ap_reset_ack(const f1ap_reset_ack_t *orig) +{ + f1ap_reset_ack_t cp = {.transaction_id = orig->transaction_id, .num_ue_to_reset = orig->num_ue_to_reset}; + if (cp.num_ue_to_reset > 0) { + cp.ue_to_reset = calloc_or_fail(cp.num_ue_to_reset, sizeof(*cp.ue_to_reset)); + for (int i = 0; i < cp.num_ue_to_reset; ++i) + cp.ue_to_reset[i] = cp_f1ap_ue_to_reset(&orig->ue_to_reset[i]); + } + return cp; +} + static const int nrb_lut[29] = {11, 18, 24, 25, 31, 32, 38, 51, 52, 65, 66, 78, 79, 93, 106, 107, 121, 132, 133, 135, 160, 162, 189, 216, 217, 245, 264, 270, 273}; diff --git a/openair2/F1AP/lib/f1ap_interface_management.h b/openair2/F1AP/lib/f1ap_interface_management.h index 6fd79b400756c3107dbb3c00605d09a8150be548..1b484f34761108a46fc33d2e0e526c24e15363f0 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.h +++ b/openair2/F1AP/lib/f1ap_interface_management.h @@ -27,6 +27,20 @@ struct F1AP_F1AP_PDU; +/* F1 Reset */ +struct F1AP_F1AP_PDU *encode_f1ap_reset(const f1ap_reset_t *msg); +bool decode_f1ap_reset(const struct F1AP_F1AP_PDU *pdu, f1ap_reset_t *out); +void free_f1ap_reset(f1ap_reset_t *msg); +bool eq_f1ap_reset(const f1ap_reset_t *a, const f1ap_reset_t *b); +f1ap_reset_t cp_f1ap_reset(const f1ap_reset_t *orig); + +/* F1 Reset Ack */ +struct F1AP_F1AP_PDU *encode_f1ap_reset_ack(const f1ap_reset_ack_t *msg); +bool decode_f1ap_reset_ack(const struct F1AP_F1AP_PDU *pdu, f1ap_reset_ack_t *out); +void free_f1ap_reset_ack(f1ap_reset_ack_t *msg); +bool eq_f1ap_reset_ack(const f1ap_reset_ack_t *a, const f1ap_reset_ack_t *b); +f1ap_reset_ack_t cp_f1ap_reset_ack(const f1ap_reset_ack_t *orig); + struct F1AP_F1AP_PDU *encode_f1ap_setup_request(const f1ap_setup_req_t *msg); bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t *out); f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg); diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index a569146815bf92ad347d2eb409597b5cb6bfc0c0..c49a87c57cca6a37c9eb2afd74f8d343a7223f5e 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -109,3 +109,58 @@ uint8_t *cp_octet_string(const OCTET_STRING_t *os, int *len) *len = os->size; return buf; } + +F1AP_Cause_t encode_f1ap_cause(f1ap_Cause_t cause, long cause_value) +{ + F1AP_Cause_t f1_cause = {0}; + switch (cause) { + case F1AP_CAUSE_RADIO_NETWORK: + f1_cause.present = F1AP_Cause_PR_radioNetwork; + f1_cause.choice.radioNetwork = cause_value; + break; + case F1AP_CAUSE_TRANSPORT: + f1_cause.present = F1AP_Cause_PR_transport; + f1_cause.choice.transport = cause_value; + break; + case F1AP_CAUSE_PROTOCOL: + f1_cause.present = F1AP_Cause_PR_protocol; + f1_cause.choice.protocol = cause_value; + break; + case F1AP_CAUSE_MISC: + f1_cause.present = F1AP_Cause_PR_misc; + f1_cause.choice.misc = cause_value; + break; + case F1AP_CAUSE_NOTHING: + default: + AssertFatal(false, "unknown cause value %d\n", cause); + break; + } + return f1_cause; +} + +bool decode_f1ap_cause(F1AP_Cause_t f1_cause, f1ap_Cause_t *cause, long *cause_value) +{ + switch (f1_cause.present) { + case F1AP_Cause_PR_radioNetwork: + *cause = F1AP_CAUSE_RADIO_NETWORK; + *cause_value = f1_cause.choice.radioNetwork; + break; + case F1AP_Cause_PR_transport: + *cause = F1AP_CAUSE_TRANSPORT; + *cause_value = f1_cause.choice.transport; + break; + case F1AP_Cause_PR_protocol: + *cause = F1AP_CAUSE_PROTOCOL; + *cause_value = f1_cause.choice.protocol; + break; + case F1AP_Cause_PR_misc: + *cause = F1AP_CAUSE_MISC; + *cause_value = f1_cause.choice.radioNetwork; + break; + case F1AP_Cause_PR_NOTHING: + default: + PRINT_ERROR("received illegal F1AP cause %d\n", f1_cause.present); + return false; + } + return true; +} diff --git a/openair2/F1AP/lib/f1ap_lib_common.h b/openair2/F1AP/lib/f1ap_lib_common.h index 2380a2da87cadb541efcb545c7effca311de475b..502200d9df21e5afcef0f3ae92a43b41211d51bc 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.h +++ b/openair2/F1AP/lib/f1ap_lib_common.h @@ -27,6 +27,9 @@ #include <stdio.h> #include "openair3/UTILS/conversions.h" +#include "F1AP_Cause.h" +#include "f1ap_messages_types.h" + #ifdef ENABLE_TESTS #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__) #else @@ -82,4 +85,7 @@ bool eq_f1ap_tx_bandwidth(const struct f1ap_transmission_bandwidth_t *a, const s struct OCTET_STRING; uint8_t *cp_octet_string(const struct OCTET_STRING *os, int *len); +F1AP_Cause_t encode_f1ap_cause(f1ap_Cause_t cause, long cause_value); +bool decode_f1ap_cause(F1AP_Cause_t f1_cause, f1ap_Cause_t *cause, long *cause_value); + #endif /* F1AP_LIB_COMMON_H_ */ diff --git a/openair2/F1AP/lib/f1ap_lib_includes.h b/openair2/F1AP/lib/f1ap_lib_includes.h index 6ff60a4897f7a87af9a3a9b1e68de5812588c37d..267e7243e76a7dc893e51ebee3fc8955f559200f 100644 --- a/openair2/F1AP/lib/f1ap_lib_includes.h +++ b/openair2/F1AP/lib/f1ap_lib_includes.h @@ -40,5 +40,6 @@ #include "F1AP_SuccessfulOutcome.h" #include "F1AP_SibtypetobeupdatedListItem.h" #include "F1AP_UnsuccessfulOutcome.h" +#include "F1AP_UE-associatedLogicalF1-ConnectionListRes.h" #endif /* F1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 5d153f1aea565b2f90c1b48220458ce3cb2bbff3..29d4b625ed6545efbbd6158d86ec8afabd8e97f8 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -383,6 +383,114 @@ static void test_f1ap_setup_failure(void) AssertFatal(ret, "eq_f1ap_setup_failure(): copied message doesn't match\n"); } +static void _test_f1ap_reset_msg(const f1ap_reset_t *orig) +{ + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_reset(orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_reset_t decoded = {0}; + bool ret = decode_f1ap_reset(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_reset(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_reset(orig, &decoded); + AssertFatal(ret, "eq_f1ap_reset(): decoded message doesn't match original\n"); + free_f1ap_reset(&decoded); + + f1ap_reset_t cp = cp_f1ap_reset(orig); + ret = eq_f1ap_reset(orig, &cp); + AssertFatal(ret, "eq_f1ap_reset(): copied message doesn't match original\n"); + free_f1ap_reset(&cp); + + printf("f1ap_reset successful\n"); +} + +/** + * @brief Test F1AP Reset message where the entire F1 interface is reset + */ +static void test_f1ap_reset_all(void) +{ + f1ap_reset_t orig = { + .transaction_id = 2, + .cause = F1AP_CAUSE_TRANSPORT, + .cause_value = 3, /* no type -> whatever */ + .reset_type = F1AP_RESET_ALL, + }; + _test_f1ap_reset_msg(&orig); + free_f1ap_reset(&orig); +} + +/** + * @brief Test F1AP Reset message where only some UEs are marked to reset + */ +static void test_f1ap_reset_part(void) +{ + f1ap_reset_t orig = { + .transaction_id = 3, + .cause = F1AP_CAUSE_MISC, + .cause_value = 3, /* no type -> whatever */ + .reset_type = F1AP_RESET_PART_OF_F1_INTERFACE, + .num_ue_to_reset = 4, + }; + orig.ue_to_reset = calloc_or_fail(orig.num_ue_to_reset, sizeof(*orig.ue_to_reset)); + orig.ue_to_reset[0].gNB_CU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[0].gNB_CU_ue_id)); + *orig.ue_to_reset[0].gNB_CU_ue_id = 10; + orig.ue_to_reset[1].gNB_DU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[1].gNB_DU_ue_id)); + *orig.ue_to_reset[1].gNB_DU_ue_id = 11; + orig.ue_to_reset[2].gNB_CU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[2].gNB_CU_ue_id)); + *orig.ue_to_reset[2].gNB_CU_ue_id = 12; + orig.ue_to_reset[2].gNB_DU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[2].gNB_DU_ue_id)); + *orig.ue_to_reset[2].gNB_DU_ue_id = 13; + // orig.ue_to_reset[3] intentionally empty (because it is allowed, both IDs are optional) + _test_f1ap_reset_msg(&orig); + free_f1ap_reset(&orig); +} + +/** + * @brief Test F1 reset ack with differently ack'd UEs ("generic ack" is + * special case with no individual UE acked) + */ +static void test_f1ap_reset_ack(void) +{ + f1ap_reset_ack_t orig = { + .transaction_id = 4, + .num_ue_to_reset = 4, + }; + orig.ue_to_reset = calloc_or_fail(orig.num_ue_to_reset, sizeof(*orig.ue_to_reset)); + orig.ue_to_reset[0].gNB_CU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[0].gNB_CU_ue_id)); + *orig.ue_to_reset[0].gNB_CU_ue_id = 10; + orig.ue_to_reset[1].gNB_DU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[1].gNB_DU_ue_id)); + *orig.ue_to_reset[1].gNB_DU_ue_id = 11; + orig.ue_to_reset[2].gNB_CU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[2].gNB_CU_ue_id)); + *orig.ue_to_reset[2].gNB_CU_ue_id = 12; + orig.ue_to_reset[2].gNB_DU_ue_id = malloc_or_fail(sizeof(*orig.ue_to_reset[2].gNB_DU_ue_id)); + *orig.ue_to_reset[2].gNB_DU_ue_id = 13; + // orig.ue_to_reset[3] intentionally empty (because it is allowed, both IDs are optional) + + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_reset_ack(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_reset_ack_t decoded = {0}; + bool ret = decode_f1ap_reset_ack(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_reset_ack(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_reset_ack(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_reset_ack(): decoded message doesn't match original\n"); + free_f1ap_reset_ack(&decoded); + + f1ap_reset_ack_t cp = cp_f1ap_reset_ack(&orig); + ret = eq_f1ap_reset_ack(&orig, &cp); + AssertFatal(ret, "eq_f1ap_reset_ack(): copied message doesn't match original\n"); + free_f1ap_reset_ack(&cp); + + printf("f1ap_reset_ack successful\n"); + + free_f1ap_reset_ack(&orig); +} + /** * @brief Test F1 gNB-DU Configuration Update */ @@ -605,6 +713,9 @@ int main() test_f1ap_setup_request(); test_f1ap_setup_response(); test_f1ap_setup_failure(); + test_f1ap_reset_all(); + test_f1ap_reset_part(); + test_f1ap_reset_ack(); test_f1ap_du_configuration_update(); test_f1ap_cu_configuration_update(); test_f1ap_cu_configuration_update_acknowledge(); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index a57d2e02879d0174eb079061c6d3ca5968f78dd7..730f08dd7db44fd9cbd6c95d5122027963f2f267 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -274,15 +274,29 @@ void fill_scc_sim(NR_ServingCellConfigCommon_t *scc, uint64_t *ssb_bitmap, int N scc->dmrs_TypeA_Position = NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2; *scc->ssbSubcarrierSpacing = mu_dl; - struct NR_FrequencyInfoDL *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; - if (mu_dl == 0) { - *frequencyInfoDL->absoluteFrequencySSB = 520432; - *frequencyInfoDL->frequencyBandList.list.array[0] = 38; - frequencyInfoDL->absoluteFrequencyPointA = 520000; - } else { - *frequencyInfoDL->absoluteFrequencySSB = 641032; - *frequencyInfoDL->frequencyBandList.list.array[0] = 78; - frequencyInfoDL->absoluteFrequencyPointA = 640000; + NR_FrequencyInfoDL_t *frequencyInfoDL = scc->downlinkConfigCommon->frequencyInfoDL; + NR_TDD_UL_DL_ConfigCommon_t *tdd_UL_DL_Config = scc->tdd_UL_DL_ConfigurationCommon; + switch (mu_dl) { + case 0 : + *frequencyInfoDL->absoluteFrequencySSB = 520432; + *frequencyInfoDL->frequencyBandList.list.array[0] = 38; + frequencyInfoDL->absoluteFrequencyPointA = 520000; + tdd_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity = NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms10; + break; + case 1 : + *frequencyInfoDL->absoluteFrequencySSB = 641032; + *frequencyInfoDL->frequencyBandList.list.array[0] = 78; + frequencyInfoDL->absoluteFrequencyPointA = 640000; + tdd_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity = NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5; + break; + case 3 : + *frequencyInfoDL->absoluteFrequencySSB = 2071387; + *frequencyInfoDL->frequencyBandList.list.array[0] = 257; + frequencyInfoDL->absoluteFrequencyPointA = 2071003; + tdd_UL_DL_Config->pattern1.dl_UL_TransmissionPeriodicity = NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms1p25; + break; + default : + AssertFatal(false, "Numerolgy %d not supported\n", mu_dl); } *frequencyInfoDL->scs_SpecificCarrierList.list.array[0] = configure_scs_carrier(mu_dl, N_RB_DL); @@ -306,7 +320,19 @@ void fill_scc_sim(NR_ServingCellConfigCommon_t *scc, uint64_t *ssb_bitmap, int N timedomainresourceallocation1); struct NR_FrequencyInfoUL *frequencyInfoUL = scc->uplinkConfigCommon->frequencyInfoUL; - *frequencyInfoUL->frequencyBandList->list.array[0] = mu_ul ? 78 : 38; + switch (mu_ul) { + case 0 : + *frequencyInfoUL->frequencyBandList->list.array[0] = 38; + break; + case 1 : + *frequencyInfoUL->frequencyBandList->list.array[0] = 78; + break; + case 3 : + *frequencyInfoUL->frequencyBandList->list.array[0] = 257; + break; + default : + AssertFatal(false, "Numerolgy %d not supported\n", mu_ul); + } *frequencyInfoUL->absoluteFrequencyPointA = -1; *frequencyInfoUL->scs_SpecificCarrierList.list.array[0] = configure_scs_carrier(mu_ul, N_RB_UL); *frequencyInfoUL->p_Max = 20; @@ -348,18 +374,15 @@ void fill_scc_sim(NR_ServingCellConfigCommon_t *scc, uint64_t *ssb_bitmap, int N scc->ssb_PositionsInBurst->present = NR_ServingCellConfigCommon__ssb_PositionsInBurst_PR_mediumBitmap; *ssb_bitmap = 0xff; - struct NR_TDD_UL_DL_ConfigCommon *tdd_UL_DL_ConfigurationCommon = scc->tdd_UL_DL_ConfigurationCommon; - tdd_UL_DL_ConfigurationCommon->referenceSubcarrierSpacing = mu_dl; + tdd_UL_DL_Config->referenceSubcarrierSpacing = mu_dl; - NR_TDD_UL_DL_Pattern_t *p1 = &tdd_UL_DL_ConfigurationCommon->pattern1; - p1->dl_UL_TransmissionPeriodicity = (mu_dl == 0) ? NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms10 - : NR_TDD_UL_DL_Pattern__dl_UL_TransmissionPeriodicity_ms5; + NR_TDD_UL_DL_Pattern_t *p1 = &tdd_UL_DL_Config->pattern1; p1->nrofDownlinkSlots = 7; p1->nrofDownlinkSymbols = 6; p1->nrofUplinkSlots = 2; p1->nrofUplinkSymbols = 4; - struct NR_TDD_UL_DL_Pattern *p2 = tdd_UL_DL_ConfigurationCommon->pattern2; + struct NR_TDD_UL_DL_Pattern *p2 = tdd_UL_DL_Config->pattern2; if (p2) { p2->dl_UL_TransmissionPeriodicity = 321; p2->nrofDownlinkSlots = -1; diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c index 1c35fcea6326e0519523d3512d4c604299d50d13..3ce0867383f3376940d482c29035d1c8b6e0a700 100644 --- a/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c +++ b/openair2/LAYER2/NR_MAC_COMMON/nr_compute_tbs_common.c @@ -63,95 +63,84 @@ uint32_t nr_compute_tbs(uint16_t Qm, const uint32_t nb_re = min(156, nbp_re) * nb_rb; // Intermediate number of information bits // Rx1024 is tabulated as 10 times the actual code rate - const uint32_t R_5 = R/5; // R can be fractional so we can't divide by 10 + const uint32_t R_5 = R / 5; // R can be fractional so we can't divide by 10 // So we ned to right shift by 11 (10 for x1024 and 1 additional as above) - const uint32_t Ninfo = ((nb_re * R_5 * Qm * Nl)>>11)>>tb_scaling; - - uint32_t nr_tbs=0; + const uint32_t Ninfo = ((nb_re * R_5 * Qm * Nl) >> 11) >> tb_scaling; + uint32_t nr_tbs = 0; uint32_t Np_info, C, n; - if (Ninfo <= NR_MAX_PDSCH_TBS) { n = max(3, floor(log2(Ninfo)) - 6); - Np_info = max(24, (Ninfo>>n)<<n); - for (int i=0; i<INDEX_MAX_TBS_TABLE; i++) { - if (Tbstable_nr[i] >= Np_info){ - nr_tbs = Tbstable_nr[i]; - break; - } + Np_info = max(24, (Ninfo >> n) << n); + for (int i = 0; i < INDEX_MAX_TBS_TABLE; i++) { + if (Tbstable_nr[i] >= Np_info){ + nr_tbs = Tbstable_nr[i]; + break; } + } } else { - n = log2(Ninfo-24)-5; - Np_info = max(3840, (ROUNDIDIV((Ninfo-24),(1<<n)))<<n); + n = log2(Ninfo - 24) - 5; + Np_info = max(3840, (ROUNDIDIV((Ninfo - 24), (1 << n))) << n); if (R <= 2560) { - C = CEILIDIV((Np_info+24),3816); - nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; + C = CEILIDIV((Np_info + 24), 3816); + nr_tbs = (C << 3) * CEILIDIV((Np_info + 24), (C << 3)) - 24; } else { if (Np_info > 8424){ - C = CEILIDIV((Np_info+24),8424); - nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; + C = CEILIDIV((Np_info + 24), 8424); + nr_tbs = (C << 3) * CEILIDIV((Np_info + 24), (C << 3)) - 24; } else { - nr_tbs = ((CEILIDIV((Np_info+24),8))<<3) - 24; + nr_tbs = ((CEILIDIV((Np_info + 24), 8)) << 3) - 24; } } } LOG_D(NR_MAC, "Ninfo %u nbp_re %d nb_re %d Qm %d, R %d, tbs %d bits\n", Ninfo, nbp_re, nb_re, Qm, R, nr_tbs); - return nr_tbs; } //tbslbrm calculation according to 5.4.2.1 of 38.212 -uint32_t nr_compute_tbslbrm(uint16_t table, - uint16_t nb_rb, - uint8_t Nl) { - - uint16_t R, nb_re; - uint16_t nb_rb_lbrm=0; - uint8_t Qm; - int i; - uint32_t nr_tbs=0; - uint32_t Ninfo, Np_info, C; - uint8_t n; - - for (i=0; i<7; i++) { +uint32_t nr_compute_tbslbrm(uint16_t table, uint16_t nb_rb, uint8_t Nl) +{ + uint16_t nb_rb_lbrm = 0; + for (int i = 0; i < 7; i++) { if (NPRB_LBRM[i] >= nb_rb){ nb_rb_lbrm = NPRB_LBRM[i]; break; } } - Qm = ((table == 1)? 8 : 6); - R = 948; - nb_re = 156 * nb_rb_lbrm; + int Qm = (table == 1) ? 8 : 6; + uint32_t R = 948; + uint32_t nb_re = 156 * nb_rb_lbrm; // Intermediate number of information bits - Ninfo = (nb_re * R * Qm * Nl)>>10; - + uint32_t Ninfo = (nb_re * R * Qm * Nl) >> 10; + uint32_t nr_tbs = 0; + uint32_t Np_info, n; if (Ninfo <= NR_MAX_PDSCH_TBS) { n = max(3, floor(log2(Ninfo)) - 6); - Np_info = max(24, (Ninfo>>n)<<n); - for (int i=0; i<INDEX_MAX_TBS_TABLE; i++) { + Np_info = max(24, (Ninfo >> n) << n); + for (int i = 0; i < INDEX_MAX_TBS_TABLE; i++) { if (Tbstable_nr[i] >= Np_info){ nr_tbs = Tbstable_nr[i]; break; } } } else { - n = log2(Ninfo-24)-5; - Np_info = max(3840, (ROUNDIDIV((Ninfo-24),(1<<n)))<<n); - + n = log2(Ninfo - 24) - 5; + Np_info = max(3840, (ROUNDIDIV((Ninfo - 24), (1 << n))) << n); + int C; if (R <= 256) { - C = CEILIDIV((Np_info+24),3816); - nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; + C = CEILIDIV((Np_info + 24), 3816); + nr_tbs = (C << 3) * CEILIDIV((Np_info + 24), (C << 3)) - 24; } else { if (Np_info > 8424){ - C = CEILIDIV((Np_info+24),8424); - nr_tbs = (C<<3)*CEILIDIV((Np_info+24),(C<<3)) - 24; + C = CEILIDIV((Np_info + 24), 8424); + nr_tbs = (C << 3) * CEILIDIV((Np_info + 24), (C << 3)) - 24; } else - nr_tbs = ((CEILIDIV((Np_info+24),8))<<3) - 24; + nr_tbs = ((CEILIDIV((Np_info + 24), 8)) << 3) - 24; } } return nr_tbs; diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c index 70d3aacb66957850403df417e249bff6eb0d9cd9..b27735210568e9c200b0692598689a93cddfbf30 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c @@ -233,7 +233,7 @@ float nr_get_Pcmax(int p_Max, float nr_get_Pcmin(int bandwidth_index) { const float table_38101_6_3_1_1[] = { - -40, -40, -40, -40, -39, -38.2, -37.5, -37, -36.5, -35.2, -34.6, -34, -33.5, -33 + -40, -40, -40, -40, -39, -38.2, -37.5, -37, -36.5, -36, -35.2, -34.6, -34, -33.5, -33 }; return table_38101_6_3_1_1[bandwidth_index]; } diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp index ac7ed2f73acb7868b764e16c42cfaa2e48fc2a79..59f932ac5723428007cd06cab35b045046ec513a 100644 --- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp +++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp @@ -178,7 +178,7 @@ TEST(test_pucch_power_state, test_accumulated_delta_pucch) TEST(pc_min, check_all_bw_indexes) { - const int bws[] = {5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100}; + const int bws[] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100}; for (auto i = 0U; i < sizeofArray(bws); i++) { (void)nr_get_Pcmin(i); } diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index fda1dc6c11e7abb841621864475b71a1e7e7497e..415cfc79e3290d11f316e33a11fc44f32f42f29c 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -500,34 +500,28 @@ int get_ul_slot_offset(const frame_structure_t *fs, int idx, bool count_mixed) * * @param mu numerology * @param scc pointer to scc - * @param cfg pointer to NFAPI config request + * @param tdd_period TDD period + * @param frame_type type of frame structure (FDD or TDD) * @param fs pointer to the frame structure to update - * - * @return Number of periods in frame */ -static int config_frame_structure(int mu, - NR_ServingCellConfigCommon_t *scc, - nfapi_nr_config_request_scf_t *cfg, - frame_structure_t *fs) +void config_frame_structure(int mu, + NR_ServingCellConfigCommon_t *scc, + uint8_t tdd_period, + uint8_t frame_type, + frame_structure_t *fs) { fs->numb_slots_frame = nr_slots_per_frame[mu]; - if (cfg->cell_config.frame_duplex_type.value == TDD) { - cfg->tdd_table.tdd_period.tl.tag = NFAPI_NR_CONFIG_TDD_PERIOD_TAG; - cfg->num_tlv++; - cfg->tdd_table.tdd_period.value = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); - LOG_D(NR_MAC, "Setting TDD configuration period to %d\n", cfg->tdd_table.tdd_period.value); - fs->numb_period_frame = get_nb_periods_per_frame(cfg->tdd_table.tdd_period.value); + if (frame_type == TDD) { + fs->numb_period_frame = get_nb_periods_per_frame(tdd_period); fs->numb_slots_period = fs->numb_slots_frame / fs->numb_period_frame; fs->is_tdd = true; config_tdd_patterns(scc->tdd_UL_DL_ConfigurationCommon, fs); - set_tdd_config_nr(cfg, fs); } else { // FDD fs->is_tdd = false; fs->numb_period_frame = 1; fs->numb_slots_period = nr_slots_per_frame[mu]; } AssertFatal(fs->numb_period_frame > 0, "Frame configuration cannot be configured!\n"); - return fs->numb_period_frame; } static void config_common(gNB_MAC_INST *nrmac, @@ -819,7 +813,16 @@ static void config_common(gNB_MAC_INST *nrmac, // Frame structure configuration uint8_t mu = frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; - config_frame_structure(mu, scc, cfg, &nrmac->frame_structure); + if (cfg->cell_config.frame_duplex_type.value == TDD) { + cfg->tdd_table.tdd_period.tl.tag = NFAPI_NR_CONFIG_TDD_PERIOD_TAG; + cfg->num_tlv++; + cfg->tdd_table.tdd_period.value = get_tdd_period_idx(scc->tdd_UL_DL_ConfigurationCommon); + LOG_D(NR_MAC, "Setting TDD configuration period to %d\n", cfg->tdd_table.tdd_period.value); + } + frame_structure_t *fs = &nrmac->frame_structure; + config_frame_structure(mu, scc, cfg->tdd_table.tdd_period.value, cfg->cell_config.frame_duplex_type.value, fs); + if (cfg->cell_config.frame_duplex_type.value == TDD) + set_tdd_config_nr(cfg, fs); int nb_tx = config->nb_bfw[0]; // number of tx antennas int nb_beams = config->nb_bfw[1]; // number of beams diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c index f2c014a65fec5089f8b86b35f7bfcda75d9f284c..989aa1be9a97bb47160b5fb5e2146edc9502ee23 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_phytest.c @@ -41,27 +41,29 @@ // #define ENABLE_MAC_PAYLOAD_DEBUG 1 /* This function checks whether the given Dl/UL slot is set - in the input bitmap, which is a mask indicating in which + in the input bitmap (per period), which is a mask indicating in which slot to transmit (among those available in the TDD configuration) */ static bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) { - return (bitmap >> (slot % 64)) & 0x01; + AssertFatal(slot < 64, "Unable to handle periods with length larger than 64 slots in phy-test mode\n"); + return (bitmap >> slot) & 0x01; } uint32_t target_dl_mcs = 9; uint32_t target_dl_Nl = 1; uint32_t target_dl_bw = 50; uint64_t dlsch_slot_bitmap = (1<<1); + /* schedules whole bandwidth for first user, all the time */ -void nr_preprocessor_phytest(module_id_t module_id, - frame_t frame, - sub_frame_t slot) +void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot) { + gNB_MAC_INST *mac = RC.nrmac[module_id]; /* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */ - if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot)) + int slot_period = slot % mac->frame_structure.numb_slots_period; + if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period)) return; - NR_UE_info_t *UE = RC.nrmac[module_id]->UE_info.list[0]; - NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon; + NR_UE_info_t *UE = mac->UE_info.list[0]; + NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon; NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP; const int CC_id = 0; @@ -72,7 +74,7 @@ void nr_preprocessor_phytest(module_id_t module_id, return; } - const int tda = get_dl_tda(RC.nrmac[module_id], slot); + const int tda = get_dl_tda(mac, slot); NR_tda_info_t tda_info = get_dl_tda_info(dl_bwp, sched_ctrl->search_space->searchSpaceType->present, tda, @@ -98,7 +100,7 @@ void nr_preprocessor_phytest(module_id_t module_id, int rbSize = 0; if (target_dl_bw>bwpSize) target_dl_bw = bwpSize; - uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map[beam]; + uint16_t *vrb_map = mac->common_channels[CC_id].vrb_map[beam]; /* loop ensures that we allocate exactly target_dl_bw, or return */ while (true) { /* advance to first free RB */ @@ -139,7 +141,7 @@ void nr_preprocessor_phytest(module_id_t module_id, 0); sched_ctrl->num_total_bytes += sched_ctrl->rlc_status[lcid].bytes_in_buffer; - int CCEIndex = get_cce_index(RC.nrmac[module_id], + int CCEIndex = get_cce_index(mac, CC_id, slot, UE->rnti, &sched_ctrl->aggregation_level, beam, @@ -147,10 +149,7 @@ void nr_preprocessor_phytest(module_id_t module_id, sched_ctrl->coreset, &sched_ctrl->sched_pdcch, false); - AssertFatal(CCEIndex >= 0, - "%s(): could not find CCE for UE %04x\n", - __func__, - UE->rnti); + AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti); NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch; if (sched_pdsch->dl_harq_pid == -1) @@ -159,20 +158,16 @@ void nr_preprocessor_phytest(module_id_t module_id, int alloc = -1; if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) { int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex); - alloc = nr_acknack_scheduling(RC.nrmac[module_id], UE, frame, slot, 0, r_pucch, 0); + alloc = nr_acknack_scheduling(mac, UE, frame, slot, 0, r_pucch, 0); if (alloc < 0) { - LOG_D(MAC, - "Could not find PUCCH for UE %04x@%d.%d\n", - rnti, - frame, - slot); + LOG_D(NR_MAC, "Could not find PUCCH for UE %04x@%d.%d\n", rnti, frame, slot); return; } } sched_ctrl->cce_index = CCEIndex; - fill_pdcch_vrb_map(RC.nrmac[module_id], + fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, @@ -270,7 +265,8 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_ /* check if slot is UL, and that slot is 8 (assuming K2=6 because of UE * limitations). Note that if K2 or the TDD configuration is changed, below * conditions might exclude each other and never be true */ - if (!is_xlsch_in_slot(ulsch_slot_bitmap, sched_slot)) + int slot_period = sched_slot % nr_mac->frame_structure.numb_slots_period; + if (!is_xlsch_in_slot(ulsch_slot_bitmap, slot_period)) return false; uint16_t rbStart = 0; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index 4cd5563200dd4d884905133657b4970a4603e3d6..ee66bcaf9039d34a036edfa8c0971b0a1cd7080b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -39,6 +39,11 @@ void set_cset_offset(uint16_t); void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers); int get_NTN_Koffset(const NR_ServingCellConfigCommon_t *scc); +void config_frame_structure(int mu, + NR_ServingCellConfigCommon_t *scc, + uint8_t tdd_period, + uint8_t frame_type, + frame_structure_t *fs); int get_first_ul_slot(const frame_structure_t *fs, bool mixed); int get_ul_slots_per_period(const frame_structure_t *fs); int get_ul_slots_per_frame(const frame_structure_t *fs); @@ -150,9 +155,7 @@ uint16_t nr_mac_compute_RIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs); /* \brief preprocessor for phytest: schedules UE_id 0 with fixed MCS on all * freq resources */ -void nr_preprocessor_phytest(module_id_t module_id, - frame_t frame, - sub_frame_t slot); +void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot); /* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a * fixed set of resources */ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, sub_frame_t slot); 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 124d63d293baf0578f38378f5f5fb47820c671b0..f92559c4ee86ec24ea5d28a9631e988b480baa0e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -125,12 +125,9 @@ void f1_reset_cu_initiated(const f1ap_reset_t *reset) { LOG_I(MAC, "F1 Reset initiated by CU\n"); - f1ap_reset_ack_t ack = {0}; + f1ap_reset_ack_t ack = {.transaction_id = reset->transaction_id}; if(reset->reset_type == F1AP_RESET_ALL) { du_clear_all_ue_states(); - ack = (f1ap_reset_ack_t) { - .transaction_id = reset->transaction_id - }; } else { // reset->reset_type == F1AP_RESET_PART_OF_F1_INTERFACE AssertFatal(1==0, "Not implemented yet\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index ad8978d5140077ff017b7d5fe32c77848d3c9be7..e687991a5e6fe49e11a0cfb5ed6614d8d7d7dbf0 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -34,8 +34,10 @@ static void f1_reset_du_initiated_direct(const f1ap_reset_t *reset) static void f1_reset_acknowledge_cu_initiated_direct(const f1ap_reset_ack_t *ack) { - (void) ack; - AssertFatal(false, "%s() not implemented yet\n", __func__); + MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_RESET_ACK); + msg->ittiMsgHeader.originInstance = -1; // means monolithic + F1AP_RESET_ACK(msg) = cp_f1ap_reset_ack(ack); + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } static void f1_setup_request_direct(const f1ap_setup_req_t *req) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 544ab3889c50f12d58830e1983105ddd00fc81c7..81373e0bc9ec0ac23a82b924793a4af0c9c7031b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -61,8 +61,7 @@ static void f1_reset_du_initiated_f1ap(const f1ap_reset_t *reset) static void f1_reset_acknowledge_cu_initiated_f1ap(const f1ap_reset_ack_t *ack) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_RESET_ACK); - f1ap_reset_ack_t *f1ap_msg = &F1AP_RESET_ACK(msg); - *f1ap_msg = *ack; + F1AP_RESET_ACK(msg) = cp_f1ap_reset_ack(ack); itti_send_msg_to_task(TASK_DU_F1, 0, msg); } diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 3c3ef5367f1f3e3eff880ab648ebddb16eb1df57..f93044f9cde469d6425218629190762ff4cce95f 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -2172,22 +2172,35 @@ uint64_t pdcp_module_init( uint64_t pdcp_optmask, int id) { if (UE_NAS_USE_TUN) { int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) ? MAX_MOBILES_PER_ENB : 1; - tun_init("oaitun_ue", num_if, id); - tun_init_mbms("oaitun_uem", id + 1); - tun_config(1, "10.0.2.2", NULL, "oaitun_uem"); + 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, "oaitun_ue", i); + tun_init(ifname, i); + } + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_uem", id + 1); + tun_init_mbms(ifname); + tun_config(ifname, "10.0.2.2", NULL); LOG_I(PDCP, "UE pdcp will use tun interface\n"); } else if (ENB_NAS_USE_TUN) { - tun_init("oaitun_enb", 1, 0); - tun_config(1, "10.0.1.1", NULL, "oaitun_enb"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_enb", 0); + tun_init(ifname, 0); + tun_config(ifname, "10.0.1.1", NULL); if (pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT) { - tun_init_mbms("oaitun_enm", 1); - tun_config(1, "10.0.2.1", NULL, "oaitun_enm"); + tun_generate_ifname(ifname, "oaitun_enm", 0); + tun_init_mbms(ifname); + tun_config(ifname, "10.0.2.1", NULL); LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); } LOG_I(PDCP, "ENB pdcp will use tun interface\n"); } else if (pdcp_optmask & ENB_NAS_USE_TUN_W_MBMS_BIT) { - tun_init_mbms("oaitun_enm", 0); - tun_config(1, "10.0.2.1", NULL, "oaitun_enm"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_enm", 0); + tun_init_mbms(ifname); + tun_config(ifname, "10.0.2.1", NULL); LOG_I(PDCP, "ENB pdcp will use mbms tun interface\n"); } diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 380ae1f60a4eec4ebd704abbd477b77848090baf..96701dbb83c86c9aca4692427de560100335339c 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -168,7 +168,6 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) const pdu_session_to_setup_t *req_pdu = req->pduSession + i; resp_pdu->id = req_pdu->sessionId; - AssertFatal(req_pdu->numDRB2Modify == 0, "DRB modification not implemented\n"); AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n"); resp_pdu->numDRBSetup = req_pdu->numDRB2Setup; const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0]; @@ -178,7 +177,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; for (int k = 0; k < resp_drb->numQosFlowSetup; k++) { const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k]; - qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k]; + qos_flow_list_t *qosflowSetup = &resp_drb->qosFlows[k]; qosflowSetup->qfi = qosflow2Setup->qfi; } @@ -197,17 +196,17 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[0]; - memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); + resp_pdu->tl_info.teId = resp_n3.gnb_NGu_teid[0]; + memcpy(&resp_pdu->tl_info.tlAddress, &resp_n3.gnb_addr.buffer, 4); // create PDCP bearers. This will also create SDAP bearers NR_DRB_ToAddModList_t DRB_configList = {0}; fill_DRB_configList_e1(&DRB_configList, req_pdu); nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + security_parameters.ciphering_algorithm = req->secInfo.cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE); nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE cu_up_ue_id, &DRB_configList, @@ -230,8 +229,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_f1); resp_drb->numUpParam = 1; AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n"); - memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4); - resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0]; + memcpy(&resp_drb->UpParamList[0].tl_info.tlAddress, &resp_f1.gnb_addr.buffer, 4); + resp_drb->UpParamList[0].tl_info.teId = resp_f1.gnb_NGu_teid[0]; } // We assume all DRBs to setup have been setup successfully, so we always @@ -273,12 +272,18 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j]; modified->id = to_modif->id; - if (to_modif->pdcp_config.pDCP_Reestablishment) { + if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) { nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + if (req->secInfo) { + security_parameters.ciphering_algorithm = req->secInfo->cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo->integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo->encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo->integrityProtectionKey, NR_K_KEY_SIZE); + } else { + /* don't change security settings if not present in the Bearer Context Modification Request */ + security_parameters.ciphering_algorithm = -1; + security_parameters.integrity_algorithm = -1; + } nr_pdcp_reestablishment(req->gNB_cu_up_ue_id, to_modif->id, false, @@ -291,8 +296,8 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) /* Loop through DL UP Transport Layer params list * and update GTP tunnel outgoing addr and TEID */ for (int k = 0; k < to_modif->numDlUpParam; k++) { - in_addr_t addr = to_modif->DlUpParamList[k].tlAddress; - GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].teId); + in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress; + GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId); } } } @@ -300,24 +305,28 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) get_e1_if()->bearer_modif_response(&modif); } -void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) +static void remove_ue_e1(const uint32_t ue_id) { bool need_ue_id_mgmt = e1_used(); instance_t n3inst = get_n3_gtp_instance(); instance_t f1inst = get_f1_gtp_instance(); - LOG_I(E1AP, "releasing UE %d\n", cmd->gNB_cu_up_ue_id); - - newGtpuDeleteAllTunnels(n3inst, cmd->gNB_cu_up_ue_id); + newGtpuDeleteAllTunnels(n3inst, ue_id); if (f1inst >= 0) // is there F1-U? - newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id); + newGtpuDeleteAllTunnels(f1inst, ue_id); if (need_ue_id_mgmt) { // see issue #706: in monolithic, gNB will free PDCP of UE - nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id); - cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id); + nr_pdcp_remove_UE(ue_id); + cu_remove_f1_ue_data(ue_id); } - nr_sdap_delete_ue_entities(cmd->gNB_cu_up_ue_id); + nr_sdap_delete_ue_entities(ue_id); +} + +void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) +{ + LOG_I(E1AP, "releasing UE %d\n", cmd->gNB_cu_up_ue_id); + remove_ue_e1(cmd->gNB_cu_up_ue_id); e1ap_bearer_release_cplt_t cplt = { .gNB_cu_cp_ue_id = cmd->gNB_cu_cp_ue_id, @@ -326,3 +335,15 @@ void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) get_e1_if()->bearer_release_complete(&cplt); } + +void e1_reset(void) +{ + /* we get the list of all UEs from the PDCP, which maintains a list */ + ue_id_t ue_ids[MAX_MOBILES_PER_GNB]; + int num = nr_pdcp_get_num_ues(ue_ids, MAX_MOBILES_PER_GNB); + for (uint32_t i = 0; i < num; ++i) { + ue_id_t ue_id = ue_ids[i]; + LOG_W(E1AP, "releasing UE %ld\n", ue_id); + remove_ue_e1(ue_id); + } +} diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h index 7290043371863887e79e7790d39e58c877ce15b7..c74623da7da741b90a919439592529c778b41086 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h @@ -27,9 +27,11 @@ void nr_pdcp_e1_if_init(bool uses_e1); struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_release_cmd_s; void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req); -void e1_bearer_context_modif(const struct e1ap_bearer_setup_req_s *req); +void e1_bearer_context_modif(const struct e1ap_bearer_mod_req_s *req); void e1_bearer_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd); +void e1_reset(void); #endif /* CUCP_CUUP_HANDLER_H */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 7691871b33ec675bded6b4eeb82f76f5e1a13f37..54880e828a2556c03c3dee6f2c6927c920cc1f35 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -640,18 +640,28 @@ uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id) int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) ? MAX_MOBILES_PER_ENB : 1; - tun_init(ifprefix, num_if, id); + 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"; - tun_config(1, ip, NULL, ifprefix); + 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"; - tun_init(ifprefix, 1, id); - tun_config(1, "10.0.1.1", NULL, ifprefix); + 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(); } diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c index 1e125436049edc3a93c6e48eba07342ccafe784d..f7b513d2646fe0dd8affe6183edf83f60b4712f9 100644 --- a/openair2/RRC/LTE/rrc_UE.c +++ b/openair2/RRC/LTE/rrc_UE.c @@ -777,7 +777,9 @@ rrc_ue_establish_drb( "10.0.%d.%d", UE_NAS_USE_TUN ? 1 : (ip_addr_offset3 + ue_mod_idP + 1), ip_addr_offset4 + ue_mod_idP + 1); - oip_ifup = tun_config(ip_addr_offset3 + ue_mod_idP + 1, ip, NULL, "oaitun_ue"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_ue", ip_addr_offset3 + ue_mod_idP); + oip_ifup = tun_config(ifname, ip, NULL); if (oip_ifup == 0 && (!UE_NAS_USE_TUN)) { // interface is up --> send a config the DRB LOG_I(OIP,"[UE %d] Config the ue net interface %d to send/receive pkt on DRB %ld to/from the protocol stack\n", diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c index 78f05cf56a086c0bd2f1513cd09635ce87379e79..8d0fd2f8ed5042258629fa63e6f82922958d8118 100644 --- a/openair2/RRC/LTE/rrc_eNB.c +++ b/openair2/RRC/LTE/rrc_eNB.c @@ -5250,7 +5250,9 @@ rrc_eNB_process_RRCConnectionReconfigurationComplete( ctxt_pP->module_id); char ip[20]; snprintf(ip, sizeof(ip), "10.0.%d.%d", ctxt_pP->module_id + 1, ctxt_pP->module_id + 1); - oip_ifup = tun_config(ctxt_pP->module_id, ip, NULL, "oaitun_oai"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_oai", ctxt_pP->module_id); + oip_ifup = tun_config(ifname, ip, NULL); if (oip_ifup == 0) { // interface is up --> send a config the DRB module_id_t ue_module_id; diff --git a/openair2/RRC/NR/cucp_cuup_e1ap.c b/openair2/RRC/NR/cucp_cuup_e1ap.c index 69cb92f50a5b4b78c082265eb7f26559f064b6dd..538cd3f524318e3ec45c24537989f69f7a18a156 100644 --- a/openair2/RRC/NR/cucp_cuup_e1ap.c +++ b/openair2/RRC/NR/cucp_cuup_e1ap.c @@ -26,6 +26,7 @@ #include "e1ap_messages_types.h" #include "intertask_interface.h" #include "nr_rrc_defs.h" +#include "E1AP/lib/e1ap_bearer_context_management.h" static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { @@ -33,8 +34,7 @@ static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1a MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_REQ); msg_p->ittiMsgHeader.originInstance = assoc_id; e1ap_bearer_setup_req_t *bearer_req = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg_p); - memcpy(bearer_req, req, sizeof(e1ap_bearer_setup_req_t)); - + *bearer_req = cp_bearer_context_setup_request(req); itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p); } diff --git a/openair2/RRC/NR/cucp_cuup_if.h b/openair2/RRC/NR/cucp_cuup_if.h index 86b3a2435ec69de6b4a2bc1724a0d292c6784e52..418e1f362efa4750809a34d31cbda2a43787d7b7 100644 --- a/openair2/RRC/NR/cucp_cuup_if.h +++ b/openair2/RRC/NR/cucp_cuup_if.h @@ -29,9 +29,11 @@ #include "common/platform_types.h" struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_setup_resp_s; struct e1ap_bearer_release_cmd_s; typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req); +typedef void (*cucp_cuup_bearer_context_mod_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_mod_req_s *req); typedef void (*cucp_cuup_bearer_context_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd); struct gNB_RRC_INST_s; diff --git a/openair2/RRC/NR/mac_rrc_dl_direct.c b/openair2/RRC/NR/mac_rrc_dl_direct.c index 77113f6c8bddf573750de63d0bdac2a206919766..4f8d45ac8c00a343ca6038e72d23ac1ca5466450 100644 --- a/openair2/RRC/NR/mac_rrc_dl_direct.c +++ b/openair2/RRC/NR/mac_rrc_dl_direct.c @@ -30,8 +30,8 @@ static void f1_reset_cu_initiated_direct(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) { - (void)reset; - AssertFatal(false, "%s() not implemented yet\n", __func__); + AssertFatal(assoc_id == -1, "illegal assoc_id %d\n", assoc_id); + f1_reset_cu_initiated(reset); } static void f1_reset_acknowledge_du_initiated_direct(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack) diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 8593ff816a9cb61673a040cb078f9cc5ace1d4c3..8a84a7f85d6b59e6dc62d26c9bceac9f0a3ca8b2 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -35,8 +35,11 @@ static void f1_reset_cu_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) { - (void)reset; - AssertFatal(false, "%s() not implemented yet\n", __func__); + MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_RESET); + msg->ittiMsgHeader.originInstance = assoc_id; + f1ap_reset_t *f1ap_msg = &F1AP_RESET(msg); + *f1ap_msg = cp_f1ap_reset(reset); + itti_send_msg_to_task(TASK_CU_F1, 0, msg); } static void f1_reset_acknowledge_du_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack) diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 18487e96577363a3ab646d59f8d5f1a477ec01f4..d2266a74f3e02784a92536443c352e0b0f73a105 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -566,9 +566,8 @@ static void config_csiim(int do_csirs, void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig, const NR_ServingCellConfigCommon_t *scc, const NR_UE_NR_Capability_t *uecap, - int maxMIMO_layers) + int maxMIMO_layers) { - if(!pdsch_servingcellconfig->ext1) pdsch_servingcellconfig->ext1=calloc(1,sizeof(*pdsch_servingcellconfig->ext1)); if(!pdsch_servingcellconfig->ext1->maxMIMO_Layers) @@ -822,6 +821,48 @@ static NR_SetupRelease_SRS_Config_t *get_config_srs(const NR_ServingCellConfigCo return setup_release_srs_Config; } +static int get_SupportedBandwidth_fr1_bw_index(int bw_index) +{ + int val = -1; + + switch (bw_index) { + case NR_SupportedBandwidth_v1700__fr1_r17_mhz5: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz10: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz15: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz20: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz25: + val = bw_index; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz30: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz35: + val = NR_SupportedBandwidth__fr1_mhz30; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz40: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz45: + val = NR_SupportedBandwidth__fr1_mhz40; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz50: + val = NR_SupportedBandwidth__fr1_mhz50; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz60: + val = NR_SupportedBandwidth__fr1_mhz60; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz70: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz80: + val = NR_SupportedBandwidth__fr1_mhz80; + break; + case NR_SupportedBandwidth_v1700__fr1_r17_mhz90: + case NR_SupportedBandwidth_v1700__fr1_r17_mhz100: + val = NR_SupportedBandwidth__fr1_mhz100; + break; + default: + AssertFatal(1==0, "Invalid bw index\n"); + } + + return val; +} + + void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, NR_ServingCellConfigCommon_t *scc, int numerology, @@ -858,26 +899,41 @@ void prepare_sim_uecap(NR_UE_NR_Capability_t *cap, fs->featureSetsDownlinkPerCC = calloc(1, sizeof(*fs->featureSetsDownlinkPerCC)); NR_FeatureSetDownlinkPerCC_t *fs_cc = calloc(1, sizeof(*fs_cc)); fs_cc->supportedSubcarrierSpacingDL = numerology; - int bw = get_supported_band_index(numerology, freq_range, rbsize); - if (bw == 10) // 90MHz + int bw_index = get_supported_band_index(numerology, freq_range, rbsize); + int bw = get_supported_bw_mhz(freq_range, bw_index); + if (bw == 90) // 90MHz fs_cc->channelBW_90mhz = calloc(1, sizeof(*fs_cc->channelBW_90mhz)); - if (bw == 11) // 100MHz - bw--; if(freq_range == FR2) { fs_cc->supportedBandwidthDL.present = NR_SupportedBandwidth_PR_fr2; - fs_cc->supportedBandwidthDL.choice.fr2 = bw; + fs_cc->supportedBandwidthDL.choice.fr2 = bw_index; } else{ fs_cc->supportedBandwidthDL.present = NR_SupportedBandwidth_PR_fr1; - fs_cc->supportedBandwidthDL.choice.fr1 = bw; + fs_cc->supportedBandwidthDL.choice.fr1 = get_SupportedBandwidth_fr1_bw_index(bw_index); } + fs_cc->maxNumberMIMO_LayersPDSCH = calloc(1, sizeof(*fs_cc->maxNumberMIMO_LayersPDSCH)); + *fs_cc->maxNumberMIMO_LayersPDSCH = NR_MIMO_LayersDL_fourLayers; fs_cc->supportedModulationOrderDL = calloc(1, sizeof(*fs_cc->supportedModulationOrderDL)); *fs_cc->supportedModulationOrderDL = NR_ModulationOrder_qam256; asn1cSeqAdd(&fs->featureSetsDownlinkPerCC->list, fs_cc); + + if (bw == 35 || bw == 45 || bw == 70) { + fs->ext6 = calloc(1, sizeof(*fs->ext6)); + fs->ext6->featureSetsDownlinkPerCC_v1700 = calloc(1, sizeof(*fs->ext6->featureSetsDownlinkPerCC_v1700)); + NR_FeatureSetDownlinkPerCC_v1700_t *fs_dlcc_v1700 = calloc(1, sizeof(*fs_dlcc_v1700)); + fs_dlcc_v1700->supportedBandwidthDL_v1710 = calloc(1, sizeof(*fs_dlcc_v1700->supportedBandwidthDL_v1710)); + fs_dlcc_v1700->supportedBandwidthDL_v1710->present = NR_SupportedBandwidth_v1700_PR_fr1_r17; + fs_dlcc_v1700->supportedBandwidthDL_v1710->choice.fr1_r17 = bw_index; + asn1cSeqAdd(&fs->ext6->featureSetsDownlinkPerCC_v1700->list, fs_dlcc_v1700); + } } phy_Parameters->phy_ParametersFRX_Diff = calloc(1, sizeof(*phy_Parameters->phy_ParametersFRX_Diff)); phy_Parameters->phy_ParametersFRX_Diff->pucch_F0_2WithoutFH = NULL; + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, cap); + } } void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsch_TimeDomainAllocationList, diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7ed9bf322e3b90cd7d26eefabf96f78b813463fb..7c02ad4f9f204f63d78516c52136cc0efe408281 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -343,7 +343,7 @@ typedef struct nr_mac_rrc_dl_if_s { typedef struct cucp_cuup_if_s { cucp_cuup_bearer_context_setup_func_t bearer_context_setup; - cucp_cuup_bearer_context_setup_func_t bearer_context_mod; + cucp_cuup_bearer_context_mod_func_t bearer_context_mod; cucp_cuup_bearer_context_release_func_t bearer_context_release; } cucp_cuup_if_t; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index fd69a4fafd37bf13e790b08472fd0d8efcc635dd..281af514fac213a702b0980b69d93f9a0f3175a5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -736,6 +736,14 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size); } +static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) +{ + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); +} + /* \brief find existing PDU session inside E1AP Bearer Modif message, or * point to new one. * \param bearer_modif E1AP Bearer Modification Message @@ -793,20 +801,27 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid; + memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid; /* PDCP configuration */ - bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; + if (!drb_e1->pdcp_config) + drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config)); + bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config; set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; } - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? ue_p->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? ue_p->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, ue_p->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, ue_p->kgnb, (uint8_t *)req.integrityProtectionKey); +#if 0 + /* According to current understanding of E1 specifications, it is not needed + * to send security information because this does not change. + * But let's keep the code here in case it's needed. + */ + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, ue_p, req.secInfo); +#endif /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); @@ -1855,12 +1870,12 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC /* \brief fill E1 bearer modification's DRB from F1 DRB * \param drb_e1 pointer to a DRB inside an E1 bearer modification message * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ -static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) { drb_e1->id = drb_f1->drb_id; drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; + drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; } /** @@ -1892,8 +1907,8 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R */ static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) { - f1u->teid = p->teId; - memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4); + f1u->teid = p->tl_info.teId; + memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); f1u->addr.length = sizeof(in_addr_t); } @@ -1919,10 +1934,10 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); continue; } - pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; - DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; + DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; @@ -1930,10 +1945,9 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(req.numPDUSessionsMod > 0); DevAssert(req.numPDUSessions == 0); - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, UE->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)req.integrityProtectionKey); + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, UE, req.secInfo); // send the E1 bearer modification request message to update F1-U tunnel info sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); @@ -2074,10 +2088,6 @@ void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p) * are in E1, we also need to free the UE in the CU-CP, so call it twice to * cover all cases */ nr_pdcp_remove_UE(UE->rrc_ue_id); - uint32_t pdu_sessions[256]; - for (int i = 0; i < UE->nb_of_pdusessions && i < 256; ++i) - pdu_sessions[i] = UE->pduSession[i].param.pdusession_id; - rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions); LOG_I(NR_RRC, "removed UE CU UE ID %u/RNTI %04x \n", UE->rrc_ue_id, UE->rnti); rrc_delete_ue_data(UE); rrc_gNB_remove_ue_context(rrc, ue_context_p); @@ -2099,6 +2109,9 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p) /* only trigger release if it has been requested by core * otherwise, it might be CU that requested release on a DU during normal * operation (i.e, handover) */ + uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]; + get_pduSession_array(UE, pdu_sessions); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions); rrc_remove_ue(RC.nrrrc[0], ue_context_p); } } @@ -2271,9 +2284,9 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; drb->drb_id = pduSession[p].DRBnGRanList[i].id; drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; + drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress; drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; drb->up_ul_tnl_length = 1; /* pass QoS info to MAC */ @@ -2324,8 +2337,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4); + rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; + memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); // save the tunnel address for the DRBs @@ -2607,6 +2620,11 @@ void *rrc_gnb_task(void *args_p) { LOG_E(NR_RRC, "Handling of F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE not implemented\n"); break; + case F1AP_RESET_ACK: + LOG_I(NR_RRC, "received F1AP reset acknowledgement\n"); + free_f1ap_reset_ack(&F1AP_RESET_ACK(msg_p)); + break; + /* Messages from X2AP */ case X2AP_ENDC_SGNB_ADDITION_REQ: LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n"); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 0b1c3012f494aa6678e16351e30d60c29242be47..c1715c438c3e6d8490ebc95d8ccb7d6bd4498ced 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -353,10 +353,11 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession session->nssai = sessions[i].nssai; decodePDUSessionResourceSetup(session); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + security_information_t *secInfo = &bearer_req.secInfo; + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; bearer_req.numPDUSessions++; @@ -1231,6 +1232,9 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_ /* UE will be freed after UE context release complete */ } else { // the DU is offline already + uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]; + get_pduSession_array(UE, pdu_sessions); + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions); rrc_remove_ue(rrc, ue_context_p); } diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index b2ef792ac5bdd672e12bd84a4449ab777a1b46b1..c06529982496c2cd11379541add03b67160d52a2 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -24,13 +24,17 @@ #include <stdbool.h> #include <stdint.h> #include <stdlib.h> -#include "PHY/defs_common.h" + +#include "common/utils/alg/find.h" +#include "common/utils/alg/foreach.h" #include "RRC/NR/nr_rrc_proto.h" #include "T.h" #include "as_message.h" #include "assertions.h" #include "common/ran_context.h" #include "common/utils/T/T.h" +#include "rrc_gNB_UE_context.h" +#include "rrc_gNB_du.h" #include "e1ap_messages_types.h" #include "intertask_interface.h" #include "nr_rrc_defs.h" @@ -38,6 +42,7 @@ #include "rrc_messages_types.h" #include "tree.h" #include "e1ap_interface_management.h" +#include "rrc_gNB_NGAP.h" static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_container_t *b) { @@ -168,6 +173,69 @@ static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id, e1ap_ itti_send_msg_to_task(TASK_CUCP_E1, 0 /*unused by callee*/, msg_p); } +static bool has_assoc_id(const void *vval, const void *vit) +{ + sctp_assoc_t val = *(sctp_assoc_t *)vval; + sctp_assoc_t it = *(sctp_assoc_t *)vit; + return val == it; +} + +/* @brief Remove RRC UE contexts of UE without E1 connection. + * + * 38.463 sec 8.2.3. says that "[E1 Setup] procedure also re-initialises the + * E1AP UE-related contexts (if any) and erases all related signalling + * connections in the two nodes like a Reset procedure would do.". If the CU-UP + * reconnects, it's previous UE contexts are here, but not associated. To + * fulfil the above, we simply free all UE contexts that don't have a CU-UP, + * and send a F1 Reset message to the corresponding DU(s), following the fact + * that (38.473 sec 8.2.1.2.1) "a failure at the gNB-CU [...] has resulted in + * the loss of some or all transaction reference information[...] a RESET + * message shall be sent to the gNB-DU.". This might be overarching in that UEs + * that are in the process of connecting or that are on another DU might be + * affected by that reset procedure as well; we suppose they will connect later + * again. */ +static void remove_unassociated_e1_connections(gNB_RRC_INST *rrc, sctp_assoc_t e1_assoc_id) +{ + seq_arr_t affected_du; + seq_arr_init(&affected_du, sizeof(sctp_assoc_t)); + seq_arr_t ue_context_to_remove; + seq_arr_init(&ue_context_to_remove, sizeof(rrc_gNB_ue_context_t *)); + + rrc_gNB_ue_context_t *ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) { + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + uint32_t ue_id = UE->rrc_ue_id; + if (ue_associated_to_cuup(rrc, UE)) + continue; + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); + elm_arr_t ret = find_if(&affected_du, &ue_data.du_assoc_id, has_assoc_id); + if (!ret.found) + seq_arr_push_back(&affected_du, &ue_data.du_assoc_id, sizeof(ue_data.du_assoc_id)); + + /* remove UE context: we store the pointer, so pass pointer to ue_context_p */ + seq_arr_push_back(&ue_context_to_remove, &ue_context_p, sizeof(ue_context_p)); + LOG_I(NR_RRC, "remove E1-unassociated UE context ID %d\n", ue_id); + } + + for (int i = 0; i < seq_arr_size(&ue_context_to_remove); ++i) { + /* we retrieve a pointer (=iterator) to the UE context pointer + * (ue_context_p), so dereference once */ + rrc_gNB_ue_context_t *p = *(rrc_gNB_ue_context_t **)seq_arr_at(&ue_context_to_remove, i); + ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST}; + rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, p, cause); + rrc_remove_ue(rrc, p); + } + seq_arr_free(&ue_context_to_remove, NULL); + + for (int i = 0; i < seq_arr_size(&affected_du); ++i) { + void *it = seq_arr_at(&affected_du, i); + sctp_assoc_t du_assoc_id = *(sctp_assoc_t *)it; + LOG_W(NR_RRC, "trigger F1 reset on DU %d due to E1 connection loss\n", du_assoc_id); + trigger_f1_reset(rrc, du_assoc_id); + } + seq_arr_free(&affected_du, NULL); +} + /** * @brief E1AP Setup Request processing on CU-CP */ @@ -216,6 +284,8 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t * RB_INSERT(rrc_cuup_tree, &rrc->cuups, cuup); rrc->num_cuups++; + remove_unassociated_e1_connections(rrc, assoc_id); + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_RESP); msg_p->ittiMsgHeader.originInstance = assoc_id; e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p); @@ -225,6 +295,24 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t * return 0; } +/* @brief invalidate (remove) all E1 assoc ID from UE contexts belonging to this CU-UP */ +static void invalidate_cuup_connections(gNB_RRC_INST *rrc, sctp_assoc_t e1_assoc_id) +{ + rrc_gNB_ue_context_t *ue_context_p = NULL; + RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) { + gNB_RRC_UE_t *UE = &ue_context_p->ue_context; + uint32_t ue_id = UE->rrc_ue_id; + f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id); + if (ue_data.e1_assoc_id != e1_assoc_id) + continue; /* UE is on another CU-UP */ + + ue_data.e1_assoc_id = 0; + bool success = cu_update_f1_ue_data(ue_id, &ue_data); + DevAssert(success); + LOG_W(NR_RRC, "CU-UP %d of UE %d is gone\n", e1_assoc_id, ue_id); + } +} + /** * @brief RRC Processing of the indication of E1 connection loss on CU-CP */ @@ -232,6 +320,7 @@ void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_ { LOG_I(NR_RRC, "Received E1 connection loss indication on RRC\n"); AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n"); + invalidate_cuup_connections(rrc, assoc_id); nr_rrc_cuup_container_t e = {.assoc_id = assoc_id}; nr_rrc_cuup_container_t *cuup = RB_FIND(rrc_cuup_tree, &rrc->cuups, &e); if (cuup == NULL) { @@ -241,6 +330,7 @@ void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_ if (cuup->setup_req != NULL) { e1ap_setup_req_t *req = cuup->setup_req; LOG_I(NR_RRC, "releasing CU-UP %s on assoc_id %d\n", req->gNB_cu_up_name, assoc_id); + free_e1ap_cuup_setup_request(cuup->setup_req); free(cuup->setup_req); } nr_rrc_cuup_container_t *removed = RB_REMOVE(rrc_cuup_tree, &rrc->cuups, cuup); diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 802735ee85b41dd668434341ae2f18fbb80bd961..402e245dac9d1ef5b3287ec4725e6cf9a68e1a34 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -644,3 +644,14 @@ nr_rrc_du_container_t *find_target_du(gNB_RRC_INST *rrc, sctp_assoc_t source_ass } return target_du; } + +void trigger_f1_reset(gNB_RRC_INST *rrc, sctp_assoc_t du_assoc_id) +{ + f1ap_reset_t reset = { + .transaction_id = F1AP_get_next_transaction_identifier(0, 0), + .cause = F1AP_CAUSE_TRANSPORT, + .cause_value = 1, // F1AP_CauseTransport_transport_resource_unavailable + .reset_type = F1AP_RESET_ALL, // DU does not support partial reset yet + }; + rrc->mac_rrc.f1_reset(du_assoc_id, &reset); +} diff --git a/openair2/RRC/NR/rrc_gNB_du.h b/openair2/RRC/NR/rrc_gNB_du.h index aadac0845a746790534540eaee1263ef2f1dfcc8..514416211f313919fd6295857b1dec194809215f 100644 --- a/openair2/RRC/NR/rrc_gNB_du.h +++ b/openair2/RRC/NR/rrc_gNB_du.h @@ -60,4 +60,6 @@ struct nr_rrc_du_container_t *find_target_du(struct gNB_RRC_INST_s *rrc, sctp_as } \ } +void trigger_f1_reset(struct gNB_RRC_INST_s *rrc, sctp_assoc_t du_assoc_id); + #endif /* RRC_GNB_DU_H_ */ diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index ce6eb40bbebb5e7ab83b5865d58d83e153526869..8255ccdb38704fbbd4b13dbd25689dcae284ffcf 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -58,6 +58,12 @@ rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id return find_pduSession(ue, id, false); } +void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]) +{ + for (int i = 0; i < ue->nb_of_pdusessions && i < NGAP_MAX_PDU_SESSION; ++i) + pdu_sessions[i] = ue->pduSession[i].param.pdusession_id; +} + drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) { DevAssert(drb_id > 0 && drb_id <= 32); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 37ddbdd4313add99759269511a1bdabb38c1c88c..133e17627f84c684ed89f5164539fd212d1eb82e 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -73,6 +73,9 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create); /// @brief get PDU session of UE ue through the DRB drb_id rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id); +/// @brief get the PDU sessions of this UE in a single array +void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]); + /// @brief set PDCP configuration in a bearer context management message void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb); diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d7a1c42bf34af3bad3f73c6073af5c2e41ebddde..d2764ac2e1b2719bf4afdd2fb7eabcf87ceb85c5 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -855,14 +855,18 @@ 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)); - tun_config(1, ip, NULL, "oaitun_ue"); - setup_ue_ipv4_route(1, ip, "oaitun_ue"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_ue", 0); + tun_config(ifname, ip, NULL); + setup_ue_ipv4_route(ifname, 0, ip); } break; case PDU_SESSION_TYPE_IPV6: { char ipv6[40]; capture_ipv6_addr(addr, ipv6, sizeof(ipv6)); - tun_config(1, NULL, ipv6, "oaitun_ue"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_ue", 0); + tun_config(ifname, NULL, ipv6); } break; case PDU_SESSION_TYPE_IPV4V6: { @@ -870,8 +874,10 @@ 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)); - tun_config(1, ipv4, ipv6, "oaitun_ue"); - setup_ue_ipv4_route(1, ipv4, "oaitun_ue"); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, "oaitun_ue", 0); + tun_config(ifname, ipv4, ipv6); + setup_ue_ipv4_route(ifname, 0, ipv4); } break; default: diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c index 72b5d240e06c11a71ba6c680a75ed3e5208a1490..7a8de459e7818b4c01c16024553d4bed94cbec1d 100644 --- a/openair3/NAS/UE/ESM/esm_ebr_context.c +++ b/openair3/NAS/UE/ESM/esm_ebr_context.c @@ -207,8 +207,10 @@ int esm_ebr_context_create( char *ip_addr = 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"; - tun_config(1, ip, NULL, ifn); - setup_ue_ipv4_route(1, ip, ifn); + char ifname[IFNAMSIZ]; + tun_generate_ifname(ifname, ifn, 0); + tun_config(ifname, ip, NULL); + setup_ue_ipv4_route(ifname, 0, ip); } break; case NET_PDN_TYPE_IPV6: diff --git a/radio/rfsimulator/simulator.c b/radio/rfsimulator/simulator.c index faa185a0cb576412b05ab0c89e0c404699fc3b8c..262cb87deb28a8ba7d56653abdcb17da081c5a29 100644 --- a/radio/rfsimulator/simulator.c +++ b/radio/rfsimulator/simulator.c @@ -973,7 +973,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest } } else { bool have_to_wait; - + int loops = 0; do { have_to_wait=false; @@ -995,6 +995,12 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest t->nextRxTstamp + nsamps); flushInput(t, 3, nsamps); } + if (loops++ > 10 && t->role == SIMU_ROLE_SERVER) { + // Just start producing samples. The clients will catch up. + have_to_wait = false; + LOG_W(HW, + "No longer waiting for clients to catch up, starting to produce samples\n"); + } } while (have_to_wait); } diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf new file mode 100644 index 0000000000000000000000000000000000000000..527058727194f687c3b451dd27e4abba7c99a5f6 --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.189PRB.rfsim.conf @@ -0,0 +1,245 @@ +Active_gNBs = ( "gnb-rfsim"); +# Asn1_verbosity, choice in: none, info, annoying +Asn1_verbosity = "none"; + +gNBs = +( + { + ////////// Identification parameters: + gNB_ID = 0xe00; + +# cell_type = "CELL_MACRO_GNB"; + + gNB_name = "gnb-rfsim"; + + // Tracking area code, 0x0000 and 0xfffe are reserved values + tracking_area_code = 1; + + plmn_list = ({ mcc = 208; mnc = 99; mnc_length = 2; snssaiList = ({ sst = 1, sd = 0xffffff }) }); + + nr_cellid = 12345678L + +# tr_s_preference = "local_mac" + + ////////// Physical parameters: + + min_rxtxtime = 6; + + servingCellConfigCommon = ( + { + #spCellConfigCommon + + physCellId = 0; + +# downlinkConfigCommon + #frequencyInfoDL + # this is 3300.60 MHz + 53*12*30e-3 MHz = 3319.68 + absoluteFrequencySSB = 621312; + # this is 3300.60 MHz + dl_absoluteFrequencyPointA = 620040; + #scs-SpecificCarrierList + dl_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + dl_subcarrierSpacing = 1; + dl_carrierBandwidth = 189 + #initialDownlinkBWP + #genericParameters + # this is RBstart=0,L=189 (275*(275-L+1) + 275-1-RBstart) + initialDLBWPlocationAndBandwidth = 24199; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialDLBWPsubcarrierSpacing = 1; + #pdcch-ConfigCommon + initialDLBWPcontrolResourceSetZero = 11; + initialDLBWPsearchSpaceZero = 0; + + + + #uplinkConfigCommon + #frequencyInfoUL + ul_frequencyBand = 78; + #scs-SpecificCarrierList + ul_offstToCarrier = 0; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + ul_subcarrierSpacing = 1; + ul_carrierBandwidth = 189; + pMax = 20; + #initialUplinkBWP + #genericParameters + initialULBWPlocationAndBandwidth = 24199; +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + initialULBWPsubcarrierSpacing = 1; + #rach-ConfigCommon + #rach-ConfigGeneric + prach_ConfigurationIndex = 98; +#prach_msg1_FDM +#0 = one, 1=two, 2=four, 3=eight + prach_msg1_FDM = 0; + prach_msg1_FrequencyStart = 0; + zeroCorrelationZoneConfig = 12; + preambleReceivedTargetPower = -104; +#preamblTransMax (0...10) = (3,4,5,6,7,8,10,20,50,100,200) + preambleTransMax = 6; +#powerRampingStep +# 0=dB0,1=dB2,2=dB4,3=dB6 + powerRampingStep = 1; +#ra_ReponseWindow +#1,2,4,8,10,20,40,80 + ra_ResponseWindow = 5; +#ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR +#1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen + ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; +#one (0..15) 4,8,12,16,...60,64 + ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 15; +#ra_ContentionResolutionTimer +#(0..7) 8,16,24,32,40,48,56,64 + ra_ContentionResolutionTimer = 7; + rsrp_ThresholdSSB = 19; +#prach-RootSequenceIndex_PR +#1 = 839, 2 = 139 + prach_RootSequenceIndex_PR = 2; + prach_RootSequenceIndex = 1; + # SCS for msg1, can only be 15 for 30 kHz < 6 GHz, takes precendence over the one derived from prach-ConfigIndex + # + msg1_SubcarrierSpacing = 1, +# restrictedSetConfig +# 0=unrestricted, 1=restricted type A, 2=restricted type B + restrictedSetConfig = 0, + + msg3_DeltaPreamble = 1; + p0_NominalWithGrant =-90; + +# pucch-ConfigCommon setup : +# pucchGroupHopping +# 0 = neither, 1= group hopping, 2=sequence hopping + pucchGroupHopping = 0; + hoppingId = 40; + p0_nominal = -90; + + ssb_PositionsInBurst_Bitmap = 1; + +# ssb_periodicityServingCell +# 0 = ms5, 1=ms10, 2=ms20, 3=ms40, 4=ms80, 5=ms160, 6=spare2, 7=spare1 + ssb_periodicityServingCell = 2; + +# dmrs_TypeA_position +# 0 = pos2, 1 = pos3 + dmrs_TypeA_Position = 0; + +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + subcarrierSpacing = 1; + + + #tdd-UL-DL-ConfigurationCommon +# subcarrierSpacing +# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120 + referenceSubcarrierSpacing = 1; + # pattern1 + # dl_UL_TransmissionPeriodicity + # 0=ms0p5, 1=ms0p625, 2=ms1, 3=ms1p25, 4=ms2, 5=ms2p5, 6=ms5, 7=ms10 + dl_UL_TransmissionPeriodicity = 6; + nrofDownlinkSlots = 7; + nrofDownlinkSymbols = 6; + nrofUplinkSlots = 2; + nrofUplinkSymbols = 4; + + ssPBCH_BlockPower = -25; + } + + ); + + + # ------- SCTP definitions + SCTP : + { + # Number of streams to use in input/output + SCTP_INSTREAMS = 2; + SCTP_OUTSTREAMS = 2; + }; + + ////////// AMF parameters: + amf_ip_address = ({ ipv4 = "192.168.71.132"; }); + + NETWORK_INTERFACES : + { + + GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.71.140"; + GNB_IPV4_ADDRESS_FOR_NGU = "192.168.71.140"; + GNB_PORT_FOR_S1U = 2152; # Spec 2152 + }; + + } +); + +MACRLCs = ( + { + num_cc = 1; + tr_s_preference = "local_L1"; + tr_n_preference = "local_RRC"; + pusch_TargetSNRx10 = 200; + pucch_TargetSNRx10 = 200; + } +); + +L1s = ( +{ + num_cc = 1; + tr_n_preference = "local_mac"; + prach_dtx_threshold = 200; +# pucch0_dtx_threshold = 150; +} +); + +RUs = ( + { + local_rf = "yes" + nb_tx = 1 + nb_rx = 1 + att_tx = 0 + att_rx = 0; + bands = [78]; + max_pdschReferenceSignalPower = -27; + max_rxgain = 75; + eNB_instances = [0]; + sf_extension = 0 + sdr_addrs = "serial=XXXXXXX" + } +); + + +rfsimulator: { + serveraddr = "server"; +}; + +security = { + # preferred ciphering algorithms + # the first one of the list that an UE supports in chosen + # valid values: nea0, nea1, nea2, nea3 + ciphering_algorithms = ( "nea0" ); + + # preferred integrity algorithms + # the first one of the list that an UE supports in chosen + # valid values: nia0, nia1, nia2, nia3 + integrity_algorithms = ( "nia2", "nia0" ); + + # setting 'drb_ciphering' to "no" disables ciphering for DRBs, no matter + # what 'ciphering_algorithms' configures; same thing for 'drb_integrity' + drb_ciphering = "yes"; + drb_integrity = "no"; +}; + + log_config : + { + global_log_level ="info"; + hw_log_level ="info"; + phy_log_level ="info"; + mac_log_level ="info"; + rlc_log_level ="info"; + pdcp_log_level ="info"; + rrc_log_level ="info"; + f1ap_log_level ="debug"; + };