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:
Robert Schmidt
2024-10-29 06:55:10 +00:00
97 changed files with 3844 additions and 1325 deletions
+3 -4
View File
@@ -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>
+10 -17
View File
@@ -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})
+3
View File
@@ -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()
+18
View File
@@ -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 */
+21
View File
@@ -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;
}
+9 -2
View File
@@ -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) \
+62 -19
View File
@@ -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[] = {
+1 -1
View File
@@ -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) |
| | | | |
+5 -4
View File
@@ -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
View File
@@ -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 \
+1 -1
View File
@@ -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
+2
View File
@@ -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
+5 -2
View File
@@ -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
+1
View File
@@ -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):
+9
View File
@@ -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
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

+318
View File
@@ -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.
+99
View File
@@ -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.
+329
View File
@@ -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.
![F1 Handover setup](./RRC/ho.png)
# 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
View File
@@ -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;
}
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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);
+2 -1
View File
@@ -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':
+1 -3
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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':
+1 -1
View File
@@ -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 */
+1 -1
View File
@@ -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 */
+1 -1
View File
@@ -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 */
+1 -1
View File
@@ -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 */
+1 -1
View File
@@ -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 */
+1 -2
View File
@@ -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 */
+1 -1
View File
@@ -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 */
+9
View File
@@ -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 {
+2 -1
View File
@@ -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
+26 -2
View File
@@ -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;
}
+2
View File
@@ -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:
+50 -11
View File
@@ -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;
}
+16 -32
View File
@@ -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;
}
+31 -1
View File
@@ -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));
+7 -3
View File
@@ -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) {
+3 -3
View File
@@ -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);
+15 -36
View File
@@ -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;
}
+106 -145
View File
@@ -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;
+103 -157
View File
@@ -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;
}
+8 -2
View File
@@ -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__*/
+138 -31
View File
@@ -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");
+6 -3
View File
@@ -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;
+2 -1
View File
@@ -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,
+41
View File
@@ -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;
}
+2
View File
@@ -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);
+13 -1
View File
@@ -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);
}
+42 -40
View File
@@ -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;
}
+2
View File
@@ -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
+4 -26
View File
@@ -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;
+3
View File
@@ -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
View File
@@ -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:
+47 -3
View File
@@ -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;
}
+13
View File
@@ -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_ */
+360
View File
@@ -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);
}
+77
View File
@@ -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_ */
+9
View File
@@ -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);
+3
View File
@@ -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);
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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 {
+54 -54
View File
@@ -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__*/
-178
View File
@@ -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;
}
-214
View File
@@ -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;
}
+1 -1
View File
@@ -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)
+61 -12
View File
@@ -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";
}
);