Merge branch 'integration_2024_w43' into 'develop'
Integration: `2024.w43` Closes #769 and #841 See merge request oai/openairinterface5g!3069 * !2994 Refactor file descriptor handling in rfsimulator * !3010 Fix heap overflow in websrv * !3043 CI: Update RAN-gNB-N300-Timing-Phytest-LDPC test cases * !3060 process registration reject in UE * !3062 fix nr rlc tests * !3067 Bugfix: Fill QFI for N3 GTP messages * !3057 Bugfix in ue pusch mac pdu creation * !3068 getopt() returns int * !3056 F1AP Enc/Dec Library follow-up * !3064 T: don't check argument in optimized version of T IDs * !2786 Add F1 Handover procedures * !2980 Refactor NAS 5GS PDU Session Establishment Accept handling and other NAS improvements * !3063 Update yaml-cpp dependency handling * !2989 NR gNB scheduler improvements for BWP operation
This commit is contained in:
+3
-4
@@ -32,7 +32,7 @@ set (OPENAIR_DIR ${CMAKE_SOURCE_DIR})
|
||||
|
||||
include("cmake_targets/macros.cmake")
|
||||
if(NOT DEFINED ENV{CPM_SOURCE_CACHE})
|
||||
set(CPM_SOURCE_CACHE ~/.cache/cpm/)
|
||||
set(CPM_SOURCE_CACHE ~/.cache/cpm/ CACHE FILEPATH "Directory to download CPM dependencies")
|
||||
endif()
|
||||
include("cmake_targets/CPM.cmake")
|
||||
|
||||
@@ -1271,6 +1271,7 @@ set(L2_NR_SRC
|
||||
${NR_RRC_DIR}/rrc_gNB_radio_bearers.c
|
||||
${NR_RRC_DIR}/rrc_gNB_cuup.c
|
||||
${NR_RRC_DIR}/rrc_gNB_du.c
|
||||
${NR_RRC_DIR}/rrc_gNB_mobility.c
|
||||
)
|
||||
|
||||
set(L2_SRC_UE
|
||||
@@ -1781,7 +1782,7 @@ add_library(LIB_NAS_SIMUE
|
||||
${NAS_SRC}UE/nas_parser.c
|
||||
${NAS_SRC}UE/nas_proc.c
|
||||
${NAS_SRC}UE/nas_user.c
|
||||
${NAS_SRC}NR_UE/nr_nas_msg_sim.c
|
||||
${NAS_SRC}NR_UE/nr_nas_msg.c
|
||||
${libnas_api_OBJS}
|
||||
${libnas_ue_api_OBJS}
|
||||
${libnas_emm_msg_OBJS}
|
||||
@@ -1844,8 +1845,6 @@ add_library(NB_IoT MODULE ${NBIOT_SOURCES} )
|
||||
|
||||
add_library(LIB_5GNAS_GNB
|
||||
${NAS_SRC}/COMMON/nr_common.c
|
||||
${NAS_SRC}/gNB/network_process_nas.c
|
||||
${NAS_SRC}/NR_UE/ue_process_nas.c
|
||||
${OPENAIR3_DIR}//UICC/usim_interface.c
|
||||
)
|
||||
|
||||
|
||||
@@ -33,145 +33,163 @@
|
||||
<testCase id="010111">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r106 -R106 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r106 -R106 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010112">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>100</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010121">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r106 -R106 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r106 -R106 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010122">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>150</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010131">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>250</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r106 -R106 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r106 -R106 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010132">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>250</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r106 -R106 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010211">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r273 -R273 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010212">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>150</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010221">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r273 -R273 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010222">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>350</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010231">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r273 -R273 -C10 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010232">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>550</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -o -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010311">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010312">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>250</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m5 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m5 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010321">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>600</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010322">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>650</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m15 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m15 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010331">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>650</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -C10 -W2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="010332">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_ulsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_ulsim</physim_run>
|
||||
<physim_time_threshold>1100</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -m25 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -m25 -r273 -R273 -o -W2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
</testCaseList>
|
||||
|
||||
@@ -27,151 +27,223 @@
|
||||
000111 000112 000121 000122 000131 000132
|
||||
000211 000212 000221 000222 000231 000232
|
||||
000311 000312 000321 000322 000331 000332
|
||||
000411 000412 000421 000422 000431 000432
|
||||
</TestCaseRequestedList>
|
||||
<TestCaseExclusionList></TestCaseExclusionList>
|
||||
|
||||
<testCase id="000111">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 5, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>200</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b106 -R106 -X8 -P</physim_run_args>
|
||||
<physim_time_threshold>230</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b106 -R106 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000112">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>100</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000121">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 15, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>3000</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b106 -R106 -X8 -P</physim_run_args>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b106 -R106 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000122">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>100</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000131">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 25, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b106 -R106 -X8 -P</physim_run_args>
|
||||
<physim_time_threshold>350</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b106 -R106 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000132">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 106 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>200</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b106 -R106 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000211">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b273 -R273 -X8 -P</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000212">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>150</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000221">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>450</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b273 -R273 -X8 -P</physim_run_args>
|
||||
<physim_time_threshold>350</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000222">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>250</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000231">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>500</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b273 -R273 -X8 -P</physim_run_args>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000232">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 1 layer</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000311">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>350</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b273 -R273 -X8 -x2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000312">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>200</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e5 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000321">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 15, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>600</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b273 -R273 -X8 -x2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_time_threshold>450</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000322">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 15, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>500</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e15 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000331">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 25, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>800</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b273 -R273 -X8 -x2 -z2 -y2 -P</physim_run_args>
|
||||
<physim_time_threshold>500</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X 8,9,10,11,12 -x2 -z2 -y2 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000332">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 25, 273 PRBs, 2 layers</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>800</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
<physim_time_threshold>500</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z2 -y2 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000411">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000412">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 5, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>150</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e5 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000421">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>400</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000422">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 20, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>300</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e15 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000431">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with CPU: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>450</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -X8,9,10,11,12 -x2 -z4 -y4 -P</physim_run_args>
|
||||
</testCase>
|
||||
|
||||
<testCase id="000432">
|
||||
<class>Run_T2Test</class>
|
||||
<desc>Run nr_dlsim with T2 LDPC offload: SNR = 30, MCS = 27, 273 PRBs, 2 layers, 4 antennas</desc>
|
||||
<always_exec>true</always_exec>
|
||||
<physim_run>nr_dlsim</physim_run>
|
||||
<physim_time_threshold>450</physim_time_threshold>
|
||||
<physim_run_args>-n100 -s30 -S30.2 -e25 -b273 -R273 -c -x2 -z4 -y4 -P --ldpc_offload.dpdk_dev d8:00.0</physim_run_args>
|
||||
</testCase>
|
||||
</testCaseList>
|
||||
|
||||
@@ -1,25 +1,18 @@
|
||||
find_package(yaml-cpp REQUIRED PATHS /usr/lib/aarch64-linux-gnu/pkgconfig/)
|
||||
# include(FetchContent)
|
||||
|
||||
# FetchContent_Declare(
|
||||
# yaml-cpp
|
||||
# GIT_REPOSITORY https://github.com/jbeder/yaml-cpp.git
|
||||
# GIT_TAG 0.8.0
|
||||
# )
|
||||
# FetchContent_GetProperties(yaml-cpp)
|
||||
|
||||
# if(NOT yaml-cpp_POPULATED)
|
||||
# message(STATUS "Fetching yaml-cpp...")
|
||||
# FetchContent_Populate(yaml-cpp)
|
||||
# add_subdirectory(${yaml-cpp_SOURCE_DIR} ${yaml-cpp_BINARY_DIR})
|
||||
# endif()
|
||||
find_package(yaml-cpp)
|
||||
if (NOT yaml-cpp_FOUND)
|
||||
CPMAddPackage("gh:jbeder/yaml-cpp#yaml-cpp-0.7.0@0.7.0")
|
||||
else()
|
||||
if (NOT TARGET yaml-cpp::yaml-cpp)
|
||||
add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_library(params_yaml_static config_yaml.cpp)
|
||||
target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp)
|
||||
target_link_libraries(params_yaml_static PUBLIC UTIL yaml-cpp::yaml-cpp)
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
add_library(params_yaml MODULE config_yaml.cpp)
|
||||
target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp)
|
||||
target_link_libraries(params_yaml PUBLIC UTIL yaml-cpp::yaml-cpp)
|
||||
set_target_properties(params_yaml PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
@@ -16,3 +16,6 @@ add_subdirectory(threadPool)
|
||||
add_library(utils utils.c system.c time_meas.c time_stat.c tun_if.c)
|
||||
target_include_directories(utils PUBLIC .)
|
||||
target_link_libraries(utils PRIVATE ${T_LIB})
|
||||
if (ENABLE_TESTS)
|
||||
add_subdirectory(hashtable/tests)
|
||||
endif()
|
||||
|
||||
@@ -177,6 +177,7 @@ extern int *T_active;
|
||||
#else /* #ifdef __cplusplus */
|
||||
|
||||
/* C version of T_HEADER with time */
|
||||
#ifdef CHECK_T_TYPE
|
||||
#define T_HEADER(x) \
|
||||
do { \
|
||||
if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \
|
||||
@@ -191,6 +192,16 @@ extern int *T_active;
|
||||
T_LOCAL_size += sizeof(struct timespec); \
|
||||
T_PUT_int(1, (int)(uintptr_t)(x)); \
|
||||
} while (0)
|
||||
#else /* CHECK_T_TYPE */
|
||||
#define T_HEADER(x) \
|
||||
do { \
|
||||
struct timespec T_HEADER_time; \
|
||||
if (clock_gettime(CLOCK_REALTIME, &T_HEADER_time)) abort(); \
|
||||
memcpy(T_LOCAL_buf, &T_HEADER_time, sizeof(struct timespec)); \
|
||||
T_LOCAL_size += sizeof(struct timespec); \
|
||||
T_PUT_int(1, (int)(uintptr_t)(x)); \
|
||||
} while (0)
|
||||
#endif /* CHECK_T_TYPE */
|
||||
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
@@ -207,6 +218,7 @@ extern int *T_active;
|
||||
#else /* #ifdef __cplusplus */
|
||||
|
||||
/* C version of T_HEADER without time */
|
||||
#ifdef CHECK_T_TYPE
|
||||
#define T_HEADER(x) \
|
||||
do { \
|
||||
if (!__builtin_types_compatible_p(typeof(x), struct T_header *)) { \
|
||||
@@ -217,6 +229,12 @@ extern int *T_active;
|
||||
} \
|
||||
T_PUT_int(1, (int)(uintptr_t)(x)); \
|
||||
} while (0)
|
||||
#else /* CHECK_T_TYPE */
|
||||
#define T_HEADER(x) \
|
||||
do { \
|
||||
T_PUT_int(1, (int)(uintptr_t)(x)); \
|
||||
} while (0)
|
||||
#endif /* CHECK_T_TYPE */
|
||||
|
||||
#endif /* #ifdef __cplusplus */
|
||||
|
||||
|
||||
@@ -305,3 +305,24 @@ hashtable_rc_t hashtable_get(const hash_table_t *const hashtblP, const hash_key_
|
||||
*dataP = NULL;
|
||||
return HASH_TABLE_KEY_NOT_EXISTS;
|
||||
}
|
||||
|
||||
hash_table_iterator_s hashtable_get_iterator(const hash_table_t *const hashtbl)
|
||||
{
|
||||
return (hash_table_iterator_s){.index = 0, .node = hashtbl->nodes[0], .hashtbl = hashtbl};
|
||||
}
|
||||
|
||||
bool hashtable_iterator_getnext(hash_table_iterator_s *iterator, void **dataP)
|
||||
{
|
||||
// Iterate over table indexes
|
||||
while (iterator->node == NULL) {
|
||||
iterator->index++;
|
||||
if (iterator->index >= iterator->hashtbl->size) {
|
||||
*dataP = NULL;
|
||||
return false;
|
||||
}
|
||||
iterator->node = iterator->hashtbl->nodes[iterator->index];
|
||||
}
|
||||
*dataP = iterator->node->data;
|
||||
iterator->node = iterator->node->next;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include<stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef size_t hash_size_t;
|
||||
typedef uint64_t hash_key_t;
|
||||
@@ -54,6 +55,12 @@ typedef struct hash_table_s {
|
||||
void (*freefunc)(void *);
|
||||
} hash_table_t;
|
||||
|
||||
typedef struct hash_table_iterator_s {
|
||||
int index;
|
||||
hash_node_t* node;
|
||||
const hash_table_t* const hashtbl;
|
||||
} hash_table_iterator_s;
|
||||
|
||||
char *hashtable_rc_code2string(hashtable_rc_t rcP);
|
||||
void hash_free_int_func(void *memoryP);
|
||||
hash_table_t *hashtable_create (const hash_size_t size, hash_size_t (*hashfunc)(const hash_key_t ), void (*freefunc)(void *));
|
||||
@@ -63,8 +70,8 @@ hashtable_rc_t hashtable_dump_content (const hash_table_t *const hashtblP, char
|
||||
hashtable_rc_t hashtable_insert (hash_table_t *const hashtbl, const hash_key_t key, void *data);
|
||||
hashtable_rc_t hashtable_remove (hash_table_t *const hashtbl, const hash_key_t key);
|
||||
hashtable_rc_t hashtable_get (const hash_table_t *const hashtbl, const hash_key_t key, void **dataP);
|
||||
|
||||
|
||||
hash_table_iterator_s hashtable_get_iterator(const hash_table_t *const hashtbl);
|
||||
bool hashtable_iterator_getnext(hash_table_iterator_s* iterator, void **dataP);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable(test_hashtable test_hashtable.cpp)
|
||||
add_dependencies(tests test_hashtable)
|
||||
target_link_libraries(test_hashtable PRIVATE HASHTABLE GTest::gtest)
|
||||
add_test(NAME test_hashtable
|
||||
COMMAND ./test_hashtable)
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 <gtest/gtest.h>
|
||||
extern "C" {
|
||||
#include "hashtable.h"
|
||||
}
|
||||
|
||||
TEST(hashtable, test_insert_remove) {
|
||||
hash_table_t* table = hashtable_create(250, NULL, NULL);
|
||||
int* a = (int*)calloc(1, sizeof(*a));
|
||||
EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK);
|
||||
EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK);
|
||||
EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK);
|
||||
}
|
||||
|
||||
TEST(hashtable, test_insert_iterate_remove) {
|
||||
hash_table_t* table = hashtable_create(250, NULL, NULL);
|
||||
int* a = (int*)calloc(1, sizeof(*a));
|
||||
EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK);
|
||||
auto iterator = hashtable_get_iterator(table);
|
||||
void* ptr;
|
||||
int num_items = 0;
|
||||
while(hashtable_iterator_getnext(&iterator, &ptr)) {
|
||||
num_items++;
|
||||
}
|
||||
EXPECT_EQ(num_items, 1);
|
||||
EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK);
|
||||
num_items = 0;
|
||||
|
||||
auto iterator2 = hashtable_get_iterator(table);
|
||||
while(hashtable_iterator_getnext(&iterator2, &ptr)) {
|
||||
num_items++;
|
||||
}
|
||||
EXPECT_EQ(num_items, 0);
|
||||
EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK);
|
||||
}
|
||||
|
||||
TEST(hashtable, test_insert_three_iterate_remove) {
|
||||
hash_table_t* table = hashtable_create(250, NULL, NULL);
|
||||
int* a1 = (int*)calloc(1, sizeof(*a1));
|
||||
int* a2 = (int*)calloc(1, sizeof(*a2));
|
||||
int* a3 = (int*)calloc(1, sizeof(*a3));
|
||||
EXPECT_EQ(hashtable_insert(table, 1, a1), HASH_TABLE_OK);
|
||||
EXPECT_EQ(hashtable_insert(table, 2, a2), HASH_TABLE_OK);
|
||||
EXPECT_EQ(hashtable_insert(table, 3, a3), HASH_TABLE_OK);
|
||||
auto iterator = hashtable_get_iterator(table);
|
||||
void* ptr;
|
||||
int num_items = 0;
|
||||
while(hashtable_iterator_getnext(&iterator, &ptr)) {
|
||||
num_items++;
|
||||
}
|
||||
EXPECT_EQ(num_items, 3);
|
||||
EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK);
|
||||
num_items = 0;
|
||||
|
||||
auto iterator2 = hashtable_get_iterator(table);
|
||||
while(hashtable_iterator_getnext(&iterator2, &ptr)) {
|
||||
num_items++;
|
||||
}
|
||||
EXPECT_EQ(num_items, 2);
|
||||
EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK);
|
||||
}
|
||||
|
||||
TEST(hashtable, test_insert_empty_insert_interate) {
|
||||
hash_table_t* table = hashtable_create(250, NULL, NULL);
|
||||
int* a = (int*)calloc(1, sizeof(*a));
|
||||
EXPECT_EQ(hashtable_insert(table, 1, a), HASH_TABLE_OK);
|
||||
EXPECT_EQ(hashtable_remove(table, 1), HASH_TABLE_OK);
|
||||
|
||||
int* a2 = (int*)calloc(1, sizeof(*a2));
|
||||
EXPECT_EQ(hashtable_insert(table, 1, a2), HASH_TABLE_OK);
|
||||
auto iterator3 = hashtable_get_iterator(table);
|
||||
int num_items = 0;
|
||||
void* ptr;
|
||||
while(hashtable_iterator_getnext(&iterator3, &ptr)) {
|
||||
num_items++;
|
||||
}
|
||||
EXPECT_EQ(num_items, 1);
|
||||
|
||||
EXPECT_EQ(hashtable_destroy(&table), HASH_TABLE_OK);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -321,8 +321,6 @@ typedef struct {
|
||||
TASK_DEF(TASK_DU_F1, 200) \
|
||||
TASK_DEF(TASK_CUCP_E1, 200) \
|
||||
TASK_DEF(TASK_CUUP_E1, 200) \
|
||||
TASK_DEF(TASK_RRC_UE_SIM, 200) \
|
||||
TASK_DEF(TASK_RRC_GNB_SIM, 200) \
|
||||
TASK_DEF(TASK_RRC_NSA_UE, 200) \
|
||||
TASK_DEF(TASK_RRC_NSA_NRUE, 200) \
|
||||
TASK_DEF(TASK_NAS_NRUE, 200) \
|
||||
|
||||
@@ -71,30 +71,41 @@ int get_single_rnti(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
rrc_gNB_ue_context_t *get_single_rrc_ue(void)
|
||||
{
|
||||
rrc_gNB_ue_context_t *ue = NULL;
|
||||
rrc_gNB_ue_context_t *l = NULL;
|
||||
int n = 0;
|
||||
RB_FOREACH (l, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
|
||||
if (ue == NULL)
|
||||
ue = l;
|
||||
n++;
|
||||
}
|
||||
if (!ue) {
|
||||
printf("could not find any UE in RRC\n");
|
||||
}
|
||||
if (n > 1) {
|
||||
printf("more than one UE in RRC present\n");
|
||||
ue = NULL;
|
||||
}
|
||||
|
||||
return ue;
|
||||
}
|
||||
|
||||
int get_reestab_count(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!RC.nrrrc)
|
||||
ERROR_MSG_RET("no RRC present, cannot list counts\n");
|
||||
rrc_gNB_ue_context_t *ue = NULL;
|
||||
int rnti = -1;
|
||||
if (!buf) {
|
||||
rrc_gNB_ue_context_t *l = NULL;
|
||||
int n = 0;
|
||||
RB_FOREACH(l, rrc_nr_ue_tree_s, &RC.nrrrc[0]->rrc_ue_head) {
|
||||
if (ue == NULL) ue = l;
|
||||
n++;
|
||||
}
|
||||
ue = get_single_rrc_ue();
|
||||
if (!ue)
|
||||
ERROR_MSG_RET("could not find any UE in RRC\n");
|
||||
if (n > 1)
|
||||
ERROR_MSG_RET("more than one UE in RRC present\n");
|
||||
ERROR_MSG_RET("no single UE in RRC present\n");
|
||||
} else {
|
||||
rnti = strtol(buf, NULL, 16);
|
||||
if (rnti < 1 || rnti >= 0xfffe)
|
||||
ERROR_MSG_RET("RNTI needs to be [1,0xfffe]\n");
|
||||
ue = rrc_gNB_get_ue_context_by_rnti_any_du(RC.nrrrc[0], rnti);
|
||||
ue_id_t ue_id = strtol(buf, NULL, 10);
|
||||
ue = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id);
|
||||
if (!ue)
|
||||
ERROR_MSG_RET("could not find UE with RNTI %04x in RRC\n");
|
||||
ERROR_MSG_RET("could not find UE with ue_id %d in RRC\n");
|
||||
}
|
||||
|
||||
prnt("UE RNTI %04x reestab %d reconfig %d\n",
|
||||
@@ -125,11 +136,43 @@ int trigger_reestab(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id);
|
||||
/**
|
||||
* @brief Trigger F1 handover for UE
|
||||
* @param buf: RRC UE ID or NULL for the first UE in list
|
||||
* @param debug: Debug flag
|
||||
* @param prnt: Print function
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int rrc_gNB_trigger_f1_ho(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
{
|
||||
if (!RC.nrrrc)
|
||||
ERROR_MSG_RET("no RRC present, cannot list counts\n");
|
||||
rrc_gNB_ue_context_t *ue = NULL;
|
||||
if (!buf) {
|
||||
ue = get_single_rrc_ue();
|
||||
if (!ue)
|
||||
ERROR_MSG_RET("no single UE in RRC present\n");
|
||||
} else {
|
||||
ue_id_t ue_id = strtol(buf, NULL, 10);
|
||||
ue = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id);
|
||||
if (!ue)
|
||||
ERROR_MSG_RET("could not find UE with ue_id %d in RRC\n", ue_id);
|
||||
}
|
||||
|
||||
gNB_RRC_UE_t *UE = &ue->ue_context;
|
||||
nr_HO_F1_trigger_telnet(RC.nrrrc[0], UE->rrc_ue_id);
|
||||
prnt("RRC F1 handover triggered for UE %u\n", UE->rrc_ue_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static telnetshell_cmddef_t cicmds[] = {
|
||||
{"get_single_rnti", "", get_single_rnti},
|
||||
{"force_reestab", "[rnti(hex,opt)]", trigger_reestab},
|
||||
{"get_reestab_count", "[rnti(hex,opt)]", get_reestab_count},
|
||||
{"", "", NULL},
|
||||
{"get_single_rnti", "", get_single_rnti},
|
||||
{"force_reestab", "[rnti(hex,opt)]", trigger_reestab},
|
||||
{"get_reestab_count", "[rnti(hex,opt)]", get_reestab_count},
|
||||
{"trigger_f1_ho", "[rrc_ue_id(int,opt)]", rrc_gNB_trigger_f1_ho},
|
||||
{"", "", NULL},
|
||||
};
|
||||
|
||||
static telnetshell_vardef_t civars[] = {
|
||||
|
||||
@@ -268,7 +268,7 @@ The web server back-end is using the [oai configuration module](Config/Rtusage).
|
||||
| `listenaddr` | `ipV4 address, ascii format` | "0.0.0.0" | local address the back-end is listening on |
|
||||
| `listenport` | `integer` | 8090 | port number the server is listening on |
|
||||
| debug | `integer` | 0 | When not 0, http requests headers and json objects dump are added to back-end traces |
|
||||
| fpath | character string | websrv | The path to on-disk http server resources . The default value matches the front-end installation when running the softmodem from the executables repository. |
|
||||
| fpath | character string | common/utils/websrv | The path to on-disk http server resources . The default value matches the front-end installation when running the softmodem from the executables repository. |
|
||||
| cert, key, rootca | `character string` | null | certificates and key used to trigger https protocol (not tested) |
|
||||
| | | | |
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ paramdef_t websrvoptions[] = {
|
||||
{"listenport", "<local port>\n", 0, uptr : &(websrvparams.listenport), defuintval : 8090, TYPE_UINT, 0},
|
||||
{"priority", "<scheduling policy (0-99)\n", 0, iptr : &websrvparams.priority, defuintval : 0, TYPE_INT, 0},
|
||||
{"debug", "<debug level>\n", 0, uptr : &websrvparams.dbglvl, defuintval : 0, TYPE_UINT, 0},
|
||||
{"fpath", "<file directory>\n", 0, strptr : &websrvparams.fpath, defstrval : "websrv", TYPE_STRING, 0},
|
||||
{"fpath", "<file directory>\n", 0, strptr : &websrvparams.fpath, defstrval : "common/utils/websrv", TYPE_STRING, 0},
|
||||
{"cert", "<cert file>\n", 0, strptr : &websrvparams.certfile, defstrval : NULL, TYPE_STRING, 0},
|
||||
{"key", "<key file>\n", 0, strptr : &websrvparams.keyfile, defstrval : NULL, TYPE_STRING, 0},
|
||||
{"rootca", "<root ca file>\n", 0, strptr : &websrvparams.rootcafile, defstrval : NULL, TYPE_STRING, 0},
|
||||
@@ -267,7 +267,7 @@ int websrv_callback_get_softmodemhelp(const struct _u_request *request, struct _
|
||||
int httpstatus = 204; // no content
|
||||
char *hlpfile = strstr(request->http_url, "helpfiles");
|
||||
if (hlpfile != NULL) {
|
||||
char *hlppath = malloc(strlen(hlpfile) + strlen(websrvparams.fpath) + 1);
|
||||
char *hlppath = malloc(strlen(hlpfile) + strlen(websrvparams.fpath) + 2);
|
||||
sprintf(hlppath, "%s/%s", websrvparams.fpath, hlpfile);
|
||||
help_string = websrv_read_file(hlppath);
|
||||
if (help_string == NULL) {
|
||||
@@ -291,9 +291,10 @@ int websrv_callback_default(const struct _u_request *request, struct _u_response
|
||||
LOG_I(UTIL, "[websrv] Requested file is: %s %s\n", request->http_verb, request->http_url);
|
||||
websrv_dump_request("default ", request, websrvparams.dbglvl);
|
||||
|
||||
char *fpath = malloc(strlen(request->http_url) + strlen(websrvparams.fpath) + 2);
|
||||
const char *index_file_name = "index.html";
|
||||
char *fpath = malloc(strlen(request->http_url) + strlen(websrvparams.fpath) + strlen(index_file_name) + 2);
|
||||
if ((strcmp(request->http_url + 1, websrvparams.fpath) == 0) || (strcmp(request->http_url, "/") == 0)) {
|
||||
sprintf(fpath, "%s/index.html", websrvparams.fpath);
|
||||
sprintf(fpath, "%s/%s", websrvparams.fpath, index_file_name);
|
||||
} else {
|
||||
sprintf(fpath, "%s/%s", websrvparams.fpath, request->http_url);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1133,9 +1133,8 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/UICC/usim_interface.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/UICC/usim_interface.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/ocp-gtpu/gtp_itf.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg_sim.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/ue_process_nas.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg_sim.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msg.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/NR_UE/nr_nas_msgc \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/nas_itti_messaging.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/user_defs.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/UE/EMM/emm_proc.h \
|
||||
@@ -1584,7 +1583,6 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/userDef.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/COMMON/nr_common.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NAS/gNB/network_process_nas.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/UTILS/conversions.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/X2AP/x2ap_eNB_encoder.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/X2AP/x2ap_eNB_management_procedures.c \
|
||||
|
||||
@@ -59,8 +59,8 @@ This is the current status:
|
||||
* SA
|
||||
* Single cell per DU
|
||||
* Multiple DUs connected to one CU (both CP and UP)
|
||||
* Mobility between DUs connected to a single CU
|
||||
- Not supported:
|
||||
* Mobility
|
||||
* NSA
|
||||
|
||||
## F1-C
|
||||
|
||||
@@ -137,6 +137,7 @@ These modes of operation are supported:
|
||||
- evaluation of CQI report
|
||||
- MAC scheduling of SR reception
|
||||
- Support of up to 16 UEs (can be increased to 32)
|
||||
- Intra-frequency handover
|
||||
|
||||
## gNB RLC
|
||||
|
||||
@@ -221,6 +222,7 @@ These modes of operation are supported:
|
||||
- Interface with RRC
|
||||
- Interface with GTP-u (tunnel creation/handling for F1-U interface)
|
||||
- One CU(-CP) can handle multiple DUs
|
||||
- Support for intra-CU mobility (across DUs)
|
||||
|
||||
## gNB E1AP
|
||||
|
||||
|
||||
@@ -143,10 +143,13 @@ In the last lines:
|
||||
|
||||
# Configuration of the MAC
|
||||
|
||||
## Split-related options
|
||||
## Split-related options (running in a DU)
|
||||
|
||||
See [nFAPI documentation](../L2NFAPI.md) or [Aerial
|
||||
tutorial](../Aerial_FAPI_Split_Tutorial.md).
|
||||
tutorial](../Aerial_FAPI_Split_Tutorial.md) for information about the FAPI
|
||||
split.
|
||||
|
||||
See [F1 documentation](../F1-design.md) for information about the F1 split.
|
||||
|
||||
## MAC scheduler-related configuration options
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ There is some general information in the [OpenAirInterface Gitlab Wiki](https://
|
||||
- [How to run with E2 agent](../openair2/E2AP/README.md)
|
||||
- [How to run the physical simulators](./physical-simulators.md)
|
||||
- [How to setup OAI with Nvidia Aerial and Foxconn](./Aerial_FAPI_Split_Tutorial.md)
|
||||
- [How to do a handover](./handover-tutorial.md)
|
||||
|
||||
Legacy unmaintained files:
|
||||
- [`L2NFAPI_NOS1.md`](./L2NFAPI_NOS1.md), [`L2NFAPI_S1.md`](./L2NFAPI_S1.md):
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
block-beta
|
||||
columns 5
|
||||
space space DU0 space UE
|
||||
CU space space space space
|
||||
space space DU1 space pos["new pos"]
|
||||
CU<-- "F1" -->DU0
|
||||
CU<-- "F1" -->DU1
|
||||
DU0-- "Uu" -->UE
|
||||
UE-- "move" -->pos
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
@@ -0,0 +1,318 @@
|
||||
This document contains documentation for the 5G RRC layer, destined towards
|
||||
developers. It explains the basic working of the RRC, and various UE procedure
|
||||
schemes (connection, reestablishment, handover) including their interworking
|
||||
with other layers.
|
||||
|
||||
User documentation, such as general configuration options, are described in [a
|
||||
separate page](./rrc-usage.md).
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
# General
|
||||
|
||||
5G RRC is basically an ITTI message queue with associated handlers. It
|
||||
sequentially reads received ITTI messages and handles them through the function
|
||||
`rrc_gnb_task()` (constituing the thread entry point function). In this
|
||||
function, one can see three main groups of messages in a big switch statement:
|
||||
|
||||
- NGAP (messages starting with `NGAP_`)
|
||||
- F1AP (messages starting with `F1AP_`)
|
||||
- E1AP (messages starting with `E1AP_`)
|
||||
|
||||
For each message, a corresponding handler is called. The messages are roughly
|
||||
named according to the 3GPP specification messages, so it should already be
|
||||
possible to find the message in the switch based on a message name in the spec.
|
||||
|
||||
Note that RRC is inherently single-threaded, and processes messages in a FIFO
|
||||
order.
|
||||
|
||||
# Sequence Diagrams of UE procedures
|
||||
|
||||
The following section presents a number of common UE procedures for connection
|
||||
establishment&control, bearer establishment, etc. The intention is to help
|
||||
developers find specific functions within RRC in the context of these
|
||||
procedures. For more information on message handlers at F1 and E1 layers,
|
||||
please refer to the respective [F1 documentation](../F1AP/F1-design.md) and [E1
|
||||
documentation](../E1AP/E1-design.md).
|
||||
|
||||
For more information on these procedures, please also refer to 3GPP TS 38.401
|
||||
(NG-RAN Architecture Description) and O-RAN.WG5.C.1-v11 (NR C-plane profile).
|
||||
|
||||
A lot of the following diagrams would show an exchange between CU-CP, DU, and
|
||||
UE, in which the CU-CP forwards an "RRC Message" to the UE via an F1AP DL RRC
|
||||
Message Transfer through the DU, and correspondingly receives the "RRC Message
|
||||
Answer", as follows:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant du as DU
|
||||
participant cucp as CU-CP
|
||||
cucp->>du: F1AP DL RRC Msg Transfer (RRC Message)
|
||||
du->>ue: RRC Message
|
||||
ue->>du: RRC Message Answer
|
||||
du->>cucp: F1AP UL RRC Msg Transfer (RRC Message Answer)
|
||||
```
|
||||
|
||||
To better utilize horizontal space, these exchanges have been collapsed as
|
||||
follows, but should be read as the above exchange:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant du as DU
|
||||
participant cucp as CU-CP
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Message)
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Message Answer)
|
||||
```
|
||||
|
||||
## Initial connection setup/Registration
|
||||
|
||||
This sequence diagram shows the principal steps for an initial UE connection.
|
||||
This can either happen through a _Registration Request_ (e.g., UE connects
|
||||
"from flight mode"), or a _Service Request_ (i.e., UE connects after leaving
|
||||
coverage). Both requests are handled similarly by the gNB, and basically
|
||||
distinguish themselves, from the point of view of the gNB, by having PDU
|
||||
sessions in the NGAP Initial Context Setup Request present (Service Request) or
|
||||
not (Registration Request, with following PDU Session Resource Setup Request
|
||||
procedure).
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant du as DU
|
||||
participant cucp as CU-CP
|
||||
participant cuup as CU-UP
|
||||
participant amf as AMF
|
||||
|
||||
ue->>du: Msg1/Preamble
|
||||
du->>ue: Msg2/RAR
|
||||
ue->>cucp: F1AP Initial UL RRC Msg Tr (RRC Setup Req, in Msg3)
|
||||
Note over cucp: rrc_handle_RRCSetupRequest()
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Setup, in Msg4)
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Setup Complete)
|
||||
Note over cucp: rrc_handle_RRCSetupComplete()
|
||||
%% TODO: when is RRC connected?
|
||||
cucp->>amf: NGAP Initial UE Message (NAS Registration/Service Req)
|
||||
Note over amf,ue: NAS Authentication Procedure (see 24.501)
|
||||
Note over amf,ue: NAS Security Procedure (see 24.501)
|
||||
amf->>cucp: NGAP Initial Context Setup Req
|
||||
Note over cucp: rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ()
|
||||
Note over cucp: rrc_gNB_generate_SecurityModeCommand()
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Security Mode Command)
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Security Mode Complete)
|
||||
Note over cucp: rrc_gNB_decode_dcch() (inline)
|
||||
opt No UE Capabilities present
|
||||
Note over cucp: rrc_gNB_generate_UECapabilityEnquiry()
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC UE Capability Enquiry)
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC UE Capability Information)
|
||||
Note over cucp: handle_ueCapabilityInformation()
|
||||
end
|
||||
opt PDU Sessions in NGAP Initial Context Setup Req present
|
||||
Note over cucp: trigger_bearer_setup()
|
||||
cucp->>cuup: E1AP Bearer Context Setup Req
|
||||
cuup->>cucp: E1AP Bearer Context Setup Resp
|
||||
Note over cucp: rrc_gNB_process_e1_bearer_context_setup_resp()
|
||||
cucp->>du: F1AP UE Context Setup Req
|
||||
du->>cucp: F1AP UE Context Setup Resp
|
||||
Note over cucp: rrc_CU_process_ue_context_setup_response()
|
||||
Note over cucp: e1_send_bearer_updates()
|
||||
cucp->>cuup: E1AP Bearer Context Modification Req
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration)
|
||||
cuup->>cucp: E1AP Bearer Context Modification Resp
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete)
|
||||
Note over cucp: handle_rrcReconfigurationComplete()
|
||||
end
|
||||
Note over cucp: rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP()
|
||||
cucp->>amf: NGAP Initial Context Setup Resp (NAS Registration/Service Complete)
|
||||
```
|
||||
|
||||
Note that if no PDU session is present in the NGAP Initial UE Context Setup
|
||||
Req, no F1AP UE Context Setup will be observed during this initial phase.
|
||||
|
||||
If there is no PDU session set up during NGAP Initial Context Setup Req, the UE
|
||||
typically requests a PDU session(s) through a NAS procedure, which is basically
|
||||
the same code paths as the above optional PDU Session setup during an NGAP
|
||||
Initial Context Setup procedure:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant du as DU
|
||||
participant cucp as CU-CP
|
||||
participant cuup as CU-UP
|
||||
participant amf as AMF
|
||||
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC UL Information Transfer)
|
||||
cucp->>amf: NGAP UL NAS Transport (NAS PDU Session Establishment Req)
|
||||
amf->>cucp: NGAP PDU Session Resource Setup Req (NAS PDU Session Establishment Accept)
|
||||
Note over cucp: rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ()
|
||||
Note over cucp: trigger_bearer_setup()
|
||||
cucp->>cuup: E1AP Bearer Context Setup Req
|
||||
cuup->>cucp: E1AP Bearer Context Setup Resp
|
||||
Note over cucp: rrc_gNB_process_e1_bearer_context_setup_resp()
|
||||
cucp->>du: F1AP UE Context Setup Req
|
||||
du->>cucp: F1AP UE Context Setup Resp
|
||||
Note over cucp: rrc_CU_process_ue_context_setup_response()
|
||||
Note over cucp: e1_send_bearer_updates()
|
||||
cucp->>cuup: E1AP Bearer Context Modification Req
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration + NAS PDU Session Establishment Accept)
|
||||
cuup->>cucp: E1AP Bearer Context Modification Resp
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete)
|
||||
Note over cucp: handle_rrcReconfigurationComplete()
|
||||
Note over cucp: rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP()
|
||||
cucp->>amf: NGAP PDU Session Resource Setup Resp
|
||||
```
|
||||
|
||||
## Reestablishment
|
||||
|
||||
The following sequence diagram shows the principal steps during a
|
||||
reestablishment request. When handling the RRC Reestablishment Request at the
|
||||
CU-CP, it notably checks if this UE is already known, if the UE is still at the
|
||||
same DU as it used to be previously (might change because of, or despite
|
||||
handover), and other validation checks. If all checks pass, the CU-CP continues
|
||||
with the reestablishment procedure; if any check fails, the CU-CP tries to
|
||||
release the old UE at the AMF, and continues with the "normal" connection setup
|
||||
(registration/service request) described above.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant du as DU
|
||||
participant cucp as CU-CP
|
||||
participant cuup as CU-UP
|
||||
participant amf as AMF
|
||||
|
||||
ue->>du: Msg1/Preamble
|
||||
du->>ue: Msg2/RAR
|
||||
ue->>du: Msg3 w/ RRC Reestabishment Request (old C-RNTI/PCI)
|
||||
Note over du: DU creates UE context for new RNTI
|
||||
du->>cucp: F1AP Initial UL RRC Msg Tr (RRC Reestab Req, in Msg3)
|
||||
Note over cucp: rrc_handle_RRCReestablishmentRequest()
|
||||
alt UE known and at the original DU
|
||||
Note over cucp: rrc_gNB_generate_RRCReestablishment()<br />SRB1 PDCP reestablishment
|
||||
cucp->>du: F1AP DL RRC Msg Tr (old gNB-DU-UE ID)
|
||||
Note over du: Reuse configuration of and delete old UE<br />(in dl_rrc_message_transfer())
|
||||
du->>ue: RRC Reestablishment
|
||||
ue->>du: RRC Reestablishment Complete
|
||||
du->>cucp: F1AP UL RRC Msg Tr (RRC Reestab Complete)
|
||||
Note over cucp: handle_rrcReestablishmentComplete()
|
||||
Note over cucp: cuup_notify_reestablishment()
|
||||
cucp->>cuup: E1AP Bearer Context Modification Req
|
||||
cucp->>ue: F1AP DL RRC Msg Transfer (RRC Reconfiguration)
|
||||
cuup->>cucp: E1AP Bearer Context Modification Resp
|
||||
ue->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete)
|
||||
Note over cucp: handle_rrcReestablishmentComplete()
|
||||
else Fallback*
|
||||
cucp->>amf: NGAP UE Context Release Request
|
||||
Note over cucp: rrc_gNB_generate_RRCSetup()
|
||||
Note over ue,amf: Continue with connection setup (registration/service request)
|
||||
end
|
||||
```
|
||||
|
||||
## Handover
|
||||
|
||||
The basic handover (HO) structure is as follows. In order to support various
|
||||
handover "message passing implementation" (F1AP, NGAP, XnAP), RRC employs
|
||||
callbacks to signal HO Accept (`ho_req_ack()`), HO Success (`ho_success()`),
|
||||
and HO Cancel (`ho_cancel()`). These can be used to trigger the corresponding
|
||||
functionality based on mentioned "message passing implementation".
|
||||
|
||||
The following sequence diagram shows the basic functional execution of a
|
||||
successful handover in the case of an F1 handover. Note the callbacks as
|
||||
mentioned above:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ue as UE
|
||||
participant sdu as source DU
|
||||
participant tdu as target DU
|
||||
participant cucp as CU-CP
|
||||
participant cuup as CU-UP
|
||||
|
||||
Note over ue,sdu: UE active on source DU
|
||||
alt HO triggered through A3 event
|
||||
ue->>sdu: RRC Measurement Report
|
||||
sdu->>cucp: F1AP UL RRC Msg Transfer (RRC Measurement Report)
|
||||
Note over cucp: Handover decision (A3 event trigger)
|
||||
else Manual Trigger
|
||||
Note over cucp: Handover decision (e.g., telnet)
|
||||
end
|
||||
Note over cucp: nr_rrc_trigger_f1_ho() ("on source CU")
|
||||
Note over cucp: nr_initiate_handover() ("on target CU")
|
||||
cucp->>tdu: F1AP UE Context Setup Req
|
||||
Note over tdu: Create UE context
|
||||
tdu->>cucp: F1AP UE Context Setup Resp (incl. CellGroupConfig)
|
||||
Note over cucp: rrc_CU_process_ue_context_setup_response() ("on target CU")
|
||||
Note over cucp: cuup_notify_reestablishment()
|
||||
cucp->>cuup: E1AP Bearer Context Modification Req
|
||||
cucp-->>cucp: callback: ho_req_ack()
|
||||
Note over cucp: nr_rrc_f1_ho_acknowledge() ("on source CU")
|
||||
cucp->>sdu: F1AP Context Modification Req (RRC Reconfiguration)
|
||||
cuup->>cucp: E1AP Bearer Context Modification Resp
|
||||
sdu->>ue: RRC Reconfiguration
|
||||
sdu->>cucp: F1AP Context Modification Resp
|
||||
Note over sdu: Stop scheduling UE
|
||||
Note over ue: Resync
|
||||
Note over ue,tdu: RA (Msg1 + Msg2)
|
||||
ue->>tdu: RRC Reconfiguration Complete
|
||||
tdu->>cucp: F1AP UL RRC Msg Transfer (RRC Reconfiguration Complete)
|
||||
Note over cucp: handle_rrcReconfigurationComplete() ("on target CU")
|
||||
cucp-->>cucp: callback: ho_success()
|
||||
Note over cucp: nr_rrc_f1_ho_complete() ("on source CU")
|
||||
cucp->>sdu: F1AP UE Context Release Command
|
||||
sdu->>cucp: F1AP UE Context Release Complete
|
||||
Note over ue,tdu: UE active on target DU
|
||||
```
|
||||
|
||||
# Structures
|
||||
|
||||
## Cells
|
||||
|
||||
OAI 5G RRC does not actually handle multiple cells as of now, but multiple DUs,
|
||||
each being limited to one cell.
|
||||
|
||||
Cell-related data is stored in `nr_rrc_du_container_t`, and kept in a tree
|
||||
indexed by the SCTP association ID.
|
||||
|
||||
## CU-UPs
|
||||
|
||||
CU-UP information is stored in `nr_rrc_cuup_container_t`, and kept in a tree
|
||||
indexed by the SCTP association ID.
|
||||
|
||||
## Transactions
|
||||
|
||||
The RRC keeps track of ongoing transaction (RRC procedures) through a per-UE
|
||||
array `xids`, which is indexed with a transaction ID `xid` in `[0,3]` to keep
|
||||
track of ongoing transactions. Upon RRC Reconfiguration Complete, these IDs are
|
||||
deleted.
|
||||
|
||||
Note that while 38.331 requires only one RRC transaction to happen at a time,
|
||||
the 5G RRC does not actually ensure this; it only tries to prevent it by
|
||||
chaining of transactions and some checks. For instance, the Security Mode
|
||||
procedure is followed by a UE capability procedure, and some procedures are not
|
||||
executed if others are ongoing (ex.: handover if there is reconfiguratio).
|
||||
However, it might be possible to trigger a procedure while another is ongoing.
|
||||
|
||||
As of now, no queueing mechanims exists to ensure only one operation is
|
||||
ongoing, which would likely also simplify the code.
|
||||
|
||||
## Handover
|
||||
|
||||
Handover-related data is stored in a per-UE structure of type
|
||||
`nr_handover_context_t`. It is a pointer and only set during handover
|
||||
operation. This data structure has in turn two pointers, one to the source CU
|
||||
(`nr_ho_source_cu_t`), and one to the target CU (`nr_ho_target_cu_t`). In F1,
|
||||
both are present. In N2 and Xn, only one pointer is supposed to be set a the
|
||||
corresponding CU.
|
||||
|
||||
`nr_ho_source_cu_t` contains notably a function pointer `ho_cancel` for
|
||||
handover cancel. `nr_ho_target_cu_t` contains function pointers `ho_req_ack`
|
||||
for handover request acknowledge and `ho_success` for handover success. As can
|
||||
be seen in the sequence diagram above, either the "target CU" or "source CU"
|
||||
needs to do an operation, and a "switch" from target to source CU is done using
|
||||
these function pointers. For instance, in F1, the handover request acknowledge
|
||||
function pointers merely calls another (RRC) function which triggers a
|
||||
reconfiguration. In the case of N2, the handover request acknowledge function
|
||||
pointer should trigger the NGAP Handover Request Acknowledge, and the handover
|
||||
success function pointer should trigger the NGAP Handover Success message.
|
||||
@@ -0,0 +1,99 @@
|
||||
This document describes the basic functioning of the 5G RRC layer, describes
|
||||
the periodic output, and explains the various configuration options that
|
||||
influence its behavior.
|
||||
|
||||
Developer documentation, such as UE connection control flow, reestablishment, or handover, are described in [a separate page](./rrc-dev.md).
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
# General
|
||||
|
||||
The RRC layer controls the basic connection setup of UEs as well as additional
|
||||
procedures. It is the fundamental building block of OAI's CU-CP, and interacts
|
||||
with lower layers (DU, basically MAC and RLC) through F1AP messages, and with
|
||||
the CU-UP through E1AP messages. More information can be found in the
|
||||
respective [F1AP page](../F1-design.md) and [E1AP page](../E1AP/E1-design.md).
|
||||
|
||||
# Periodic output and interpretation
|
||||
|
||||
Similarly to the scheduler, the RRC periodically prints information about
|
||||
connected UEs and DUs into file `nrRRC_stats.log` in the current working
|
||||
directory of the executable running the RRC (typically, `nr-softmodem`). The
|
||||
output lists first all UEs that are currently connected, and then all DUs, in
|
||||
order.
|
||||
|
||||
For each UE, it prints:
|
||||
|
||||
```
|
||||
UE 0 CU UE ID 1 DU UE ID 40352 RNTI 9da0 random identity c0f1ac9824000000:
|
||||
last RRC activity: 5 seconds ago
|
||||
PDU session 0 ID 10 status established
|
||||
associated DU: DU assoc ID 8
|
||||
```
|
||||
|
||||
where `UE 0` is the UE index, CU UE ID and DU UE IDs are the IDs used to
|
||||
exchange over F1 (cf. scheduler logs). Further, it shows RNTI, when the last
|
||||
RRC activity happened, the status of PDU sessions and which DU is associated
|
||||
(through the SCTP association ID).
|
||||
|
||||
|
||||
For each DU, it prints:
|
||||
|
||||
```
|
||||
1 connected DUs
|
||||
[1] DU ID 3584 (gNB-OAI-DU) assoc_id 8: nrCellID 12345678, PCI 0, SSB ARFCN 641280
|
||||
TDD: band 78 ARFCN 640008 SCS 30 (kHz) PRB 106
|
||||
```
|
||||
|
||||
i.e., an index (`[1]`), the DU ID and it's name, the SCTP association ID
|
||||
(`assoc_id 8`, cf. UE information), and DU specific information for the cell
|
||||
(cell ID, physical cell identity/PCI, the SSB frequency in ARFCN notation, the
|
||||
band and Point A ARFCN, subcarrier spacing/SCS, and the number of resource
|
||||
blocks/PRB). Only one cell per DU is supported.
|
||||
|
||||
As of now, it does not print information about connected CU-UPs or AMFs.
|
||||
|
||||
# Configuration of the RRC
|
||||
|
||||
## Split-related options (when running in a CU or CU-CP)
|
||||
|
||||
See [F1 documentation](../F1-design.md) for information about the F1 split.
|
||||
See [E1 documentation](../E1AP/E1-design.md) for information about the E1 split.
|
||||
|
||||
## RRC-specific configuration options
|
||||
|
||||
In the `gNBs` section of the gNB/CU/CU-CP configuration file is the
|
||||
RRC-specific configuration
|
||||
|
||||
### cell-specific options
|
||||
|
||||
- `gNB_ID` and `gNB_name`: ID and name of the gNB
|
||||
- `tracking_area_code`: the current tracking area code in the range `[0x0001,
|
||||
0xfffd]`
|
||||
- `plmn`: the PLMN, which is a list of entries consisting of:
|
||||
- `mcc`: mobile country code
|
||||
- `mnc`: mobile network code
|
||||
- `mnc_length`: length of mobile network code, allowed values: 2, 3
|
||||
- `snssaiList`: list of NSSAI (network selection slice assistence
|
||||
information, "slice ID"), which itself consists in
|
||||
- `sst`: slice service type, in `[1,255]`
|
||||
- `sd` (default `0xffffff`): slice differentiator, in `[0,0xffffff]`,
|
||||
`0xffffff` is a reserved value and means "no SD"
|
||||
Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD
|
||||
is "mMTC"
|
||||
- `enable_sdap` (default: false): enable the use of the SDAP layer. If
|
||||
deactivated, a transparent SDAP header is prepended to packets, but no
|
||||
further processing is being done.
|
||||
|
||||
### UE-specific configuration
|
||||
|
||||
- `um_on_default_drb` (default: false): use RLC UM instead of RLC AM on default
|
||||
bearers
|
||||
- `drbs` (default: 0): the number of DRBs to allocate for a UE, only useful for
|
||||
do-ra or phy-test testing
|
||||
|
||||
### Neighbor-gNB configuration
|
||||
|
||||
TBD
|
||||
|
||||
Refer to the [handover tutorial](../handover-tutorial.md) for more information.
|
||||
@@ -0,0 +1,329 @@
|
||||
This tutorial explains how to perform handovers. For the moment, only F1
|
||||
handovers are supported.
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
# Considered setup for F1 handover
|
||||
|
||||
We consider one CU and two DUs, connected over F1. The UE is initially
|
||||
connected over the radio interface ("Uu") to DU0. Via movement to a new
|
||||
position ("new pos"), it will trigger an event such that the CU triggers a
|
||||
handover of the UE from DU0 to DU1. Alternatively, a manual trigger can do the
|
||||
same.
|
||||
|
||||

|
||||
|
||||
# Steps to run F1 handover with OAI UE
|
||||
|
||||
Measurement reporting and processing of RRC Reconfiguration for Mobility are
|
||||
not completed at the UE. Nevertheless, it is possible to make simple handover
|
||||
tests without any radio setup, on a single PC, with the OAI UE, in RFsimulator.
|
||||
|
||||
## Build with telnet support
|
||||
|
||||
Since the UE does not support any measurement reporting, it cannot trigger a
|
||||
handover on its own; it has to be triggered manually through telnet. Thus,
|
||||
build both gNB and UE as well as activate the build of telnet to that purpose:
|
||||
|
||||
./build_oai --ninja --nrUE --gNB --build-lib telnetsrv
|
||||
|
||||
## Run the setup
|
||||
|
||||
This tutorial assumes you have a core network running; [refer to the
|
||||
corresponding tutorial](./NR_SA_Tutorial_OAI_CN5G.md) if this is not the case
|
||||
yet.
|
||||
|
||||
We will use the TDD configuration files in the repository for the
|
||||
[CU](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf) as well for
|
||||
[DU0](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf)
|
||||
and
|
||||
[DU1](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf).
|
||||
Note how the DUs differ in their DU ID (for identification at the CU), nr
|
||||
cellid (global identification), physical cell ID (identification through UE),
|
||||
frequency (limitation at OAI UE), and IP address.
|
||||
|
||||
Make sure that using RFsimulator and the CU and each DU, you can achieve a full
|
||||
connection of the UE (independently, i.e., running one DU a time). Once this is
|
||||
done, follow below steps to trigger a handover:
|
||||
|
||||
Start the CU including telnet support:
|
||||
|
||||
sudo ./nr-softmodem --sa -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf --telnetsrv --telnetsrv.shrmod ci
|
||||
|
||||
Start DU0:
|
||||
|
||||
sudo ./nr-softmodem --sa --rfsim -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf --rfsimulator.serveraddr 127.0.0.1
|
||||
|
||||
Start the UE, and let it connect completely:
|
||||
|
||||
sudo ./nr-uesoftmodem --sa -C 3450720000 -r 106 --numerology 1 --ssb 516 -O <config> --rfsim --rfsimulator.serveraddr server
|
||||
|
||||
Note how the RFsimulator roles have been switched, and RFsim server is at the
|
||||
UE side; _this is important_. Replace `<config>` with the UE configuration
|
||||
matching your core. If you followed the CN and oaiUE tutorials, you can remove
|
||||
`-O <config>` and replace it with `--uicc0.imsi 001010000000001`.
|
||||
|
||||
Once the UE is connected, start DU1:
|
||||
|
||||
sudo ./nr-softmodem --sa --rfsim -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci1.conf --rfsimulator.serveraddr 127.0.0.1
|
||||
|
||||
Once DU1 is online, you can trigger a handover by issuing this command
|
||||
|
||||
echo ci trigger_f1_ho | nc 127.0.0.1 9090 && echo
|
||||
|
||||
You should see how the UE switches from one DU to another. See additional
|
||||
information further below.
|
||||
|
||||
A number of remarks:
|
||||
|
||||
1. It is important that you start DU0, UE, DU1 in order, and having UE connect
|
||||
to DU0 before starting DU1. This is because we don't employ any channel
|
||||
emulation, and the UE could not decode the SIB1 of DU0 to connect.
|
||||
1. The RFsimulator roles are switched. Typically, the gNB RFsim acts as the
|
||||
server and the UE as a client. However, RFsim is limited to one server with
|
||||
multiple clients. Since the UE should be able to connect to both DUs, it has
|
||||
to act as the server, and both DUs are a client.
|
||||
1. If you see errors `could not open a socket` and/or `Could not start the RF
|
||||
device`, this means that RFsim could not be started. Handover will not work;
|
||||
please refer to the preceding point to fix this (i.e., run the UE as the
|
||||
RFsim server).
|
||||
1. In some cases, if the RFsim server is at the UE, the whole system can block;
|
||||
in this case, stop UE and all DUs and restart (the CU can keep running).
|
||||
|
||||
## Additional information to the manual HO trigger
|
||||
|
||||
You can trigger the handover manually by logging in through telnet:
|
||||
|
||||
telnet 127.0.0.1 9090
|
||||
|
||||
and then manually typing `ci trigger_f1_ho`.
|
||||
|
||||
The command using `nc` (`netcat`) above triggers handovers directly from bash.
|
||||
It does the same as logging in through telnet otherwise, and is a shorthand.
|
||||
|
||||
The full command is
|
||||
|
||||
ci trigger_f1_ho [cu-ue-id]
|
||||
|
||||
`cu-ue-id` is optional. If only one UE context is present in the RRC, it will
|
||||
trigger the handover for this UE in a round-robin fashion across all DUs. If
|
||||
there is only one DU, the handover request will be rejected. Similarly, if
|
||||
there are multiple UE contexts present at RRC, the handover will be rejected,
|
||||
and you have to manually type the CU UE ID. You can see a list of all UEs in
|
||||
the file `nrRRC_stats.log` that is printed periodically in the working
|
||||
directory of the CU.
|
||||
|
||||
# Steps to run F1 handover with COTS UE
|
||||
|
||||
You can do handover across DUs with a COTS UE. Note that these DUs should be
|
||||
separated by at least multiple meters to ensure that the UE will receive
|
||||
different signal strengths when moving between cells.
|
||||
|
||||
We only support intra-frequency handovers yet. We have verified with USRPs
|
||||
only, although other radios should work as well.
|
||||
|
||||
For UEs, we verified Quectel modules and iPhones. Note, though, that not all
|
||||
phones might work; for instance, we did not achieve handovers with a OnePlus
|
||||
Nord, yet.
|
||||
|
||||
## Steps
|
||||
|
||||
First, make sure that you can run both DUs with the CU independently. Use the
|
||||
same radio hardware for both radios to ensure that both cells can be received
|
||||
equally good by the UE.
|
||||
|
||||
In order to enable handovers (triggered by the UE), you have to configure the
|
||||
neighbour relation of the DUs at the CU. To do so, proceed as follows:
|
||||
|
||||
1. To simplify filling the right values in the neighbour configuration, you can
|
||||
rely on the information the CU has about both DUs. Start the CU and both
|
||||
DUs. Navigate to the directory from which you started the CU, and print RRC
|
||||
statistics:
|
||||
```
|
||||
cat nrRRC_stats.log
|
||||
```
|
||||
1. Fill in the `neighbour-config.conf` configuration file as shown below, and
|
||||
`@include` it in the CU file.
|
||||
1. Start the CU and both DUs.
|
||||
1. Bring the phone close to one cell, and leave flight mode. It should connect
|
||||
to the DU to which it is closer.
|
||||
1. Move the UE towards the other DU; it should trigger an "A3 event" (Neighbour
|
||||
Becomes Better than Serving), and the CU will trigger the handover to the
|
||||
other DU.
|
||||
|
||||
The output on the terminal should be the same as with RFsim. If no handover is
|
||||
triggered:
|
||||
|
||||
- Make sure that both DUs use the same hardware.
|
||||
- Make sure that the UE sees both cells. For instance, you can switch to flight
|
||||
mode, go closer to the other DU, and switch off flight mode -- the UE should
|
||||
connect to that second UE.
|
||||
- We did not manage handover with every phone yet -- make sure you use one of
|
||||
the list provided above.
|
||||
|
||||
You can also force a handover through telnet as described above. (In fact, the
|
||||
decision about a handover is always at the network-side, the UE only "assists"
|
||||
through measurements telling the CU that one DU is stronger than others.
|
||||
Hence, "forcing" a handover just means that you manually trigger the handover,
|
||||
instead of waiting for UE measurement report.)
|
||||
|
||||
## Example neighbour configuration
|
||||
|
||||
Below is an example neighbour configuration. It is based on this DU information
|
||||
gathered from `nrRRC_stats.log` at the CU:
|
||||
|
||||
```
|
||||
[1] DU ID 3585 (gNB-in-docker) assoc_id 4161: nrCellID 11111111, PCI 1, SSB ARFCN 643296
|
||||
TDD: band 78 ARFCN 642024 SCS 30 (kHz) PRB 106
|
||||
[2] DU ID 3584 (gNB-in-docker) assoc_id 4163: nrCellID 12345678, PCI 0, SSB ARFCN 643296
|
||||
TDD: band 78 ARFCN 642024 SCS 30 (kHz) PRB 106
|
||||
```
|
||||
|
||||
Note how both DUs have one cell on the same frequency and the same radio
|
||||
configuration. From this, fill the neighbour list as shown below.
|
||||
|
||||
Concretely, the first cell is `12345678` (on DU `[2]`), and it has `11111111`
|
||||
(on DU `[1]`) as its neighbour; hence in the first block, you fill
|
||||
`physical_cellId` and other values for DU `[1]`, and vice versa.
|
||||
|
||||
The below configuration further enables periodic measurements, A2 event
|
||||
("Serving becomes worse than threshold"), and A3 events ("Neighbour Becomes
|
||||
Better than Serving"). The A2 event can be disabled by setting `enable = 0`. A3
|
||||
events cannot be disabled as of now. Further, the A3 events can be made
|
||||
specific to cells; `cell_id = -1` means "any cell".
|
||||
|
||||
```
|
||||
neighbour_list = (
|
||||
{
|
||||
nr_cellid = 12345678;
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe01;
|
||||
nr_cellid = 11111111;
|
||||
physical_cellId = 1;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; #30 KHz
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
nr_cellid = 11111111;
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe00;
|
||||
nr_cellid = 12345678;
|
||||
physical_cellId = 0;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; #30 KHz
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2};
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
nr_measurement_configuration = {
|
||||
Periodical = {
|
||||
enable = 1;
|
||||
includeBeamMeasurements = 1;
|
||||
maxNrofRS_IndexesToReport = 4;
|
||||
};
|
||||
|
||||
A2 = {
|
||||
enable = 1;
|
||||
threshold = 60;
|
||||
timeToTrigger = 1;
|
||||
};
|
||||
|
||||
A3 = ({
|
||||
cell_id = -1; #Default
|
||||
offset = 10;
|
||||
hysteresis = 0;
|
||||
timeToTrigger = 1
|
||||
})
|
||||
};
|
||||
```
|
||||
|
||||
# Handovers triggers and NTN
|
||||
|
||||
Typically, in terrestrial networks, channel measurements as well as criteria
|
||||
such as load in base stations, is used to determine when and where to handover
|
||||
a UE.
|
||||
|
||||
## NTN
|
||||
|
||||
Doppler spreading and time selectivity of the channel are already a challenge
|
||||
for conventional terrestrial networks. However, in the context of
|
||||
non-terrestrial networks (NTN), and low-earth orbit (LEO) systems, the
|
||||
satellites can have speeds up 7.56 km/s, which is much faster than 0.14 km/s of
|
||||
a high-speed train in terrestrial networks. Also, the delays in LEO are more varied
|
||||
and longer, and the path loss is larger, because the communication distances is up
|
||||
to 10 times longer than in terrestrial networks. Moreover, downlink in LEO
|
||||
presents a high interference from adjacent satellite beams, and all these
|
||||
features contribute to reduced received signal strength variation in these
|
||||
networks compared to terrestrial networks. Typically, the criteria used in
|
||||
algorithms presented in conventional terrestrial networks to trigger a handover
|
||||
from a gNB to another one is based on signal strength measurements (cf., A3
|
||||
event above). However, the reduced received signal strength variation in NTNs
|
||||
make these algorithms inefficient for LEO systems. Therefore, algorithms with
|
||||
criteria for handover triggering that address the specifics of LEO systems are
|
||||
crucial for an efficient handover processing that ensures a robust
|
||||
communication with low dropping probability. Some criteria for handovers in NTN
|
||||
are as follows:
|
||||
|
||||
- **Measurement-based triggering**: This method is based on signal strength
|
||||
measurement, and as stated above, it may not be efficient. The triggering
|
||||
thresholds and which measurement events to use as triggers, as reference
|
||||
signal received power (RSRP), reference signal received quality (RSRQ), or
|
||||
received signal strength indicator (RSSI), should be configured. This method
|
||||
relies on UE estimates and established channel estimation techniques, however
|
||||
it would require neighbouring cell lists which can be hard because the
|
||||
fast-moving of satellites leads to a fast cell coverage deviation.
|
||||
|
||||
- **Location-based triggering**: This method is based on UE and satellite
|
||||
location, which can be applied jointly (or not) with another trigger as the
|
||||
measurement-based trigger. For instance, for a deterministic satellite
|
||||
movement, it is possible to predict the configure triggering condition, and
|
||||
the initial association of the UE can be performed based on the distance with
|
||||
the nearest satellite, because we can know the location of the UE and NTN
|
||||
satellite to compute the distance.
|
||||
|
||||
- **Elevation angles of source and target cells based triggering**: This method
|
||||
is similar to the previous one, but it is based on the largest elevation
|
||||
angle.
|
||||
|
||||
- **Time/timer-based triggering**: This method uses triggering conditions based
|
||||
on UTC time or a timer-based solution, which can also be applied jointly (or
|
||||
not) with another trigger as the measurement-based trigger. The timer-based
|
||||
handover trigger considers the deterministic satellite movement to predict
|
||||
the time duration for which the satellite’s footprint covers a certain zone.
|
||||
|
||||
- **Timing advance value-based triggering**: This method uses the timing
|
||||
advance value (independently or jointly with another trigger) to trigger a
|
||||
handover to the target cell. It is appropriate to overcome the Random-Access
|
||||
preamble reception issue, where the UE needs to pre-compensate the instant
|
||||
which sends the preamble. However, UEs with GNSS support are required to
|
||||
perform this method.
|
||||
|
||||
## Simple location/time-based trigger
|
||||
|
||||
A location-based handover trigger, somewhat aligned with 3GPP Rel.17, taking
|
||||
advantage of deterministic satellite movement, can be implemented whereby it is
|
||||
assumed that the locations of the UE and the NTN satellite are known. From a
|
||||
practical point of view, this means that we know how long it takes to perform
|
||||
the handover, and therefore we only need to implement a timer.
|
||||
|
||||
It is possible to modify the source code to trigger a time-based handover, or
|
||||
combine with other methods. If all what is required is a trigger every 15
|
||||
seconds, you can also resort to the telnet-based handover trigger above, and
|
||||
run in a terminal:
|
||||
|
||||
```bash
|
||||
while true; do
|
||||
echo ci trigger_f1_ho | nc -N 127.0.0.1 9090 && echo
|
||||
sleep 15
|
||||
done
|
||||
```
|
||||
+17
-2
@@ -38,6 +38,7 @@
|
||||
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
||||
#include "openair1/PHY/TOOLS/phy_scope_interface.h"
|
||||
#include "PHY/MODULATION/nr_modulation.h"
|
||||
|
||||
/*
|
||||
* NR SLOT PROCESSING SEQUENCE
|
||||
@@ -604,9 +605,23 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE, const UE_nr_rxtx_proc_t *proc
|
||||
|
||||
// Start synchronization with a target gNB
|
||||
if (UE->synch_request.received_synch_request == 1) {
|
||||
fapi_nr_synch_request_t *synch_req = &UE->synch_request.synch_req;
|
||||
UE->is_synchronized = 0;
|
||||
UE->UE_scan_carrier = UE->synch_request.synch_req.ssb_bw_scan;
|
||||
UE->target_Nid_cell = UE->synch_request.synch_req.target_Nid_cell;
|
||||
UE->UE_scan_carrier = synch_req->ssb_bw_scan;
|
||||
UE->target_Nid_cell = synch_req->target_Nid_cell;
|
||||
|
||||
uint64_t dl_bw = (12 * fp->N_RB_DL) * (15000 << fp->numerology_index);
|
||||
uint64_t dl_CarrierFreq = (dl_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.dl_frequency * 1000;
|
||||
uint64_t ul_bw = (12 * fp->N_RB_UL) * (15000 << fp->numerology_index);
|
||||
uint64_t ul_CarrierFreq = (ul_bw >> 1) + (uint64_t)UE->nrUE_config.carrier_config.uplink_frequency * 1000;
|
||||
if (dl_CarrierFreq != fp->dl_CarrierFreq || ul_CarrierFreq != fp->ul_CarrierFreq) {
|
||||
fp->dl_CarrierFreq = dl_CarrierFreq;
|
||||
fp->ul_CarrierFreq = ul_CarrierFreq;
|
||||
nr_rf_card_config_freq(&openair0_cfg[UE->rf_map.card], ul_CarrierFreq, dl_CarrierFreq, 0);
|
||||
UE->rfdevice.trx_set_freq_func(&UE->rfdevice, &openair0_cfg[0]);
|
||||
init_symbol_rotation(fp);
|
||||
}
|
||||
|
||||
clean_UE_harq(UE);
|
||||
UE->synch_request.received_synch_request = 0;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ unsigned short config_frames[4] = {2,9,11,13};
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "executables/thread-common.h"
|
||||
|
||||
#include "nr_nas_msg_sim.h"
|
||||
#include "nr_nas_msg.h"
|
||||
#include <openair1/PHY/MODULATION/nr_modulation.h>
|
||||
#include "openair2/GNB_APP/gnb_paramdef.h"
|
||||
|
||||
@@ -335,7 +335,7 @@ static void trigger_stop(int sig)
|
||||
static void trigger_deregistration(int sig)
|
||||
{
|
||||
if (!stop_immediately) {
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_RRC_UE_SIM, 0, NAS_DEREGISTRATION_REQ);
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, 0, NAS_DEREGISTRATION_REQ);
|
||||
NAS_DEREGISTRATION_REQ(msg).cause = AS_DETACH;
|
||||
itti_send_msg_to_task(TASK_NAS_NRUE, 0, msg);
|
||||
stop_immediately = true;
|
||||
|
||||
@@ -340,7 +340,7 @@ int test_viterbi(uint8_t dabflag)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
char c;
|
||||
int c;
|
||||
uint8_t dabflag=0;
|
||||
|
||||
while ((c = getopt (argc, argv, "d")) != -1) {
|
||||
|
||||
@@ -250,8 +250,8 @@ void nr_generate_pdsch(processingData_L1tx_t *msgTx, int frame, int slot)
|
||||
NR_DL_FRAME_PARMS *fp = &gNB->frame_parms;
|
||||
const uint32_t *gold =
|
||||
nr_gold_pdsch(fp->N_RB_DL, fp->symbols_per_slot, rel15->dlDmrsScramblingId, rel15->SCID, slot, l_symbol);
|
||||
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER,
|
||||
(int16_t *)mod_dmrs); // Qm = 2 as DMRS is QPSK modulated
|
||||
// Qm = 2 as DMRS is QPSK modulated
|
||||
nr_modulation(gold, n_dmrs * DMRS_MOD_ORDER, DMRS_MOD_ORDER, (int16_t *)mod_dmrs);
|
||||
|
||||
#ifdef DEBUG_DLSCH
|
||||
printf("DMRS modulation (symbol %d, %d symbols, type %d):\n", l_symbol, n_dmrs, dmrs_Type);
|
||||
|
||||
@@ -567,7 +567,7 @@ void help (void)
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
|
||||
char c,smbv_ip[16],smbv_fname[256];
|
||||
char smbv_ip[16], smbv_fname[256];
|
||||
extern char *optarg;
|
||||
int i;
|
||||
|
||||
@@ -575,6 +575,7 @@ int main(int argc,char **argv)
|
||||
strcpy(smbv_ip,DEFAULT_SMBV_IP);
|
||||
strcpy(smbv_fname,DEFAULT_SMBV_FNAME);
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "hW:")) != -1) {
|
||||
switch (c) {
|
||||
case 'W':
|
||||
|
||||
@@ -461,9 +461,6 @@ void lte_param_init( unsigned char transmission_mode,
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
char c;
|
||||
|
||||
int i,l,aa,aarx,sector;
|
||||
|
||||
unsigned char pbch_pdu[6];
|
||||
@@ -504,6 +501,7 @@ int main(int argc, char **argv)
|
||||
logInit();
|
||||
g_log->log_component[PHY].level = LOG_DEBUG;
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "hpFb:n:m:x:N:R:")) != -1) {
|
||||
switch (c) {
|
||||
case 'n':
|
||||
|
||||
@@ -57,7 +57,6 @@ int32_t dummy3[2048*14];
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,l,aa;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1;
|
||||
uint8_t snr1set=0;
|
||||
@@ -104,6 +103,7 @@ int main(int argc, char **argv) {
|
||||
logInit();
|
||||
number_of_cards = 1;
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:N:F:GR:O:dP:")) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
|
||||
@@ -374,7 +374,6 @@ DCI_PDU *get_dci(LTE_DL_FRAME_PARMS *lte_frame_parms,uint8_t log2L, uint8_t log2
|
||||
extern int QPSK[4],QPSK2[4];
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,l,aa;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1;
|
||||
int **txdata;
|
||||
@@ -425,6 +424,7 @@ int main(int argc, char **argv) {
|
||||
cpuf = get_cpu_freq_GHz();
|
||||
logInit();
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "hapFg:R:c:n:s:x:y:z:L:M:N:I:f:i:S:P:Y")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
|
||||
@@ -45,7 +45,6 @@ double cpuf;
|
||||
void dump_prach_config(LTE_DL_FRAME_PARMS *frame_parms,uint8_t subframe);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,aa,aarx;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1=0.0,ue_speed0=0.0,ue_speed1=0.0;
|
||||
uint8_t snr1set=0;
|
||||
@@ -85,6 +84,7 @@ int main(int argc, char **argv) {
|
||||
logInit();
|
||||
number_of_cards = 1;
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "hHaA:Cr:p:g:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
|
||||
@@ -45,7 +45,6 @@ PHY_VARS_UE *UE;
|
||||
double cpuf;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,l,aa;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1=0.0;
|
||||
uint8_t snr1set=0;
|
||||
@@ -88,6 +87,7 @@ int main(int argc, char **argv) {
|
||||
number_of_cards = 1;
|
||||
cpuf = get_cpu_freq_GHz();
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "har:pf:g:n:s:S:x:y:z:N:F:T:R:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
|
||||
@@ -57,7 +57,6 @@ mod_sym_t dummy3[2048*14];
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,l,aa;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=-2.0,snr1;
|
||||
uint8_t snr1set=0;
|
||||
@@ -103,6 +102,7 @@ int main(int argc, char **argv) {
|
||||
number_of_cards = 1;
|
||||
openair_daq_vars.rx_rf_mode = 1;
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "f:hpf:g:n:s:S:t:x:y:z:N:F:GdP:")) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
|
||||
@@ -304,7 +304,6 @@ void lte_param_init(unsigned char N_tx, unsigned char N_rx,unsigned char transmi
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char c;
|
||||
int i,iout,l,aa,aarx;
|
||||
double sigma2, sigma2_dB=0,SNR,snr0=10.0,snr1=11.0;
|
||||
uint8_t snr1set=0;
|
||||
@@ -377,6 +376,7 @@ int main(int argc, char **argv) {
|
||||
rxdata[0] = (int *)malloc16(FRAME_LENGTH_BYTES);
|
||||
rxdata[1] = (int *)malloc16(FRAME_LENGTH_BYTES);
|
||||
*/
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "aehc:f:g:i:j:n:r:s:t:x:y:z:A:F:N:O:R:S:ZYDT:C:G:dB:U:u")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
|
||||
@@ -101,7 +101,6 @@ configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
double SNR, SNR_lin, snr0 = -2.0, snr1 = 2.0;
|
||||
double snr_step = 0.1;
|
||||
@@ -146,6 +145,7 @@ int main(int argc, char **argv)
|
||||
// logInit();
|
||||
randominit(0);
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:df:hpVg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:L:X:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -177,7 +177,6 @@ void nr_phy_config_request_sim_pbchsim(PHY_VARS_gNB *gNB,
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
int i,aa,start_symbol;
|
||||
double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
|
||||
double cfo=0;
|
||||
@@ -246,6 +245,7 @@ int main(int argc, char **argv)
|
||||
exit_fun("[NR_PBCHSIM] Error, configuration module init failed\n");
|
||||
}
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "--:O:c:F:g:hIL:m:M:n:N:o:P:r:R:s:S:x:y:z:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -117,7 +117,6 @@ int NB_UE_INST = 1;
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
int main(int argc, char **argv){
|
||||
|
||||
char c;
|
||||
get_softmodem_params()->sl_mode = 0;
|
||||
double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0;
|
||||
double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs=-1, bw;
|
||||
@@ -155,6 +154,7 @@ int main(int argc, char **argv){
|
||||
|
||||
randominit(0);
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "--:O:hHaA:Cc:l:r:p:g:m:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -315,7 +315,6 @@ double cpuf;
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
int test_freqdomain_loopback = 0, test_slss_search = 0;
|
||||
int frame = 5, slot = 10, frame_tx = 0, slot_tx = 0;
|
||||
int loglvl = OAILOG_INFO;
|
||||
@@ -343,6 +342,7 @@ int main(int argc, char **argv)
|
||||
|
||||
randominit(0);
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:c:hn:o:s:FIL:N:R:S:T:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -97,7 +97,6 @@ nrUE_params_t *get_nrUE_params(void) {
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
int i;//,l;
|
||||
double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
|
||||
double cfo=0;
|
||||
@@ -155,6 +154,7 @@ int main(int argc, char **argv)
|
||||
randominit(0);
|
||||
logInit();
|
||||
|
||||
int c;
|
||||
while ((c = getopt (argc, argv, "--:O:f:hA:f:g:i:I:P:B:b:t:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:cd:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -121,7 +121,6 @@ nrUE_params_t *get_nrUE_params(void) {
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char c;
|
||||
int i;
|
||||
double SNR, snr0 = -2.0, snr1 = 2.0, SNR_lin;
|
||||
double snr_step = 0.1;
|
||||
@@ -165,7 +164,7 @@ int main(int argc, char **argv)
|
||||
//logInit();
|
||||
randominit(0);
|
||||
|
||||
//while ((c = getopt(argc, argv, "--:df:hpg:i:j:n:l:m:r:s:S:y:z:M:N:F:R:P:")) != -1) {
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:hg:n:s:S:py:z:M:N:R:F:m:l:q:r:W:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -145,7 +145,6 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *csv_file = NULL;
|
||||
char *filename_csv = NULL;
|
||||
char c;
|
||||
int i;
|
||||
double SNR, snr0 = -2.0, snr1 = 2.0;
|
||||
double sigma, sigma_dB;
|
||||
@@ -224,6 +223,7 @@ int main(int argc, char *argv[])
|
||||
/* initialize the sin-cos table */
|
||||
InitSinLUT();
|
||||
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "--:O:a:b:c:d:ef:g:h:i:k:m:n:op:q:r:s:t:u:v:w:y:z:C:F:G:H:I:M:N:PR:S:T:U:L:ZW:E:X:")) != -1) {
|
||||
|
||||
/* ignore long options starting with '--', option '-O' and their arguments that are handled by configmodule */
|
||||
|
||||
@@ -442,6 +442,8 @@ typedef struct cu_to_du_rrc_information_s {
|
||||
uint32_t uE_CapabilityRAT_ContainerList_length;
|
||||
uint8_t * measConfig;
|
||||
uint32_t measConfig_length;
|
||||
uint8_t *handoverPreparationInfo;
|
||||
uint32_t handoverPreparationInfo_length;
|
||||
}cu_to_du_rrc_information_t;
|
||||
|
||||
typedef struct du_to_cu_rrc_information_s {
|
||||
@@ -464,6 +466,11 @@ typedef enum ReconfigurationCompl_e {
|
||||
RRCreconf_success = 2,
|
||||
} ReconfigurationCompl_t;
|
||||
|
||||
typedef enum TransmActionInd_e {
|
||||
TransmActionInd_STOP,
|
||||
TransmActionInd_RESTART,
|
||||
} TransmActionInd_t;
|
||||
|
||||
typedef struct f1ap_ue_context_setup_s {
|
||||
uint32_t gNB_CU_ue_id;
|
||||
uint32_t gNB_DU_ue_id;
|
||||
@@ -478,6 +485,7 @@ typedef struct f1ap_ue_context_setup_s {
|
||||
//uint8_t *du_to_cu_rrc_information;
|
||||
du_to_cu_rrc_information_t *du_to_cu_rrc_information;
|
||||
uint32_t du_to_cu_rrc_information_length;
|
||||
uint16_t *crnti;
|
||||
f1ap_drb_to_be_setup_t *drbs_to_be_setup;
|
||||
uint8_t drbs_to_be_setup_length;
|
||||
f1ap_drb_to_be_setup_t *drbs_to_be_modified;
|
||||
@@ -494,6 +502,7 @@ typedef struct f1ap_ue_context_setup_s {
|
||||
ReconfigurationCompl_t ReconfigComplOutcome;
|
||||
uint8_t *rrc_container;
|
||||
int rrc_container_length;
|
||||
TransmActionInd_t *transm_action_ind;
|
||||
} f1ap_ue_context_setup_t, f1ap_ue_context_modif_req_t, f1ap_ue_context_modif_resp_t;
|
||||
|
||||
typedef enum F1ap_Cause_e {
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "f1ap_cu_interface_management.h"
|
||||
#include "f1ap_cu_rrc_message_transfer.h"
|
||||
#include "f1ap_cu_ue_context_management.h"
|
||||
#include "lib/f1ap_rrc_message_transfer.h"
|
||||
#include "f1ap_cu_paging.h"
|
||||
#include "f1ap_cu_task.h"
|
||||
#include <openair3/ocp-gtpu/gtp_itf.h>
|
||||
@@ -174,7 +175,7 @@ void *F1AP_CU_task(void *arg) {
|
||||
case F1AP_DL_RRC_MESSAGE: // from rrc
|
||||
CU_send_DL_RRC_MESSAGE_TRANSFER(assoc_id,
|
||||
&F1AP_DL_RRC_MESSAGE(received_msg));
|
||||
free(F1AP_DL_RRC_MESSAGE(received_msg).rrc_container);
|
||||
free_dl_rrc_message_transfer(&F1AP_DL_RRC_MESSAGE(received_msg));
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_SETUP_REQ: // from rrc
|
||||
|
||||
@@ -276,6 +276,21 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
|
||||
OCTET_STRING_fromBuf(measConfig, (const char*)f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig,
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->measConfig_length);
|
||||
}
|
||||
|
||||
/* optional */
|
||||
/* HandoverPreparationInformation */
|
||||
if (f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length > 0) {
|
||||
DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo != NULL);
|
||||
F1AP_ProtocolExtensionContainer_10696P60_t *p = calloc(1, sizeof(*p));
|
||||
ie6->value.choice.CUtoDURRCInformation.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p;
|
||||
asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext);
|
||||
ie_ext->id = F1AP_ProtocolIE_ID_id_HandoverPreparationInformation;
|
||||
ie_ext->criticality = F1AP_Criticality_ignore;
|
||||
ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation;
|
||||
OCTET_STRING_fromBuf(&ie_ext->extensionValue.choice.HandoverPreparationInformation,
|
||||
(const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo,
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->handoverPreparationInfo_length);
|
||||
}
|
||||
}
|
||||
|
||||
/* optional */
|
||||
@@ -607,6 +622,12 @@ int CU_handle_UE_CONTEXT_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_
|
||||
F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
|
||||
f1ap_ue_context_setup_resp->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
|
||||
LOG_D(F1AP, "f1ap_ue_context_setup_resp->gNB_DU_ue_id is: %d \n", f1ap_ue_context_setup_resp->gNB_DU_ue_id);
|
||||
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, false);
|
||||
if (ie) {
|
||||
f1ap_ue_context_setup_resp->crnti = calloc(1, sizeof(uint16_t));
|
||||
*f1ap_ue_context_setup_resp->crnti = ie->value.choice.C_RNTI;
|
||||
}
|
||||
|
||||
// DUtoCURRCInformation
|
||||
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupResponseIEs_t, ie, container,
|
||||
F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true);
|
||||
@@ -1008,12 +1029,15 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
|
||||
|
||||
/* optional */
|
||||
/* c7. TransmissionActionIndicator */
|
||||
if (0) {
|
||||
if (f1ap_ue_context_modification_req->transm_action_ind != NULL) {
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7);
|
||||
ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator;
|
||||
ie7->criticality = F1AP_Criticality_ignore;
|
||||
ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator;
|
||||
ie7->value.choice.TransmissionActionIndicator = F1AP_TransmissionActionIndicator_stop;
|
||||
ie7->value.choice.TransmissionActionIndicator = *f1ap_ue_context_modification_req->transm_action_ind;
|
||||
// Stop is guaranteed to be 0, by restart might be different from 1
|
||||
static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART,
|
||||
"mismatch of ASN.1 and internal representation\n");
|
||||
}
|
||||
|
||||
/* optional */
|
||||
|
||||
@@ -186,6 +186,8 @@ int DU_handle_F1_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint
|
||||
}
|
||||
LOG_D(F1AP, "Sending F1AP_SETUP_RESP ITTI message\n");
|
||||
f1_setup_response(&resp);
|
||||
// free F1AP message after use
|
||||
free_f1ap_setup_response(&resp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "f1ap_du_interface_management.h"
|
||||
#include "f1ap_du_ue_context_management.h"
|
||||
#include "f1ap_du_rrc_message_transfer.h"
|
||||
#include "lib/f1ap_rrc_message_transfer.h"
|
||||
#include "f1ap_du_task.h"
|
||||
#include <openair3/ocp-gtpu/gtp_itf.h>
|
||||
|
||||
@@ -180,6 +181,7 @@ void *F1AP_DU_task(void *arg) {
|
||||
|
||||
case F1AP_UL_RRC_MESSAGE: // to rrc
|
||||
DU_send_UL_NR_RRC_MESSAGE_TRANSFER(assoc_id, &F1AP_UL_RRC_MESSAGE(msg));
|
||||
free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg));
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_SETUP_RESP:
|
||||
|
||||
@@ -133,8 +133,13 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
|
||||
/* GNB_DU_UE_F1AP_ID */
|
||||
F1AP_UEContextSetupRequestIEs_t *ieDU_UE;
|
||||
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextSetupRequestIEs_t, ieDU_UE, container,
|
||||
F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
|
||||
f1ap_ue_context_setup_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID;
|
||||
F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, false);
|
||||
// this should be optional. At present, the DU uses the RNTI, and hence, this
|
||||
// value cannot exceed 0xffff (or something below, whatever is a valid
|
||||
// C-RNTI). So we use a value > 0xffff to mark optionality
|
||||
f1ap_ue_context_setup_req->gNB_DU_ue_id = -1; // 0xffffffff
|
||||
if (ieDU_UE != NULL)
|
||||
f1ap_ue_context_setup_req->gNB_DU_ue_id = ieDU_UE->value.choice.GNB_DU_UE_F1AP_ID;
|
||||
|
||||
/* SpCell_ID */
|
||||
F1AP_UEContextSetupRequestIEs_t *ieNet;
|
||||
@@ -171,12 +176,34 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
|
||||
F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, false);
|
||||
if(ieCuRrcInfo!=NULL){
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t));
|
||||
if(ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList!=NULL){
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList = (uint8_t *)calloc(1,ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size);
|
||||
memcpy(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->buf, ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size);
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length = ieCuRrcInfo->value.choice.CUtoDURRCInformation.uE_CapabilityRAT_ContainerList->size;
|
||||
cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_setup_req->cu_to_du_rrc_information;
|
||||
const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCuRrcInfo->value.choice.CUtoDURRCInformation;
|
||||
if(cu2duie->uE_CapabilityRAT_ContainerList!=NULL){
|
||||
cu2du->uE_CapabilityRAT_ContainerList = calloc(1, cu2duie->uE_CapabilityRAT_ContainerList->size);
|
||||
memcpy(cu2du->uE_CapabilityRAT_ContainerList,
|
||||
cu2duie->uE_CapabilityRAT_ContainerList->buf,
|
||||
cu2duie->uE_CapabilityRAT_ContainerList->size);
|
||||
cu2du->uE_CapabilityRAT_ContainerList_length = cu2duie->uE_CapabilityRAT_ContainerList->size;
|
||||
LOG_D(F1AP, "Size f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length: %d \n", f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length);
|
||||
}
|
||||
if (cu2duie->iE_Extensions != NULL) {
|
||||
const F1AP_ProtocolExtensionContainer_10696P60_t *ext = (const F1AP_ProtocolExtensionContainer_10696P60_t *)cu2duie->iE_Extensions;
|
||||
for (int i = 0; i < ext->list.count; ++i) {
|
||||
const F1AP_CUtoDURRCInformation_ExtIEs_t *cu2du_info = ext->list.array[i];
|
||||
switch (cu2du_info->id) {
|
||||
case F1AP_ProtocolIE_ID_id_HandoverPreparationInformation:
|
||||
DevAssert(cu2du_info->extensionValue.present == F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation);
|
||||
const F1AP_HandoverPreparationInformation_t *hopi = &cu2du_info->extensionValue.choice.MeasurementTimingConfiguration;
|
||||
cu2du->handoverPreparationInfo = calloc_or_fail(1, hopi->size);
|
||||
memcpy(cu2du->handoverPreparationInfo, hopi->buf, hopi->size);
|
||||
cu2du->handoverPreparationInfo_length = hopi->size;
|
||||
break;
|
||||
default:
|
||||
LOG_W(F1AP, "unsupported CUtoDURRCInformation_ExtIE %ld encountered, ignoring\n", cu2du_info->id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* DRB */
|
||||
@@ -353,15 +380,12 @@ int DU_send_UE_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_ue_context_set
|
||||
|
||||
/* optional */
|
||||
/* c4. C_RNTI */
|
||||
if (0) {
|
||||
if (resp->crnti!=NULL) {
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie4);
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_C_RNTI;
|
||||
ie4->criticality = F1AP_Criticality_ignore;
|
||||
ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI;
|
||||
//C_RNTI_TO_BIT_STRING(rntiP, &ie->value.choice.C_RNTI);
|
||||
ie4->value.choice.C_RNTI=0;
|
||||
AssertFatal(false, "not implemented\n");
|
||||
LOG_E(F1AP,"RNTI to code!\n");
|
||||
ie4->value.choice.C_RNTI = *resp->crnti;
|
||||
}
|
||||
|
||||
/* optional */
|
||||
@@ -889,6 +913,21 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
|
||||
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t, ieSrb, container,
|
||||
F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List, false);
|
||||
|
||||
F1AP_UEContextModificationRequestIEs_t *ieTxInd;
|
||||
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t,
|
||||
ieTxInd,
|
||||
container,
|
||||
F1AP_ProtocolIE_ID_id_TransmissionActionIndicator,
|
||||
false);
|
||||
|
||||
if (ieTxInd != NULL) {
|
||||
f1ap_ue_context_modification_req->transm_action_ind = calloc_or_fail(1, sizeof(*f1ap_ue_context_modification_req->transm_action_ind));
|
||||
*f1ap_ue_context_modification_req->transm_action_ind = ieTxInd->value.choice.TransmissionActionIndicator;
|
||||
// Stop is guaranteed to be 0, by restart might be different from 1
|
||||
static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART,
|
||||
"mismatch of ASN.1 and internal representation\n");
|
||||
}
|
||||
|
||||
if(ieSrb != NULL) {
|
||||
f1ap_ue_context_modification_req->srbs_to_be_setup_length = ieSrb->value.choice.SRBs_ToBeSetupMod_List.list.count;
|
||||
f1ap_ue_context_modification_req->srbs_to_be_setup = calloc(f1ap_ue_context_modification_req->srbs_to_be_setup_length,
|
||||
|
||||
@@ -955,8 +955,7 @@ bool decode_f1ap_setup_failure(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_failure_t
|
||||
*/
|
||||
bool eq_f1ap_setup_failure(const f1ap_setup_failure_t *a, const f1ap_setup_failure_t *b)
|
||||
{
|
||||
if (a->transaction_id != b->transaction_id)
|
||||
return false;
|
||||
_F1_EQ_CHECK_INT(a->transaction_id, b->transaction_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,32 +37,24 @@ bool eq_f1ap_plmn(const f1ap_plmn_t *a, const f1ap_plmn_t *b)
|
||||
|
||||
bool eq_f1ap_freq_info(const f1ap_nr_frequency_info_t *a, const f1ap_nr_frequency_info_t *b)
|
||||
{
|
||||
if (a->arfcn != b->arfcn)
|
||||
return false;
|
||||
if (a->band != b->band)
|
||||
return false;
|
||||
_F1_EQ_CHECK_INT(a->arfcn, b->arfcn);
|
||||
_F1_EQ_CHECK_INT(a->band, b->band);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eq_f1ap_tx_bandwidth(const f1ap_transmission_bandwidth_t *a, const f1ap_transmission_bandwidth_t *b)
|
||||
{
|
||||
if (a->nrb != b->nrb)
|
||||
return false;
|
||||
if (a->scs != b->scs)
|
||||
return false;
|
||||
_F1_EQ_CHECK_INT(a->nrb, b->nrb);
|
||||
_F1_EQ_CHECK_INT(a->scs, b->scs);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b)
|
||||
{
|
||||
if (a->nr_cellid != b->nr_cellid)
|
||||
return false;
|
||||
if (a->nr_pci != b->nr_pci)
|
||||
return false;
|
||||
if (*a->tac != *b->tac)
|
||||
return false;
|
||||
if (a->mode != b->mode)
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci);
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
_F1_EQ_CHECK_INT(a->mode, b->mode);
|
||||
if (a->mode == F1AP_MODE_TDD) {
|
||||
/* TDD */
|
||||
if (!eq_f1ap_tx_bandwidth(&a->tdd.tbw, &b->tdd.tbw))
|
||||
@@ -80,10 +72,8 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
if (!eq_f1ap_freq_info(&a->fdd.ul_freqinfo, &b->fdd.ul_freqinfo))
|
||||
return false;
|
||||
}
|
||||
if (a->measurement_timing_config_len != b->measurement_timing_config_len)
|
||||
return false;
|
||||
if (*a->measurement_timing_config != *b->measurement_timing_config)
|
||||
return false;
|
||||
_F1_EQ_CHECK_INT(a->measurement_timing_config_len, b->measurement_timing_config_len);
|
||||
_F1_EQ_CHECK_INT(*a->measurement_timing_config, *b->measurement_timing_config);
|
||||
if (!eq_f1ap_plmn(&a->plmn, &b->plmn))
|
||||
return false;
|
||||
return true;
|
||||
@@ -92,19 +82,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b)
|
||||
{
|
||||
/* MIB */
|
||||
if (a->mib_length != b->mib_length)
|
||||
return false;
|
||||
for (int i = 0; i < a->mib_length; i++) {
|
||||
if (a->mib[i] != b->mib[i])
|
||||
return false;
|
||||
}
|
||||
_F1_EQ_CHECK_INT(a->mib_length, b->mib_length);
|
||||
for (int i = 0; i < a->mib_length; i++)
|
||||
_F1_EQ_CHECK_INT(a->mib[i], b->mib[i]);
|
||||
/* SIB1 */
|
||||
if (a->sib1_length != b->sib1_length)
|
||||
return false;
|
||||
for (int i = 0; i < a->sib1_length; i++) {
|
||||
if (a->sib1[i] != b->sib1[i])
|
||||
return false;
|
||||
}
|
||||
_F1_EQ_CHECK_INT(a->sib1_length, b->sib1_length);
|
||||
for (int i = 0; i < a->sib1_length; i++)
|
||||
_F1_EQ_CHECK_INT(a->sib1[i], b->sib1[i]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file f1ap_lib_test.c
|
||||
* \brief Test functions for F1AP encoding/decoding library
|
||||
* \author Guido Casati, Robert Schmidt
|
||||
* \date 2024
|
||||
* \version 0.1
|
||||
* \note
|
||||
* \warning
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -166,7 +196,7 @@ static void test_f1ap_setup_request(void)
|
||||
/* gNB_DU_name */
|
||||
uint8_t *gNB_DU_name = calloc(strlen("OAI DU") + 1, sizeof(uint8_t));
|
||||
AssertFatal(gNB_DU_name != NULL, "out of memory\n");
|
||||
memcpy((void *)gNB_DU_name, "OAI DU", strlen("OAI DU") + 1);
|
||||
memcpy(gNB_DU_name, "OAI DU", strlen("OAI DU") + 1);
|
||||
/* sys_info */
|
||||
uint8_t *mib = calloc(3, sizeof(uint8_t));
|
||||
uint8_t *sib1 = calloc(3, sizeof(uint8_t));
|
||||
|
||||
@@ -2240,7 +2240,7 @@ static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_a
|
||||
ssb_info_p->mapped_ro[n_mapped_ro]->frame,
|
||||
ssb_info_p->mapped_ro[n_mapped_ro]->slot,
|
||||
prach_assoc_pattern->nb_of_frame);
|
||||
if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) &&
|
||||
if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame != 0 &&
|
||||
(ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) {
|
||||
uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
|
||||
uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
|
||||
@@ -3450,7 +3450,7 @@ static bool fill_mac_sdu(NR_UE_MAC_INST_t *mac,
|
||||
*pdu -= sh_size;
|
||||
lcids_data_status[lc_idx] = false;
|
||||
(*num_lcids_same_priority)--;
|
||||
LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x\n and hence set to false", lcid);
|
||||
LOG_D(NR_MAC, "No data to transmit for RB with LCID 0x%02x and hence set to false\n", lcid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3608,7 +3608,11 @@ uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac,
|
||||
buflen_remain);
|
||||
|
||||
if (num_lcids_same_priority == count_same_priority_lcids) {
|
||||
buflen_ep = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids;
|
||||
const int32_t buflen_ep_tmp = (buflen_remain - (count_same_priority_lcids * sh_size)) / count_same_priority_lcids;
|
||||
/* after serving equal priority LCIDs in the first round, buflen_remain could be > 0 and < (count_same_priority_lcids * sh_size)
|
||||
if above division yeilds a remainder. hence the following sets buflen_ep to 0 if there is not enough buffer left for subsequent rounds
|
||||
*/
|
||||
buflen_ep = buflen_ep_tmp < 0 ? 0 : buflen_ep_tmp;
|
||||
}
|
||||
|
||||
while (buflen_remain > 0) {
|
||||
|
||||
@@ -844,9 +844,9 @@ bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig
|
||||
/* Prepare a new CellGroupConfig to be applied for this UE. We cannot
|
||||
* immediatly apply it, as we have to wait for the reconfiguration through RRC.
|
||||
* This function sets up everything to apply the reconfiguration. Later, we
|
||||
* will trigger the timer with nr_mac_enable_ue_rrc_processing_timer(); upon
|
||||
* expiry nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio config
|
||||
* etc). */
|
||||
* will trigger the UE inactivity with nr_mac_interrupt_ue_transmission(); upon
|
||||
* expiry, nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio
|
||||
* config etc). */
|
||||
bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup)
|
||||
{
|
||||
DevAssert(nrmac != NULL);
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include "common/utils/LOG/vcd_signal_dumper.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#include "UTIL/OPT/opt.h"
|
||||
#include "SIMULATION/TOOLS/sim.h" // for taus
|
||||
|
||||
/* rlc */
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
@@ -677,16 +676,6 @@ static NR_RA_t *find_free_nr_RA(NR_RA_t *ra_base, int ra_count, uint16_t preambl
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti)
|
||||
{
|
||||
for (int i = 0; i < ra_count; ++i) {
|
||||
const NR_RA_t *ra = &ra_base[i];
|
||||
if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti)
|
||||
return ra;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nr_initiate_ra_proc(module_id_t module_idP,
|
||||
int CC_id,
|
||||
frame_t frameP,
|
||||
@@ -712,23 +701,13 @@ void nr_initiate_ra_proc(module_id_t module_idP,
|
||||
}
|
||||
|
||||
if (ra->rnti == 0) { // This condition allows for the usage of a preconfigured rnti for the CFRA
|
||||
int loop = 0;
|
||||
bool exist_connected_ue, exist_in_pending_ra_ue;
|
||||
rnti_t trial = 0;
|
||||
do {
|
||||
// 3GPP TS 38.321 version 15.13.0 Section 7.1 Table 7.1-1: RNTI values
|
||||
while (trial < 1 || trial > 0xffef)
|
||||
trial = (taus() % 0xffef) + 1;
|
||||
exist_connected_ue = find_nr_UE(&nr_mac->UE_info, trial) != NULL;
|
||||
exist_in_pending_ra_ue = find_nr_RA_rnti(cc->ra, sizeofArray(cc->ra), ra->rnti) != NULL;
|
||||
loop++;
|
||||
} while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue) );
|
||||
if (loop == 100) {
|
||||
bool rnti_found = nr_mac_get_new_rnti(&nr_mac->UE_info, cc->ra, sizeofArray(cc->ra), &ra->rnti);
|
||||
if (!rnti_found) {
|
||||
LOG_E(NR_MAC, "initialisation random access: no more available RNTIs for new UE\n");
|
||||
nr_clear_ra_proc(ra);
|
||||
NR_SCHED_UNLOCK(&nr_mac->sched_lock);
|
||||
return;
|
||||
}
|
||||
ra->rnti = trial;
|
||||
}
|
||||
|
||||
ra->preamble_frame = frameP;
|
||||
@@ -1698,12 +1677,9 @@ static void nr_generate_Msg2(module_id_t module_idP,
|
||||
if (ra->cfra) {
|
||||
NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[module_idP]->UE_info, ra->rnti);
|
||||
if (UE) {
|
||||
const NR_ServingCellConfig_t *servingCellConfig = UE->CellGroup ? UE->CellGroup->spCellConfig->spCellConfigDedicated : NULL;
|
||||
uint32_t delay_ms = servingCellConfig && servingCellConfig->downlinkBWP_ToAddModList
|
||||
? NR_RRC_SETUP_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS
|
||||
: NR_RRC_SETUP_DELAY_MS;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
sched_ctrl->rrc_processing_timer = (delay_ms << ra->DL_BWP.scs);
|
||||
int delay = nr_mac_get_reconfig_delay_slots(ra->DL_BWP.scs);
|
||||
interrupt_followup_action_t action = UE->reconfigCellGroup ? FOLLOW_INSYNC_RECONFIG : FOLLOW_INSYNC;
|
||||
nr_mac_interrupt_ue_transmission(RC.nrmac[module_idP], UE, action, delay);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2248,8 +2224,9 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
// 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs
|
||||
// Msg4 may transmit a RRCReconfiguration, for example when UE sends RRCReestablishmentComplete and MAC CE for C-RNTI in Msg3.
|
||||
// In that case, gNB will generate a RRCReconfiguration that will be transmitted in Msg4, so we need to apply CellGroup after the Ack,
|
||||
// UE->apply_cellgroup was already set when processing RRCReestablishment message
|
||||
nr_mac_enable_ue_rrc_processing_timer(nr_mac, UE, UE->apply_cellgroup);
|
||||
// UE->reconfigCellGroup was already set when processing RRCReestablishment message
|
||||
int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs);
|
||||
nr_mac_interrupt_ue_transmission(nr_mac, UE, UE->interrupt_action, delay);
|
||||
|
||||
nr_clear_ra_proc(ra);
|
||||
} else {
|
||||
@@ -2291,8 +2268,9 @@ static void nr_check_Msg4_MsgB_Ack(module_id_t module_id, int CC_id, frame_t fra
|
||||
// 3GPP TS 38.331 Section 12 Table 12.1-1: UE performance requirements for RRC procedures for UEs
|
||||
// Msg4 may transmit a RRCReconfiguration, for example when UE sends RRCReestablishmentComplete and MAC CE for C-RNTI in Msg3.
|
||||
// In that case, gNB will generate a RRCReconfiguration that will be transmitted in Msg4, so we need to apply CellGroup after the Ack,
|
||||
// UE->apply_cellgroup was already set when processing RRCReestablishment message
|
||||
nr_mac_enable_ue_rrc_processing_timer(RC.nrmac[module_id], UE, UE->apply_cellgroup);
|
||||
// UE->reconfigCellGroup already set when processing RRCReestablishment message
|
||||
int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs);
|
||||
nr_mac_interrupt_ue_transmission(RC.nrmac[module_id], UE, UE->interrupt_action, delay);
|
||||
|
||||
nr_clear_ra_proc(ra);
|
||||
if (sched_ctrl->retrans_dl_harq.head >= 0) {
|
||||
@@ -2457,8 +2435,9 @@ void nr_schedule_RA(module_id_t module_idP,
|
||||
ra->contention_resolution_timer--;
|
||||
if (ra->contention_resolution_timer < 0) {
|
||||
LOG_W(NR_MAC, "(%d.%d) RA Contention Resolution timer expired for UE 0x%04x, RA procedure failed...\n", frameP, slotP, ra->rnti);
|
||||
nr_mac_release_ue(mac, ra->rnti);
|
||||
nr_mac_trigger_release_complete(mac, ra->rnti);
|
||||
bool requested = nr_mac_request_release_ue(mac, ra->rnti);
|
||||
if (!requested)
|
||||
nr_mac_release_ue(mac, ra->rnti);
|
||||
nr_clear_ra_proc(ra);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@
|
||||
#define WORD 32
|
||||
//#define SIZE_OF_POINTER sizeof (void *)
|
||||
|
||||
int get_dl_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot) {
|
||||
|
||||
int get_dl_tda(const gNB_MAC_INST *nrmac, const NR_ServingCellConfigCommon_t *scc, int slot)
|
||||
{
|
||||
/* we assume that this function is mutex-protected from outside */
|
||||
const NR_TDD_UL_DL_Pattern_t *tdd = scc->tdd_UL_DL_ConfigurationCommon ? &scc->tdd_UL_DL_ConfigurationCommon->pattern1 : NULL;
|
||||
AssertFatal(tdd || nrmac->common_channels->frame_type == FDD, "Dynamic TDD not handled yet\n");
|
||||
@@ -334,9 +334,8 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram
|
||||
const int lcid = c->lcid;
|
||||
const uint16_t rnti = UE->rnti;
|
||||
LOG_D(NR_MAC, "In %s: UE %x: LCID %d\n", __FUNCTION__, rnti, lcid);
|
||||
if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) {
|
||||
if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt))
|
||||
continue;
|
||||
}
|
||||
start_meas(&RC.nrmac[module_id]->rlc_status_ind);
|
||||
sched_ctrl->rlc_status[lcid] = mac_rlc_status_ind(module_id,
|
||||
rnti,
|
||||
@@ -390,10 +389,12 @@ void abort_nr_dl_harq(NR_UE_info_t* UE, int8_t harq_pid)
|
||||
UE->mac_stats.dl.errors++;
|
||||
}
|
||||
|
||||
static void get_start_stop_allocation(gNB_MAC_INST *mac,
|
||||
NR_UE_info_t *UE,
|
||||
int *rbStart,
|
||||
int *rbStop)
|
||||
typedef struct {
|
||||
int bwpStart;
|
||||
int bwpSize;
|
||||
} dl_bwp_info_t;
|
||||
|
||||
static dl_bwp_info_t get_bwp_start_size(gNB_MAC_INST *mac, NR_UE_info_t *UE)
|
||||
{
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
@@ -402,25 +403,28 @@ static void get_start_stop_allocation(gNB_MAC_INST *mac,
|
||||
// in which case the size of CORESET 0 shall be used if CORESET 0 is configured for the cell
|
||||
// and the size of initial DL bandwidth part shall be used if CORESET 0 is not configured for the cell.
|
||||
// TS 38.214 Section 5.1.2.2.2
|
||||
*rbStop = dl_bwp->BWPSize - 1;
|
||||
*rbStart = 0; // start wrt BWPstart
|
||||
dl_bwp_info_t bwp_info;
|
||||
bwp_info.bwpSize = dl_bwp->BWPSize;
|
||||
bwp_info.bwpStart = dl_bwp->BWPStart;
|
||||
if (sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common &&
|
||||
dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0) {
|
||||
if (mac->cset0_bwp_size != 0) {
|
||||
*rbStart = mac->cset0_bwp_start;
|
||||
*rbStop = *rbStart + mac->cset0_bwp_size - 1;
|
||||
bwp_info.bwpStart = mac->cset0_bwp_start;
|
||||
bwp_info.bwpSize = mac->cset0_bwp_size;
|
||||
}
|
||||
else {
|
||||
*rbStart = UE->sc_info.initial_dl_BWPStart;
|
||||
*rbStop = *rbStart + UE->sc_info.initial_dl_BWPSize - 1;
|
||||
// TODO this is not entirely correct
|
||||
// start would be the start of CORESET not of the initial BWP
|
||||
bwp_info.bwpStart = UE->sc_info.initial_dl_BWPStart;
|
||||
bwp_info.bwpSize = UE->sc_info.initial_dl_BWPSize;
|
||||
}
|
||||
}
|
||||
return bwp_info;
|
||||
}
|
||||
|
||||
static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
frame_t frame,
|
||||
sub_frame_t slot,
|
||||
uint16_t *rballoc_mask,
|
||||
int *n_rb_sched,
|
||||
NR_UE_info_t *UE,
|
||||
int current_harq_pid)
|
||||
@@ -442,12 +446,6 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
int pm_index = (curInfo->nrOfLayers < retInfo->nrOfLayers) ? curInfo->pm_index : retInfo->pm_index;
|
||||
|
||||
const int coresetid = sched_ctrl->coreset->controlResourceSetId;
|
||||
|
||||
int rbStop = 0;
|
||||
int rbStart = 0;
|
||||
get_start_stop_allocation(nr_mac, UE, &rbStart, &rbStop);
|
||||
|
||||
int rbSize = 0;
|
||||
const int tda = get_dl_tda(nr_mac, scc, slot);
|
||||
AssertFatal(tda>=0,"Unable to find PDSCH time domain allocation in list\n");
|
||||
|
||||
@@ -470,6 +468,14 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
reuse_old_tda ? "reuse" : "do not reuse",
|
||||
layers == retInfo->nrOfLayers ? "same" : "different");
|
||||
|
||||
// TODO assuming beam 0 for now
|
||||
uint16_t *rballoc_mask = nr_mac->common_channels[CC_id].vrb_map[0];
|
||||
|
||||
dl_bwp_info_t bwp_info = get_bwp_start_size(nr_mac, UE);
|
||||
int rbStart = bwp_info.bwpStart;
|
||||
int rbStop = bwp_info.bwpStart + bwp_info.bwpSize - 1;
|
||||
int rbSize = 0;
|
||||
|
||||
if (reuse_old_tda && layers == retInfo->nrOfLayers) {
|
||||
/* Check that there are enough resources for retransmission */
|
||||
while (rbSize < retInfo->rbSize) {
|
||||
@@ -477,35 +483,27 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
rbSize = 0;
|
||||
|
||||
const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap))
|
||||
rbStart++;
|
||||
|
||||
if (rbStart >= rbStop) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate DL retransmission: no resources\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot);
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate DL retransmission: no resources\n", UE->rnti, frame, slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (rbStart + rbSize <= rbStop &&
|
||||
(rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap &&
|
||||
rbSize < retInfo->rbSize)
|
||||
while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap) && rbSize < retInfo->rbSize)
|
||||
rbSize++;
|
||||
}
|
||||
} else {
|
||||
/* the retransmission will use a different time domain allocation, check
|
||||
* that we have enough resources */
|
||||
NR_pdsch_dmrs_t temp_dmrs = get_dl_dmrs_params(scc,
|
||||
dl_bwp,
|
||||
&temp_tda,
|
||||
layers);
|
||||
NR_pdsch_dmrs_t temp_dmrs = get_dl_dmrs_params(scc, dl_bwp, &temp_tda, layers);
|
||||
|
||||
const uint16_t slbitmap = SL_to_bitmap(temp_tda.startSymbolIndex, temp_tda.nrOfSymbols);
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap))
|
||||
rbStart++;
|
||||
|
||||
while (rbStart + rbSize <= rbStop && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap)
|
||||
while (rbStart + rbSize <= rbStop && !(rballoc_mask[rbStart + rbSize] & slbitmap))
|
||||
rbSize++;
|
||||
|
||||
uint32_t new_tbs;
|
||||
@@ -548,7 +546,9 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
|
||||
/* Find a free CCE */
|
||||
int CCEIndex = get_cce_index(nr_mac,
|
||||
CC_id, slot, UE->rnti,
|
||||
CC_id,
|
||||
slot,
|
||||
UE->rnti,
|
||||
&sched_ctrl->aggregation_level,
|
||||
beam,
|
||||
sched_ctrl->search_space,
|
||||
@@ -556,10 +556,7 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false);
|
||||
if (CCEIndex<0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot);
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find free CCE for DL DCI retransmission\n", UE->rnti, frame, slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -571,30 +568,27 @@ static bool allocate_dl_retransmission(module_id_t module_id,
|
||||
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, ul_bwp->pucch_Config, CCEIndex);
|
||||
alloc = nr_acknack_scheduling(nr_mac, UE, frame, slot, beam, r_pucch, 0);
|
||||
if (alloc < 0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot);
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not find PUCCH for DL DCI retransmission\n", UE->rnti, frame, slot);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sched_ctrl->cce_index = CCEIndex;
|
||||
fill_pdcch_vrb_map(nr_mac,
|
||||
/* CC_id = */ 0,
|
||||
CC_id,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
CCEIndex,
|
||||
sched_ctrl->aggregation_level,
|
||||
beam);
|
||||
/* just reuse from previous scheduling opportunity, set new start RB */
|
||||
sched_ctrl->sched_pdsch = *retInfo;
|
||||
sched_ctrl->sched_pdsch.rbStart = rbStart;
|
||||
sched_ctrl->sched_pdsch.rbStart = rbStart - bwp_info.bwpStart;
|
||||
sched_ctrl->sched_pdsch.pucch_allocation = alloc;
|
||||
/* retransmissions: directly allocate */
|
||||
*n_rb_sched -= sched_ctrl->sched_pdsch.rbSize;
|
||||
|
||||
for (int rb = 0; rb < sched_ctrl->sched_pdsch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pdsch.rbStart] ^= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
|
||||
for (int rb = rbStart; rb < sched_ctrl->sched_pdsch.rbSize; rb++)
|
||||
rballoc_mask[rb] |= SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -614,8 +608,7 @@ static void pf_dl(module_id_t module_id,
|
||||
sub_frame_t slot,
|
||||
NR_UE_info_t **UE_list,
|
||||
int max_num_ue,
|
||||
int n_rb_sched,
|
||||
uint16_t *rballoc_mask)
|
||||
int n_rb_sched)
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[module_id];
|
||||
NR_ServingCellConfigCommon_t *scc=mac->common_channels[0].ServingCellConfigCommon;
|
||||
@@ -651,7 +644,7 @@ static void pf_dl(module_id_t module_id,
|
||||
/* retransmission */
|
||||
if (sched_pdsch->dl_harq_pid >= 0) {
|
||||
/* Allocate retransmission */
|
||||
bool r = allocate_dl_retransmission(module_id, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pdsch->dl_harq_pid);
|
||||
bool r = allocate_dl_retransmission(module_id, frame, slot, &n_rb_sched, UE, sched_pdsch->dl_harq_pid);
|
||||
|
||||
if (!r) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] DL retransmission could not be allocated\n",
|
||||
@@ -742,11 +735,60 @@ static void pf_dl(module_id_t module_id,
|
||||
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
|
||||
sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head;
|
||||
|
||||
/* MCS has been set above */
|
||||
sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot);
|
||||
AssertFatal(sched_pdsch->time_domain_allocation>=0,"Unable to find PDSCH time domain allocation in list\n");
|
||||
|
||||
const int coresetid = sched_ctrl->coreset->controlResourceSetId;
|
||||
sched_pdsch->tda_info = get_dl_tda_info(dl_bwp,
|
||||
sched_ctrl->search_space->searchSpaceType->present,
|
||||
sched_pdsch->time_domain_allocation,
|
||||
scc->dmrs_TypeA_Position,
|
||||
1,
|
||||
TYPE_C_RNTI_,
|
||||
coresetid,
|
||||
false);
|
||||
AssertFatal(sched_pdsch->tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n");
|
||||
|
||||
NR_tda_info_t *tda_info = &sched_pdsch->tda_info;
|
||||
|
||||
const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols);
|
||||
|
||||
// TODO assuming beam 0 for now
|
||||
uint16_t *rballoc_mask = mac->common_channels[CC_id].vrb_map[0];
|
||||
dl_bwp_info_t bwp_info = get_bwp_start_size(mac, iterator->UE);
|
||||
int rbStart = 0; // WRT BWP start
|
||||
int rbStop = bwp_info.bwpSize - 1;
|
||||
int bwp_start = bwp_info.bwpStart;
|
||||
// Freq-demain allocation
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart + bwp_start] & slbitmap))
|
||||
rbStart++;
|
||||
|
||||
uint16_t max_rbSize = 1;
|
||||
|
||||
while (rbStart + max_rbSize <= rbStop && !(rballoc_mask[rbStart + max_rbSize + bwp_start] & slbitmap))
|
||||
max_rbSize++;
|
||||
|
||||
if (max_rbSize < min_rbSize) {
|
||||
LOG_D(NR_MAC,
|
||||
"(%d.%d) Cannot schedule RNTI %04x, rbStart %d, rbSize %d, rbStop %d\n",
|
||||
frame,
|
||||
slot,
|
||||
rnti,
|
||||
rbStart,
|
||||
max_rbSize,
|
||||
rbStop);
|
||||
iterator++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO properly set the beam index (currently only done for RA)
|
||||
int beam = 0;
|
||||
|
||||
int CCEIndex = get_cce_index(mac,
|
||||
CC_id, slot, iterator->UE->rnti,
|
||||
CC_id,
|
||||
slot,
|
||||
iterator->UE->rnti,
|
||||
&sched_ctrl->aggregation_level,
|
||||
beam,
|
||||
sched_ctrl->search_space,
|
||||
@@ -780,48 +822,9 @@ static void pf_dl(module_id_t module_id,
|
||||
}
|
||||
|
||||
sched_ctrl->cce_index = CCEIndex;
|
||||
fill_pdcch_vrb_map(mac,
|
||||
/* CC_id = */ 0,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
CCEIndex,
|
||||
sched_ctrl->aggregation_level,
|
||||
beam);
|
||||
fill_pdcch_vrb_map(mac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, beam);
|
||||
|
||||
/* MCS has been set above */
|
||||
sched_pdsch->time_domain_allocation = get_dl_tda(mac, scc, slot);
|
||||
AssertFatal(sched_pdsch->time_domain_allocation>=0,"Unable to find PDSCH time domain allocation in list\n");
|
||||
|
||||
const int coresetid = sched_ctrl->coreset->controlResourceSetId;
|
||||
sched_pdsch->tda_info = get_dl_tda_info(dl_bwp,
|
||||
sched_ctrl->search_space->searchSpaceType->present,
|
||||
sched_pdsch->time_domain_allocation,
|
||||
scc->dmrs_TypeA_Position,
|
||||
1,
|
||||
TYPE_C_RNTI_,
|
||||
coresetid,
|
||||
false);
|
||||
AssertFatal(sched_pdsch->tda_info.valid_tda, "Invalid TDA from get_dl_tda_info\n");
|
||||
|
||||
NR_tda_info_t *tda_info = &sched_pdsch->tda_info;
|
||||
|
||||
const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols);
|
||||
|
||||
int rbStop = 0;
|
||||
int rbStart = 0;
|
||||
get_start_stop_allocation(mac, iterator->UE, &rbStart, &rbStop);
|
||||
// Freq-demain allocation
|
||||
while (rbStart < rbStop && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
rbStart++;
|
||||
|
||||
uint16_t max_rbSize = 1;
|
||||
|
||||
while (rbStart + max_rbSize <= rbStop && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap)
|
||||
max_rbSize++;
|
||||
|
||||
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc,
|
||||
dl_bwp,
|
||||
tda_info,
|
||||
sched_pdsch->nrOfLayers);
|
||||
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, tda_info, sched_pdsch->nrOfLayers);
|
||||
sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
|
||||
sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
|
||||
sched_pdsch->pucch_allocation = alloc;
|
||||
@@ -850,8 +853,8 @@ static void pf_dl(module_id_t module_id,
|
||||
/* transmissions: directly allocate */
|
||||
n_rb_sched -= sched_pdsch->rbSize;
|
||||
|
||||
for (int rb = 0; rb < sched_pdsch->rbSize; rb++)
|
||||
rballoc_mask[rb + sched_pdsch->rbStart] ^= slbitmap;
|
||||
for (int rb = bwp_start; rb < sched_pdsch->rbSize; rb++)
|
||||
rballoc_mask[rb + sched_pdsch->rbStart] |= slbitmap;
|
||||
|
||||
remainUEs--;
|
||||
iterator++;
|
||||
@@ -866,45 +869,11 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_
|
||||
return;
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = RC.nrmac[module_id]->common_channels[0].ServingCellConfigCommon;
|
||||
const int CC_id = 0;
|
||||
/* Get bwpSize and TDAfrom the first UE */
|
||||
/* This is temporary and it assumes all UEs have the same BWP and TDA*/
|
||||
NR_UE_info_t *UE=UE_info->list[0];
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
const int tda = get_dl_tda(RC.nrmac[module_id], scc, slot);
|
||||
int startSymbolIndex, nrOfSymbols;
|
||||
const int coresetid = sched_ctrl->coreset->controlResourceSetId;
|
||||
const struct NR_PDSCH_TimeDomainResourceAllocationList *tdaList =
|
||||
get_dl_tdalist(current_BWP, coresetid, sched_ctrl->search_space->searchSpaceType->present, TYPE_C_RNTI_);
|
||||
AssertFatal(tda < tdaList->list.count, "time_domain_allocation %d>=%d\n", tda, tdaList->list.count);
|
||||
const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
|
||||
SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
|
||||
|
||||
const uint16_t bwpSize = current_BWP->BWPSize;
|
||||
const uint16_t BWPStart = current_BWP->BWPStart;
|
||||
|
||||
const uint16_t slbitmap = SL_to_bitmap(startSymbolIndex, nrOfSymbols);
|
||||
// TODO improve handling of beam in vrb_map (for now just using 0)
|
||||
uint16_t *vrb_map = RC.nrmac[module_id]->common_channels[CC_id].vrb_map[0];
|
||||
uint16_t rballoc_mask[bwpSize];
|
||||
int n_rb_sched = 0;
|
||||
|
||||
for (int i = 0; i < bwpSize; i++) {
|
||||
// calculate mask: init with "NOT" vrb_map:
|
||||
// if any RB in vrb_map is blocked (1), the current RBG will be 0
|
||||
rballoc_mask[i] = (~vrb_map[i+BWPStart])&0x3fff; //bitwise not and 14 symbols
|
||||
|
||||
// if all the pdsch symbols are free
|
||||
if ((rballoc_mask[i]&slbitmap) == slbitmap) {
|
||||
n_rb_sched++;
|
||||
}
|
||||
}
|
||||
int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
|
||||
/* Retrieve amount of data to send for this UE */
|
||||
nr_store_dlsch_buffer(module_id, frame, slot);
|
||||
|
||||
int bw = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
int average_agg_level = 4; // TODO find a better estimation
|
||||
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
|
||||
|
||||
@@ -917,8 +886,7 @@ static void nr_fr1_dlsch_preprocessor(module_id_t module_id, frame_t frame, sub_
|
||||
slot,
|
||||
UE_info->list,
|
||||
max_sched_ues,
|
||||
n_rb_sched,
|
||||
rballoc_mask);
|
||||
bw); // we set the whole BW as max number
|
||||
}
|
||||
|
||||
nr_pp_impl_dl nr_init_fr1_dlsch_preprocessor(int CC_id) {
|
||||
@@ -985,7 +953,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
* Possible improvement: take the periodicity from input file.
|
||||
* If such UE is not scheduled now, it will be by the preprocessor later.
|
||||
* If we add the CE, ta_apply will be reset */
|
||||
if (frame == (sched_ctrl->ta_frame + 100) % 1024) {
|
||||
if (frame == ((sched_ctrl->ta_frame + 100) % 1024) && !nr_timer_is_active(&sched_ctrl->transm_interrupt)) {
|
||||
sched_ctrl->ta_apply = true; /* the timer is reset once TA CE is scheduled */
|
||||
LOG_D(NR_MAC, "[UE %04x][%d.%d] UL timing alignment procedures: setting flag for Timing Advance command\n", UE->rnti, frame, slot);
|
||||
}
|
||||
@@ -1093,8 +1061,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
const int pduindex = gNB_mac->pdu_index[CC_id]++;
|
||||
pdsch_pdu->pduIndex = pduindex;
|
||||
|
||||
pdsch_pdu->BWPSize = current_BWP->BWPSize;
|
||||
pdsch_pdu->BWPStart = current_BWP->BWPStart;
|
||||
dl_bwp_info_t bwp_info = get_bwp_start_size(gNB_mac, UE);
|
||||
pdsch_pdu->BWPSize = bwp_info.bwpSize;
|
||||
pdsch_pdu->BWPStart = bwp_info.bwpStart;
|
||||
|
||||
pdsch_pdu->SubcarrierSpacing = current_BWP->scs;
|
||||
pdsch_pdu->CyclicPrefix = current_BWP->cyclicprefix ? *current_BWP->cyclicprefix : 0;
|
||||
@@ -1208,17 +1177,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
AssertFatal(pdsch_Config == NULL || pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1,
|
||||
"Only frequency resource allocation type 1 is currently supported\n");
|
||||
|
||||
|
||||
// For a PDSCH scheduled with a DCI format 1_0 in any type of PDCCH common search space, regardless of which
|
||||
// bandwidth part is the active bandwidth part, RB numbering starts from the lowest RB of the CORESET in which the
|
||||
// DCI was received; otherwise RB numbering starts from the lowest RB in the determined downlink bandwidth part.
|
||||
// TS 38.214 Section 5.1.2.2.2
|
||||
int rbStop = 0;
|
||||
int rbStart = 0;
|
||||
get_start_stop_allocation(gNB_mac, UE, &rbStart, &rbStop);
|
||||
dci_payload.frequency_domain_assignment.val = PRBalloc_to_locationandbandwidth0(pdsch_pdu->rbSize,
|
||||
pdsch_pdu->rbStart - rbStart,
|
||||
rbStop - rbStart + 1);
|
||||
pdsch_pdu->rbStart,
|
||||
pdsch_pdu->BWPSize);
|
||||
dci_payload.format_indicator = 1;
|
||||
dci_payload.time_domain_assignment.val = sched_pdsch->time_domain_allocation;
|
||||
dci_payload.mcs = sched_pdsch->mcs;
|
||||
|
||||
@@ -53,6 +53,8 @@
|
||||
#include "uper_encoder.h"
|
||||
#include "uper_decoder.h"
|
||||
|
||||
#include "SIMULATION/TOOLS/sim.h" // for taus
|
||||
|
||||
#define ENABLE_MAC_PAYLOAD_DEBUG
|
||||
#define DEBUG_gNB_SCHEDULER 1
|
||||
|
||||
@@ -2673,6 +2675,16 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
|
||||
memcpy(UE_info->list, newUEs, sizeof(UE_info->list));
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
|
||||
const int CC_id = 0;
|
||||
NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id];
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
NR_RA_t *ra = &cc->ra[i];
|
||||
if (ra->rnti == UE->rnti) {
|
||||
nr_clear_ra_proc(ra);
|
||||
ra->cfra = 0;
|
||||
}
|
||||
}
|
||||
|
||||
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
|
||||
}
|
||||
|
||||
@@ -2733,9 +2745,8 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo
|
||||
if (UE_info->sched_csirs & (1 << dl_bwp->bwp_id))
|
||||
continue;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
if (sched_ctrl->rrc_processing_timer > 0) {
|
||||
if (nr_timer_is_active(&sched_ctrl->transm_interrupt))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!UE->sc_info.csi_MeasConfig)
|
||||
continue;
|
||||
@@ -2949,28 +2960,41 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group)
|
||||
{
|
||||
/* remove a reconfigurationWithSync, we don't need it anymore */
|
||||
if (cell_group->spCellConfig->reconfigurationWithSync != NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cell_group->spCellConfig->reconfigurationWithSync);
|
||||
cell_group->spCellConfig->reconfigurationWithSync = NULL;
|
||||
}
|
||||
/* remove the rlc_BearerToReleaseList, we don't need it anymore */
|
||||
if (cell_group->rlc_BearerToReleaseList != NULL) {
|
||||
struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = cell_group->rlc_BearerToReleaseList;
|
||||
asn_sequence_del(&l->list, l->list.count, /* free */ 1);
|
||||
free(cell_group->rlc_BearerToReleaseList);
|
||||
cell_group->rlc_BearerToReleaseList = NULL;
|
||||
}
|
||||
/* remove reestablishRLC, we don't need it anymore */
|
||||
for (int i = 0; i < cell_group->rlc_BearerToAddModList->list.count; ++i)
|
||||
free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC);
|
||||
}
|
||||
|
||||
static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, sub_frame_t slot)
|
||||
{
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: RRC processing timer expired\n", frame, slot, UE->rnti);
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti);
|
||||
|
||||
/* check if there is a new CellGroupConfig to be applied */
|
||||
if (UE->apply_cellgroup && UE->reconfigCellGroup != NULL) {
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after RRC processing timer expiry\n", frame, slot, UE->rnti);
|
||||
if (UE->interrupt_action == FOLLOW_INSYNC_RECONFIG && UE->reconfigCellGroup != NULL) {
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after UE inactivity\n", frame, slot, UE->rnti);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = UE->reconfigCellGroup;
|
||||
UE->reconfigCellGroup = NULL;
|
||||
UE->apply_cellgroup = false;
|
||||
UE->interrupt_action = FOLLOW_INSYNC;
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup);
|
||||
|
||||
/* remove the rlc_BearerToReleaseList, we don't need it anymore */
|
||||
if (UE->CellGroup->rlc_BearerToReleaseList != NULL) {
|
||||
struct NR_CellGroupConfig__rlc_BearerToReleaseList *l = UE->CellGroup->rlc_BearerToReleaseList;
|
||||
asn_sequence_del(&l->list, l->list.count, /* free */1);
|
||||
free(UE->CellGroup->rlc_BearerToReleaseList);
|
||||
UE->CellGroup->rlc_BearerToReleaseList = NULL;
|
||||
}
|
||||
nr_mac_clean_cellgroup(UE->CellGroup);
|
||||
}
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
@@ -2987,31 +3011,42 @@ static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t
|
||||
}
|
||||
}
|
||||
|
||||
int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, bool apply_cellgroup)
|
||||
int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs)
|
||||
{
|
||||
/* we previously assumed a specific "slot ahead" value for the PHY processing
|
||||
* time. However, we cannot always know it (e.g., third-party PHY), so simply
|
||||
* assume a tentative worst-case slot processing time */
|
||||
const uint16_t sl_ahead = 10;
|
||||
/* 16ms seems to be the most common: See 38.331 Tab 12.1-1 */
|
||||
int delay_ms = NR_RRC_RECONFIGURATION_DELAY_MS + NR_RRC_BWP_SWITCHING_DELAY_MS;
|
||||
return (delay_ms << scs) + sl_ahead;
|
||||
}
|
||||
|
||||
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots)
|
||||
{
|
||||
DevAssert(mac != NULL);
|
||||
DevAssert(UE != NULL);
|
||||
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
|
||||
|
||||
const uint16_t sl_ahead = mac->if_inst->sl_ahead;
|
||||
// TODO: account for BWP switch with NR_RRC_BWP_SWITCHING_DELAY_MS
|
||||
int delay = NR_RRC_RECONFIGURATION_DELAY_MS;
|
||||
NR_SubcarrierSpacing_t scs = UE->current_UL_BWP.scs;
|
||||
nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1);
|
||||
nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt);
|
||||
UE->interrupt_action = action;
|
||||
|
||||
UE->UE_sched_ctrl.rrc_processing_timer = (delay << scs) + sl_ahead;
|
||||
UE->apply_cellgroup = apply_cellgroup;
|
||||
AssertFatal(!UE->apply_cellgroup || (UE->apply_cellgroup && UE->reconfigCellGroup),
|
||||
"logic bug: apply_cellgroup %d and UE->reconfigCellGroup %p: did you try to apply a cellGroup, while none is deposited?\n",
|
||||
UE->apply_cellgroup,
|
||||
UE->reconfigCellGroup);
|
||||
|
||||
// it might happen that timing advance command should be sent during the RRC
|
||||
// processing timer. To prevent this, set a variable as if we would have just
|
||||
// it might happen that timing advance command should be sent during the UE
|
||||
// inactivity time. To prevent this, set a variable as if we would have just
|
||||
// sent it. This way, another TA command will for sure be sent in some
|
||||
// frames, after RRC processing timer.
|
||||
// frames, after the inactivity of the UE.
|
||||
UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024;
|
||||
|
||||
LOG_D(NR_MAC, "UE %04x: Activate RRC processing timer (%d ms)\n", UE->rnti, delay);
|
||||
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d reconfigCellGroup %p\n", UE->rnti, slots, UE->interrupt_action, UE->reconfigCellGroup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info)
|
||||
{
|
||||
int delay = nr_mac_get_reconfig_delay_slots(UE_info->current_DL_BWP.scs);
|
||||
nr_mac_interrupt_ue_transmission(mac, UE_info, FOLLOW_OUTOFSYNC, delay);
|
||||
LOG_I(NR_MAC, "gNB-DU received the TransmissionActionIndicator with Stop value for UE %04x\n", UE_info->rnti);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3073,9 +3108,12 @@ void nr_mac_update_timers(module_id_t module_id,
|
||||
/* check if UL failure and trigger release request if necessary */
|
||||
nr_mac_check_ul_failure(mac, UE->rnti, sched_ctrl);
|
||||
|
||||
if (sched_ctrl->rrc_processing_timer > 0) {
|
||||
sched_ctrl->rrc_processing_timer--;
|
||||
if (sched_ctrl->rrc_processing_timer == 0)
|
||||
if (nr_timer_tick(&sched_ctrl->transm_interrupt)) {
|
||||
/* expired */
|
||||
nr_timer_stop(&sched_ctrl->transm_interrupt);
|
||||
if (UE->interrupt_action == FOLLOW_OUTOFSYNC)
|
||||
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
|
||||
else
|
||||
nr_mac_apply_cellgroup(mac, UE, frame, slot);
|
||||
}
|
||||
}
|
||||
@@ -3264,7 +3302,27 @@ void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl)
|
||||
sched_ctrl->pusch_consecutive_dtx_cnt = 0;
|
||||
}
|
||||
|
||||
void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl)
|
||||
/* \brief trigger a release request towards the CU.
|
||||
* \returns true if release was requested, else false (in which case the CU
|
||||
* does not know the UE, and we can safely remove it). */
|
||||
bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti)
|
||||
{
|
||||
if (!du_exists_f1_ue_data(rnti)) {
|
||||
LOG_W(NR_MAC, "UE %04x: no CU-UE ID stored, cannot request release\n", rnti);
|
||||
return false;
|
||||
}
|
||||
f1_ue_data_t ue_data = du_get_f1_ue_data(rnti);
|
||||
f1ap_ue_context_release_req_t request = {
|
||||
.gNB_CU_ue_id = ue_data.secondary_ue,
|
||||
.gNB_DU_ue_id = rnti,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_others,
|
||||
};
|
||||
nrmac->mac_rrc.ue_context_release_request(&request);
|
||||
return true;
|
||||
}
|
||||
|
||||
void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl)
|
||||
{
|
||||
if (!sched_ctrl->ul_failure)
|
||||
return;
|
||||
@@ -3274,14 +3332,9 @@ void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ct
|
||||
* stop at 0 and we wait for a UE release command from upper layers */
|
||||
if (sched_ctrl->ul_failure_timer == 1) {
|
||||
LOG_W(MAC, "UE %04x: request release after UL failure timer expiry\n", rnti);
|
||||
f1_ue_data_t ue_data = du_get_f1_ue_data(rnti);
|
||||
f1ap_ue_context_release_req_t request = {
|
||||
.gNB_CU_ue_id = ue_data.secondary_ue,
|
||||
.gNB_DU_ue_id = rnti,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_others,
|
||||
};
|
||||
nrmac->mac_rrc.ue_context_release_request(&request);
|
||||
bool requested = nr_mac_request_release_ue(nrmac, rnti);
|
||||
if (!requested)
|
||||
nr_mac_release_ue(nrmac, rnti);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3382,3 +3435,26 @@ bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid)
|
||||
seq_arr_erase(&sched_ctrl->lc_config, elm.it);
|
||||
return true;
|
||||
}
|
||||
|
||||
static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti)
|
||||
{
|
||||
for (int i = 0; i < ra_count; ++i) {
|
||||
const NR_RA_t *ra = &ra_base[i];
|
||||
if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti)
|
||||
return ra;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti)
|
||||
{
|
||||
int loop = 0;
|
||||
bool exist_connected_ue, exist_in_pending_ra_ue;
|
||||
do {
|
||||
*rnti = (taus() % 0xffef) + 1;
|
||||
exist_connected_ue = find_nr_UE(UEs, *rnti) != NULL;
|
||||
exist_in_pending_ra_ue = find_nr_RA_rnti(ra_base, ra_count, *rnti) != NULL;
|
||||
loop++;
|
||||
} while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue));
|
||||
return loop < 100; // nothing found: loop count 100
|
||||
}
|
||||
|
||||
@@ -533,7 +533,7 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot)
|
||||
sched_ctrl->sched_srs.srs_scheduled = false;
|
||||
}
|
||||
|
||||
if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || sched_ctrl->rrc_processing_timer > 0) {
|
||||
if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ void nr_csi_meas_reporting(int Mod_idP,
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs];
|
||||
if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) {
|
||||
if (nr_timer_is_active(&sched_ctrl->transm_interrupt) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) {
|
||||
continue;
|
||||
}
|
||||
const NR_CSI_MeasConfig_t *csi_measconfig = UE->sc_info.csi_MeasConfig;
|
||||
@@ -1389,7 +1389,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot)
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs];
|
||||
if (sched_ctrl->ul_failure || sched_ctrl->rrc_processing_timer > 0)
|
||||
if (sched_ctrl->ul_failure || nr_timer_is_active(&sched_ctrl->transm_interrupt))
|
||||
continue;
|
||||
NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config;
|
||||
|
||||
|
||||
@@ -501,7 +501,7 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_MAC, "RNTI %0x, received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, rx_lcid);
|
||||
LOG_E(NR_MAC, "RNTI %0x [%d.%d], received unknown MAC header (LCID = 0x%02x)\n", UE->rnti, frameP, slot, rx_lcid);
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
@@ -561,12 +561,16 @@ static void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid)
|
||||
sched_ctrl->sched_ul_bytes = 0;
|
||||
}
|
||||
|
||||
static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac, const int CC_id, const frame_t frame, const sub_frame_t slot)
|
||||
static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac,
|
||||
const int CC_id,
|
||||
const frame_t frame,
|
||||
const sub_frame_t slot,
|
||||
rnti_t rnti)
|
||||
{
|
||||
bool UE_waiting_CFRA_msg3 = false;
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
const NR_RA_t *ra = &gNB_mac->common_channels[CC_id].ra[i];
|
||||
if (ra->cfra == true && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot) {
|
||||
if (ra->cfra && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot && rnti == ra->rnti) {
|
||||
UE_waiting_CFRA_msg3 = true;
|
||||
break;
|
||||
}
|
||||
@@ -584,7 +588,7 @@ void handle_nr_ul_harq(const int CC_idP,
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, crc_pdu->rnti);
|
||||
bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot);
|
||||
bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(nrmac, CC_idP, frame, slot, crc_pdu->rnti);
|
||||
|
||||
if (!UE || UE_waiting_CFRA_msg3 == true) {
|
||||
LOG_D(NR_MAC, "handle harq for rnti %04x, in RA process\n", crc_pdu->rnti);
|
||||
@@ -700,7 +704,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
const int pusch_failure_thres = gNB_mac->pusch_failure_thres;
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti);
|
||||
bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP);
|
||||
bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP, current_rnti);
|
||||
|
||||
if (UE && UE_waiting_CFRA_msg3 == false) {
|
||||
|
||||
@@ -1640,7 +1644,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
|
||||
int rbStart = 0; // wrt BWP start
|
||||
const uint16_t bwpSize = ul_bwp->BWPSize;
|
||||
const uint32_t bwpSize = ul_bwp->BWPSize;
|
||||
const uint32_t bwpStart = ul_bwp->BWPStart;
|
||||
const uint8_t nrOfLayers = retInfo->nrOfLayers;
|
||||
LOG_D(NR_MAC,"retInfo->time_domain_allocation = %d, tda = %d\n", retInfo->time_domain_allocation, tda);
|
||||
LOG_D(NR_MAC,"tbs %d\n",retInfo->tb_size);
|
||||
@@ -1651,11 +1656,12 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
tda);
|
||||
if (!tda_info.valid_tda)
|
||||
return false;
|
||||
|
||||
bool reuse_old_tda = (retInfo->tda_info.startSymbolIndex == tda_info.startSymbolIndex) && (retInfo->tda_info.nrOfSymbols <= tda_info.nrOfSymbols);
|
||||
if (reuse_old_tda && nrOfLayers == retInfo->nrOfLayers) {
|
||||
/* Check the resource is enough for retransmission */
|
||||
const uint16_t slbitmap = SL_to_bitmap(retInfo->tda_info.startSymbolIndex, retInfo->tda_info.nrOfSymbols);
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap))
|
||||
rbStart++;
|
||||
if (rbStart + retInfo->rbSize > bwpSize) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources (rbStart %d, retInfo->rbSize %d, bwpSize %d) \n",
|
||||
@@ -1667,19 +1673,16 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
bwpSize);
|
||||
return false;
|
||||
}
|
||||
LOG_D(NR_MAC, "%s(): retransmission keeping TDA %d and TBS %d\n", __func__, tda, retInfo->tb_size);
|
||||
LOG_D(NR_MAC, "Retransmission keeping TDA %d and TBS %d\n", tda, retInfo->tb_size);
|
||||
} else {
|
||||
NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc,
|
||||
ul_bwp,
|
||||
&tda_info,
|
||||
nrOfLayers);
|
||||
NR_pusch_dmrs_t dmrs_info = get_ul_dmrs_params(scc, ul_bwp, &tda_info, nrOfLayers);
|
||||
/* the retransmission will use a different time domain allocation, check
|
||||
* that we have enough resources */
|
||||
const uint16_t slbitmap = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap))
|
||||
rbStart++;
|
||||
int rbSize = 0;
|
||||
while (rbStart + rbSize < bwpSize && (rballoc_mask[rbStart + rbSize] & slbitmap) == slbitmap)
|
||||
while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + rbSize] & slbitmap))
|
||||
rbSize++;
|
||||
uint32_t new_tbs;
|
||||
uint16_t new_rbSize;
|
||||
@@ -1703,7 +1706,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
retInfo->tb_size);
|
||||
return false; /* the maximum TBsize we might have is smaller than what we need */
|
||||
}
|
||||
LOG_D(NR_MAC, "%s(): retransmission with TDA %d->%d and TBS %d -> %d\n", __func__, retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs);
|
||||
LOG_D(NR_MAC, "Retransmission with TDA %d->%d and TBS %d -> %d\n", retInfo->time_domain_allocation, tda, retInfo->tb_size, new_tbs);
|
||||
/* we can allocate it. Overwrite the time_domain_allocation, the number
|
||||
* of RBs, and the new TB size. The rest is done below */
|
||||
retInfo->tb_size = new_tbs;
|
||||
@@ -1715,7 +1718,9 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
|
||||
/* Find a free CCE */
|
||||
int CCEIndex = get_cce_index(nrmac,
|
||||
CC_id, slot, UE->rnti,
|
||||
CC_id,
|
||||
slot,
|
||||
UE->rnti,
|
||||
&sched_ctrl->aggregation_level,
|
||||
0, // TODO use beam index
|
||||
sched_ctrl->search_space,
|
||||
@@ -1723,10 +1728,7 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
false);
|
||||
if (CCEIndex<0) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot);
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] no free CCE for retransmission UL DCI UE\n", UE->rnti, frame, slot);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1738,11 +1740,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
sched_ctrl->aggregation_level,
|
||||
0); // TODO use beam index when implemented
|
||||
|
||||
/* frame/slot in sched_pusch has been set previously. In the following, we
|
||||
* overwrite the information in the retransmission information before storing
|
||||
* as the new scheduling instruction */
|
||||
retInfo->frame = sched_ctrl->sched_pusch.frame;
|
||||
retInfo->slot = sched_ctrl->sched_pusch.slot;
|
||||
retInfo->frame = (frame + (slot + tda_info.k2) / nr_slots_per_frame[ul_bwp->scs]) % MAX_FRAME_NUMBER;
|
||||
retInfo->slot = (slot + tda_info.k2) % nr_slots_per_frame[ul_bwp->scs];
|
||||
/* Get previous PSUCH field info */
|
||||
sched_ctrl->sched_pusch = *retInfo;
|
||||
NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
|
||||
@@ -1761,8 +1760,8 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
|
||||
|
||||
/* Mark the corresponding RBs as used */
|
||||
n_rb_sched -= sched_pusch->rbSize;
|
||||
for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
|
||||
for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1778,22 +1777,22 @@ static int comparator(const void *p, const void *q) {
|
||||
|
||||
static void pf_ul(module_id_t module_id,
|
||||
frame_t frame,
|
||||
sub_frame_t slot,
|
||||
int slot,
|
||||
frame_t sched_frame,
|
||||
int sched_slot,
|
||||
NR_UE_info_t *UE_list[],
|
||||
int max_num_ue,
|
||||
int n_rb_sched,
|
||||
uint16_t *rballoc_mask)
|
||||
int n_rb_sched)
|
||||
{
|
||||
|
||||
const int CC_id = 0;
|
||||
gNB_MAC_INST *nrmac = RC.nrmac[module_id];
|
||||
NR_ServingCellConfigCommon_t *scc = nrmac->common_channels[CC_id].ServingCellConfigCommon;
|
||||
|
||||
|
||||
const int min_rb = nrmac->min_grant_prb;
|
||||
// UEs that could be scheduled
|
||||
UEsched_t UE_sched[MAX_MOBILES_PER_GNB] = {0};
|
||||
int remainUEs = max_num_ue;
|
||||
int curUE=0;
|
||||
int curUE = 0;
|
||||
|
||||
/* Loop UE_list to calculate throughput and coeff */
|
||||
UE_iterator(UE_list, UE) {
|
||||
@@ -1805,9 +1804,6 @@ static void pf_ul(module_id_t module_id,
|
||||
LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti);
|
||||
NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
|
||||
|
||||
int rbStart = 0; // wrt BWP start
|
||||
|
||||
const uint16_t bwpSize = current_BWP->BWPSize;
|
||||
NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
|
||||
const NR_mac_dir_stats_t *stats = &UE->mac_stats.ul;
|
||||
|
||||
@@ -1819,12 +1815,16 @@ static void pf_ul(module_id_t module_id,
|
||||
if(remainUEs == 0)
|
||||
continue;
|
||||
|
||||
const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size);
|
||||
// TODO improve handling of beam in vrb_map (for now just using 0)
|
||||
uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE];
|
||||
|
||||
/* Check if retransmission is necessary */
|
||||
sched_pusch->ul_harq_pid = sched_ctrl->retrans_ul_harq.head;
|
||||
LOG_D(NR_MAC,"pf_ul: UE %04x harq_pid %d\n",UE->rnti,sched_pusch->ul_harq_pid);
|
||||
if (sched_pusch->ul_harq_pid >= 0) {
|
||||
/* Allocate retransmission*/
|
||||
const int tda = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
|
||||
const int tda = get_ul_tda(nrmac, scc, sched_frame, sched_slot);
|
||||
bool r = allocate_ul_retransmission(nrmac, frame, slot, rballoc_mask, &n_rb_sched, UE, sched_pusch->ul_harq_pid, scc, tda);
|
||||
if (!r) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] UL retransmission could not be allocated\n",
|
||||
@@ -1853,10 +1853,10 @@ static void pf_ul(module_id_t module_id,
|
||||
|
||||
const int B = max(0, sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes);
|
||||
/* preprocessor computed sched_frame/sched_slot */
|
||||
const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity);
|
||||
const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_frame, sched_slot, nrmac->ulsch_max_frame_inactivity);
|
||||
|
||||
LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no");
|
||||
if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) {
|
||||
if ((B == 0 && !do_sched) || nr_timer_is_active(&sched_ctrl->transm_interrupt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1892,7 +1892,7 @@ static void pf_ul(module_id_t module_id,
|
||||
}
|
||||
|
||||
sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_frame, sched_slot);
|
||||
sched_pusch->tda_info = get_ul_tda_info(current_BWP,
|
||||
sched_ctrl->coreset->controlResourceSetId,
|
||||
sched_ctrl->search_space->searchSpaceType->present,
|
||||
@@ -1904,13 +1904,20 @@ static void pf_ul(module_id_t module_id,
|
||||
&sched_pusch->tda_info,
|
||||
sched_pusch->nrOfLayers);
|
||||
|
||||
LOG_D(NR_MAC,"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n",
|
||||
min_rb, rbStart, sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data);
|
||||
int rbStart = 0; // wrt BWP start
|
||||
LOG_D(NR_MAC,
|
||||
"Looking for min_rb %d RBs, starting at %d num_dmrs_cdm_grps_no_data %d\n",
|
||||
min_rb,
|
||||
rbStart,
|
||||
sched_pusch->dmrs_info.num_dmrs_cdm_grps_no_data);
|
||||
const uint32_t bwpSize = current_BWP->BWPSize;
|
||||
const uint32_t bwpStart = current_BWP->BWPStart;
|
||||
const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap))
|
||||
rbStart++;
|
||||
if (rbStart + min_rb >= bwpSize) {
|
||||
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n",
|
||||
LOG_D(NR_MAC,
|
||||
"[UE %04x][%4d.%2d] could not allocate continuous UL data: no resources (rbStart %d, min_rb %d, bwpSize %d)\n",
|
||||
UE->rnti,
|
||||
frame,
|
||||
slot,
|
||||
@@ -1921,18 +1928,15 @@ static void pf_ul(module_id_t module_id,
|
||||
}
|
||||
|
||||
sched_ctrl->cce_index = CCEIndex;
|
||||
fill_pdcch_vrb_map(nrmac,
|
||||
CC_id,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
CCEIndex,
|
||||
sched_ctrl->aggregation_level,
|
||||
0); // TODO use beam index);
|
||||
fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index
|
||||
|
||||
NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
|
||||
sched_pusch->mcs = min(nrmac->min_grant_mcs, sched_pusch->mcs);
|
||||
update_ul_ue_R_Qm(sched_pusch->mcs, current_BWP->mcs_table, current_BWP->pusch_Config, &sched_pusch->R, &sched_pusch->Qm);
|
||||
sched_pusch->rbStart = rbStart;
|
||||
sched_pusch->rbSize = min_rb;
|
||||
sched_pusch->frame = sched_frame;
|
||||
sched_pusch->slot = sched_slot;
|
||||
sched_pusch->tb_size = nr_compute_tbs(sched_pusch->Qm,
|
||||
sched_pusch->R,
|
||||
sched_pusch->rbSize,
|
||||
@@ -1963,8 +1967,8 @@ static void pf_ul(module_id_t module_id,
|
||||
|
||||
/* Mark the corresponding RBs as used */
|
||||
n_rb_sched -= sched_pusch->rbSize;
|
||||
for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap;
|
||||
for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap;
|
||||
|
||||
remainUEs--;
|
||||
continue;
|
||||
@@ -1982,8 +1986,8 @@ static void pf_ul(module_id_t module_id,
|
||||
UE->ul_thr_ue,
|
||||
tbs,
|
||||
coeff_ue);
|
||||
UE_sched[curUE].coef=coeff_ue;
|
||||
UE_sched[curUE].UE=UE;
|
||||
UE_sched[curUE].coef = coeff_ue;
|
||||
UE_sched[curUE].UE = UE;
|
||||
curUE++;
|
||||
}
|
||||
|
||||
@@ -2018,7 +2022,7 @@ static void pf_ul(module_id_t module_id,
|
||||
NR_sched_pusch_t *sched_pusch = &sched_ctrl->sched_pusch;
|
||||
|
||||
sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_pusch->frame, sched_pusch->slot);
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, scc, sched_frame, sched_slot);
|
||||
sched_pusch->tda_info = get_ul_tda_info(current_BWP,
|
||||
sched_ctrl->coreset->controlResourceSetId,
|
||||
sched_ctrl->search_space->searchSpaceType->present,
|
||||
@@ -2030,14 +2034,19 @@ static void pf_ul(module_id_t module_id,
|
||||
&sched_pusch->tda_info,
|
||||
sched_pusch->nrOfLayers);
|
||||
|
||||
const int index = ul_buffer_index(sched_frame, sched_slot, current_BWP->scs, nrmac->vrb_map_UL_size);
|
||||
// TODO improve handling of beam in vrb_map (for now just using 0)
|
||||
uint16_t *rballoc_mask = &nrmac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE];
|
||||
|
||||
int rbStart = 0;
|
||||
const uint16_t slbitmap = SL_to_bitmap(sched_pusch->tda_info.startSymbolIndex, sched_pusch->tda_info.nrOfSymbols);
|
||||
const uint16_t bwpSize = current_BWP->BWPSize;
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart] & slbitmap) != slbitmap)
|
||||
const uint32_t bwpSize = current_BWP->BWPSize;
|
||||
const uint32_t bwpStart = current_BWP->BWPStart;
|
||||
while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap))
|
||||
rbStart++;
|
||||
sched_pusch->rbStart = rbStart;
|
||||
uint16_t max_rbSize = 1;
|
||||
while (rbStart + max_rbSize < bwpSize && (rballoc_mask[rbStart + max_rbSize] & slbitmap) == slbitmap)
|
||||
while (rbStart + max_rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + max_rbSize] & slbitmap))
|
||||
max_rbSize++;
|
||||
|
||||
if (rbStart + min_rb >= bwpSize || max_rbSize < min_rb) {
|
||||
@@ -2051,13 +2060,18 @@ static void pf_ul(module_id_t module_id,
|
||||
iterator++;
|
||||
continue;
|
||||
} else
|
||||
LOG_D(NR_MAC, "allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n", iterator->UE->rnti, rbStart, min_rb, max_rbSize, bwpSize);
|
||||
LOG_D(NR_MAC,
|
||||
"allocating UL data for RNTI %04x (rbStart %d, min_rb %d, max_rbSize %d, bwpSize %d)\n",
|
||||
iterator->UE->rnti,
|
||||
rbStart,
|
||||
min_rb,
|
||||
max_rbSize,
|
||||
bwpSize);
|
||||
|
||||
/* Calculate the current scheduling bytes */
|
||||
const int B = cmax(sched_ctrl->estimated_ul_buffer - sched_ctrl->sched_ul_bytes, 0);
|
||||
/* adjust rbSize and MCS according to PHR and BPRE */
|
||||
if(sched_ctrl->pcmax!=0 ||
|
||||
sched_ctrl->ph!=0) // verify if the PHR related parameter have been initialized
|
||||
if(sched_ctrl->pcmax != 0 || sched_ctrl->ph != 0) // verify if the PHR related parameter have been initialized
|
||||
nr_ue_max_mcs_min_rb(current_BWP->scs, sched_ctrl->ph, sched_pusch, current_BWP, min_rb, B, &max_rbSize, &sched_pusch->mcs);
|
||||
|
||||
if (sched_pusch->mcs < sched_ctrl->ul_bler_stats.mcs)
|
||||
@@ -2093,23 +2107,28 @@ static void pf_ul(module_id_t module_id,
|
||||
|
||||
sched_pusch->rbSize = rbSize;
|
||||
sched_pusch->tb_size = TBS;
|
||||
LOG_D(NR_MAC,"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n",
|
||||
rbSize, max_rbSize,sched_pusch->tb_size, sched_ctrl->estimated_ul_buffer, sched_ctrl->sched_ul_bytes, B,
|
||||
sched_ctrl->cce_index,sched_pusch->dmrs_info.num_dmrs_symb,sched_pusch->dmrs_info.N_PRB_DMRS);
|
||||
sched_pusch->frame = sched_frame;
|
||||
sched_pusch->slot = sched_slot;
|
||||
LOG_D(NR_MAC,
|
||||
"rbSize %d (max_rbSize %d), TBS %d, est buf %d, sched_ul %d, B %d, CCE %d, num_dmrs_symb %d, N_PRB_DMRS %d\n",
|
||||
rbSize,
|
||||
max_rbSize,
|
||||
sched_pusch->tb_size,
|
||||
sched_ctrl->estimated_ul_buffer,
|
||||
sched_ctrl->sched_ul_bytes,
|
||||
B,
|
||||
sched_ctrl->cce_index,
|
||||
sched_pusch->dmrs_info.num_dmrs_symb,
|
||||
sched_pusch->dmrs_info.N_PRB_DMRS);
|
||||
|
||||
/* Mark the corresponding RBs as used */
|
||||
|
||||
sched_ctrl->cce_index = CCEIndex;
|
||||
fill_pdcch_vrb_map(nrmac,
|
||||
CC_id,
|
||||
&sched_ctrl->sched_pdcch,
|
||||
CCEIndex,
|
||||
sched_ctrl->aggregation_level,
|
||||
0); // TODO use beam index);
|
||||
fill_pdcch_vrb_map(nrmac, CC_id, &sched_ctrl->sched_pdcch, CCEIndex, sched_ctrl->aggregation_level, 0); // TODO use beam index
|
||||
|
||||
n_rb_sched -= sched_pusch->rbSize;
|
||||
for (int rb = 0; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] ^= slbitmap;
|
||||
for (int rb = bwpStart; rb < sched_ctrl->sched_pusch.rbSize; rb++)
|
||||
rballoc_mask[rb + sched_ctrl->sched_pusch.rbStart] |= slbitmap;
|
||||
|
||||
/* reduce max_num_ue once we are sure UE can be allocated, i.e., has CCE */
|
||||
remainUEs--;
|
||||
@@ -2120,92 +2139,25 @@ static void pf_ul(module_id_t module_id,
|
||||
static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_frame_t slot)
|
||||
{
|
||||
gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
|
||||
NR_COMMON_channels_t *cc = nr_mac->common_channels;
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
|
||||
NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL;
|
||||
|
||||
AssertFatal(scc || scc_sib1, "We need one serving cell config common\n");
|
||||
|
||||
// no UEs
|
||||
if (nr_mac->UE_info.list[0] == NULL)
|
||||
return false;
|
||||
|
||||
const int CC_id = 0;
|
||||
|
||||
/* Get the K2 for first UE to compute offset. The other UEs are guaranteed to
|
||||
* have the same K2 (we don't support multiple/different K2s via different
|
||||
* TDAs yet). If the TDA is negative, it means that there is no UL slot to
|
||||
* schedule now (slot + k2 is not UL slot) */
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &nr_mac->UE_info.list[0]->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *current_BWP = &nr_mac->UE_info.list[0]->current_UL_BWP;
|
||||
int mu = current_BWP->scs;
|
||||
const int temp_tda = get_ul_tda(nr_mac, scc, frame, slot);
|
||||
NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList = get_ul_tdalist(current_BWP,
|
||||
sched_ctrl->coreset->controlResourceSetId,
|
||||
sched_ctrl->search_space->searchSpaceType->present,
|
||||
TYPE_C_RNTI_);
|
||||
int K2 = get_K2(tdaList, temp_tda, mu, scc);
|
||||
const int sched_frame = (frame + (slot + K2) / nr_slots_per_frame[mu]) % MAX_FRAME_NUMBER;
|
||||
const int sched_slot = (slot + K2) % nr_slots_per_frame[mu];
|
||||
const int tda = get_ul_tda(nr_mac, scc, sched_frame, sched_slot);
|
||||
if (tda < 0)
|
||||
return false;
|
||||
DevAssert(K2 == get_K2(tdaList, tda, mu, scc));
|
||||
|
||||
NR_COMMON_channels_t *cc = nr_mac->common_channels;
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
const NR_SIB1_t *sib1 = nr_mac->common_channels[0].sib1 ? nr_mac->common_channels[0].sib1->message.choice.c1->choice.systemInformationBlockType1 : NULL;
|
||||
NR_ServingCellConfigCommonSIB_t *scc_sib1 = sib1 ? sib1->servingCellConfigCommon : NULL;
|
||||
AssertFatal(scc || scc_sib1, "We need one serving cell config common\n");
|
||||
const int slots_frame = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
|
||||
// TODO we assume the same K2 for all UEs
|
||||
const int K2 = nr_mac->radio_config.minRXTXTIME + get_NTN_Koffset(scc);
|
||||
const int sched_frame = (frame + (slot + K2) / slots_frame) % MAX_FRAME_NUMBER;
|
||||
const int sched_slot = (slot + K2) % slots_frame;
|
||||
if (!is_xlsch_in_slot(nr_mac->ulsch_slot_bitmap[sched_slot / 64], sched_slot))
|
||||
return false;
|
||||
|
||||
sched_ctrl->sched_pusch.slot = sched_slot;
|
||||
sched_ctrl->sched_pusch.frame = sched_frame;
|
||||
UE_iterator(nr_mac->UE_info.list, UE2) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE2->UE_sched_ctrl;
|
||||
AssertFatal(K2 == get_K2(tdaList, tda, mu, scc),
|
||||
"Different K2, %d(UE%d) != %ld(UE%04x)\n",
|
||||
K2, 0, get_K2(tdaList, tda, mu, scc), UE2->rnti);
|
||||
sched_ctrl->sched_pusch.slot = sched_slot;
|
||||
sched_ctrl->sched_pusch.frame = sched_frame;
|
||||
}
|
||||
|
||||
/* Change vrb_map_UL to rballoc_mask: check which symbols per RB (in
|
||||
* vrb_map_UL) overlap with the "default" tda and exclude those RBs.
|
||||
* Calculate largest contiguous RBs */
|
||||
const int index = ul_buffer_index(sched_frame, sched_slot, mu, nr_mac->vrb_map_UL_size);
|
||||
// TODO improve handling of beam in vrb_map (for now just using 0)
|
||||
uint16_t *vrb_map_UL = &nr_mac->common_channels[CC_id].vrb_map_UL[0][index * MAX_BWP_SIZE];
|
||||
|
||||
const uint16_t bwpSize = current_BWP->BWPSize;
|
||||
const uint16_t bwpStart = current_BWP->BWPStart;
|
||||
|
||||
const int startSymbolAndLength = tdaList->list.array[tda]->startSymbolAndLength;
|
||||
int startSymbolIndex, nrOfSymbols;
|
||||
SLIV2SL(startSymbolAndLength, &startSymbolIndex, &nrOfSymbols);
|
||||
const uint16_t symb = SL_to_bitmap(startSymbolIndex, nrOfSymbols);
|
||||
|
||||
int st = 0, e = 0, len = 0;
|
||||
|
||||
for (int i = 0; i < bwpSize; i++) {
|
||||
while ((vrb_map_UL[bwpStart + i] & symb) != 0 && i < bwpSize)
|
||||
i++;
|
||||
st = i;
|
||||
while ((vrb_map_UL[bwpStart + i] & symb) == 0 && i < bwpSize)
|
||||
i++;
|
||||
if (i - st > len) {
|
||||
len = i - st;
|
||||
e = i - 1;
|
||||
}
|
||||
}
|
||||
st = e - len + 1;
|
||||
|
||||
LOG_D(NR_MAC,"UL %d.%d : start_prb %d, end PRB %d\n",frame,slot,st,e);
|
||||
|
||||
uint16_t rballoc_mask[bwpSize];
|
||||
|
||||
/* Calculate mask: if any RB in vrb_map_UL is blocked (1), the current RB will be 0 */
|
||||
for (int i = 0; i < bwpSize; i++)
|
||||
rballoc_mask[i] = (i >= st && i <= e)*SL_to_bitmap(startSymbolIndex, nrOfSymbols);
|
||||
|
||||
int bw = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
|
||||
|
||||
int average_agg_level = 4; // TODO find a better estimation
|
||||
int max_sched_ues = bw / (average_agg_level * NR_NB_REG_PER_CCE);
|
||||
|
||||
@@ -2213,13 +2165,7 @@ static bool nr_fr1_ulsch_preprocessor(module_id_t module_id, frame_t frame, sub_
|
||||
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);
|
||||
|
||||
/* proportional fair scheduling algorithm */
|
||||
pf_ul(module_id,
|
||||
frame,
|
||||
slot,
|
||||
nr_mac->UE_info.list,
|
||||
max_sched_ues,
|
||||
len,
|
||||
rballoc_mask);
|
||||
pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, bw);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,8 +53,11 @@ void nr_mac_configure_sib19(gNB_MAC_INST *nrmac);
|
||||
bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup);
|
||||
bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup);
|
||||
|
||||
int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs);
|
||||
|
||||
bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup);
|
||||
int nr_mac_enable_ue_rrc_processing_timer(gNB_MAC_INST *mac, NR_UE_info_t *UE, bool apply_cellGroup);
|
||||
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots);
|
||||
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info);
|
||||
|
||||
void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
|
||||
int CC_idP,
|
||||
@@ -461,10 +464,11 @@ void nr_mac_trigger_release_timer(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierS
|
||||
bool nr_mac_check_release(NR_UE_sched_ctrl_t *sched_ctrl, int rnti);
|
||||
void nr_mac_trigger_release_complete(gNB_MAC_INST *mac, int rnti);
|
||||
void nr_mac_release_ue(gNB_MAC_INST *mac, int rnti);
|
||||
bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti);
|
||||
|
||||
void nr_mac_trigger_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl, NR_SubcarrierSpacing_t subcarrier_spacing);
|
||||
void nr_mac_reset_ul_failure(NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
void nr_mac_check_ul_failure(const gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
void nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
|
||||
void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE);
|
||||
|
||||
@@ -474,4 +478,6 @@ void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c);
|
||||
bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid);
|
||||
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti);
|
||||
|
||||
#endif /*__LAYER2_NR_MAC_PROTO_H__*/
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "openair2/F1AP/f1ap_common.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "F1AP_CauseRadioNetwork.h"
|
||||
#include "NR_HandoverPreparationInformation.h"
|
||||
#include "openair3/ocp-gtpu/gtp_itf.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "lib/f1ap_interface_management.h"
|
||||
@@ -172,8 +173,6 @@ void f1_setup_response(const f1ap_setup_resp_t *resp)
|
||||
AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n");
|
||||
// Copy F1AP message
|
||||
*mac->f1_config.setup_resp = cp_f1ap_setup_response(resp);
|
||||
// free F1AP message after copy
|
||||
free_f1ap_setup_response(resp);
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
// NOTE: Before accepting any UEs, we should initialize the UE states.
|
||||
@@ -237,8 +236,16 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE,
|
||||
(*resp_srbs)[i].srb_id = srb->srb_id;
|
||||
(*resp_srbs)[i].lcid = c.lcid;
|
||||
|
||||
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
|
||||
DevAssert(ret == 0);
|
||||
if (rlc_BearerConfig->logicalChannelIdentity == 1) {
|
||||
// CU asks to add SRB1: when creating a cellGroupConfig, we always add it
|
||||
// (see get_initial_cellGroupConfig())
|
||||
const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = cellGroupConfig->rlc_BearerToAddModList;
|
||||
DevAssert(addmod->list.count >= 1 && addmod->list.array[0]->logicalChannelIdentity == 1);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, rlc_BearerConfig);
|
||||
} else {
|
||||
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
}
|
||||
return srbs_len;
|
||||
}
|
||||
@@ -375,6 +382,33 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE,
|
||||
return drbs_len;
|
||||
}
|
||||
|
||||
static NR_UE_NR_Capability_t *get_nr_cap(const NR_UE_CapabilityRAT_ContainerList_t *clist)
|
||||
{
|
||||
for (int i = 0; i < clist->list.count; i++) {
|
||||
const NR_UE_CapabilityRAT_Container_t *c = clist->list.array[i];
|
||||
if (c->rat_Type != NR_RAT_Type_nr) {
|
||||
LOG_W(NR_MAC, "ignoring capability of type %ld\n", c->rat_Type);
|
||||
continue;
|
||||
}
|
||||
|
||||
NR_UE_NR_Capability_t *cap = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL,
|
||||
&asn_DEF_NR_UE_NR_Capability,
|
||||
(void **)&cap,
|
||||
c->ue_CapabilityRAT_Container.buf,
|
||||
c->ue_CapabilityRAT_Container.size,
|
||||
0,
|
||||
0);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_W(NR_MAC, "cannot decode NR UE capability, ignoring\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, cap);
|
||||
continue;
|
||||
}
|
||||
return cap;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (buf == NULL || len == 0)
|
||||
@@ -387,27 +421,37 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap(int rnti, uint8_t *buf, uint32_t len
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NR_UE_NR_Capability_t *cap = NULL;
|
||||
for (int i = 0; i < clist->list.count; i++) {
|
||||
const NR_UE_CapabilityRAT_Container_t *c = clist->list.array[i];
|
||||
if (cap != NULL || c->rat_Type != NR_RAT_Type_nr) {
|
||||
LOG_W(NR_MAC, "UE RNTI %04x: ignoring capability of type %ld\n", rnti, c->rat_Type);
|
||||
continue;
|
||||
}
|
||||
NR_UE_NR_Capability_t *cap = get_nr_cap(clist);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist);
|
||||
return cap;
|
||||
}
|
||||
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL,
|
||||
&asn_DEF_NR_UE_NR_Capability,
|
||||
(void **)&cap,
|
||||
c->ue_CapabilityRAT_Container.buf,
|
||||
c->ue_CapabilityRAT_Container.size,
|
||||
0,
|
||||
0);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_W(NR_MAC, "cannot decode NR UE capabilities of UE RNTI %04x, ignoring NR capability\n", rnti);
|
||||
cap = NULL;
|
||||
continue;
|
||||
}
|
||||
/* \brief return UE capabilties from HandoverPreparationInformation.
|
||||
*
|
||||
* The HandoverPreparationInformation contains more, but for the moment, let's
|
||||
* keep it simple and only handle that. The function asserts if other IEs are
|
||||
* present. */
|
||||
static NR_UE_NR_Capability_t *get_ue_nr_cap_from_ho_prep_info(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (buf == NULL || len == 0)
|
||||
return NULL;
|
||||
NR_HandoverPreparationInformation_t *hpi = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_HandoverPreparationInformation, (void **)&hpi, buf, len);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_W(NR_MAC, "cannot decode HandoverPreparationInformation, ignoring capabilities\n");
|
||||
return NULL;
|
||||
}
|
||||
NR_UE_NR_Capability_t *cap = NULL;
|
||||
if (hpi->criticalExtensions.present != NR_HandoverPreparationInformation__criticalExtensions_PR_c1
|
||||
|| hpi->criticalExtensions.choice.c1 == NULL
|
||||
|| hpi->criticalExtensions.choice.c1->present
|
||||
!= NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation
|
||||
|| hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation == NULL) {
|
||||
} else {
|
||||
const NR_HandoverPreparationInformation_IEs_t *hpi_ie = hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation;
|
||||
cap = get_nr_cap(&hpi_ie->ue_CapabilityRAT_List);
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
return cap;
|
||||
}
|
||||
|
||||
@@ -423,6 +467,40 @@ NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig)
|
||||
return cloned;
|
||||
}
|
||||
|
||||
static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id)
|
||||
{
|
||||
int CC_id = 0;
|
||||
const NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||
rnti_t rnti;
|
||||
bool found = nr_mac_get_new_rnti(&mac->UE_info, cc->ra, sizeofArray(cc->ra), &rnti);
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
NR_UE_info_t* UE = add_new_nr_ue(mac, rnti, NULL);
|
||||
if (!UE)
|
||||
return NULL;
|
||||
|
||||
f1_ue_data_t new_ue_data = {.secondary_ue = cu_id};
|
||||
du_add_f1_ue_data(rnti, &new_ue_data);
|
||||
|
||||
const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon;
|
||||
const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig;
|
||||
NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config);
|
||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc);
|
||||
// note: we don't pass the cellGroupConfig to add_new_nr_ue() because we need
|
||||
// the uid to create the CellGroupConfig (which is in the UE context created
|
||||
// by add_new_nr_ue(); it's a kind of chicken-and-egg problem), so below we
|
||||
// complete the UE context with the information that add_new_nr_ue() would
|
||||
// have added
|
||||
UE->Msg4_MsgB_ACKed = true;
|
||||
UE->CellGroup = cellGroupConfig;
|
||||
|
||||
nr_rlc_activate_srb0(UE->rnti, UE, NULL);
|
||||
nr_mac_prepare_ra_ue(mac, rnti, UE->CellGroup);
|
||||
/* SRB1 is added to RLC and MAC in the handler later */
|
||||
return UE;
|
||||
}
|
||||
|
||||
void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
@@ -432,19 +510,34 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
.gNB_DU_ue_id = req->gNB_DU_ue_id,
|
||||
};
|
||||
|
||||
/* gNB-DU UE ID is optional. As of now, the F1AP module fills -1 (on uint, so
|
||||
* 0xffffffff), but the DU uses the RNTI, so check if it's a legal RNTI in
|
||||
* which case we consider; if not, assume no DU UE ID given */
|
||||
bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff;
|
||||
|
||||
NR_UE_NR_Capability_t *ue_cap = NULL;
|
||||
if (req->cu_to_du_rrc_information != NULL) {
|
||||
AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n");
|
||||
ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id,
|
||||
req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList,
|
||||
req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList_length);
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL, "MeasConfig not handled\n");
|
||||
const cu_to_du_rrc_information_t *cu2du = req->cu_to_du_rrc_information;
|
||||
AssertFatal(cu2du->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n");
|
||||
if (cu2du->handoverPreparationInfo != NULL) {
|
||||
ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length);
|
||||
} else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) {
|
||||
ue_cap = get_ue_nr_cap(req->gNB_DU_ue_id, cu2du->uE_CapabilityRAT_ContainerList, cu2du->uE_CapabilityRAT_ContainerList_length);
|
||||
}
|
||||
AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n");
|
||||
}
|
||||
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&RC.nrmac[0]->UE_info, req->gNB_DU_ue_id);
|
||||
AssertFatal(UE, "did not find UE with RNTI %04x, but UE Context Setup Failed not implemented\n", req->gNB_DU_ue_id);
|
||||
NR_UE_info_t *UE = NULL;
|
||||
if (!ue_id_provided) {
|
||||
UE = create_new_UE(mac, req->gNB_CU_ue_id);
|
||||
resp.gNB_DU_ue_id = UE->rnti;
|
||||
resp.crnti = &UE->rnti;
|
||||
} else {
|
||||
UE = find_nr_UE(&mac->UE_info, req->gNB_DU_ue_id);
|
||||
}
|
||||
AssertFatal(UE, "no UE found or could not be created, but UE Context Setup Failed not implemented\n");
|
||||
|
||||
NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup);
|
||||
|
||||
@@ -476,6 +569,14 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc);
|
||||
}
|
||||
|
||||
if (!ue_id_provided) {
|
||||
/* new UE: tell the UE to reestablish RLC */
|
||||
struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = new_CellGroup->rlc_BearerToAddModList;
|
||||
for (int i = 0; i < addmod->list.count; ++i) {
|
||||
asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true);
|
||||
}
|
||||
}
|
||||
|
||||
resp.du_to_cu_rrc_information = calloc(1, sizeof(du_to_cu_rrc_information_t));
|
||||
AssertFatal(resp.du_to_cu_rrc_information != NULL, "out of memory\n");
|
||||
resp.du_to_cu_rrc_information->cellGroupConfig = calloc(1,1024);
|
||||
@@ -588,6 +689,11 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
|
||||
} else {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it
|
||||
}
|
||||
|
||||
if (req->transm_action_ind != NULL) {
|
||||
AssertFatal(*req->transm_action_ind == TransmActionInd_STOP, "Transmission Action Indicator restart not handled yet\n");
|
||||
nr_transmission_action_indicator_stop(mac, UE);
|
||||
}
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
/* some sanity checks, since we use the same type for request and response */
|
||||
@@ -728,7 +834,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
|
||||
* the CellGroupConfig. Below, we trigger a timer, and the CellGroupConfig
|
||||
* will be applied after its expiry in nr_mac_apply_cellgroup().*/
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
nr_mac_enable_ue_rrc_processing_timer(mac, UE, /* apply_cellGroup = */ true);
|
||||
int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs);
|
||||
nr_mac_interrupt_ue_transmission(mac, UE, FOLLOW_INSYNC_RECONFIG, delay);
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
UE->expect_reconfiguration = false;
|
||||
/* Re-establish RLC for all remaining bearers */
|
||||
|
||||
@@ -112,6 +112,10 @@ static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, c
|
||||
for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i)
|
||||
f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i];
|
||||
}
|
||||
if (resp->crnti) {
|
||||
f1ap_msg->crnti = calloc(1, sizeof(uint16_t));
|
||||
*f1ap_msg->crnti = *resp->crnti;
|
||||
}
|
||||
|
||||
f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information));
|
||||
AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n");
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include "common/utils/ds/seq_arr.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
|
||||
#define NR_SCHED_LOCK(lock) \
|
||||
do { \
|
||||
@@ -664,8 +665,8 @@ typedef struct {
|
||||
NR_list_t retrans_ul_harq;
|
||||
NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl; // MAC CE related information
|
||||
|
||||
/// Timer for RRC processing procedures
|
||||
uint32_t rrc_processing_timer;
|
||||
/// Timer for RRC processing procedures and transmission activity
|
||||
NR_timer_t transm_interrupt;
|
||||
|
||||
/// sri, ul_ri and tpmi based on SRS
|
||||
nr_srs_feedback_t srs_feedback;
|
||||
@@ -738,6 +739,8 @@ typedef struct nr_mac_rrc_ul_if_s {
|
||||
initial_ul_rrc_message_transfer_func_t initial_ul_rrc_message_transfer;
|
||||
} nr_mac_rrc_ul_if_t;
|
||||
|
||||
typedef enum interrupt_followup_action { FOLLOW_INSYNC, FOLLOW_INSYNC_RECONFIG, FOLLOW_OUTOFSYNC } interrupt_followup_action_t;
|
||||
|
||||
/*! \brief UE list used by gNB to order UEs/CC for scheduling*/
|
||||
typedef struct {
|
||||
rnti_t rnti;
|
||||
@@ -756,7 +759,7 @@ typedef struct {
|
||||
/// reestablishRLC has to be signaled in RRCreconfiguration
|
||||
bool reestablish_rlc;
|
||||
NR_CellGroupConfig_t *reconfigCellGroup;
|
||||
bool apply_cellgroup;
|
||||
interrupt_followup_action_t interrupt_action;
|
||||
NR_UE_NR_Capability_t *capability;
|
||||
// UE selected beam index
|
||||
uint8_t UE_beam_index;
|
||||
|
||||
@@ -157,6 +157,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
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];
|
||||
AssertFatal(req_drb->numQosFlow2Setup == 1, "can only handle one QoS Flow per DRB\n");
|
||||
DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[0];
|
||||
resp_drb->id = req_drb->id;
|
||||
resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
|
||||
@@ -168,7 +169,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
|
||||
// GTP tunnel for N3/to core
|
||||
gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0};
|
||||
int qfi = 0; // put PDU session marker
|
||||
int qfi = req_drb->qosFlows[0].qfi;
|
||||
int ret = drb_gtpu_create(n3inst,
|
||||
cu_up_ue_id,
|
||||
req_drb->id,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "LOG/log.h"
|
||||
#include "common/utils/time_stat.h"
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
/* for a given SDU/SDU segment, computes the corresponding PDU header size */
|
||||
static int compute_pdu_header_size(nr_rlc_entity_am_t *entity,
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
#include "NR_PCCH-Message.h"
|
||||
#include "NR_PagingRecord.h"
|
||||
#include "NR_UE-CapabilityRequestFilterNR.h"
|
||||
#include "NR_HandoverPreparationInformation.h"
|
||||
#include "NR_HandoverPreparationInformation-IEs.h"
|
||||
#include "common/utils/nr/nr_common.h"
|
||||
#if defined(NR_Rel16)
|
||||
#include "NR_SCS-SpecificCarrier.h"
|
||||
@@ -1373,3 +1375,42 @@ int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi)
|
||||
|
||||
return((enc_rval.encoded+7)/8);
|
||||
}
|
||||
|
||||
/* \brief generate HandoverPreparationInformation to be sent to the DU for
|
||||
* handover. Takes uecap_buf in encoded form as (1) this is the form present at
|
||||
* the CU already (2) we have to clone this information anyway, so can take it
|
||||
* in encoded form which we decode + add to the handoverPreparationInformation */
|
||||
int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf_size, uint8_t *buf, int buf_size)
|
||||
{
|
||||
NR_HandoverPreparationInformation_t *hpi = calloc(1, sizeof(*hpi));
|
||||
AssertFatal(hpi != NULL, "out of memory\n");
|
||||
hpi->criticalExtensions.present = NR_HandoverPreparationInformation__criticalExtensions_PR_c1;
|
||||
hpi->criticalExtensions.choice.c1 = calloc(1, sizeof(*hpi->criticalExtensions.choice.c1));
|
||||
AssertFatal(hpi->criticalExtensions.choice.c1 != NULL, "out of memory\n");
|
||||
hpi->criticalExtensions.choice.c1->present =
|
||||
NR_HandoverPreparationInformation__criticalExtensions__c1_PR_handoverPreparationInformation;
|
||||
NR_HandoverPreparationInformation_IEs_t *hpi_ie = calloc(1, sizeof(*hpi_ie));
|
||||
AssertFatal(hpi_ie != NULL, "out of memory\n");
|
||||
hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation = hpi_ie;
|
||||
|
||||
NR_UE_CapabilityRAT_ContainerList_t *list = NULL;
|
||||
asn_dec_rval_t dec_rval =
|
||||
uper_decode_complete(NULL, &asn_DEF_NR_UE_CapabilityRAT_ContainerList, (void **)&list, uecap_buf, uecap_buf_size);
|
||||
if (dec_rval.code == RC_OK) {
|
||||
hpi_ie->ue_CapabilityRAT_List = *list;
|
||||
free(list); /* list itself is not needed, members below will be freed in ASN_STRUCT_FREE */
|
||||
} else {
|
||||
/* problem with decoding, don't put a capability */
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, list);
|
||||
list = NULL;
|
||||
}
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_HandoverPreparationInformation, NULL, hpi, buf, buf_size);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
return (enc_rval.encoded + 7) / 8;
|
||||
}
|
||||
|
||||
@@ -109,6 +109,8 @@ int do_RRCSetupComplete(uint8_t *buffer,
|
||||
const int dedicatedInfoNASLength,
|
||||
const char *dedicatedInfoNAS);
|
||||
|
||||
int do_NR_HandoverPreparationInformation(const uint8_t *uecap_buf, int uecap_buf_size, uint8_t *buf, int buf_size);
|
||||
|
||||
int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv);
|
||||
|
||||
int do_NR_RRCReconfigurationComplete_for_nsa(uint8_t *buffer, size_t buffer_size, NR_RRC_TransactionIdentifier_t Transaction_id);
|
||||
|
||||
@@ -79,8 +79,8 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c
|
||||
AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information;
|
||||
if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) {
|
||||
const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information;
|
||||
cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0);
|
||||
du2cu_new->uE_CapabilityRAT_ContainerList_length = du2cu_req->uE_CapabilityRAT_ContainerList_length;
|
||||
@@ -88,6 +88,13 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c
|
||||
AssertFatal(du2cu_new->uE_CapabilityRAT_ContainerList != NULL, "out of memory\n");
|
||||
memcpy(du2cu_new->uE_CapabilityRAT_ContainerList, du2cu_req->uE_CapabilityRAT_ContainerList, du2cu_new->uE_CapabilityRAT_ContainerList_length);
|
||||
}
|
||||
if (req->cu_to_du_rrc_information->handoverPreparationInfo != NULL) {
|
||||
cu_to_du_rrc_information_t *du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
DevAssert(du2cu_req->handoverPreparationInfo_length > 0);
|
||||
du2cu_new->handoverPreparationInfo_length = du2cu_req->handoverPreparationInfo_length;
|
||||
du2cu_new->handoverPreparationInfo = malloc_or_fail(du2cu_new->handoverPreparationInfo_length);
|
||||
memcpy(du2cu_new->handoverPreparationInfo, du2cu_req->handoverPreparationInfo, du2cu_new->handoverPreparationInfo_length);
|
||||
}
|
||||
}
|
||||
if (req->drbs_to_be_setup_length > 0) {
|
||||
int n = req->drbs_to_be_setup_length;
|
||||
@@ -161,6 +168,11 @@ static void ue_context_modification_request_f1ap(sctp_assoc_t assoc_id, const f1
|
||||
f1ap_msg->rrc_container_length = req->rrc_container_length;
|
||||
memcpy(f1ap_msg->rrc_container, req->rrc_container, req->rrc_container_length);
|
||||
}
|
||||
if (req->transm_action_ind != NULL) {
|
||||
f1ap_msg->transm_action_ind = malloc(sizeof *f1ap_msg->transm_action_ind);
|
||||
AssertFatal(f1ap_msg->transm_action_ind != NULL, "out of memory\n");
|
||||
*f1ap_msg->transm_action_ind = *req->transm_action_ind;
|
||||
}
|
||||
itti_send_msg_to_task(TASK_CU_F1, 0, msg);
|
||||
}
|
||||
|
||||
|
||||
@@ -3293,46 +3293,8 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync =
|
||||
calloc(1, sizeof(*secondaryCellGroup->spCellConfig->reconfigurationWithSync));
|
||||
|
||||
NR_ReconfigurationWithSync_t *reconfigurationWithSync = secondaryCellGroup->spCellConfig->reconfigurationWithSync;
|
||||
reconfigurationWithSync->spCellConfigCommon = clone_ServingCellConfigCommon(servingcellconfigcommon);
|
||||
reconfigurationWithSync->newUE_Identity =
|
||||
(get_softmodem_params()->phy_test == 1) ? 0x1234 : (taus() & 0xffff);
|
||||
reconfigurationWithSync->t304 = NR_ReconfigurationWithSync__t304_ms2000;
|
||||
reconfigurationWithSync->rach_ConfigDedicated = NULL;
|
||||
reconfigurationWithSync->ext1 = NULL;
|
||||
|
||||
// For 2-step contention-free random access procedure
|
||||
reconfigurationWithSync->rach_ConfigDedicated = calloc(1, sizeof(*reconfigurationWithSync->rach_ConfigDedicated));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->present = NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink;
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink = calloc(1, sizeof(struct NR_RACH_ConfigDedicated));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra = calloc(1, sizeof(struct NR_CFRA));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->ra_Prioritization = NULL;
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions));
|
||||
memcpy(&reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->rach_ConfigGeneric,
|
||||
&servingcellconfigcommon->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric,
|
||||
sizeof(NR_RACH_ConfigGeneric_t));
|
||||
asn1cCallocOne(reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->occasions->ssb_perRACH_Occasion,
|
||||
NR_CFRA__occasions__ssb_perRACH_Occasion_one);
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb;
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb =
|
||||
calloc(1, sizeof(struct NR_CFRA__resources__ssb));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0;
|
||||
|
||||
int n_ssb = 0;
|
||||
struct NR_CFRA_SSB_Resource *ssbElem[64];
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if ((bitmap >> (63 - i)) & 0x01) {
|
||||
ssbElem[n_ssb] = calloc(1, sizeof(struct NR_CFRA_SSB_Resource));
|
||||
ssbElem[n_ssb]->ssb = i;
|
||||
ssbElem[n_ssb]->ra_PreambleIndex = 63 - (uid % 64);
|
||||
asn1cSeqAdd(&secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources
|
||||
.choice.ssb->ssb_ResourceList.list,
|
||||
ssbElem[n_ssb]);
|
||||
n_ssb++;
|
||||
}
|
||||
}
|
||||
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->ext1 = NULL;
|
||||
rnti_t rnti = get_softmodem_params()->phy_test == 1 ? 0x1234 : (taus() & 0xffff);
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, servingcellconfigcommon);
|
||||
|
||||
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants =
|
||||
calloc(1, sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants));
|
||||
@@ -3602,3 +3564,43 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
}
|
||||
return secondaryCellGroup;
|
||||
}
|
||||
|
||||
NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc)
|
||||
{
|
||||
NR_ReconfigurationWithSync_t *reconfigurationWithSync = calloc(1, sizeof(*reconfigurationWithSync));
|
||||
reconfigurationWithSync->newUE_Identity = rnti;
|
||||
reconfigurationWithSync->t304 = NR_ReconfigurationWithSync__t304_ms2000;
|
||||
reconfigurationWithSync->rach_ConfigDedicated = NULL;
|
||||
reconfigurationWithSync->ext1 = NULL;
|
||||
|
||||
reconfigurationWithSync->spCellConfigCommon = clone_ServingCellConfigCommon(scc);
|
||||
|
||||
reconfigurationWithSync->rach_ConfigDedicated = calloc(1, sizeof(*reconfigurationWithSync->rach_ConfigDedicated));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->present = NR_ReconfigurationWithSync__rach_ConfigDedicated_PR_uplink;
|
||||
NR_RACH_ConfigDedicated_t *uplink = calloc(1, sizeof(*uplink));
|
||||
reconfigurationWithSync->rach_ConfigDedicated->choice.uplink = uplink;
|
||||
uplink->ra_Prioritization = NULL;
|
||||
uplink->cfra = calloc(1, sizeof(struct NR_CFRA));
|
||||
uplink->cfra->ext1 = NULL;
|
||||
uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions));
|
||||
memcpy(&uplink->cfra->occasions->rach_ConfigGeneric,
|
||||
&scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric,
|
||||
sizeof(NR_RACH_ConfigGeneric_t));
|
||||
asn1cCallocOne(uplink->cfra->occasions->ssb_perRACH_Occasion, NR_CFRA__occasions__ssb_perRACH_Occasion_one);
|
||||
uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb;
|
||||
uplink->cfra->resources.choice.ssb = calloc(1, sizeof(struct NR_CFRA__resources__ssb));
|
||||
uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0;
|
||||
|
||||
uint64_t bitmap = get_ssb_bitmap(scc);
|
||||
for (int i = 0; i < 64; i++) {
|
||||
if (((bitmap >> (63 - i)) & 0x01) == 0)
|
||||
continue;
|
||||
|
||||
NR_CFRA_SSB_Resource_t *ssbElem = calloc(1, sizeof(*ssbElem));
|
||||
ssbElem->ssb = i;
|
||||
ssbElem->ra_PreambleIndex = 63 - (uid % 64);
|
||||
asn1cSeqAdd(&uplink->cfra->resources.choice.ssb->ssb_ResourceList.list, ssbElem);
|
||||
}
|
||||
|
||||
return reconfigurationWithSync;
|
||||
}
|
||||
|
||||
@@ -102,4 +102,6 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
const nr_mac_config_t *configuration,
|
||||
int uid);
|
||||
|
||||
NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -69,14 +69,6 @@
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
/* TODO: be sure this include is correct.
|
||||
* It solves a problem of compilation of the RRH GW,
|
||||
* issue #186.
|
||||
*/
|
||||
#include "as_message.h"
|
||||
|
||||
#include "commonDef.h"
|
||||
|
||||
#define PROTOCOL_NR_RRC_CTXT_UE_FMT PROTOCOL_CTXT_FMT
|
||||
#define PROTOCOL_NR_RRC_CTXT_UE_ARGS(CTXT_Pp) PROTOCOL_NR_CTXT_ARGS(CTXT_Pp)
|
||||
|
||||
@@ -120,23 +112,6 @@ typedef struct nr_e_rab_param_s {
|
||||
uint8_t xid; // transaction_id
|
||||
} __attribute__ ((__packed__)) nr_e_rab_param_t;
|
||||
|
||||
|
||||
typedef struct HANDOVER_INFO_NR_s {
|
||||
uint8_t ho_prepare;
|
||||
uint8_t ho_complete;
|
||||
uint8_t modid_s; //module_idP of serving cell
|
||||
uint8_t modid_t; //module_idP of target cell
|
||||
uint8_t ueid_s; //UE index in serving cell
|
||||
uint8_t ueid_t; //UE index in target cell
|
||||
|
||||
// NR not define at this moment
|
||||
//AS_Config_t as_config; /* these two parameters are taken from 36.331 section 10.2.2: HandoverPreparationInformation-r8-IEs */
|
||||
//AS_Context_t as_context; /* They are mandatory for HO */
|
||||
|
||||
uint8_t buf[NR_RRC_BUF_SIZE]; /* ASN.1 encoded handoverCommandMessage */
|
||||
int size; /* size of above message in bytes */
|
||||
} NR_HANDOVER_INFO;
|
||||
|
||||
typedef struct nr_rrc_guami_s {
|
||||
uint16_t mcc;
|
||||
uint16_t mnc;
|
||||
@@ -222,6 +197,9 @@ typedef enum {
|
||||
RRC_UECAPABILITY_ENQUIRY,
|
||||
} rrc_action_t;
|
||||
|
||||
/* forward declaration */
|
||||
typedef struct nr_handover_context_s nr_handover_context_t;
|
||||
|
||||
typedef struct gNB_RRC_UE_s {
|
||||
time_t last_seen; // last time this UE has been accessed
|
||||
|
||||
@@ -230,7 +208,7 @@ typedef struct gNB_RRC_UE_s {
|
||||
|
||||
NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB];
|
||||
NR_MeasConfig_t *measConfig;
|
||||
NR_HANDOVER_INFO *handover_info;
|
||||
nr_handover_context_t *ho_context;
|
||||
NR_MeasResults_t *measResults;
|
||||
|
||||
bool as_security_active;
|
||||
|
||||
@@ -130,4 +130,7 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc,
|
||||
int n_rel_drbs,
|
||||
const f1ap_drb_to_be_released_t *rel_drbs);
|
||||
|
||||
pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession);
|
||||
f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param);
|
||||
|
||||
#endif
|
||||
|
||||
+268
-78
@@ -77,6 +77,7 @@
|
||||
|
||||
#include "rrc_gNB_NGAP.h"
|
||||
#include "rrc_gNB_du.h"
|
||||
#include "rrc_gNB_mobility.h"
|
||||
|
||||
#include "rrc_gNB_GTPV1U.h"
|
||||
|
||||
@@ -98,6 +99,7 @@
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
|
||||
#include "openair2/E1AP/e1ap.h"
|
||||
#include "cucp_cuup_if.h"
|
||||
#include "lib/f1ap_interface_management.h"
|
||||
|
||||
#include "BIT_STRING.h"
|
||||
#include "assertions.h"
|
||||
@@ -112,16 +114,6 @@ extern RAN_CONTEXT_t RC;
|
||||
|
||||
mui_t rrc_gNB_mui = 0;
|
||||
|
||||
// the assoc_id might be 0 (if the DU goes offline). Below helper macro to
|
||||
// print an error and return from the function in that case
|
||||
#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \
|
||||
{ \
|
||||
if (assoc_id == 0) { \
|
||||
LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
|
||||
@@ -481,6 +473,60 @@ static void rrc_gNB_process_RRCSetupComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
rrc_gNB_send_NGAP_NAS_FIRST_REQ(rrc, UE, rrcSetupComplete);
|
||||
}
|
||||
|
||||
static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
uint8_t xid,
|
||||
struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *nas_messages,
|
||||
uint8_t *buf,
|
||||
int max_len,
|
||||
bool reestablish)
|
||||
{
|
||||
NR_CellGroupConfig_t *cellGroupConfig = UE->masterCellGroup;
|
||||
nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id);
|
||||
DevAssert(du != NULL);
|
||||
f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||
NR_MeasConfig_t *measconfig = NULL;
|
||||
if (du->mtc != NULL) {
|
||||
int scs = get_ssb_scs(cell_info);
|
||||
int band = get_dl_band(cell_info);
|
||||
const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
|
||||
const NR_MeasTiming_t *mt = mtlist->list.array[0];
|
||||
const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid);
|
||||
seq_arr_t *neighbour_cells = NULL;
|
||||
if (neighbour_config)
|
||||
neighbour_cells = neighbour_config->neighbour_cells;
|
||||
|
||||
measconfig = get_MeasConfig(mt, band, scs, &rrc->measurementConfiguration, neighbour_cells);
|
||||
}
|
||||
|
||||
if (UE->measConfig)
|
||||
free_MeasConfig(UE->measConfig);
|
||||
|
||||
UE->measConfig = measconfig;
|
||||
|
||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, reestablish);
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, reestablish);
|
||||
|
||||
int size = do_RRCReconfiguration(UE,
|
||||
buf,
|
||||
max_len,
|
||||
xid,
|
||||
SRBs,
|
||||
DRBs,
|
||||
UE->DRB_ReleaseList,
|
||||
NULL,
|
||||
measconfig,
|
||||
nas_messages,
|
||||
cellGroupConfig);
|
||||
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buf, size, "[MSG] RRC Reconfiguration\n");
|
||||
freeSRBlist(SRBs);
|
||||
freeDRBlist(DRBs);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, UE->DRB_ReleaseList);
|
||||
UE->DRB_ReleaseList = NULL;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
{
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
@@ -517,51 +563,10 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_
|
||||
for (int i = 0; i < ue_p->nb_of_pdusessions; i++)
|
||||
clear_nas_pdu(&ue_p->pduSession[i].param.nas_pdu);
|
||||
|
||||
NR_CellGroupConfig_t *cellGroupConfig = ue_p->masterCellGroup;
|
||||
|
||||
const nr_rrc_du_container_t *du = get_du_for_ue(rrc, ue_p->rrc_ue_id);
|
||||
DevAssert(du != NULL);
|
||||
f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||
NR_MeasConfig_t *measconfig = NULL;
|
||||
|
||||
if (du->mtc != NULL) {
|
||||
int scs = get_ssb_scs(cell_info);
|
||||
int band = get_dl_band(cell_info);
|
||||
const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
|
||||
const NR_MeasTiming_t *mt = mtlist->list.array[0];
|
||||
const neighbour_cell_configuration_t *neighbour_config = get_neighbour_config(cell_info->nr_cellid);
|
||||
seq_arr_t *neighbour_cells = NULL;
|
||||
if (neighbour_config)
|
||||
neighbour_cells = neighbour_config->neighbour_cells;
|
||||
|
||||
measconfig = get_MeasConfig(mt, band, scs, &rrc->measurementConfiguration, neighbour_cells);
|
||||
}
|
||||
|
||||
if (ue_p->measConfig)
|
||||
free_MeasConfig(ue_p->measConfig);
|
||||
|
||||
ue_p->measConfig = measconfig;
|
||||
|
||||
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
|
||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false);
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false);
|
||||
|
||||
int size = do_RRCReconfiguration(ue_p,
|
||||
buffer,
|
||||
NR_RRC_BUF_SIZE,
|
||||
xid,
|
||||
SRBs,
|
||||
DRBs,
|
||||
ue_p->DRB_ReleaseList,
|
||||
NULL,
|
||||
measconfig,
|
||||
dedicatedNAS_MessageList,
|
||||
cellGroupConfig);
|
||||
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n");
|
||||
freeSRBlist(SRBs);
|
||||
freeDRBlist(DRBs);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, ue_p->DRB_ReleaseList);
|
||||
ue_p->DRB_ReleaseList = NULL;
|
||||
// TODO refactor dedicatedNAS_MessageList
|
||||
int size = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, xid, dedicatedNAS_MessageList, buffer, sizeof(buffer), false);
|
||||
DevAssert(size > 0 && size <= sizeof(buffer));
|
||||
|
||||
LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d, xid %d)\n", ue_p->rrc_ue_id, size, xid);
|
||||
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size);
|
||||
@@ -905,6 +910,17 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR
|
||||
NR_RLC_BearerConfig__reestablishRLC_true);
|
||||
}
|
||||
|
||||
/* TODO: remove a reconfigurationWithSync, we don't need it for
|
||||
* reestablishment. The whole reason why this might be here is that we store
|
||||
* the CellGroupConfig (after handover), and simply reuse it for
|
||||
* reestablishment, instead of re-requesting the CellGroupConfig from the DU.
|
||||
* Hence, add below hack; the solution would be to request the
|
||||
* CellGroupConfig from the DU when doing reestablishment. */
|
||||
if (cellGroupConfig->spCellConfig->reconfigurationWithSync != NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cellGroupConfig->spCellConfig->reconfigurationWithSync);
|
||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = NULL;
|
||||
}
|
||||
|
||||
/* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331
|
||||
* (SRB1 is re-established with RRCReestablishment message)
|
||||
*/
|
||||
@@ -1026,9 +1042,18 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
|
||||
return;
|
||||
}
|
||||
|
||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
||||
&asn_DEF_NR_CellGroupConfig,
|
||||
(void **)&cellGroupConfig,
|
||||
msg->du2cu_rrc_container,
|
||||
msg->du2cu_rrc_container_length);
|
||||
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n");
|
||||
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
UE = &ue_context_p->ue_context;
|
||||
UE->establishment_cause = rrcSetupRequest->establishmentCause;
|
||||
UE->masterCellGroup = cellGroupConfig;
|
||||
activate_srb(UE, 1);
|
||||
rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length);
|
||||
}
|
||||
@@ -1048,6 +1073,20 @@ static const char *get_reestab_cause(NR_ReestablishmentCause_t c)
|
||||
return "UNKNOWN Failure (ASN.1 decoder error?)";
|
||||
}
|
||||
|
||||
static rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_source_cell(gNB_RRC_INST *rrc_instance_pP, long pci, rnti_t rntiP)
|
||||
{
|
||||
rrc_gNB_ue_context_t *ue_context_p;
|
||||
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head) {
|
||||
gNB_RRC_UE_t *ue = &ue_context_p->ue_context;
|
||||
if (!ue->ho_context || !ue->ho_context->source)
|
||||
continue;
|
||||
nr_ho_source_cu_t *source_ctx = ue->ho_context->source;
|
||||
if (source_ctx->old_rnti == rntiP && source_ctx->du->setup_req->cell[0].info.nr_pci == pci)
|
||||
return ue_context_p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
|
||||
sctp_assoc_t assoc_id,
|
||||
const NR_RRCReestablishmentRequest_IEs_t *req,
|
||||
@@ -1058,7 +1097,12 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
|
||||
const long physCellId = req->ue_Identity.physCellId;
|
||||
long ngap_cause = NGAP_CAUSE_RADIO_NETWORK_UNSPECIFIED; /* cause in case of NGAP release req */
|
||||
rrc_gNB_ue_context_t *ue_context_p = NULL;
|
||||
LOG_I(NR_RRC, "UE %04x physCellId %ld NR_RRCReestablishmentRequest cause %s\n", msg->crnti, physCellId, scause);
|
||||
LOG_I(NR_RRC,
|
||||
"Reestablishment RNTI %04x req C-RNTI %04lx physCellId %ld cause %s\n",
|
||||
msg->crnti,
|
||||
req->ue_Identity.c_RNTI,
|
||||
physCellId,
|
||||
scause);
|
||||
|
||||
const nr_rrc_du_container_t *du = get_du_by_assoc_id(rrc, assoc_id);
|
||||
if (du == NULL) {
|
||||
@@ -1093,13 +1137,47 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
|
||||
rnti_t old_rnti = req->ue_Identity.c_RNTI;
|
||||
ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti);
|
||||
if (ue_context_p == NULL) {
|
||||
LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n");
|
||||
goto fallback_rrc_setup;
|
||||
ue_context_p = rrc_gNB_get_ue_context_source_cell(rrc, physCellId, old_rnti);
|
||||
if (ue_context_p == NULL) {
|
||||
LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n");
|
||||
goto fallback_rrc_setup;
|
||||
}
|
||||
}
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
|
||||
/* should check phys cell ID to identify the correct cell */
|
||||
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||
if (physCellId != cell_info->nr_pci) {
|
||||
const f1ap_served_cell_info_t *previous_cell_info = get_cell_information_by_phycellId(physCellId);
|
||||
|
||||
nr_ho_source_cu_t *source_ctx = UE->ho_context ? UE->ho_context->source : NULL;
|
||||
DevAssert(!source_ctx || source_ctx->du->setup_req->num_cells_available == 1);
|
||||
bool ho_reestab_on_source = source_ctx && previous_cell_info->nr_cellid == source_ctx->du->setup_req->cell[0].info.nr_cellid;
|
||||
|
||||
if (ho_reestab_on_source) {
|
||||
/* the UE came back on the source DU while doing handover, release at
|
||||
* target DU and and update the association to the initial DU one */
|
||||
LOG_W(NR_RRC, "handover for UE %d/RNTI %04x failed, rollback to original cell\n", UE->rrc_ue_id, UE->rnti);
|
||||
|
||||
// find the transaction of handover (the corresponding reconfig) and abort it
|
||||
for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) {
|
||||
if (UE->xids[i] == RRC_DEDICATED_RECONF)
|
||||
UE->xids[i] = RRC_ACTION_NONE;
|
||||
}
|
||||
|
||||
source_ctx->ho_cancel(rrc, UE);
|
||||
|
||||
/* we need the original CellGroupConfig */
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
UE->masterCellGroup = source_ctx->old_cellGroupConfig;
|
||||
source_ctx->old_cellGroupConfig = NULL;
|
||||
|
||||
/* update to old DU assoc id -- RNTI + secondary DU UE ID further below */
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
ue_data.du_assoc_id = source_ctx->du->assoc_id;
|
||||
cu_remove_f1_ue_data(UE->rrc_ue_id);
|
||||
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
} else if (physCellId != cell_info->nr_pci) {
|
||||
/* UE was moving from previous cell so quickly that RRCReestablishment for previous cell was received in this cell */
|
||||
LOG_I(NR_RRC,
|
||||
"RRC Reestablishment Request from different physCellId (%ld) than current physCellId (%d), fallback to RRC setup\n",
|
||||
@@ -1159,7 +1237,7 @@ static void process_Periodical_Measurement_Report(gNB_RRC_UE_t *ue_ctxt, NR_Meas
|
||||
measurementReport->criticalExtensions.choice.measurementReport = NULL;
|
||||
}
|
||||
|
||||
static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report, NR_MeasurementReport_t *measurementReport)
|
||||
static void process_Event_Based_Measurement_Report(gNB_RRC_UE_t *ue, NR_ReportConfigNR_t *report, NR_MeasurementReport_t *measurementReport)
|
||||
{
|
||||
NR_EventTriggerConfig_t *event_triggered = report->reportType.choice.eventTriggered;
|
||||
|
||||
@@ -1173,7 +1251,7 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
|
||||
break;
|
||||
|
||||
case NR_EventTriggerConfig__eventId_PR_eventA3: {
|
||||
LOG_I(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n");
|
||||
LOG_W(NR_RRC, "HO LOG: Event A3 Report - Neighbour Becomes Better than Serving!\n");
|
||||
const NR_MeasResults_t *measResults = &measurementReport->criticalExtensions.choice.measurementReport->measResults;
|
||||
|
||||
for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) {
|
||||
@@ -1212,13 +1290,13 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
|
||||
neighbourCellId,
|
||||
neighbourCellRSRP);
|
||||
|
||||
const f1ap_served_cell_info_t *neighbour_cell_du_context = get_cell_information_by_phycellId(neighbourCellId);
|
||||
const f1ap_served_cell_info_t *serving_cell_du_context = get_cell_information_by_phycellId(servingCellId);
|
||||
const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbourCellId);
|
||||
const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(servingCellId);
|
||||
const nr_neighbour_gnb_configuration_t *neighbour =
|
||||
get_neighbour_cell_information(serving_cell_du_context->nr_cellid, neighbourCellId);
|
||||
get_neighbour_cell_information(serving_cell->nr_cellid, neighbourCellId);
|
||||
// CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a
|
||||
// neighbour.
|
||||
if (!neighbour_cell_du_context && neighbour) {
|
||||
if (!neigh_cell && neighbour) {
|
||||
// No F1 connection but static neighbour configuration is available
|
||||
const nr_a3_event_t *a3_event_configuration = get_a3_configuration(neighbour->physicalCellId);
|
||||
// Additional check - This part can be modified according to additional cell specific Handover Margin
|
||||
@@ -1227,6 +1305,15 @@ static void process_Event_Based_Measurement_Report(NR_ReportConfigNR_t *report,
|
||||
< (neighbourCellRSRP - servingCellRSRP))) {
|
||||
LOG_D(NR_RRC, "HO LOG: Trigger N2 HO for the neighbour gnb: %u cell: %lu\n", neighbour->gNB_ID, neighbour->nrcell_id);
|
||||
}
|
||||
} else if (neigh_cell && neighbour) {
|
||||
/* we know the cell and are connected to the DU! */
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
nr_rrc_du_container_t *source_du = get_du_by_cell_id(rrc, serving_cell->nr_cellid);
|
||||
DevAssert(source_du);
|
||||
nr_rrc_du_container_t *target_du = get_du_by_cell_id(rrc, neigh_cell->nr_cellid);
|
||||
nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du);
|
||||
} else {
|
||||
LOG_W(NR_RRC, "UE %d: received A3 event for stronger neighbor PCI %d, but no such neighbour in configuration\n", ue->rrc_ue_id, neighbourCellId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1288,12 +1375,10 @@ static void rrc_gNB_process_MeasurementReport(gNB_RRC_UE_t *UE, NR_MeasurementRe
|
||||
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_periodical)
|
||||
return process_Periodical_Measurement_Report(UE, measurementReport);
|
||||
|
||||
if (report_config->choice.reportConfigNR->reportType.present != NR_ReportConfigNR__reportType_PR_eventTriggered) {
|
||||
LOG_D(NR_RRC, "Incoming Report Type: %d is not supported! \n", report_config->choice.reportConfigNR->reportType.present);
|
||||
return;
|
||||
}
|
||||
if (report_config->choice.reportConfigNR->reportType.present == NR_ReportConfigNR__reportType_PR_eventTriggered)
|
||||
return process_Event_Based_Measurement_Report(UE, report_config->choice.reportConfigNR, measurementReport);
|
||||
|
||||
process_Event_Based_Measurement_Report(report_config->choice.reportConfigNR, measurementReport);
|
||||
LOG_E(NR_RRC, "Incoming Report Type: %d is not supported! \n", report_config->choice.reportConfigNR->reportType.present);
|
||||
}
|
||||
|
||||
static int handle_rrcReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_RRCReestablishmentComplete_t *cplt)
|
||||
@@ -1545,6 +1630,14 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
|
||||
LOG_I(RRC, "UE %d: transaction %d still ongoing for action %d\n", UE->rrc_ue_id, i, UE->xids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (UE->ho_context != NULL) {
|
||||
LOG_A(NR_RRC, "handover for UE %d/RNTI %04x complete!\n", UE->rrc_ue_id, UE->rnti);
|
||||
DevAssert(UE->ho_context->target != NULL);
|
||||
|
||||
UE->ho_context->target->ho_success(rrc, UE);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
}
|
||||
|
||||
static void rrc_gNB_generate_UECapabilityEnquiry(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue)
|
||||
@@ -1838,27 +1931,80 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
|
||||
if (resp->drbs_to_be_setup_length > 0) {
|
||||
int num_drb = get_number_active_drbs(UE);
|
||||
DevAssert(num_drb == 0 || num_drb == resp->drbs_to_be_setup_length);
|
||||
|
||||
/* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU
|
||||
* seems buggy and does not ack, so simply check that locally we activated */
|
||||
AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment");
|
||||
store_du_f1u_tunnel(resp->drbs_to_be_setup, resp->drbs_to_be_setup_length, UE);
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup);
|
||||
if (num_drb == 0)
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup);
|
||||
else
|
||||
cuup_notify_reestablishment(rrc, UE);
|
||||
}
|
||||
|
||||
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
|
||||
if (UE->ho_context == NULL) {
|
||||
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
|
||||
} else {
|
||||
// case of handover
|
||||
// handling of "target CU" information
|
||||
DevAssert(UE->ho_context->target != NULL);
|
||||
DevAssert(resp->crnti != NULL);
|
||||
UE->ho_context->target->du_ue_id = resp->gNB_DU_ue_id;
|
||||
UE->ho_context->target->new_rnti = *resp->crnti;
|
||||
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(0);
|
||||
UE->xids[xid] = RRC_DEDICATED_RECONF;
|
||||
uint8_t buffer[NR_RRC_BUF_SIZE] = {0};
|
||||
int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true);
|
||||
DevAssert(size > 0 && size <= sizeof(buffer));
|
||||
|
||||
// TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to
|
||||
// Source Transparent Container (9.3.1.21) which encodes the RRC
|
||||
// reconfiguration above
|
||||
UE->ho_context->target->ho_req_ack(rrc, UE, buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p)
|
||||
static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_assoc_t assoc_id)
|
||||
{
|
||||
const int instance = 0;
|
||||
f1ap_ue_context_release_req_t *req = &F1AP_UE_CONTEXT_RELEASE_REQ(msg_p);
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[instance];
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id);
|
||||
// TODO what happens if no AMF connected? should also handle, set an_release true
|
||||
if (!ue_context_p) {
|
||||
LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id);
|
||||
// TODO just request the DU to release to make it happy
|
||||
return;
|
||||
}
|
||||
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
if (UE->ho_context != NULL) {
|
||||
nr_ho_source_cu_t *source_ctx = UE->ho_context->source;
|
||||
bool from_source_du = source_ctx && source_ctx->du->assoc_id == assoc_id;
|
||||
if (from_source_du) {
|
||||
// we received release request from the source DU, but HO is still
|
||||
// ongoing; free the UE, and remove the HO context.
|
||||
LOG_W(NR_RRC, "UE %d: release request from source DU ID %ld during HO, marking HO as complete\n", UE->rrc_ue_id, source_ctx->du->setup_req->gNB_DU_id);
|
||||
RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id);
|
||||
f1ap_ue_context_release_cmd_t cmd = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = source_ctx->du_ue_id,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure
|
||||
.srb_id = DCCH,
|
||||
};
|
||||
rrc->mac_rrc.ue_context_release_command(assoc_id, &cmd);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
return;
|
||||
}
|
||||
// if we receive the release request from the target DU (regardless if
|
||||
// successful), we assume it is "genuine" and ask the AMF to release
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
|
||||
/* TODO: marshall types correctly */
|
||||
LOG_I(NR_RRC, "received UE Context Release Request for UE %u, forwarding to AMF\n", req->gNB_CU_ue_id);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(instance,
|
||||
@@ -1944,9 +2090,27 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
|
||||
|
||||
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
|
||||
}
|
||||
|
||||
// Reconfiguration should have been sent to the UE, so it will attempt the
|
||||
// handover. In the F1 case, update with new RNTI, and update secondary UE
|
||||
// association, so we can receive the new UE from the target DU (in N2/Xn,
|
||||
// nothing is to be done, we wait for confirmation to release the UE in the
|
||||
// CU/DU)
|
||||
if (UE->ho_context && UE->ho_context->target && UE->ho_context->source) {
|
||||
nr_ho_target_cu_t *target_ctx = UE->ho_context->target;
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
ue_data.secondary_ue = target_ctx->du_ue_id;
|
||||
ue_data.du_assoc_id = target_ctx->du->assoc_id;
|
||||
cu_remove_f1_ue_data(UE->rrc_ue_id);
|
||||
cu_add_f1_ue_data(UE->rrc_ue_id, &ue_data);
|
||||
LOG_I(NR_RRC, "UE %d handover: update RNTI from %04x to %04x\n", UE->rrc_ue_id, UE->rnti, target_ctx->new_rnti);
|
||||
nr_ho_source_cu_t *source_ctx = UE->ho_context->source;
|
||||
DevAssert(source_ctx->old_rnti == UE->rnti);
|
||||
UE->rnti = target_ctx->new_rnti;
|
||||
}
|
||||
}
|
||||
|
||||
static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_t instance)
|
||||
static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_t instance, sctp_assoc_t assoc_id)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[instance];
|
||||
f1ap_ue_context_modif_required_t *required = &F1AP_UE_CONTEXT_MODIFICATION_REQUIRED(msg_p);
|
||||
@@ -1963,6 +2127,12 @@ static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_
|
||||
return;
|
||||
}
|
||||
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
if (UE->ho_context && UE->ho_context->source && UE->ho_context->source->du && UE->ho_context->source->du->assoc_id == assoc_id) {
|
||||
LOG_W(NR_RRC, "UE %d: UE Context Modification Required during handover, ignoring message\n", UE->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (required->du_to_cu_rrc_information && required->du_to_cu_rrc_information->cellGroupConfig) {
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
LOG_I(RRC,
|
||||
@@ -2010,7 +2180,7 @@ unsigned int mask_flip(unsigned int x) {
|
||||
return((((x>>8) + (x<<8))&0xffff)>>6);
|
||||
}
|
||||
|
||||
static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession)
|
||||
pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession)
|
||||
{
|
||||
pdusession_t *pdu = &pduSession->param;
|
||||
for (int i = 0; i < pdu->nb_qos; i++) {
|
||||
@@ -2022,7 +2192,7 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi,
|
||||
}
|
||||
|
||||
/* \bref return F1AP QoS characteristics based on Qos flow parameters */
|
||||
static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param)
|
||||
f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param)
|
||||
{
|
||||
f1ap_qos_characteristics_t qos_char = {0};
|
||||
if (qos_param->fiveQI_type == DYNAMIC) {
|
||||
@@ -2181,6 +2351,24 @@ static void print_rrc_meas(FILE *f, const NR_MeasResults_t *measresults)
|
||||
} else {
|
||||
fprintf(f, "NOT PROVIDED\n");
|
||||
}
|
||||
|
||||
if (measresults->measResultNeighCells
|
||||
&& measresults->measResultNeighCells->present == NR_MeasResults__measResultNeighCells_PR_measResultListNR) {
|
||||
NR_MeasResultListNR_t *meas_neigh = measresults->measResultNeighCells->choice.measResultListNR;
|
||||
for (int i = 0; i < meas_neigh->list.count; ++i) {
|
||||
NR_MeasResultNR_t *measresultneigh = meas_neigh->list.array[i];
|
||||
NR_MeasQuantityResults_t *neigh_mqr = measresultneigh->measResult.cellResults.resultsSSB_Cell;
|
||||
fprintf(f, " neighboring cell for phyCellId %ld:\n resultSSB:", *measresultneigh->physCellId);
|
||||
if (mqr != NULL) {
|
||||
const long rrsrp = *neigh_mqr->rsrp - 156;
|
||||
const float rrsrq = (float)(*neigh_mqr->rsrq - 87) / 2.0f;
|
||||
const float rsinr = (float)(*neigh_mqr->sinr - 46) / 2.0f;
|
||||
fprintf(f, "RSRP %ld dBm RSRQ %.1f dB SINR %.1f dB\n", rrsrp, rrsrq, rsinr);
|
||||
} else {
|
||||
fprintf(f, "NOT PROVIDED\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_pdusession_status_text(pdu_session_status_t status)
|
||||
@@ -2309,7 +2497,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
/* From DU -> CU */
|
||||
case F1AP_UL_RRC_MESSAGE:
|
||||
rrc_gNB_decode_dcch(RC.nrrrc[instance], &F1AP_UL_RRC_MESSAGE(msg_p));
|
||||
free(F1AP_UL_RRC_MESSAGE(msg_p).rrc_container);
|
||||
free_ul_rrc_message_transfer(&F1AP_UL_RRC_MESSAGE(msg_p));
|
||||
break;
|
||||
|
||||
case NGAP_DOWNLINK_NAS:
|
||||
@@ -2332,6 +2520,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
case F1AP_SETUP_REQ:
|
||||
AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n");
|
||||
rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p), msg_p->ittiMsgHeader.originInstance);
|
||||
free_f1ap_setup_request(&F1AP_SETUP_REQ(msg_p));
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_SETUP_RESP:
|
||||
@@ -2343,11 +2532,11 @@ void *rrc_gnb_task(void *args_p) {
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_MODIFICATION_REQUIRED:
|
||||
rrc_CU_process_ue_modification_required(msg_p, instance);
|
||||
rrc_CU_process_ue_modification_required(msg_p, instance, msg_p->ittiMsgHeader.originInstance);
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_RELEASE_REQ:
|
||||
rrc_CU_process_ue_context_release_request(msg_p);
|
||||
rrc_CU_process_ue_context_release_request(msg_p, msg_p->ittiMsgHeader.originInstance);
|
||||
break;
|
||||
|
||||
case F1AP_UE_CONTEXT_RELEASE_COMPLETE:
|
||||
@@ -2361,6 +2550,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
case F1AP_GNB_DU_CONFIGURATION_UPDATE:
|
||||
AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n");
|
||||
rrc_gNB_process_f1_du_configuration_update(&F1AP_GNB_DU_CONFIGURATION_UPDATE(msg_p), msg_p->ittiMsgHeader.originInstance);
|
||||
free_f1ap_du_configuration_update(&F1AP_GNB_DU_CONFIGURATION_UPDATE(msg_p));
|
||||
break;
|
||||
|
||||
case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "common/ran_context.h"
|
||||
#include "nr_rrc_defs.h"
|
||||
#include "rrc_gNB_UE_context.h"
|
||||
#include "rrc_gNB_mobility.h"
|
||||
#include "openair2/F1AP/f1ap_common.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
@@ -383,8 +384,6 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id,
|
||||
.num_cells_to_activate = 1,
|
||||
.cells_to_activate[0] = cell};
|
||||
// free F1AP message after use
|
||||
free_f1ap_setup_request(req);
|
||||
int num = read_version(TO_STRING(NR_RRC_VERSION), &resp.rrc_ver[0], &resp.rrc_ver[1], &resp.rrc_ver[2]);
|
||||
AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION));
|
||||
if (rrc->node_name != NULL)
|
||||
@@ -397,7 +396,12 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
int count = 0;
|
||||
rrc_gNB_ue_context_t *ue_context_p = NULL;
|
||||
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
|
||||
uint32_t ue_id = ue_context_p->ue_context.rrc_ue_id;
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
uint32_t ue_id = UE->rrc_ue_id;
|
||||
if (UE->ho_context != NULL) {
|
||||
LOG_W(NR_RRC, "DU disconnected while handover for UE %d active\n", ue_id);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||
if (ue_data.du_assoc_id == assoc_id) {
|
||||
/* this UE belongs to the DU that disconnected, set du_assoc_id to 0,
|
||||
@@ -561,6 +565,18 @@ nr_rrc_du_container_t *get_du_by_assoc_id(gNB_RRC_INST *rrc, sctp_assoc_t assoc_
|
||||
return RB_FIND(rrc_du_tree, &rrc->dus, &e);
|
||||
}
|
||||
|
||||
/* \brief find DU by cell ID. Note: currently the CU is limited to one cell per
|
||||
* DU, hence here, DU == cell. Modify this to look up a specific cell. */
|
||||
nr_rrc_du_container_t *get_du_by_cell_id(gNB_RRC_INST *rrc, uint64_t cell_id)
|
||||
{
|
||||
nr_rrc_du_container_t *du = NULL;
|
||||
RB_FOREACH(du, rrc_du_tree, &rrc->dus) {
|
||||
if (cell_id == du->setup_req->cell[0].info.nr_cellid)
|
||||
return du;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dump_du_info(const gNB_RRC_INST *rrc, FILE *f)
|
||||
{
|
||||
fprintf(f, "%ld connected DUs \n", rrc->num_dus);
|
||||
@@ -592,3 +608,31 @@ void dump_du_info(const gNB_RRC_INST *rrc, FILE *f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nr_rrc_du_container_t *find_target_du(gNB_RRC_INST *rrc, sctp_assoc_t source_assoc_id)
|
||||
{
|
||||
nr_rrc_du_container_t *target_du = NULL;
|
||||
nr_rrc_du_container_t *it = NULL;
|
||||
bool next_du = false;
|
||||
RB_FOREACH (it, rrc_du_tree, &rrc->dus) {
|
||||
if (next_du == false && source_assoc_id != it->assoc_id) {
|
||||
continue;
|
||||
} else if (source_assoc_id == it->assoc_id) {
|
||||
next_du = true;
|
||||
} else {
|
||||
target_du = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target_du == NULL) {
|
||||
RB_FOREACH (it, rrc_du_tree, &rrc->dus) {
|
||||
if (source_assoc_id == it->assoc_id) {
|
||||
continue;
|
||||
} else {
|
||||
target_du = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return target_du;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration
|
||||
struct nr_rrc_du_container_t *get_du_for_ue(struct gNB_RRC_INST_s *rrc, uint32_t ue_id);
|
||||
struct nr_rrc_du_container_t *get_du_by_assoc_id(struct gNB_RRC_INST_s *rrc, sctp_assoc_t assoc_id);
|
||||
const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyCellId);
|
||||
struct nr_rrc_du_container_t *get_du_by_cell_id(struct gNB_RRC_INST_s *rrc, uint64_t cell_id);
|
||||
|
||||
void dump_du_info(const struct gNB_RRC_INST_s *rrc, FILE *f);
|
||||
|
||||
@@ -48,4 +49,16 @@ int get_dl_band(const struct f1ap_served_cell_info_t *cell_info);
|
||||
int get_ssb_scs(const struct f1ap_served_cell_info_t *cell_info);
|
||||
int get_ssb_arfcn(const struct nr_rrc_du_container_t *du);
|
||||
|
||||
struct nr_rrc_du_container_t *find_target_du(struct gNB_RRC_INST_s *rrc, sctp_assoc_t source_assoc_id);
|
||||
|
||||
// the assoc_id might be 0 (if the DU goes offline). Below helper macro to
|
||||
// print an error and return from the function in that case
|
||||
#define RETURN_IF_INVALID_ASSOC_ID(assoc_id) \
|
||||
{ \
|
||||
if (assoc_id == 0) { \
|
||||
LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n"); \
|
||||
return; \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* RRC_GNB_DU_H_ */
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
* 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 <stdlib.h>
|
||||
|
||||
#include "assertions.h"
|
||||
|
||||
#include "rrc_gNB_mobility.h"
|
||||
|
||||
#include "nr_rrc_proto.h"
|
||||
#include "rrc_gNB_du.h"
|
||||
#include "rrc_gNB_radio_bearers.h"
|
||||
#include "rrc_gNB_UE_context.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "MESSAGES/asn1_msg.h"
|
||||
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
|
||||
/* declared in rrc_gNB.c: should be cleaned up through helper function? useful? */
|
||||
extern mui_t rrc_gNB_mui;
|
||||
|
||||
typedef enum { HO_CTX_BOTH, HO_CTX_SOURCE, HO_CTX_TARGET } ho_ctx_type_t;
|
||||
static nr_handover_context_t *alloc_ho_ctx(ho_ctx_type_t type)
|
||||
{
|
||||
nr_handover_context_t *ho_ctx = calloc(1, sizeof(*ho_ctx));
|
||||
AssertFatal(ho_ctx != NULL, "out of memory\n");
|
||||
if (type == HO_CTX_SOURCE || type == HO_CTX_BOTH) {
|
||||
ho_ctx->source = calloc(1, sizeof(*ho_ctx->source));
|
||||
AssertFatal(ho_ctx->source != NULL, "out of memory\n");
|
||||
}
|
||||
if (type == HO_CTX_TARGET || type == HO_CTX_BOTH) {
|
||||
ho_ctx->target = calloc(1, sizeof(*ho_ctx->target));
|
||||
AssertFatal(ho_ctx->target != NULL, "out of memory\n");
|
||||
}
|
||||
return ho_ctx;
|
||||
}
|
||||
|
||||
static void free_ho_ctx(nr_handover_context_t *ho_ctx)
|
||||
{
|
||||
free(ho_ctx->source);
|
||||
free(ho_ctx->target);
|
||||
free(ho_ctx);
|
||||
}
|
||||
|
||||
/* \brief Initiate a handover of UE to a specific target cell handled by this
|
||||
* CU.
|
||||
* \param ue a UE context for which the handover should be triggered. The UE
|
||||
* context must be non-null (if the HO request comes from "outside" (N2, Xn),
|
||||
* the UE contex must be created first.
|
||||
* \param target_du the DU towards which to handover. Note: currently, the CU
|
||||
* is limited to one cell per DU, so DU and cell are equivalent here.
|
||||
* \param ho_ctxt contextual data for the type of handover (F1, N2, Xn) */
|
||||
static void nr_initiate_handover(const gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *ue,
|
||||
const nr_rrc_du_container_t *source_du,
|
||||
const nr_rrc_du_container_t *target_du,
|
||||
uint8_t *ho_prep_buf,
|
||||
uint32_t ho_prep_len,
|
||||
ho_req_ack_t ack,
|
||||
ho_success_t success,
|
||||
ho_cancel_t cancel)
|
||||
{
|
||||
DevAssert(rrc != NULL);
|
||||
DevAssert(ue != NULL);
|
||||
DevAssert(target_du != NULL);
|
||||
// source_du might be NULL -> inter-CU handover
|
||||
DevAssert(ho_prep_buf != NULL && ho_prep_len > 0);
|
||||
|
||||
if (ue->ho_context != NULL) {
|
||||
LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
// if any reconfiguration is ongoing, abort handover request
|
||||
for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) {
|
||||
if (ue->xids[i] != RRC_ACTION_NONE) {
|
||||
LOG_E(NR_RRC, "UE %d: ongoig transaction %d (action %d), cannot trigger handover\n", ue->rrc_ue_id, i, ue->xids[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we know the source DU (F1 handover), allocate the context for it,
|
||||
// otherwise only for the target DU (N2, Xn)
|
||||
ho_ctx_type_t ctx_type = source_du != NULL ? HO_CTX_BOTH : HO_CTX_TARGET;
|
||||
nr_handover_context_t *ho_ctx = alloc_ho_ctx(ctx_type);
|
||||
ho_ctx->target->du = target_du;
|
||||
// we will know target->{du_ue_id,new_rnti} once we have UE ctxt setup
|
||||
// response
|
||||
ho_ctx->target->ho_req_ack = ack;
|
||||
ho_ctx->target->ho_success = success;
|
||||
|
||||
const f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
|
||||
if (source_du != NULL) {
|
||||
DevAssert(source_du->assoc_id == ue_data.du_assoc_id);
|
||||
// we also have the source DU (F1 handover), store meta info
|
||||
ho_ctx->source->ho_cancel = cancel;
|
||||
|
||||
ho_ctx->source->du = source_du;
|
||||
ho_ctx->source->du_ue_id = ue_data.secondary_ue;
|
||||
ho_ctx->source->old_rnti = ue->rnti;
|
||||
|
||||
int result = asn_copy(&asn_DEF_NR_CellGroupConfig, (void **)&ho_ctx->source->old_cellGroupConfig, ue->masterCellGroup);
|
||||
AssertFatal(result == 0, "error during asn_copy() of CellGroupConfig\n");
|
||||
}
|
||||
ue->ho_context = ho_ctx;
|
||||
LOG_A(NR_RRC,
|
||||
"Handover triggered for UE %u/RNTI %04x towards DU %ld/assoc_id %d/PCI %d\n",
|
||||
ue->rrc_ue_id,
|
||||
ue->rnti,
|
||||
target_du->setup_req->gNB_DU_id,
|
||||
target_du->assoc_id,
|
||||
target_du->setup_req->cell[0].info.nr_pci);
|
||||
|
||||
cu_to_du_rrc_information_t cu2du = {
|
||||
.handoverPreparationInfo = ho_prep_buf,
|
||||
.handoverPreparationInfo_length = ho_prep_len,
|
||||
};
|
||||
|
||||
f1ap_drb_to_be_setup_t drbs[32] = {0}; // maximum DRB can be 32
|
||||
int nb_drb = 0;
|
||||
for (int i = 0; i < 32; ++i) { /* for each DRB */
|
||||
drb_t *rrc_drb = &ue->established_drbs[i];
|
||||
if (rrc_drb->status == DRB_INACTIVE)
|
||||
continue;
|
||||
|
||||
f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb];
|
||||
nb_drb++;
|
||||
drb->drb_id = rrc_drb->drb_id;
|
||||
drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM;
|
||||
memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
|
||||
drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
|
||||
drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid;
|
||||
drb->up_ul_tnl_length = 1;
|
||||
|
||||
/* fetch an existing PDU session for this DRB */
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb->drb_id);
|
||||
AssertFatal(pdu != NULL, "no PDU session for DRB ID %ld\n", drb->drb_id);
|
||||
drb->nssai = pdu->param.nssai;
|
||||
|
||||
// for the moment, we only support one QoS flow. Put a reminder in case
|
||||
// this changes
|
||||
AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n");
|
||||
drb->drb_info.flows_to_be_setup_length = 1;
|
||||
drb->drb_info.flows_mapped_to_drb = calloc(1, sizeof(f1ap_flows_mapped_to_drb_t));
|
||||
AssertFatal(drb->drb_info.flows_mapped_to_drb, "could not allocate memory\n");
|
||||
int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0];
|
||||
DevAssert(qfi > 0);
|
||||
drb->drb_info.flows_mapped_to_drb[0].qfi = qfi;
|
||||
pdusession_level_qos_parameter_t *in_qos_char = get_qos_characteristics(qfi, pdu);
|
||||
drb->drb_info.flows_mapped_to_drb[0].qos_params.qos_characteristics = get_qos_char_from_qos_flow_param(in_qos_char);
|
||||
|
||||
/* the DRB QoS parameters: we just reuse the ones from the first flow */
|
||||
drb->drb_info.drb_qos = drb->drb_info.flows_mapped_to_drb[0].qos_params;
|
||||
}
|
||||
|
||||
f1ap_srb_to_be_setup_t srbs[2] = {{.srb_id = 1, .lcid = 1}, {.srb_id = 2, .lcid = 2}};
|
||||
f1ap_served_cell_info_t *cell_info = &target_du->setup_req->cell[0].info;
|
||||
RETURN_IF_INVALID_ASSOC_ID(target_du->assoc_id);
|
||||
f1ap_ue_context_setup_t ue_context_setup_req = {
|
||||
.gNB_CU_ue_id = ue->rrc_ue_id,
|
||||
.gNB_DU_ue_id = 0, /* TODO: this should be optional! */
|
||||
.plmn.mcc = cell_info->plmn.mcc,
|
||||
.plmn.mnc = cell_info->plmn.mnc,
|
||||
.plmn.mnc_digit_length = cell_info->plmn.mnc_digit_length,
|
||||
.nr_cellid = cell_info->nr_cellid,
|
||||
.servCellId = 0, // TODO: correct value?
|
||||
.srbs_to_be_setup_length = 2,
|
||||
.srbs_to_be_setup = srbs,
|
||||
.drbs_to_be_setup_length = nb_drb,
|
||||
.drbs_to_be_setup = drbs,
|
||||
.cu_to_du_rrc_information = &cu2du,
|
||||
};
|
||||
rrc->mac_rrc.ue_context_setup_request(target_du->assoc_id, &ue_context_setup_req);
|
||||
}
|
||||
|
||||
/*
|
||||
void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, int nr_cgi, uint8_t *ho_prep_info, uint32_t *ho_prep_len, void *pdu_session)
|
||||
{
|
||||
// call from outside (via NGAP message), with the request for handover for a
|
||||
// (any) UE. This handler should, in order:
|
||||
//
|
||||
// 1. look up the target DU =du= via get_du_by_cell_id(nr_cgi)
|
||||
// (and reject the request if it can't find the DU)
|
||||
// 2. create a context for a new UE =UE=, based on pdu_session information
|
||||
// 3. call nr_initiate_handover(rrc, UE, NULL, du, ho_prep_info, ho_prep_len);
|
||||
//
|
||||
// after success of the DU, send the result via =success_ptr= to the source
|
||||
// CU.
|
||||
}
|
||||
*/
|
||||
|
||||
typedef struct deliver_ue_ctxt_modification_data_t {
|
||||
gNB_RRC_INST *rrc;
|
||||
f1ap_ue_context_modif_req_t *modification_req;
|
||||
sctp_assoc_t assoc_id;
|
||||
} deliver_ue_ctxt_modification_data_t;
|
||||
static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
|
||||
{
|
||||
DevAssert(deliver_pdu_data != NULL);
|
||||
deliver_ue_ctxt_modification_data_t *data = deliver_pdu_data;
|
||||
data->modification_req->rrc_container = (uint8_t*)buf;
|
||||
data->modification_req->rrc_container_length = size;
|
||||
data->rrc->mac_rrc.ue_context_modification_request(data->assoc_id, data->modification_req);
|
||||
}
|
||||
static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *rrc_reconf, int rrc_reconf_len)
|
||||
{
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
|
||||
|
||||
TransmActionInd_t transmission_action_indicator = TransmActionInd_STOP;
|
||||
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
|
||||
f1ap_ue_context_modif_req_t ue_context_modif_req = {
|
||||
.gNB_CU_ue_id = ue->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.plmn.mcc = rrc->configuration.mcc[0],
|
||||
.plmn.mnc = rrc->configuration.mnc[0],
|
||||
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
|
||||
.nr_cellid = rrc->nr_cellid, // TODO target cell ID
|
||||
.servCellId = 0, // TODO: correct value?
|
||||
.ReconfigComplOutcome = RRCreconf_success,
|
||||
.transm_action_ind = &transmission_action_indicator,
|
||||
};
|
||||
deliver_ue_ctxt_modification_data_t data = {.rrc = rrc,
|
||||
.modification_req = &ue_context_modif_req,
|
||||
.assoc_id = ue_data.du_assoc_id};
|
||||
int srb_id = 1;
|
||||
nr_pdcp_data_req_srb(ue->rrc_ue_id,
|
||||
srb_id,
|
||||
rrc_gNB_mui++,
|
||||
rrc_reconf_len,
|
||||
(unsigned char *const)rrc_reconf,
|
||||
rrc_deliver_ue_ctxt_modif_req,
|
||||
&data);
|
||||
}
|
||||
|
||||
static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t *rrc_reconf_buf, uint32_t rrc_reconf_len)
|
||||
{
|
||||
// N2/Xn HO: fill with UE caps, as-context, rrc reconf, send to source CU
|
||||
// also, fill the UE->rnti from the new one (in F1 case, happens after
|
||||
// confirmation of ue ctxt modif
|
||||
|
||||
// F1 HO: handling of "source CU" information
|
||||
DevAssert(UE->ho_context->source != NULL);
|
||||
rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, rrc_reconf_buf, rrc_reconf_len);
|
||||
LOG_A(NR_RRC, "HO acknowledged: Send reconfiguration for UE %u/RNTI %04x...\n", UE->rrc_ue_id, UE->rnti);
|
||||
|
||||
/* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331
|
||||
* (SRB1 is re-established with RRCReestablishment message)
|
||||
*/
|
||||
int srb_id = 2;
|
||||
if (UE->Srb[srb_id].Active) {
|
||||
nr_pdcp_entity_security_keys_and_algos_t security_parameters;
|
||||
/* Derive the keys from kgnb */
|
||||
nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, security_parameters.ciphering_key);
|
||||
nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, security_parameters.integrity_key);
|
||||
security_parameters.integrity_algorithm = UE->integrity_algorithm;
|
||||
security_parameters.ciphering_algorithm = UE->ciphering_algorithm;
|
||||
nr_pdcp_reestablishment(UE->rrc_ue_id, srb_id, true, &security_parameters);
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_rrc_f1_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
DevAssert(UE->ho_context != NULL);
|
||||
nr_ho_source_cu_t *source_ctx = UE->ho_context->source;
|
||||
DevAssert(source_ctx != NULL);
|
||||
RETURN_IF_INVALID_ASSOC_ID(source_ctx->du->assoc_id);
|
||||
f1ap_ue_context_release_cmd_t cmd = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = source_ctx->du_ue_id,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK, // better
|
||||
.cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure
|
||||
.srb_id = DCCH,
|
||||
};
|
||||
rrc->mac_rrc.ue_context_release_command(source_ctx->du->assoc_id, &cmd);
|
||||
LOG_I(NR_RRC, "UE %d Handover: trigger release on DU assoc_id %d\n", UE->rrc_ue_id, source_ctx->du->assoc_id);
|
||||
}
|
||||
|
||||
static void nr_rrc_cancel_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
DevAssert(UE->ho_context != NULL);
|
||||
nr_ho_target_cu_t *target_ctx = UE->ho_context->target;
|
||||
DevAssert(target_ctx != NULL);
|
||||
f1ap_ue_context_release_cmd_t cmd = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = target_ctx->du_ue_id,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK, // better
|
||||
.cause_value = 5, // 5 = F1AP_CauseRadioNetwork_interaction_with_other_procedure
|
||||
.srb_id = DCCH,
|
||||
};
|
||||
rrc->mac_rrc.ue_context_release_command(target_ctx->du->assoc_id, &cmd);
|
||||
}
|
||||
|
||||
void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_container_t *source_du, nr_rrc_du_container_t *target_du)
|
||||
{
|
||||
DevAssert(rrc != NULL);
|
||||
DevAssert(ue != NULL);
|
||||
|
||||
uint8_t buf[NR_RRC_BUF_SIZE];
|
||||
int size = do_NR_HandoverPreparationInformation(ue->ue_cap_buffer.buf, ue->ue_cap_buffer.len, buf, sizeof buf);
|
||||
|
||||
// corresponds to a "handover request", 38.300 Sec 9.3.2.3
|
||||
// see also 38.413 Sec 9.3.1.29 for information on source-CU to target-CU
|
||||
// information (Source NG-RAN Node to Target NG-RAN Node Transparent Container)
|
||||
// here: target Cell is preselected, target CU has access to UE information
|
||||
// and therefore also the PDU sessions. Orig RRC reconfiguration should be in
|
||||
// handover preparation information
|
||||
ho_req_ack_t ack = nr_rrc_f1_ho_acknowledge;
|
||||
ho_success_t success = nr_rrc_f1_ho_complete;
|
||||
ho_cancel_t cancel = nr_rrc_cancel_f1_ho;
|
||||
nr_initiate_handover(rrc, ue, source_du, target_du, buf, size, ack, success, cancel);
|
||||
}
|
||||
|
||||
void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue)
|
||||
{
|
||||
if (ue->ho_context->source)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, ue->ho_context->source->old_cellGroupConfig);
|
||||
free_ho_ctx(ue->ho_context);
|
||||
ue->ho_context = NULL;
|
||||
}
|
||||
|
||||
void nr_HO_F1_trigger_telnet(gNB_RRC_INST *rrc, uint32_t rrc_ue_id)
|
||||
{
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, rrc_ue_id);
|
||||
if (ue_context_p == NULL) {
|
||||
LOG_E(NR_RRC, "cannot find UE context for UE ID %d\n", rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
gNB_RRC_UE_t *ue = &ue_context_p->ue_context;
|
||||
nr_rrc_du_container_t *source_du = get_du_for_ue(rrc, ue->rrc_ue_id);
|
||||
if (source_du == NULL) {
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(rrc_ue_id);
|
||||
LOG_E(NR_RRC, "cannot get source gNB-DU with assoc_id %d for UE %u\n", ue_data.du_assoc_id, ue->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
|
||||
nr_rrc_du_container_t *target_du = find_target_du(rrc, source_du->assoc_id);
|
||||
if (target_du == NULL) {
|
||||
LOG_E(NR_RRC, "No target gNB-DU found. Handover for UE %u aborted.\n", ue->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
|
||||
nr_rrc_trigger_f1_ho(rrc, ue, source_du, target_du);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef RRC_GNB_MOBILITY_H_
|
||||
#define RRC_GNB_MOBILITY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* forward declarations */
|
||||
typedef struct gNB_RRC_INST_s gNB_RRC_INST;
|
||||
typedef struct gNB_RRC_UE_s gNB_RRC_UE_t;
|
||||
typedef struct nr_rrc_du_container_t nr_rrc_du_container_t;
|
||||
|
||||
typedef struct NR_CellGroupConfig NR_CellGroupConfig_t;
|
||||
|
||||
typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
|
||||
typedef struct nr_ho_source_cu {
|
||||
/// pointer to the (source) DU structure
|
||||
const nr_rrc_du_container_t *du;
|
||||
/// (source) DU UE ID; in F1, the DU UE ID will change to the new (target) DU
|
||||
/// UE ID during handover, and the CU needs to keep track of this in case of
|
||||
/// reestablishment
|
||||
uint32_t du_ue_id;
|
||||
/// old (source) RNTI (to recognize a UE during reestablishment)
|
||||
rnti_t old_rnti;
|
||||
/// old (source) CellGroupConfig (to send the cellGroupConfig in case of
|
||||
/// reestablishment)
|
||||
NR_CellGroupConfig_t *old_cellGroupConfig;
|
||||
/// function pointer to announce the handover cancellation, e.g.,
|
||||
/// reestablishment
|
||||
ho_cancel_t ho_cancel;
|
||||
} nr_ho_source_cu_t;
|
||||
|
||||
/* acknowledgement of handover request. buf+len is the RRC Reconfiguration */
|
||||
typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, uint8_t *buf, uint32_t len);
|
||||
typedef void (*ho_success_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
|
||||
typedef struct nr_ho_target_cu {
|
||||
/// pointer to the (target) DU structure
|
||||
const nr_rrc_du_container_t *du;
|
||||
/// (target) DU UE ID; the (source) DU UE ID will change to the new (target)
|
||||
/// DU UE ID after sending a reconfiguration, which is later than when
|
||||
/// receiving this ID
|
||||
uint32_t du_ue_id;
|
||||
/// new (target) RNTI (as for du_ue_id)
|
||||
rnti_t new_rnti;
|
||||
/// function pointer to announce handover request acknowledgment
|
||||
ho_req_ack_t ho_req_ack;
|
||||
/// function pointer to announce handover success
|
||||
ho_success_t ho_success;
|
||||
} nr_ho_target_cu_t;
|
||||
|
||||
typedef struct nr_handover_context_s {
|
||||
nr_ho_source_cu_t *source;
|
||||
nr_ho_target_cu_t *target;
|
||||
} nr_handover_context_t;
|
||||
|
||||
void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_container_t *source_du, nr_rrc_du_container_t *target_du);
|
||||
void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue);
|
||||
|
||||
#endif /* RRC_GNB_MOBILITY_H_ */
|
||||
@@ -181,6 +181,15 @@ uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue)
|
||||
return DRB_INACTIVE;
|
||||
}
|
||||
|
||||
int get_number_active_drbs(gNB_RRC_UE_t *ue)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < MAX_DRBS_PER_UE; ++i)
|
||||
if (ue->established_drbs[i].status != DRB_INACTIVE)
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id)
|
||||
{
|
||||
drb_t *drb = get_drb(ue, drb_id);
|
||||
|
||||
@@ -61,6 +61,9 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue,
|
||||
/// @brief return the next available (inactive) DRB ID of UE ue
|
||||
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue);
|
||||
|
||||
/// @brief returns the number of active DRBs for this UE
|
||||
int get_number_active_drbs(gNB_RRC_UE_t *ue);
|
||||
|
||||
/// @brief check if DRB with ID drb_id of UE ue is active
|
||||
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
#include "SIMULATION/TOOLS/sim.h" // for taus
|
||||
|
||||
#include "nr_nas_msg_sim.h"
|
||||
#include "nr_nas_msg.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
|
||||
|
||||
static NR_UE_RRC_INST_t *NR_UE_rrc_inst;
|
||||
|
||||
@@ -423,7 +423,7 @@ usage (void) {
|
||||
int
|
||||
get_options (int argc, char *argv[]) {
|
||||
int node_t;
|
||||
char tag;
|
||||
int tag;
|
||||
|
||||
while ((tag =
|
||||
getopt (argc, argv,
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "PduSessionEstablishmentAccept.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "nr_nas_msg_sim.h"
|
||||
#include "nr_nas_msg.h"
|
||||
#include "common/utils/tun_if.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
|
||||
|
||||
@@ -124,18 +124,28 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
case IEI_PDU_ADDRESS:
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received PDU Address IE\n");
|
||||
psea_msg.pdu_addr_ie.pdu_length = *curPtr++;
|
||||
psea_msg.pdu_addr_ie.pdu_type = *curPtr++;
|
||||
|
||||
/* Octet 3 */
|
||||
// PDU type (3 bits)
|
||||
psea_msg.pdu_addr_ie.pdu_type = *curPtr & 0x07;
|
||||
// SMF's IPv6 link local address (1 bit)
|
||||
uint8_t si6lla = (*curPtr >> 3) & 0x01;
|
||||
if (si6lla)
|
||||
LOG_E(NAS, "SMF's IPv6 link local address is not handled\n");
|
||||
curPtr++;
|
||||
|
||||
/* Octet 4 to n */
|
||||
// PDU address information
|
||||
uint8_t *addr = psea_msg.pdu_addr_ie.pdu_addr_oct;
|
||||
if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV4) {
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < IPv4_ADDRESS_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
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");
|
||||
} else if (psea_msg.pdu_addr_ie.pdu_type == PDU_SESSION_TYPE_IPV6) {
|
||||
for (int i = 0; i < 8; ++i)
|
||||
for (int i = 0; i < IPv6_INTERFACE_ID_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
@@ -145,12 +155,12 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
// IPv4v6, the PDU address information in octet 4 to octet 11
|
||||
// contains an interface identifier for the IPv6 link local address
|
||||
// and in octet 12 to octet 15 contains an IPv4 address."
|
||||
for (int i = 0; i < 12; ++i)
|
||||
for (int i = 0; i < IPv4_ADDRESS_LENGTH + IPv6_INTERFACE_ID_LENGTH; ++i)
|
||||
addr[i] = *curPtr++;
|
||||
char ipv6[40];
|
||||
capture_ipv6_addr(addr, ipv6, sizeof(ipv6));
|
||||
char ipv4[20];
|
||||
capture_ipv4_addr(&addr[8], ipv4, sizeof(ipv4));
|
||||
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");
|
||||
} else {
|
||||
@@ -164,42 +174,47 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
curPtr++; /* TS 24.008 10.5.7.3 */
|
||||
break;
|
||||
|
||||
case IEI_SNSSAI: /* Ommited */
|
||||
case IEI_SNSSAI: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received S-NSSAI IE\n");
|
||||
uint8_t snssai_length = *curPtr;
|
||||
curPtr += (snssai_length + sizeof(snssai_length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_ALWAYSON_PDU: /* Ommited */
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Always-on PDU Session indication IE\n");
|
||||
curPtr++;
|
||||
break;
|
||||
|
||||
case IEI_MAPPED_EPS: /* Ommited */
|
||||
case IEI_MAPPED_EPS: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Mapped EPS bearer context IE\n");
|
||||
uint16_t mapped_eps_length = getShort(curPtr);
|
||||
curPtr += mapped_eps_length;
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_EAP_MSG: /* Ommited */
|
||||
case IEI_EAP_MSG: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received EAP message IE\n");
|
||||
uint16_t eap_length = getShort(curPtr);
|
||||
curPtr += (eap_length + sizeof(eap_length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_AUTH_QOS_DESC: /* Ommited */
|
||||
case IEI_AUTH_QOS_DESC: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Authorized QoS flow descriptions IE\n");
|
||||
psea_msg.qos_fd_ie.length = getShort(curPtr);
|
||||
curPtr += (psea_msg.qos_fd_ie.length + sizeof(psea_msg.qos_fd_ie.length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_EXT_CONF_OPT: /* Ommited */
|
||||
case IEI_EXT_CONF_OPT: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received Extended protocol configuration options IE\n");
|
||||
psea_msg.ext_pp_ie.length = getShort(curPtr);
|
||||
curPtr += (psea_msg.ext_pp_ie.length + sizeof(psea_msg.ext_pp_ie.length));
|
||||
break;
|
||||
}
|
||||
|
||||
case IEI_DNN:
|
||||
case IEI_DNN: {
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Received DNN IE\n");
|
||||
psea_msg.dnn_ie.dnn_length = *curPtr++;
|
||||
char apn[APN_MAX_LEN];
|
||||
@@ -213,6 +228,7 @@ void capture_pdu_session_establishment_accept_msg(uint8_t *buffer, uint32_t msg_
|
||||
|
||||
curPtr = buffer + msg_length; // we force stop processing
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_T(NAS, "PDU SESSION ESTABLISHMENT ACCEPT - Not known IE\n");
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
#define PDU_SESSION_TYPE_IPV4 0b001
|
||||
#define PDU_SESSION_TYPE_IPV6 0b010
|
||||
#define PDU_SESSION_TYPE_IPV4V6 0b011
|
||||
#define IPv4_ADDRESS_LENGTH 4 // length of the IPv4 address associated with a PDU session
|
||||
#define IPv6_INTERFACE_ID_LENGTH 8 // interface identifier for the IPv6 link local address
|
||||
#define SMF_IPv6_LLA_LENGTH 16
|
||||
|
||||
/* Rule operation codes - TS 24.501 Table 9.11.4.13.1 */
|
||||
|
||||
@@ -114,7 +117,8 @@ typedef struct pdu_address_s {
|
||||
uint8_t pdu_iei; /* PDU Address IEI (0x29) */
|
||||
uint8_t pdu_length; /* Length of PDU address contents */
|
||||
uint8_t pdu_type; /* PDU session type value */
|
||||
uint8_t pdu_addr_oct[12]; /* PDU address information (depending on type, up to 12 bytes)*/
|
||||
/// PDU address information (depending on type, up to 12 bytes)
|
||||
uint8_t pdu_addr_oct[IPv4_ADDRESS_LENGTH + IPv6_INTERFACE_ID_LENGTH];
|
||||
} pdu_address_t; /* TS 24.501 9.11.4.10 */
|
||||
|
||||
typedef struct dnn_s {
|
||||
|
||||
@@ -63,55 +63,55 @@ typedef enum {
|
||||
SGSmobilitymanagementmessages=0x7e,
|
||||
} Extendedprotocoldiscriminator_t;
|
||||
|
||||
#define FOREACH_TYPE(TYPE_DEF) \
|
||||
TYPE_DEF( Registrationrequest,0x41 )\
|
||||
TYPE_DEF( Registrationaccept,0x42 )\
|
||||
TYPE_DEF( Registrationcomplete,0x43 )\
|
||||
TYPE_DEF( Registrationreject,0x44 )\
|
||||
TYPE_DEF( DeregistrationrequestUEoriginating,0x45 )\
|
||||
TYPE_DEF( DeregistrationacceptUEoriginating,0x46 )\
|
||||
TYPE_DEF( DeregistrationrequestUEterminated,0x47 )\
|
||||
TYPE_DEF( DeregistrationacceptUEterminated,0x48 )\
|
||||
TYPE_DEF( Servicerequest,0x4c )\
|
||||
TYPE_DEF( Servicereject,0x4d )\
|
||||
TYPE_DEF( Serviceaccept,0x4e )\
|
||||
TYPE_DEF( Controlplaneservicerequest,0x4f )\
|
||||
TYPE_DEF( Networkslicespecificauthenticationcommand,0x50 )\
|
||||
TYPE_DEF( Networkslicespecificauthenticationcomplete,0x51 )\
|
||||
TYPE_DEF( Networkslicespecificauthenticationresult,0x52 )\
|
||||
TYPE_DEF( Configurationupdatecommand,0x54 )\
|
||||
TYPE_DEF( Configurationupdatecomplete,0x55 )\
|
||||
TYPE_DEF( Authenticationrequest,0x56 )\
|
||||
TYPE_DEF( Authenticationresponse,0x57 )\
|
||||
TYPE_DEF( Authenticationreject,0x58 )\
|
||||
TYPE_DEF( Authenticationfailure,0x59 )\
|
||||
TYPE_DEF( Authenticationresult,0x5a )\
|
||||
TYPE_DEF( Identityrequest,0x5b )\
|
||||
TYPE_DEF( Identityresponse,0x5c )\
|
||||
TYPE_DEF( Securitymodecommand,0x5d )\
|
||||
TYPE_DEF( Securitymodecomplete,0x5e )\
|
||||
TYPE_DEF( Securitymodereject,0x5f )\
|
||||
TYPE_DEF( SGMMstatus,0x64 )\
|
||||
TYPE_DEF( Notification,0x65 )\
|
||||
TYPE_DEF( Notificationresponse,0x66 )\
|
||||
TYPE_DEF( ULNAStransport,0x67 )\
|
||||
TYPE_DEF( DLNAStransport,0x68 )\
|
||||
TYPE_DEF( PDUsessionestablishmentrequest,0xc1 )\
|
||||
TYPE_DEF( PDUsessionestablishmentaccept,0xc2 )\
|
||||
TYPE_DEF( PDUsessionestablishmentreject,0xc3 )\
|
||||
TYPE_DEF( PDUsessionauthenticationcommand,0xc5 )\
|
||||
TYPE_DEF( PDUsessionauthenticationcomplete,0xc6 )\
|
||||
TYPE_DEF( PDUsessionauthenticationresult,0xc7 )\
|
||||
TYPE_DEF( PDUsessionmodificationrequest,0xc9 )\
|
||||
TYPE_DEF( PDUsessionmodificationreject,0xca )\
|
||||
TYPE_DEF( PDUsessionmodificationcommand,0xcb )\
|
||||
TYPE_DEF( PDUsessionmodificationcomplete,0xcc )\
|
||||
TYPE_DEF( PDUsessionmodificationcommandreject,0xcd )\
|
||||
TYPE_DEF( PDUsessionreleaserequest,0xd1 )\
|
||||
TYPE_DEF( PDUsessionreleasereject,0xd2 )\
|
||||
TYPE_DEF( PDUsessionreleasecommand,0xd3 )\
|
||||
TYPE_DEF( PDUsessionreleasecomplete,0xd4 )\
|
||||
TYPE_DEF( SGSMstatus,0xd6 )\
|
||||
#define FOREACH_TYPE(TYPE_DEF) \
|
||||
TYPE_DEF(REGISTRATION_REQUEST, 0x41) \
|
||||
TYPE_DEF(REGISTRATION_ACCEPT, 0x42) \
|
||||
TYPE_DEF(REGISTRATION_COMPLETE, 0x43) \
|
||||
TYPE_DEF(REGISTRATION_REJECT, 0x44) \
|
||||
TYPE_DEF(FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING, 0x45) \
|
||||
TYPE_DEF(FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING, 0x46) \
|
||||
TYPE_DEF(DeregistrationrequestUEterminated, 0x47) \
|
||||
TYPE_DEF(DeregistrationacceptUEterminated, 0x48) \
|
||||
TYPE_DEF(Servicerequest, 0x4c) \
|
||||
TYPE_DEF(Servicereject, 0x4d) \
|
||||
TYPE_DEF(Serviceaccept, 0x4e) \
|
||||
TYPE_DEF(Controlplaneservicerequest, 0x4f) \
|
||||
TYPE_DEF(Networkslicespecificauthenticationcommand, 0x50) \
|
||||
TYPE_DEF(Networkslicespecificauthenticationcomplete, 0x51) \
|
||||
TYPE_DEF(Networkslicespecificauthenticationresult, 0x52) \
|
||||
TYPE_DEF(Configurationupdatecommand, 0x54) \
|
||||
TYPE_DEF(Configurationupdatecomplete, 0x55) \
|
||||
TYPE_DEF(FGS_AUTHENTICATION_REQUEST, 0x56) \
|
||||
TYPE_DEF(FGS_AUTHENTICATION_RESPONSE, 0x57) \
|
||||
TYPE_DEF(Authenticationreject, 0x58) \
|
||||
TYPE_DEF(Authenticationfailure, 0x59) \
|
||||
TYPE_DEF(Authenticationresult, 0x5a) \
|
||||
TYPE_DEF(FGS_IDENTITY_REQUEST, 0x5b) \
|
||||
TYPE_DEF(FGS_IDENTITY_RESPONSE, 0x5c) \
|
||||
TYPE_DEF(FGS_SECURITY_MODE_COMMAND, 0x5d) \
|
||||
TYPE_DEF(FGS_SECURITY_MODE_COMPLETE, 0x5e) \
|
||||
TYPE_DEF(Securitymodereject, 0x5f) \
|
||||
TYPE_DEF(SGMMstatus, 0x64) \
|
||||
TYPE_DEF(Notification, 0x65) \
|
||||
TYPE_DEF(Notificationresponse, 0x66) \
|
||||
TYPE_DEF(FGS_UPLINK_NAS_TRANSPORT, 0x67) \
|
||||
TYPE_DEF(FGS_DOWNLINK_NAS_TRANSPORT, 0x68) \
|
||||
TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_REQ, 0xc1) \
|
||||
TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_ACC, 0xc2) \
|
||||
TYPE_DEF(FGS_PDU_SESSION_ESTABLISHMENT_REJ, 0xc3) \
|
||||
TYPE_DEF(PDUsessionauthenticationcommand, 0xc5) \
|
||||
TYPE_DEF(PDUsessionauthenticationcomplete, 0xc6) \
|
||||
TYPE_DEF(PDUsessionauthenticationresult, 0xc7) \
|
||||
TYPE_DEF(PDUsessionmodificationrequest, 0xc9) \
|
||||
TYPE_DEF(PDUsessionmodificationreject, 0xca) \
|
||||
TYPE_DEF(PDUsessionmodificationcommand, 0xcb) \
|
||||
TYPE_DEF(PDUsessionmodificationcomplete, 0xcc) \
|
||||
TYPE_DEF(PDUsessionmodificationcommandreject, 0xcd) \
|
||||
TYPE_DEF(PDUsessionreleaserequest, 0xd1) \
|
||||
TYPE_DEF(PDUsessionreleasereject, 0xd2) \
|
||||
TYPE_DEF(PDUsessionreleasecommand, 0xd3) \
|
||||
TYPE_DEF(PDUsessionreleasecomplete, 0xd4) \
|
||||
TYPE_DEF(SGSMstatus, 0xd6)
|
||||
|
||||
static const text_info_t message_text_info[] = {
|
||||
FOREACH_TYPE(TO_TEXT)
|
||||
@@ -124,11 +124,11 @@ typedef enum {
|
||||
|
||||
// TS 24.501
|
||||
typedef enum {
|
||||
notsecurityprotected=0,
|
||||
Integrityprotected=1,
|
||||
Integrityprotectedandciphered=2,
|
||||
Integrityprotectedwithnew5GNASsecuritycontext=3,
|
||||
Integrityprotectedandcipheredwithnew5GNASsecuritycontext=4,
|
||||
PLAIN_5GS_MSG = 0,
|
||||
INTEGRITY_PROTECTED = 1,
|
||||
INTEGRITY_PROTECTED_AND_CIPHERED = 2,
|
||||
INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX = 3,
|
||||
INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX = 4,
|
||||
} Security_header_t;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file nr_nas_msg_sim.c
|
||||
/*! \file nr_nas_msg.c
|
||||
* \brief simulator for nr nas message
|
||||
* \author Yoshio INOUE, Masayuki HARADA
|
||||
* \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "nas_log.h"
|
||||
#include "TLVDecoder.h"
|
||||
#include "TLVEncoder.h"
|
||||
#include "nr_nas_msg_sim.h"
|
||||
#include "nr_nas_msg.h"
|
||||
#include "aka_functions.h"
|
||||
#include "secu_defs.h"
|
||||
#include "kdf.h"
|
||||
@@ -848,16 +848,15 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas,
|
||||
}
|
||||
}
|
||||
|
||||
void decodeDownlinkNASTransport(as_nas_info_t *initialNasMsg, uint8_t *pdu_buffer)
|
||||
/**
|
||||
* @brief Handle DL NAS Transport and process piggybacked 5GSM messages
|
||||
*/
|
||||
static void handleDownlinkNASTransport(uint8_t *pdu_buffer, uint32_t msg_length)
|
||||
{
|
||||
uint8_t msg_type = *(pdu_buffer + 16);
|
||||
if (msg_type == FGS_PDU_SESSION_ESTABLISHMENT_ACC) {
|
||||
uint8_t *ip_p = pdu_buffer + 39;
|
||||
char ip[20];
|
||||
sprintf(ip, "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3));
|
||||
LOG_A(NAS, "Received PDU Session Establishment Accept\n");
|
||||
tun_config(1, ip, NULL, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ip, "oaitun_ue");
|
||||
LOG_A(NAS, "Received PDU Session Establishment Accept in DL NAS Transport\n");
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, msg_length);
|
||||
} else {
|
||||
LOG_E(NAS, "Received unexpected message in DLinformationTransfer %d\n", msg_type);
|
||||
}
|
||||
@@ -1393,7 +1392,7 @@ void *nas_nrue(void *args_p)
|
||||
if (security_state == NAS_SECURITY_UNPROTECTED) {
|
||||
int msg_type = get_msg_type(pdu_buffer, pdu_length);
|
||||
/* for the moment, only FGS_DEREGISTRATION_ACCEPT is accepted */
|
||||
if (msg_type == FGS_DEREGISTRATION_ACCEPT)
|
||||
if (msg_type == FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING)
|
||||
security_state = NAS_SECURITY_INTEGRITY_PASSED;
|
||||
}
|
||||
|
||||
@@ -1415,43 +1414,24 @@ void *nas_nrue(void *args_p)
|
||||
handle_security_mode_command(nas, &initialNasMsg, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_DOWNLINK_NAS_TRANSPORT:
|
||||
decodeDownlinkNASTransport(&initialNasMsg, pdu_buffer);
|
||||
handleDownlinkNASTransport(pdu_buffer, pdu_length);
|
||||
break;
|
||||
case REGISTRATION_ACCEPT:
|
||||
handle_registration_accept(nas, pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_DEREGISTRATION_ACCEPT:
|
||||
case FGS_DEREGISTRATION_ACCEPT_UE_ORIGINATING:
|
||||
LOG_I(NAS, "received deregistration accept\n");
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_ACC: {
|
||||
uint8_t offset = 0;
|
||||
uint8_t *payload_container = pdu_buffer;
|
||||
offset += SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH;
|
||||
uint32_t payload_container_length = htons(((dl_nas_transport_t *)(pdu_buffer + offset))->payload_container_length);
|
||||
if ((payload_container_length >= PAYLOAD_CONTAINER_LENGTH_MIN)
|
||||
&& (payload_container_length <= PAYLOAD_CONTAINER_LENGTH_MAX))
|
||||
offset += (PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH + 3);
|
||||
if (offset < NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.length)
|
||||
payload_container = pdu_buffer + offset;
|
||||
|
||||
while (offset < payload_container_length) {
|
||||
if (*(payload_container + offset) == 0x29) { // PDU address IEI
|
||||
if ((*(payload_container + offset + 1) == 0x05) && (*(payload_container + offset + 2) == 0x01)) { // IPV4
|
||||
uint8_t *ip_p = payload_container + offset + 3;
|
||||
char ip[20];
|
||||
snprintf(ip, sizeof(ip), "%d.%d.%d.%d", *(ip_p), *(ip_p + 1), *(ip_p + 2), *(ip_p + 3));
|
||||
LOG_I(NAS, "Received PDU Session Establishment Accept, UE IP: %s\n", ip);
|
||||
tun_config(1, ip, NULL, "oaitun_ue");
|
||||
setup_ue_ipv4_route(1, ip, "oaitun_ue");
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
} break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_ACC:
|
||||
capture_pdu_session_establishment_accept_msg(pdu_buffer, pdu_length);
|
||||
break;
|
||||
case FGS_PDU_SESSION_ESTABLISHMENT_REJ:
|
||||
LOG_E(NAS, "Received PDU Session Establishment reject\n");
|
||||
break;
|
||||
case REGISTRATION_REJECT:
|
||||
LOG_E(NAS, "Received Registration reject cause: %s\n", cause_text_info[pdu_buffer[17]].text);
|
||||
exit(1);
|
||||
break;
|
||||
default:
|
||||
LOG_W(NR_RRC, "unknown message type %d\n", msg_type);
|
||||
break;
|
||||
@@ -19,7 +19,7 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file nr_nas_msg_sim.h
|
||||
/*! \file nr_nas_msg.h
|
||||
* \brief simulator for nr nas message
|
||||
* \author Yoshio INOUE, Masayuki HARADA
|
||||
* \email yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com
|
||||
@@ -27,8 +27,6 @@
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef __NR_NAS_MSG_SIM_H__
|
||||
#define __NR_NAS_MSG_SIM_H__
|
||||
|
||||
@@ -43,37 +41,12 @@
|
||||
#include <openair3/UICC/usim_interface.h>
|
||||
#include "secu_defs.h"
|
||||
|
||||
#define PLAIN_5GS_MSG 0b0000
|
||||
#define INTEGRITY_PROTECTED 0b0001
|
||||
#define INTEGRITY_PROTECTED_AND_CIPHERED 0b0010
|
||||
#define INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX 0b0011 // only for SECURITY MODE COMMAND
|
||||
#define INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX 0b0100 // only for SECURITY MODE COMPLETE
|
||||
#define INITIAL_REGISTRATION 0b001
|
||||
|
||||
#define REGISTRATION_REQUEST 0b01000001 /* 65 = 0x41 */
|
||||
#define REGISTRATION_ACCEPT 0b01000010 /* 66 = 0x42 */
|
||||
#define REGISTRATION_COMPLETE 0b01000011 /* 67 = 0x43 */
|
||||
#define FGS_DEREGISTRATION_REQUEST_UE_ORIGINATING 0b01000101
|
||||
#define FGS_DEREGISTRATION_ACCEPT 0b01000110
|
||||
#define FGS_AUTHENTICATION_REQUEST 0b01010110 /* 86 = 0x56 */
|
||||
#define FGS_AUTHENTICATION_RESPONSE 0b01010111 /* 87 = 0x57 */
|
||||
#define FGS_IDENTITY_REQUEST 0b01011011 /* 91 = 0x5b */
|
||||
#define FGS_IDENTITY_RESPONSE 0b01011100 /* 92 = 0x5c */
|
||||
#define FGS_SECURITY_MODE_COMMAND 0b01011101 /* 93 = 0x5d */
|
||||
#define FGS_SECURITY_MODE_COMPLETE 0b01011110 /* 94 = 0x5e */
|
||||
#define FGS_UPLINK_NAS_TRANSPORT 0b01100111 /* 103= 0x67 */
|
||||
#define FGS_DOWNLINK_NAS_TRANSPORT 0b01101000 /* 104= 0x68 */
|
||||
|
||||
// message type for 5GS session management
|
||||
#define FGS_PDU_SESSION_ESTABLISHMENT_REQ 0b11000001 /* 193= 0xc1 */
|
||||
#define FGS_PDU_SESSION_ESTABLISHMENT_ACC 0b11000010 /* 194= 0xc2 */
|
||||
#define FGS_PDU_SESSION_ESTABLISHMENT_REJ 0b11000011 /* 195= 0xc3 */
|
||||
|
||||
#define INITIAL_REGISTRATION 0b001
|
||||
|
||||
#define PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH 3
|
||||
#define SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH 7
|
||||
#define PAYLOAD_CONTAINER_LENGTH_MIN 3
|
||||
#define PAYLOAD_CONTAINER_LENGTH_MAX 65537
|
||||
#define PLAIN_5GS_NAS_MESSAGE_HEADER_LENGTH 3
|
||||
#define SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH 7
|
||||
#define PAYLOAD_CONTAINER_LENGTH_MIN 3
|
||||
#define PAYLOAD_CONTAINER_LENGTH_MAX 65537
|
||||
|
||||
/* List of allowed NSSAI from NAS messaging. */
|
||||
typedef struct {
|
||||
@@ -103,20 +76,19 @@ typedef struct {
|
||||
stream_security_container_t *security_container;
|
||||
Guti5GSMobileIdentity_t *guti;
|
||||
bool termination_procedure;
|
||||
uint8_t *registration_request_buf;
|
||||
uint32_t registration_request_len;
|
||||
uint8_t *registration_request_buf;
|
||||
uint32_t registration_request_len;
|
||||
instance_t UE_id;
|
||||
} nr_ue_nas_t;
|
||||
|
||||
typedef enum fgs_protocol_discriminator_e {
|
||||
/* Protocol discriminator identifier for 5GS Mobility Management */
|
||||
FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E,
|
||||
FGS_MOBILITY_MANAGEMENT_MESSAGE = 0x7E,
|
||||
|
||||
/* Protocol discriminator identifier for 5GS Session Management */
|
||||
FGS_SESSION_MANAGEMENT_MESSAGE = 0x2E,
|
||||
FGS_SESSION_MANAGEMENT_MESSAGE = 0x2E,
|
||||
} fgs_protocol_discriminator_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t ex_protocol_discriminator;
|
||||
uint8_t security_header_type;
|
||||
@@ -125,27 +97,25 @@ typedef struct {
|
||||
|
||||
/* Structure of security protected header */
|
||||
typedef struct {
|
||||
fgs_protocol_discriminator_t protocol_discriminator;
|
||||
uint8_t security_header_type;
|
||||
uint32_t message_authentication_code;
|
||||
uint8_t sequence_number;
|
||||
fgs_protocol_discriminator_t protocol_discriminator;
|
||||
uint8_t security_header_type;
|
||||
uint32_t message_authentication_code;
|
||||
uint8_t sequence_number;
|
||||
} fgs_nas_message_security_header_t;
|
||||
|
||||
typedef union {
|
||||
mm_msg_header_t header;
|
||||
registration_request_msg registration_request;
|
||||
fgs_identiy_response_msg fgs_identity_response;
|
||||
fgs_authentication_response_msg fgs_auth_response;
|
||||
mm_msg_header_t header;
|
||||
registration_request_msg registration_request;
|
||||
fgs_identiy_response_msg fgs_identity_response;
|
||||
fgs_authentication_response_msg fgs_auth_response;
|
||||
fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating;
|
||||
fgs_security_mode_complete_msg fgs_security_mode_complete;
|
||||
registration_complete_msg registration_complete;
|
||||
fgs_uplink_nas_transport_msg uplink_nas_transport;
|
||||
fgs_security_mode_complete_msg fgs_security_mode_complete;
|
||||
registration_complete_msg registration_complete;
|
||||
fgs_uplink_nas_transport_msg uplink_nas_transport;
|
||||
} MM_msg;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
MM_msg mm_msg; /* 5GS Mobility Management messages */
|
||||
MM_msg mm_msg; /* 5GS Mobility Management messages */
|
||||
} fgs_nas_message_plain_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -153,7 +123,6 @@ typedef struct {
|
||||
fgs_nas_message_plain_t plain;
|
||||
} fgs_nas_message_security_protected_t;
|
||||
|
||||
|
||||
typedef union {
|
||||
fgs_nas_message_security_header_t header;
|
||||
fgs_nas_message_security_protected_t security_protected;
|
||||
@@ -164,11 +133,11 @@ typedef struct {
|
||||
union {
|
||||
mm_msg_header_t plain_nas_msg_header;
|
||||
struct security_protected_nas_msg_header_s {
|
||||
uint8_t ex_protocol_discriminator;
|
||||
uint8_t security_header_type;
|
||||
uint8_t ex_protocol_discriminator;
|
||||
uint8_t security_header_type;
|
||||
uint16_t message_authentication_code1;
|
||||
uint16_t message_authentication_code2;
|
||||
uint8_t sequence_number;
|
||||
uint8_t sequence_number;
|
||||
} security_protected_nas_msg_header_t;
|
||||
} choice;
|
||||
} nas_msg_header_t;
|
||||
@@ -181,10 +150,10 @@ typedef struct {
|
||||
} fgs_sm_nas_msg_header_t;
|
||||
|
||||
typedef struct {
|
||||
mm_msg_header_t plain_nas_msg_header;
|
||||
uint8_t payload_container_type;
|
||||
uint16_t payload_container_length;
|
||||
fgs_sm_nas_msg_header_t sm_nas_msg_header;
|
||||
mm_msg_header_t plain_nas_msg_header;
|
||||
uint8_t payload_container_type;
|
||||
uint16_t payload_container_length;
|
||||
fgs_sm_nas_msg_header_t sm_nas_msg_header;
|
||||
} dl_nas_transport_t;
|
||||
|
||||
nr_ue_nas_t *get_ue_nas_info(module_id_t module_id);
|
||||
@@ -193,6 +162,3 @@ void *nas_nrue_task(void *args_p);
|
||||
void *nas_nrue(void *args_p);
|
||||
|
||||
#endif /* __NR_NAS_MSG_SIM_H__*/
|
||||
|
||||
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Author and copyright: Laurent Thomas, open-cells.com
|
||||
*
|
||||
* 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 <openair3/NAS/COMMON/NR_NAS_defs.h>
|
||||
#include <openair3/SECU/secu_defs.h>
|
||||
|
||||
|
||||
void SGSabortNet(void *msg, nr_user_nas_t *UE) {
|
||||
}
|
||||
|
||||
void ue_nas_schedule(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
*Message reception
|
||||
*/
|
||||
|
||||
void SGSauthenticationReq(void *msg, nr_user_nas_t *UE) {
|
||||
authenticationrequestHeader_t *amsg=(authenticationrequestHeader_t *) msg;
|
||||
arrayCpy(UE->uicc->rand,amsg->RAND);
|
||||
arrayCpy(UE->uicc->autn,amsg->AUTN);
|
||||
// AUTHENTICATION REQUEST message that contains a valid ngKSI, SQN and MAC is received
|
||||
// TBD verify ngKSI (we set it as '2', see gNB code)
|
||||
// SQN and MAC are tested in auth resp processing
|
||||
ue_nas_schedule();
|
||||
}
|
||||
|
||||
void SGSidentityReq(void *msg, nr_user_nas_t *UE) {
|
||||
Identityrequest_t *idmsg=(Identityrequest_t *) msg;
|
||||
|
||||
if (idmsg->it == SUCI ) {
|
||||
LOG_I(NAS,"Received Identity request, scheduling answer\n");
|
||||
ue_nas_schedule();
|
||||
} else
|
||||
LOG_E(NAS,"Not developped: identity request for %d\n", idmsg->it);
|
||||
}
|
||||
|
||||
void SGSsecurityModeCommand(void *msg, nr_user_nas_t *UE) {
|
||||
}
|
||||
|
||||
|
||||
void UEprocessNAS(void *msg,nr_user_nas_t *UE) {
|
||||
SGScommonHeader_t *header=(SGScommonHeader_t *) msg;
|
||||
|
||||
if ( header->sh > 4 )
|
||||
SGSabortNet(msg, UE);
|
||||
else {
|
||||
switch (header->epd) {
|
||||
case SGSmobilitymanagementmessages:
|
||||
LOG_I(NAS,"Received message: %s\n", idStr(message_text_info, header->mt));
|
||||
|
||||
switch (header->mt) {
|
||||
case Authenticationrequest:
|
||||
SGSauthenticationReq(msg, UE);
|
||||
break;
|
||||
|
||||
case Identityrequest:
|
||||
SGSidentityReq(msg, UE);
|
||||
break;
|
||||
|
||||
case Securitymodecommand:
|
||||
SGSsecurityModeCommand(msg, UE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SGSabortNet(msg, UE);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SGSsessionmanagementmessages:
|
||||
SGSabortNet(msg, UE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SGSabortNet(msg, UE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Messages emission
|
||||
*/
|
||||
|
||||
int identityResponse(void **msg, nr_user_nas_t *UE) {
|
||||
if (UE->uicc == NULL)
|
||||
// config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE
|
||||
UE->uicc=init_uicc("uicc");
|
||||
|
||||
// TS 24.501 9.11.3.4
|
||||
int imsiL=strlen(UE->uicc->imsiStr);
|
||||
int msinL=imsiL-3-UE->uicc->nmc_size;
|
||||
int respSize=sizeof(IdentityresponseIMSI_t) + (msinL+1)/2;
|
||||
IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *) calloc(respSize,1);
|
||||
resp->common.epd=SGSmobilitymanagementmessages;
|
||||
resp->common.sh=0;
|
||||
resp->common.mt=Identityresponse;
|
||||
resp->common.len=htons(respSize-sizeof(Identityresponse_t));
|
||||
resp->mi=SUCI;
|
||||
resp->mcc1=UE->uicc->imsiStr[0]-'0';
|
||||
resp->mcc2=UE->uicc->imsiStr[1]-'0';
|
||||
resp->mcc3=UE->uicc->imsiStr[2]-'0';
|
||||
resp->mnc1=UE->uicc->imsiStr[3]-'0';
|
||||
resp->mnc2=UE->uicc->imsiStr[4]-'0';
|
||||
resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsiStr[3]-'0';
|
||||
// TBD: routing to fill (FF ?)
|
||||
char *out=(char *)(resp+1);
|
||||
char *ptr=UE->uicc->imsiStr + 3 + UE->uicc->nmc_size;
|
||||
|
||||
while ( ptr < UE->uicc->imsiStr+strlen(UE->uicc->imsiStr) ) {
|
||||
*out=((*(ptr+1)-'0')<<4) | (*(ptr) -'0');
|
||||
out++;
|
||||
ptr+=2;
|
||||
}
|
||||
|
||||
if (msinL%2 == 1)
|
||||
*out=((*(ptr-1)-'0')) | 0xF0;
|
||||
|
||||
*msg=resp;
|
||||
return respSize;
|
||||
}
|
||||
|
||||
int authenticationResponse(void **msg,nr_user_nas_t *UE) {
|
||||
if (UE->uicc == NULL)
|
||||
// config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE
|
||||
UE->uicc=init_uicc("uicc");
|
||||
|
||||
myCalloc(resp, authenticationresponse_t);
|
||||
resp->epd=SGSmobilitymanagementmessages;
|
||||
resp->sh=0;
|
||||
resp->mt=Authenticationresponse;
|
||||
resp->iei=IEI_AuthenticationResponse;
|
||||
resp->RESlen=sizeof(resp->RES); // always 16 see TS 24.501 Table 8.2.2.1.1
|
||||
// Verify the AUTN
|
||||
// a full implementation need to test several SQN
|
||||
// as the last 5bits can be any value
|
||||
// and the value can also be greater and accepted (if it is in the accepted window)
|
||||
uint8_t AUTN[16];
|
||||
uicc_milenage_generate(AUTN, UE->uicc);
|
||||
|
||||
if ( memcmp(UE->uicc->autn, AUTN, sizeof(AUTN)) == 0 ) {
|
||||
// prepare and send good answer
|
||||
resToresStar(resp->RES,UE->uicc);
|
||||
} else {
|
||||
// prepare and send autn is not compatible with our data
|
||||
abort();
|
||||
}
|
||||
|
||||
*msg=resp;
|
||||
return sizeof(authenticationresponse_t);
|
||||
}
|
||||
|
||||
int securityModeComplete(void **msg, nr_user_nas_t *UE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int registrationComplete(void **msg, nr_user_nas_t *UE) {
|
||||
return -1;
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Author and copyright: Laurent Thomas, open-cells.com
|
||||
*
|
||||
* 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 <openair3/NAS/COMMON/NR_NAS_defs.h>
|
||||
|
||||
void SGSabortUE(void *msg, NRUEcontext_t *UE) {
|
||||
}
|
||||
void nas_schedule(void) {
|
||||
}
|
||||
/*
|
||||
*Message reception
|
||||
*/
|
||||
|
||||
void SGSregistrationReq(void *msg, NRUEcontext_t *UE) {
|
||||
}
|
||||
|
||||
void SGSderegistrationUEReq(void *msg, NRUEcontext_t *UE) {
|
||||
}
|
||||
|
||||
void SGSidentityResp(void *msg, NRUEcontext_t *UE) {
|
||||
// use the UE SUPI to load the USIM
|
||||
IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *)msg;
|
||||
char configName[100]={0};
|
||||
char * ptr= stpcpy(configName,"uicc");
|
||||
*ptr++=resp->mcc1+'0';
|
||||
*ptr++=resp->mcc2+'0';
|
||||
*ptr++=resp->mcc3+'0';
|
||||
*ptr++=resp->mnc1+'0';
|
||||
*ptr++=resp->mnc2+'0';
|
||||
if ( resp->mnc3 != 0xF )
|
||||
*ptr++=resp->mnc3 +'0';
|
||||
int respSize=ntohs(resp->common.len);
|
||||
int msinByteSize=respSize-sizeof(IdentityresponseIMSI_t);
|
||||
uint8_t * msin=(uint8_t *) (resp+1);
|
||||
for(int i=3 ; i<msinByteSize; i++) {
|
||||
char digit1=(msin[i] >> 4) ;
|
||||
*ptr++=(msin[i] & 0xf) +'0';
|
||||
if (digit1 != 0xf)
|
||||
*ptr++=digit1 +'0';
|
||||
}
|
||||
*ptr=0;
|
||||
if (UE->uicc == NULL)
|
||||
// config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE
|
||||
UE->uicc=init_uicc(configName);
|
||||
//We schedule Authentication request
|
||||
nas_schedule();
|
||||
}
|
||||
|
||||
void SGSauthenticationResp(void *msg, NRUEcontext_t *UE) {
|
||||
// Let's check the answer
|
||||
authenticationresponse_t* resp=(authenticationresponse_t*) msg;
|
||||
uint8_t resStarLocal[16];
|
||||
resToresStar(resStarLocal,UE->uicc);
|
||||
if ( memcmp(resStarLocal, resp->RES, sizeof(resStarLocal)) == 0 ) {
|
||||
LOG_I(NAS,"UE answer to authentication resquest is correct\n");
|
||||
// we will send securityModeCommand
|
||||
nas_schedule();
|
||||
} else {
|
||||
LOG_E(NAS,"UE authentication response not good\n");
|
||||
// To be implemented ?
|
||||
}
|
||||
}
|
||||
|
||||
void SGSsecurityModeComplete(void *msg, NRUEcontext_t *UE) {
|
||||
|
||||
}
|
||||
|
||||
void SGSregistrationComplete(void *msg, NRUEcontext_t *UE) {
|
||||
}
|
||||
|
||||
void processNAS(void *msg, NRUEcontext_t *UE) {
|
||||
SGScommonHeader_t *header=(SGScommonHeader_t *) msg;
|
||||
|
||||
if ( header->sh > 4 )
|
||||
SGSabortUE(msg, UE);
|
||||
else {
|
||||
switch (header->epd) {
|
||||
case SGSmobilitymanagementmessages:
|
||||
LOG_I(NAS,"Received message: %s\n", idStr(message_text_info, header->mt));
|
||||
|
||||
switch (header->mt) {
|
||||
case Registrationrequest:
|
||||
SGSregistrationReq(msg, UE);
|
||||
break;
|
||||
|
||||
case DeregistrationrequestUEoriginating:
|
||||
SGSderegistrationUEReq(msg, UE);
|
||||
break;
|
||||
|
||||
case Authenticationresponse:
|
||||
SGSauthenticationResp(msg, UE);
|
||||
break;
|
||||
|
||||
case Identityresponse:
|
||||
SGSidentityResp(msg, UE);
|
||||
break;
|
||||
|
||||
case Securitymodecomplete:
|
||||
SGSsecurityModeComplete(msg, UE);
|
||||
break;
|
||||
|
||||
case Registrationcomplete:
|
||||
SGSregistrationComplete(msg, UE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SGSabortUE(msg, UE);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SGSsessionmanagementmessages:
|
||||
SGSabortUE(msg, UE);
|
||||
break;
|
||||
|
||||
default:
|
||||
SGSabortUE(msg, UE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Messages emission
|
||||
*/
|
||||
|
||||
int identityRequest(void **msg, NRUEcontext_t *UE) {
|
||||
myCalloc(req, Identityrequest_t);
|
||||
req->epd=SGSmobilitymanagementmessages;
|
||||
req->sh=0;
|
||||
req->mt=Identityrequest;
|
||||
req->it=SUCI;
|
||||
*msg=req;
|
||||
return sizeof(Identityrequest_t);
|
||||
}
|
||||
|
||||
int authenticationRequest(void **msg, NRUEcontext_t *UE) {
|
||||
|
||||
myCalloc(req, authenticationrequestHeader_t);
|
||||
req->epd=SGSmobilitymanagementmessages;
|
||||
req->sh=0;
|
||||
req->mt=Authenticationrequest;
|
||||
// native security context => bit 4 to 0
|
||||
// probably from TS 33.501, table A-8.1
|
||||
// N-NAS-int-alg (Native NAS integrity)
|
||||
/*
|
||||
N-NAS-enc-alg 0x01
|
||||
N-NAS-int-alg 0x02
|
||||
N-RRC-enc-alg 0x03
|
||||
N-RRC-int-alg 0x04
|
||||
N-UP-enc-alg 0x05
|
||||
N-UP-int-alg 0x06
|
||||
*/
|
||||
req->ngKSI=2;
|
||||
// TS 33.501, Annex A.7.1: Initial set of security features defined for 5GS.
|
||||
req->ABBALen=2;
|
||||
req->ABBA=0;
|
||||
//rand (TV)
|
||||
req->ieiRAND=IEI_RAND;
|
||||
FILE *h=fopen("/dev/random","r");
|
||||
|
||||
if ( sizeof(req->RAND) != fread(req->RAND,1,sizeof(req->RAND),h) )
|
||||
LOG_E(NAS, "can't read /dev/random\n");
|
||||
|
||||
fclose(h);
|
||||
memcpy(UE->uicc->rand, req->RAND, sizeof(UE->uicc->rand));
|
||||
// challenge/AUTN (TLV)
|
||||
req->ieiAUTN=IEI_AUTN;
|
||||
req->AUTNlen=sizeof(req->AUTN);
|
||||
uicc_milenage_generate( req->AUTN, UE->uicc);
|
||||
// EAP message (TLV-E)
|
||||
// not developped
|
||||
*msg=req;
|
||||
return sizeof(authenticationrequestHeader_t);
|
||||
}
|
||||
|
||||
int securityModeCommand(void **msg, NRUEcontext_t *UE) {
|
||||
*msg=NULL;
|
||||
myCalloc(req, securityModeCommand_t);
|
||||
req->epd=SGSmobilitymanagementmessages;
|
||||
req->sh=0;
|
||||
req->mt=Securitymodecommand;
|
||||
|
||||
// integrity algo from 5G-IA0 (null algo) to 5G-IA7 in first 4 bits
|
||||
unsigned int ia=0;
|
||||
// cyphering algo from 5G-EA0 (null algo) to 5G-IA7 in MSB 4 bits
|
||||
unsigned int ea=0;
|
||||
// trace from commercial: 5G-IA0 (0) 128-5G-IA2 (2)
|
||||
req->selectedNASsecurityalgorithms= ea<<4 | ia;
|
||||
|
||||
// KSI: N-NAS-int-alg 0x02
|
||||
req->ngKSI=2;
|
||||
|
||||
*msg=req;
|
||||
return 0;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ add_library(rfsimulator MODULE
|
||||
apply_channelmod.c
|
||||
../../openair1/PHY/TOOLS/signal_energy.c
|
||||
)
|
||||
target_link_libraries(rfsimulator PRIVATE SIMU)
|
||||
target_link_libraries(rfsimulator PRIVATE SIMU HASHTABLE)
|
||||
set_target_properties(rfsimulator PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
add_executable(replay_node stored_node.c)
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#define CHANNELMOD_DYNAMICLOAD
|
||||
#include <openair1/SIMULATION/TOOLS/sim.h>
|
||||
#include "rfsimulator.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#define PORT 4043 //default TCP port for this simulator
|
||||
//
|
||||
@@ -82,6 +83,8 @@
|
||||
// Until a convenient management is implemented, the MAX_FD_RFSIMU is used everywhere (instead of
|
||||
// FD_SETSIE) and reduced to 125. This should allow for around 20 simultaeous UEs.
|
||||
//
|
||||
// An indirection level via hashtable was added to allow the software to use FDs above MAX_FD_RFSIMU.
|
||||
//
|
||||
// #define MAX_FD_RFSIMU FD_SETSIZE
|
||||
#define MAX_FD_RFSIMU 250
|
||||
#define SEND_BUFF_SIZE 100000000 // Socket buffer size
|
||||
@@ -162,6 +165,9 @@ typedef struct {
|
||||
uint16_t port;
|
||||
int saveIQfile;
|
||||
buffer_t buf[MAX_FD_RFSIMU];
|
||||
int next_buf;
|
||||
// Hashtable used as an indirection level between file descriptor and the buf array
|
||||
hash_table_t *fd_to_buf_map;
|
||||
int rx_num_channels;
|
||||
int tx_num_channels;
|
||||
double sample_rate;
|
||||
@@ -178,11 +184,38 @@ typedef struct {
|
||||
double prop_delay_ms;
|
||||
} rfsimulator_state_t;
|
||||
|
||||
|
||||
static buffer_t *get_buff_from_socket(rfsimulator_state_t *simulator_state, int socket)
|
||||
{
|
||||
uint64_t buffer_index;
|
||||
if (hashtable_get(simulator_state->fd_to_buf_map, socket, (void **)&buffer_index) == HASH_TABLE_OK) {
|
||||
return &simulator_state->buf[buffer_index];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void add_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket, uint64_t buff_index)
|
||||
{
|
||||
hashtable_rc_t rc = hashtable_insert(simulator_state->fd_to_buf_map, socket, (void *)buff_index);
|
||||
AssertFatal(rc == HASH_TABLE_OK,
|
||||
"%s sock = %d\n",
|
||||
rc == HASH_TABLE_INSERT_OVERWRITTEN_DATA ? "Duplicate entry in hashtable" : "Hashtable is not allocated",
|
||||
socket);
|
||||
}
|
||||
|
||||
static void remove_buff_to_socket_mapping(rfsimulator_state_t *simulator_state, int socket)
|
||||
{
|
||||
// Failure is fine here
|
||||
hashtable_remove(simulator_state->fd_to_buf_map, socket);
|
||||
}
|
||||
|
||||
static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
||||
{
|
||||
/* TODO: cleanup code so that this AssertFatal becomes useless */
|
||||
AssertFatal(sock >= 0 && sock < sizeofArray(bridge->buf), "socket %d is not in range\n", sock);
|
||||
buffer_t *ptr=&bridge->buf[sock];
|
||||
uint64_t buff_index = bridge->next_buf++ % MAX_FD_RFSIMU;
|
||||
buffer_t *ptr=&bridge->buf[buff_index];
|
||||
ptr->circularBuf = calloc(1, sampleToByte(CirSize, 1));
|
||||
if (ptr->circularBuf == NULL) {
|
||||
LOG_E(HW, "malloc(%lu) failed\n", sampleToByte(CirSize, 1));
|
||||
@@ -235,6 +268,7 @@ static int allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
||||
random_channel(ptr->channel_model,false);
|
||||
LOG_I(HW, "Random channel %s in rfsimulator activated\n", modelname);
|
||||
}
|
||||
add_buff_to_socket_mapping(bridge, sock, buff_index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -243,17 +277,23 @@ static void removeCirBuf(rfsimulator_state_t *bridge, int sock) {
|
||||
LOG_E(HW, "epoll_ctl(EPOLL_CTL_DEL) failed\n");
|
||||
}
|
||||
close(sock);
|
||||
free(bridge->buf[sock].circularBuf);
|
||||
// Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
|
||||
// a lot of mem leaks
|
||||
//free(bridge->buf[sock].channel_model);
|
||||
memset(&bridge->buf[sock], 0, sizeof(buffer_t));
|
||||
bridge->buf[sock].conn_sock=-1;
|
||||
nb_ue--;
|
||||
buffer_t* buf = get_buff_from_socket(bridge, sock);
|
||||
if (buf) {
|
||||
free(buf->circularBuf);
|
||||
// Fixme: no free_channel_desc_scm(bridge->buf[sock].channel_model) implemented
|
||||
// a lot of mem leaks
|
||||
//free(bridge->buf[sock].channel_model);
|
||||
memset(buf, 0, sizeof(buffer_t));
|
||||
buf->conn_sock=-1;
|
||||
remove_buff_to_socket_mapping(bridge, sock);
|
||||
nb_ue--;
|
||||
}
|
||||
}
|
||||
|
||||
static void socketError(rfsimulator_state_t *bridge, int sock) {
|
||||
if (bridge->buf[sock].conn_sock!=-1) {
|
||||
buffer_t* buf = get_buff_from_socket(bridge, sock);
|
||||
if (!buf) return;
|
||||
if (buf->conn_sock != -1) {
|
||||
LOG_W(HW, "Lost socket\n");
|
||||
removeCirBuf(bridge, sock);
|
||||
|
||||
@@ -789,7 +829,7 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
||||
|
||||
rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false);
|
||||
|
||||
buffer_t *b = &t->buf[conn_sock];
|
||||
buffer_t *b = get_buff_from_socket(t, conn_sock);
|
||||
if (b->channel_model)
|
||||
b->channel_model->start_TS = t->lastWroteTS;
|
||||
} else {
|
||||
@@ -798,8 +838,8 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer_t *b=&t->buf[fd];
|
||||
|
||||
buffer_t *b = get_buff_from_socket(t, fd);
|
||||
if (!b) continue;
|
||||
if ( b->circularBuf == NULL ) {
|
||||
LOG_E(HW, "Received data on not connected socket %d\n", events[nbEv].data.fd);
|
||||
continue;
|
||||
@@ -1044,6 +1084,7 @@ static void rfsimulator_end(openair0_device *device) {
|
||||
removeCirBuf(s, b->conn_sock);
|
||||
}
|
||||
close(s->epollfd);
|
||||
hashtable_destroy(&s->fd_to_buf_map);
|
||||
}
|
||||
static int rfsimulator_stop(openair0_device *device) {
|
||||
return 0;
|
||||
@@ -1059,6 +1100,12 @@ static int rfsimulator_set_gains(openair0_device *device, openair0_config_t *ope
|
||||
static int rfsimulator_write_init(openair0_device *device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void do_not_free_integer(void *integer)
|
||||
{
|
||||
(void)integer;
|
||||
}
|
||||
|
||||
__attribute__((__visibility__("default")))
|
||||
int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
// to change the log level, use this on command line
|
||||
@@ -1104,6 +1151,8 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
||||
|
||||
for (int i = 0; i < MAX_FD_RFSIMU; i++)
|
||||
rfsimulator->buf[i].conn_sock=-1;
|
||||
rfsimulator->next_buf = 0;
|
||||
rfsimulator->fd_to_buf_map = hashtable_create(MAX_FD_RFSIMU, NULL, do_not_free_integer);
|
||||
|
||||
AssertFatal((rfsimulator->epollfd = epoll_create1(0)) != -1, "epoll_create1() failed, errno(%d)", errno);
|
||||
// we need to call randominit() for telnet server (use gaussdouble=>uniformrand)
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
Active_gNBs = ( "cu-rfsim");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
Num_Threads_PUSCH = 8;
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_name = "cu-rfsim";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
tr_s_preference = "f1";
|
||||
|
||||
local_s_if_name = "lo";
|
||||
local_s_address = "127.0.0.3";
|
||||
remote_s_address = "0.0.0.0"; # multiple DUs
|
||||
local_s_portc = 501;
|
||||
local_s_portd = 2152;
|
||||
remote_s_portc = 500;
|
||||
remote_s_portd = 2152;
|
||||
|
||||
|
||||
# ------- 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.70.132"; });
|
||||
|
||||
NETWORK_INTERFACES :
|
||||
{
|
||||
GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24";
|
||||
GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24";
|
||||
GNB_PORT_FOR_S1U = 2152; # Spec 2152
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
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";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "info";
|
||||
};
|
||||
@@ -0,0 +1,215 @@
|
||||
Active_gNBs = ( "du-rfsim");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_DU_ID = 0xe00;
|
||||
gNB_name = "du-rfsim";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 95; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 4;
|
||||
sib1_tda = 15;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
|
||||
absoluteFrequencySSB = 430610;
|
||||
dl_frequencyBand = 66;
|
||||
# this is 3600 MHz
|
||||
dl_absoluteFrequencyPointA = 430000;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 0;
|
||||
dl_carrierBandwidth = 25;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=27,L=48 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 6600; # 6366 12925 12956 28875 12952
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 0;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 0;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 66;
|
||||
# this is 1750 MHz
|
||||
ul_absoluteFrequencyPointA = 350000;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 0;
|
||||
ul_carrierBandwidth = 25;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 6600;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 0;
|
||||
#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 = 13;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#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 = 4;
|
||||
#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;
|
||||
#oneHalf (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 = 0,
|
||||
# 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 = 0;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 0;
|
||||
# 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;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = ({
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "f1";
|
||||
local_n_if_name = "lo";
|
||||
local_n_address = "127.0.0.4";
|
||||
remote_n_address = "127.0.0.3";
|
||||
local_n_portc = 500;
|
||||
local_n_portd = 2152;
|
||||
remote_n_portc = 501;
|
||||
remote_n_portd = 2152;
|
||||
pusch_FailureThres = 1000;
|
||||
});
|
||||
|
||||
L1s = ({
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
pucch0_dtx_threshold = 150;
|
||||
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
|
||||
});
|
||||
|
||||
RUs = ({
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [66];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
clock_src = "internal";
|
||||
});
|
||||
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
nr_phy_log_level = "info";
|
||||
nr_mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "debug";
|
||||
};
|
||||
@@ -0,0 +1,215 @@
|
||||
Active_gNBs = ( "du-rfsim");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_DU_ID = 0xe01;
|
||||
gNB_name = "du-rfsim";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 208; mnc = 95; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 11111111L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 4;
|
||||
sib1_tda = 15;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 1;
|
||||
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
|
||||
absoluteFrequencySSB = 435610;
|
||||
dl_frequencyBand = 66;
|
||||
# this is 3600 MHz
|
||||
dl_absoluteFrequencyPointA = 435000;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 0;
|
||||
dl_carrierBandwidth = 25;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=27,L=48 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 6600; # 6366 12925 12956 28875 12952
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 0;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 0;
|
||||
initialDLBWPsearchSpaceZero = 0;
|
||||
|
||||
#uplinkConfigCommon
|
||||
#frequencyInfoUL
|
||||
ul_frequencyBand = 66;
|
||||
# this is 1750 MHz
|
||||
ul_absoluteFrequencyPointA = 355000;
|
||||
#scs-SpecificCarrierList
|
||||
ul_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
ul_subcarrierSpacing = 0;
|
||||
ul_carrierBandwidth = 25;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 6600;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialULBWPsubcarrierSpacing = 0;
|
||||
#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 = 13;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#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 = 4;
|
||||
#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;
|
||||
#oneHalf (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 = 0,
|
||||
# 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 = 0;
|
||||
|
||||
|
||||
#tdd-UL-DL-ConfigurationCommon
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
referenceSubcarrierSpacing = 0;
|
||||
# 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;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = ({
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "f1";
|
||||
local_n_if_name = "lo";
|
||||
local_n_address = "127.0.0.5";
|
||||
remote_n_address = "127.0.0.3";
|
||||
local_n_portc = 500;
|
||||
local_n_portd = 2152;
|
||||
remote_n_portc = 501;
|
||||
remote_n_portd = 2152;
|
||||
pusch_FailureThres = 1000;
|
||||
});
|
||||
|
||||
L1s = ({
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
pucch0_dtx_threshold = 150;
|
||||
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
|
||||
});
|
||||
|
||||
RUs = ({
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [66];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
clock_src = "internal";
|
||||
});
|
||||
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
nr_phy_log_level = "info";
|
||||
nr_mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "debug";
|
||||
};
|
||||
@@ -0,0 +1,212 @@
|
||||
Active_gNBs = ( "du-rfsim");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_DU_ID = 0xe00;
|
||||
gNB_name = "du-rfsim";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 12345678L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 4;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 0;
|
||||
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
|
||||
absoluteFrequencySSB = 630048;
|
||||
dl_frequencyBand = 78;
|
||||
# this is 3600 MHz
|
||||
dl_absoluteFrequencyPointA = 628776;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=27,L=48 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
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 = 106;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# 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 = 13;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#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 = 4;
|
||||
#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;
|
||||
#oneHalf (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14;
|
||||
#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;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = ({
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "f1";
|
||||
local_n_if_name = "lo";
|
||||
local_n_address = "127.0.0.4";
|
||||
remote_n_address = "127.0.0.3";
|
||||
local_n_portc = 500;
|
||||
local_n_portd = 2152;
|
||||
remote_n_portc = 501;
|
||||
remote_n_portd = 2152;
|
||||
pusch_FailureThres = 1000;
|
||||
});
|
||||
|
||||
L1s = ({
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
pucch0_dtx_threshold = 150;
|
||||
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
|
||||
});
|
||||
|
||||
RUs = ({
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
clock_src = "internal";
|
||||
});
|
||||
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
nr_phy_log_level = "info";
|
||||
nr_mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "debug";
|
||||
};
|
||||
@@ -0,0 +1,212 @@
|
||||
Active_gNBs = ( "du-rfsim");
|
||||
# Asn1_verbosity, choice in: none, info, annoying
|
||||
Asn1_verbosity = "none";
|
||||
|
||||
gNBs =
|
||||
(
|
||||
{
|
||||
////////// Identification parameters:
|
||||
gNB_ID = 0xe00;
|
||||
gNB_DU_ID = 0xe01;
|
||||
gNB_name = "du-rfsim";
|
||||
|
||||
// Tracking area code, 0x0000 and 0xfffe are reserved values
|
||||
tracking_area_code = 1;
|
||||
plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) });
|
||||
|
||||
nr_cellid = 11111111L;
|
||||
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 4;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
#spCellConfigCommon
|
||||
|
||||
physCellId = 1;
|
||||
|
||||
# downlinkConfigCommon
|
||||
#frequencyInfoDL
|
||||
# this is 3600 MHz + 43 PRBs@30kHz SCS (same as initial BWP)
|
||||
absoluteFrequencySSB = 643296;
|
||||
dl_frequencyBand = 78;
|
||||
# this is 3600 MHz
|
||||
dl_absoluteFrequencyPointA = 642024;
|
||||
#scs-SpecificCarrierList
|
||||
dl_offstToCarrier = 0;
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
dl_subcarrierSpacing = 1;
|
||||
dl_carrierBandwidth = 106;
|
||||
#initialDownlinkBWP
|
||||
#genericParameters
|
||||
# this is RBstart=27,L=48 (275*(L-1))+RBstart
|
||||
initialDLBWPlocationAndBandwidth = 28875; # 6366 12925 12956 28875 12952
|
||||
# subcarrierSpacing
|
||||
# 0=kHz15, 1=kHz30, 2=kHz60, 3=kHz120
|
||||
initialDLBWPsubcarrierSpacing = 1;
|
||||
#pdcch-ConfigCommon
|
||||
initialDLBWPcontrolResourceSetZero = 12;
|
||||
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 = 106;
|
||||
pMax = 20;
|
||||
#initialUplinkBWP
|
||||
#genericParameters
|
||||
initialULBWPlocationAndBandwidth = 28875;
|
||||
# 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 = 13;
|
||||
preambleReceivedTargetPower = -96;
|
||||
#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 = 4;
|
||||
#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;
|
||||
#oneHalf (0..15) 4,8,12,16,...60,64
|
||||
ssb_perRACH_OccasionAndCB_PreamblesPerSSB = 14;
|
||||
#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 = 3;
|
||||
|
||||
# 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;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
MACRLCs = ({
|
||||
num_cc = 1;
|
||||
tr_s_preference = "local_L1";
|
||||
tr_n_preference = "f1";
|
||||
local_n_if_name = "lo";
|
||||
local_n_address = "127.0.0.5";
|
||||
remote_n_address = "127.0.0.3";
|
||||
local_n_portc = 500;
|
||||
local_n_portd = 2152;
|
||||
remote_n_portc = 501;
|
||||
remote_n_portd = 2152;
|
||||
pusch_FailureThres = 1000;
|
||||
});
|
||||
|
||||
L1s = ({
|
||||
num_cc = 1;
|
||||
tr_n_preference = "local_mac";
|
||||
prach_dtx_threshold = 200;
|
||||
pucch0_dtx_threshold = 150;
|
||||
ofdm_offset_divisor = 8; #set this to UINT_MAX for offset 0
|
||||
});
|
||||
|
||||
RUs = ({
|
||||
local_rf = "yes"
|
||||
nb_tx = 1
|
||||
nb_rx = 1
|
||||
att_tx = 0
|
||||
att_rx = 0;
|
||||
bands = [78];
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
clock_src = "internal";
|
||||
});
|
||||
|
||||
rfsimulator: {
|
||||
serveraddr = "server";
|
||||
serverport = 4043;
|
||||
options = (); #("saviq"); or/and "chanmod"
|
||||
modelname = "AWGN";
|
||||
IQfile = "/tmp/rfsimulator.iqs"
|
||||
}
|
||||
|
||||
log_config: {
|
||||
global_log_level = "info";
|
||||
hw_log_level = "info";
|
||||
nr_phy_log_level = "info";
|
||||
nr_mac_log_level = "info";
|
||||
rlc_log_level = "info";
|
||||
pdcp_log_level = "info";
|
||||
rrc_log_level = "info";
|
||||
f1ap_log_level = "info";
|
||||
ngap_log_level = "debug";
|
||||
};
|
||||
@@ -226,8 +226,6 @@ RUs = (
|
||||
max_pdschReferenceSignalPower = -27;
|
||||
max_rxgain = 114;
|
||||
eNB_instances = [0];
|
||||
#beamforming 1x4 matrix:
|
||||
bf_weights = [0x00007fff, 0x0000, 0x0000, 0x0000];
|
||||
clock_src = "internal";
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user