Merge branch 'integration_2025_w06' into 'develop'
Integration: `2025.w06` See merge request oai/openairinterface5g!3248 * !3202 Simplify usage of the old segment decoding libraries with the slot coding interface * !3240 Fix typos in NR_SA_Tutorial_OAI_multi_UE.md * !3242 Period based phytest bitmap * !3238 Refactor tun_if.h * !3000 Improvements for NR dlsim and ulsim * !3239 Remove inexistant SIMD instruction * !3246 Deadlock avoidance in rfsimulator * !3251 nFAPI: make 4-layer on 100MHz work * !3243 Reset E1 UE contexts after E1 Setup Response * !3245 Added Support of 35Mhz,45Mhz,70Mhz Bandwidth * !3219 E1AP enc/dec lib improvements
This commit is contained in:
+16
-8
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
+49
-12
@@ -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;
|
||||
|
||||
+38
-57
@@ -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];
|
||||
nas_sock_fd[instance_id] = tun_alloc(ifname);
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
+28
-15
@@ -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_*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
...................................
|
||||
```
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
+1
-12
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
|
||||
/* DRB QoS Flows Parameters (clause 9.3.1.26) */
|
||||
// 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_nGRAN_to_mod_t;
|
||||
} DRB_nGRAN_to_setup_t;
|
||||
|
||||
/**
|
||||
* 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_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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
long sessionId;
|
||||
long sessionType;
|
||||
e1ap_nssai_t nssai;
|
||||
security_indication_t securityIndication;
|
||||
UP_TL_information_t UP_TL_information;
|
||||
long numDRB2Setup;
|
||||
DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
|
||||
long numDRB2Modify;
|
||||
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
|
||||
} pdu_session_to_setup_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 {
|
||||
uint32_t gNB_cu_cp_ue_id;
|
||||
uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only
|
||||
// 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];
|
||||
long ueDlAggMaxBitRate;
|
||||
} security_information_t;
|
||||
|
||||
/**
|
||||
* PDU Session Resource To Setup List (clause 9.3.3.10)
|
||||
*/
|
||||
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;
|
||||
// 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_mod_t;
|
||||
|
||||
/**
|
||||
* Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463
|
||||
*/
|
||||
typedef struct e1ap_bearer_setup_req_s {
|
||||
// gNB-CU-CP UE E1AP ID (M)
|
||||
uint32_t gNB_cu_cp_ue_id;
|
||||
// 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;
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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()
|
||||
|
||||
+50
-11
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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_ */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/* encode */
|
||||
if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
LOG_E(F1AP, "Failed to encode F1ResetAcknowledge\n");
|
||||
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;
|
||||
}
|
||||
|
||||
/* send */
|
||||
ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu);
|
||||
/* encode */
|
||||
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;
|
||||
}
|
||||
f1ap_itti_send_sctp_data_req(assoc_id, buffer, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
} else {
|
||||
if (Np_info > 8424){
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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++) {
|
||||
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;
|
||||
|
||||
// Intermediate number of information bits
|
||||
Ninfo = (nb_re * R * Qm * Nl)>>10;
|
||||
|
||||
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);
|
||||
|
||||
if (R <= 2560) {
|
||||
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;
|
||||
} else {
|
||||
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 nb_rb_lbrm = 0;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (NPRB_LBRM[i] >= nb_rb){
|
||||
nb_rb_lbrm = NPRB_LBRM[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int Qm = (table == 1) ? 8 : 6;
|
||||
uint32_t R = 948;
|
||||
uint32_t nb_re = 156 * nb_rb_lbrm;
|
||||
|
||||
// Intermediate number of information bits
|
||||
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++) {
|
||||
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);
|
||||
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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+44
-26
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
Reference in New Issue
Block a user