From 139c0d548c258e5508e391c72cde10fc1c91bfc1 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Mon, 19 May 2025 15:24:38 +0200 Subject: [PATCH 001/100] CI: change path to lteue and configs after SW update --- ci-scripts/ci_infra.yaml | 78 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/ci-scripts/ci_infra.yaml b/ci-scripts/ci_infra.yaml index 64432f6188..1f040c33ff 100644 --- a/ci-scripts/ci_infra.yaml +++ b/ci-scripts/ci_infra.yaml @@ -147,125 +147,127 @@ ltebox-nepes: amarisoft_ue: Host: amariue - InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_aw2s_asue/aw2s-multi-00102-20.cfg & - TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 + InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue/aw2s-multi-00102-20.cfg & + TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 + NetworkScript: ip netns exec ue1 ip a show dev pdn0 amarisoft_ue_2x2: Host: amariue - InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_aw2s_asue_2x2/aw2s-multi-00102-2x2-v2.cfg & - TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 + InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_aw2s_asue_2x2/aw2s-multi-00102-2x2-v2.cfg & + TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 + NetworkScript: ip netns exec ue1 ip a show dev pdn0 amarisoft_ue_fhi72: Host: amariue - InitScript: /root/lteue-linux-2023-10-27/ue/lteue /root/oaicicd/ran_sa_fhi72_asue_2x2_benetel550/fhi72-multi-20897-2x2.cfg & - TermScript: /root/2023-10-27/libs/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 + InitScript: /root/lteue-linux-2025-03-15/lteue /root/oaicicd/ran_sa_fhi72_asue_2x2_benetel550/fhi72-multi-20897-2x2.cfg & + TermScript: /root/lteue-linux-2025-03-15/ws.js -t 10 127.0.0.1:9002 '{"message":"quit"}' || killall -KILL lteue-avx2 amarisoft_ue_1: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":1}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":1}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":1}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":1}' NetworkScript: ip netns exec ue1 ip a show dev pdn0 CmdPrefix: ip netns exec ue1 MTU: 1500 amarisoft_ue_2: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":2}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":2}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":2}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":2}' NetworkScript: ip netns exec ue2 ip a show dev pdn0 CmdPrefix: ip netns exec ue2 MTU: 1500 amarisoft_ue_3: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":3}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":3}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":3}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":3}' NetworkScript: ip netns exec ue3 ip a show dev pdn0 CmdPrefix: ip netns exec ue3 MTU: 1500 amarisoft_ue_4: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":4}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":4}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":4}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":4}' NetworkScript: ip netns exec ue4 ip a show dev pdn0 CmdPrefix: ip netns exec ue4 MTU: 1500 amarisoft_ue_5: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":5}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":5}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":5}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":5}' NetworkScript: ip netns exec ue5 ip a show dev pdn0 CmdPrefix: ip netns exec ue5 MTU: 1500 amarisoft_ue_6: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":6}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":6}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":6}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":6}' NetworkScript: ip netns exec ue6 ip a show dev pdn0 CmdPrefix: ip netns exec ue6 MTU: 1500 amarisoft_ue_7: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":7}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":7}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":7}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":7}' NetworkScript: ip netns exec ue7 ip a show dev pdn0 CmdPrefix: ip netns exec ue7 MTU: 1500 amarisoft_ue_8: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":8}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":8}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":8}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":8}' NetworkScript: ip netns exec ue8 ip a show dev pdn0 CmdPrefix: ip netns exec ue8 MTU: 1500 amarisoft_ue_9: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":9}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":9}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":9}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":9}' NetworkScript: ip netns exec ue9 ip a show dev pdn0 CmdPrefix: ip netns exec ue9 MTU: 1500 amarisoft_ue_10: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":10}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":10}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":10}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":10}' NetworkScript: ip netns exec ue10 ip a show dev pdn0 CmdPrefix: ip netns exec ue10 MTU: 1500 amarisoft_ue_11: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":11}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":11}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":11}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":11}' NetworkScript: ip netns exec ue11 ip a show dev pdn0 CmdPrefix: ip netns exec ue11 MTU: 1500 amarisoft_ue_12: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":12}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":12}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":12}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":12}' NetworkScript: ip netns exec ue12 ip a show dev pdn0 CmdPrefix: ip netns exec ue12 MTU: 1500 amarisoft_ue_13: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":13}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":13}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":13}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":13}' NetworkScript: ip netns exec ue13 ip a show dev pdn0 CmdPrefix: ip netns exec ue13 MTU: 1500 amarisoft_ue_14: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":14}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":14}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":14}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":14}' NetworkScript: ip netns exec ue14 ip a show dev pdn0 CmdPrefix: ip netns exec ue14 MTU: 1500 amarisoft_ue_15: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":15}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":15}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":15}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":15}' NetworkScript: ip netns exec ue15 ip a show dev pdn0 CmdPrefix: ip netns exec ue15 MTU: 1500 amarisoft_ue_16: Host: amariue - AttachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":16}' - DetachScript: /root/2023-10-27/libs/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":16}' + AttachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_on","ue_id":16}' + DetachScript: /root/lteue-linux-2025-03-15/ws.js 127.0.0.1:9002 '{"message":"power_off","ue_id":16}' NetworkScript: ip netns exec ue16 ip a show dev pdn0 CmdPrefix: ip netns exec ue16 MTU: 1500 From 4f7b44e86217306af73ed84977c4c20c38a9f55c Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 2 Apr 2025 16:10:34 +0200 Subject: [PATCH 002/100] Remove the cmake option XAPP_MULTILANGUAGE from all Dockerfiles The FlexRIC main CMakeLists.txt sets XAPP_MULTILANGUAGE to OFF by default. Related commit ID: https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/637f718c3241f2f9ee809ecbd8a67ccb88575e65 --- docker/Dockerfile.build.fhi72.rhel9 | 3 +-- docker/Dockerfile.build.fhi72.ubuntu22 | 3 +-- docker/Dockerfile.build.rhel9 | 4 +--- docker/Dockerfile.build.ubuntu22 | 3 +-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/docker/Dockerfile.build.fhi72.rhel9 b/docker/Dockerfile.build.fhi72.rhel9 index 942896c4f8..b8ad1560ba 100644 --- a/docker/Dockerfile.build.fhi72.rhel9 +++ b/docker/Dockerfile.build.fhi72.rhel9 @@ -61,7 +61,7 @@ RUN /bin/sh oaienv && \ --gNB \ --build-lib 'telnetsrv enbscope uescope nrscope' \ -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \ - --build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION" &&\ + --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION" &&\ # Mainly to see if the sanitize option was perfectly executed ldd ran_build/build/nr-softmodem && \ ldd ran_build/build/liboran_fhlib_5g.so && \ @@ -72,7 +72,6 @@ RUN mkdir -p openair2/E2AP/flexric/build && \ cd openair2/E2AP/flexric/build && \ scl enable gcc-toolset-13 "\ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ - -DXAPP_MULTILANGUAGE=OFF \ -DKPM_VERSION=$KPM_VERSION \ -DE2AP_VERSION=$E2AP_VERSION .. &&\ ninja && \ diff --git a/docker/Dockerfile.build.fhi72.ubuntu22 b/docker/Dockerfile.build.fhi72.ubuntu22 index f4a4ab6de7..5da6d0b608 100644 --- a/docker/Dockerfile.build.fhi72.ubuntu22 +++ b/docker/Dockerfile.build.fhi72.ubuntu22 @@ -71,7 +71,7 @@ RUN /bin/sh oaienv && \ --gNB \ --build-lib "telnetsrv enbscope uescope nrscope" \ -t oran_fhlib_5g --cmake-opt -Dxran_LOCATION=/opt/phy/fhi_lib/lib \ - --build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ + --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ $BUILD_OPTION && \ # Mainly to see if the sanitize option was perfectly executed ldd ran_build/build/nr-softmodem && \ @@ -82,7 +82,6 @@ RUN /bin/sh oaienv && \ RUN mkdir -p openair2/E2AP/flexric/build && \ cd openair2/E2AP/flexric/build && \ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ - -DXAPP_MULTILANGUAGE=OFF \ -DKPM_VERSION=$KPM_VERSION \ -DE2AP_VERSION=$E2AP_VERSION \ -DCMAKE_C_COMPILER=gcc-12 \ diff --git a/docker/Dockerfile.build.rhel9 b/docker/Dockerfile.build.rhel9 index cff25b7169..c707f25ad8 100644 --- a/docker/Dockerfile.build.rhel9 +++ b/docker/Dockerfile.build.rhel9 @@ -41,8 +41,7 @@ RUN /bin/sh oaienv && \ scl enable gcc-toolset-13 "\ CXXFLAGS='-Werror -fstack-protector-strong' CFLAGS='-Werror -fstack-protector-strong' ./build_oai -c --ninja \ --eNB --gNB --RU --UE --nrUE \ - --build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt \ - -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ + --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ --build-lib 'telnetsrv enbscope uescope nrscope' \ --build-tool-opt -k10 \ -w USRP -t Ethernet \ @@ -57,7 +56,6 @@ RUN mkdir -p openair2/E2AP/flexric/build && \ cd openair2/E2AP/flexric/build && \ scl enable gcc-toolset-13 "\ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ - -DXAPP_MULTILANGUAGE=OFF \ -DKPM_VERSION=$KPM_VERSION \ -DE2AP_VERSION=$E2AP_VERSION .. &&\ ninja && \ diff --git a/docker/Dockerfile.build.ubuntu22 b/docker/Dockerfile.build.ubuntu22 index c0de631c41..a3c2417b33 100644 --- a/docker/Dockerfile.build.ubuntu22 +++ b/docker/Dockerfile.build.ubuntu22 @@ -43,7 +43,7 @@ RUN /bin/sh oaienv && \ --eNB --gNB --RU --UE --nrUE \ --build-lib "telnetsrv enbscope uescope nrscope" \ -w USRP -t Ethernet \ - --build-e2 --cmake-opt -DXAPP_MULTILANGUAGE=OFF --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ + --build-e2 --cmake-opt -DKPM_VERSION=$KPM_VERSION --cmake-opt -DE2AP_VERSION=$E2AP_VERSION \ --noavx512 \ --build-tool-opt -k10 \ --cmake-opt -DCMAKE_C_FLAGS="-Werror" --cmake-opt -DCMAKE_CXX_FLAGS="-Werror" $BUILD_OPTION && \ @@ -57,7 +57,6 @@ RUN /bin/sh oaienv && \ RUN mkdir -p openair2/E2AP/flexric/build && \ cd openair2/E2AP/flexric/build && \ cmake -GNinja -DCMAKE_BUILD_TYPE=Release \ - -DXAPP_MULTILANGUAGE=OFF \ -DKPM_VERSION=$KPM_VERSION \ -DE2AP_VERSION=$E2AP_VERSION \ -DCMAKE_C_COMPILER=gcc-12 \ From f5a75caa4c46977d6b68e9544f1cd484e00494ec Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 2 Apr 2025 16:23:01 +0200 Subject: [PATCH 003/100] Do not check E2AP/KPM versions if E2 agent disabled --- CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b607056aa4..b340c8785a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -300,14 +300,15 @@ add_definitions(-DHAVE_NETINET_IN_H) set(E2_AGENT "OFF" CACHE STRING "O-RAN-compliant E2 Agent") set_property(CACHE E2_AGENT PROPERTY STRINGS "ON" "OFF") -set(E2AP_VERSION "E2AP_V2" CACHE STRING "E2AP version") -set_property(CACHE E2AP_VERSION PROPERTY STRINGS "E2AP_V1" "E2AP_V2" "E2AP_V3") -message(STATUS "Selected E2AP_VERSION: ${E2AP_VERSION}") - -set(KPM_VERSION "KPM_V2_03" CACHE STRING "The KPM SM version to use") -set_property(CACHE KPM_VERSION PROPERTY STRINGS "KPM_V2_03" "KPM_V3_00") -message(STATUS "Selected KPM Version: ${KPM_VERSION}") +if (E2_AGENT) + set(E2AP_VERSION "E2AP_V2" CACHE STRING "E2AP version") + set_property(CACHE E2AP_VERSION PROPERTY STRINGS "E2AP_V1" "E2AP_V2" "E2AP_V3") + message(STATUS "Selected E2AP version: ${E2AP_VERSION}") + set(KPM_VERSION "KPM_V2_03" CACHE STRING "The KPM SM version to use") + set_property(CACHE KPM_VERSION PROPERTY STRINGS "KPM_V2_03" "KPM_V3_00") + message(STATUS "Selected KPM version: ${KPM_VERSION}") +endif() add_boolean_option(ENABLE_IMSCOPE OFF "Enable phy scope based on imgui" OFF) add_boolean_option(ENABLE_IMSCOPE_RECORD OFF "Enable recording IQ data for imscope" OFF) From 3f930551ffc5038f3b4b67d112ae93f39844b310 Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 4 Apr 2025 17:14:05 +0200 Subject: [PATCH 004/100] Fix CU to not contain the pointer for MAC/RLC stats Segmentation fault occured since the commit ID 9e5c5497abce7e6a47079e42a4a89168f75c35d2, where we try to copy the pointer which was not even been allocated. Before, we were copying the address of a NULL pointer and therefore no segmentation fault. This commit fixes the segmentation fault by checking if the memory was allocated, i.e. should not be in the case of CU (as it doesn't contain MAC/RLC layers). --- openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index aaf46797ac..e887740402 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -115,7 +115,9 @@ static cudu_ue_info_pair_t fill_ue_related_info(arr_ue_id_t* arr_ue_id, const si if (arr_ue_id->ue_id[ue_idx].type == GNB_UE_ID_E2SM) { ue_info.rrc_ue_id = *arr_ue_id->ue_id[ue_idx].gnb.ran_ue_id; // rrc_ue_id - ue_info.ue = arr_ue_id->ue_info_list[ue_idx]; + if (arr_ue_id->ue_info_list != NULL) { + ue_info.ue = arr_ue_id->ue_info_list[ue_idx]; + } } else if (arr_ue_id->ue_id[ue_idx].type == GNB_CU_UP_UE_ID_E2SM) { /* in OAI implementation, CU-UP ue id = CU-CP ue id => CU-UP ue id = rrc_ue_id, but it should not be the case by the spec */ From 2b3e1772d6698a4de7dd2a12fb38fa2a7cf88c60 Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 9 Apr 2025 10:34:18 +0200 Subject: [PATCH 005/100] Add e2_agent section in CU/DU split configuration --- targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf | 5 +++++ .../CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf index 4acca69864..f57725cc9b 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf @@ -71,3 +71,8 @@ log_config : { f1ap_log_level = "info"; ngap_log_level = "info"; }; + +e2_agent = { + near_ric_ip_addr = "127.0.0.1"; + sm_dir = "/usr/local/lib/flexric/" +}; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf index d4f7f82c74..3221813bef 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf @@ -210,3 +210,8 @@ log_config: { f1ap_log_level = "info"; ngap_log_level = "debug"; }; + +e2_agent = { + near_ric_ip_addr = "127.0.0.1"; + sm_dir = "/usr/local/lib/flexric/" +}; From 2644594c324ae01cb466ca80d874fc39799f3aaa Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 9 Apr 2025 11:06:07 +0200 Subject: [PATCH 006/100] Update the E2AP README - prerequisites - use the links to FlexRIC tutorial - build FlexRIC - use the build tutorial from FlexRIC tutorial - explain in more details the supported service model functionalities - explanation if no RIC INDICATION is being sent - use multi-UE rfsim tutorial from doc/, not oai-workshops repository --- openair2/E2AP/README.md | 233 ++++++++++++++++++++-------------------- 1 file changed, 117 insertions(+), 116 deletions(-) diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index 9b2b2716fb..ba742b2dda 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -11,163 +11,147 @@ Please see [NOTICE](NOTICE.md) file for third party software that is included in # Overview -This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent and a nearRT-RIC using O-RAN compliant FlexRIC. +This tutorial describes the steps of deployment 5G OAI RAN, with integrated E2 agent, and a nearRT-RIC using O-RAN compliant FlexRIC. [[_TOC_]] -# 1. Installation +# 1. Mandatory prerequisites of FlexRIC before starting with E2 agent +* [GCC compiler](https://gitlab.eurecom.fr/mosaic5g/flexric#111-gcc-compiler) +* [(opt.) configure Wireshark](https://gitlab.eurecom.fr/mosaic5g/flexric#112-opt-wireshark) +* [Mandatory dependencies](https://gitlab.eurecom.fr/mosaic5g/flexric#121-mandatory-dependencies) -## 1.1 Install prerequisites - -- A *recent* CMake (at least v3.15). - - On Ubuntu, you might want to use [this PPA](https://apt.kitware.com/) to install an up-to-date version. - -- SWIG (at least v.4.1). - - We use SWIG as an interface generator to enable the multi-language feature (i.e., C/C++ and Python) for the xApps. Please, check your SWIG version (i.e, `swig - -version`) and install it from scratch if necessary as described here: https://swig.org/svn.html or via the code below: - - ```bash - git clone https://github.com/swig/swig.git - cd swig - git checkout release-4.1 - ./autogen.sh - ./configure --prefix=/usr/ - make -j8 - make install - ``` - -- Flatbuffer encoding(optional). - - We also provide a flatbuffers encoding/decoding scheme as alternative to ASN.1. In case that you want to use it follow the - instructions at https://github.com/dvidelabs/flatcc and provide the path for the lib and include when selecting it at `ccmake ..` from the build directory - -## 1.2 Download the required dependencies. - -Below an example of how to install it in ubuntu -```bash -sudo apt install libsctp-dev python3.8 cmake-curses-gui libpcre2-dev python-dev -``` # 2. Deployment ## 2.1 OAI RAN +OAI E2 agent contains: +* RAN functions: exposure of service models capabilities +* FlexRIC submodule: for message enc/dec + +Currently available versions: +| |E2SM-KPM v2.03|E2SM-KPM v3.00| +|:-----------|:-------------|:-------------| +| E2AP v1.01 | Y | Y | +| E2AP v2.03 | Y (default) | Y | +| E2AP v3.01 | Y | Y | + +Note: E2SM-KPM `v2.01` is supported only in FlexRIC, but not in OAI. ### 2.1.1 Clone the OAI repository ```bash -git clone https://gitlab.eurecom.fr/oai/openairinterface5g oai -cd oai/ +git clone https://gitlab.eurecom.fr/oai/openairinterface5g ``` ### 2.1.2 Build OAI with E2 Agent -- By default, OAI will build the E2 Agent with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at OAI's CMakeLists.txt file. - -Currently available versions: -| |KPM v2.03|KPM v3.00| -|:-----------|:--------|:--------| -| E2AP v1.01 | Y | Y | -| E2AP v2.03 | Y | Y | -| E2AP v3.01 | Y | Y | - -Please note that KPM SM v2.01 is supported only in FlexRIC, but not in OAI. - +#### Using build_oai script ```bash -cd cmake_targets/ -./build_oai -I -w SIMU --gNB --nrUE --build-e2 --ninja +cd openairinterface5g/cmake_targets/ +./build_oai -I # if you never installed OAI, use this command once before the next line +# +./build_oai --gNB --nrUE --build-e2 --cmake-opt -DE2AP_VERSION=E2AP_VX --cmake-opt -DKPM_VERSION=KPM_VY --ninja ``` +where `X`=`1`,`2`,`3`, and `Y`=`2_03`,`3_00`. * `-I` option is to install pre-requisites, you only need it the first time you build the softmodem or when some oai dependencies have changed. - * `-w` option is to select the radio head support you want to include in your build. Radio head support is provided via a shared library, which is called the "oai device" The build script creates a soft link from `liboai_device.so` to the true device which will be used at run-time (here the USRP one, liboai_usrpdevif.so). The RF simulatorRF simulator is implemented as a specific device replacing RF hardware, it can be specifically built using `-w SIMU` option, but is also built during any softmodem build. + * `-w` option is to select the radio head support you want to include in your build. Radio head support is provided via a shared library, which is called the "oai device" The build script creates a soft link from `liboai_device.so` to the true device which will be used at run-time (here the USRP one, `liboai_usrpdevif.so`). The RF simulator is implemented as a specific device replacing RF hardware, it can be specifically built using `-w SIMU` option, but is also built during any softmodem build. * `--gNB` is to build the `nr-softmodem` and `nr-cuup` executables and all required shared libraries * `--nrUE` is to build the `nr-uesoftmodem` executable and all required shared libraries * `--ninja` is to use the ninja build tool, which speeds up compilation - * `--build-e2` option is to use the E2 agent, integrated within RAN. + * `--build-e2` option is to use the E2 agent, integrated within E2 nodes (gNB-mono, DU, CU, CU-UP, CU-CP). -If the openair2/E2AP/flexric folder is empty, try manually the following commands: +#### Using cmake directly ```bash -git submodule init -git submodule update +cd openairinterface5g +mkdir build && cd build +cmake .. -GNinja -DE2_AGENT=ON -DE2AP_VERSION=E2AP_VX -DKPM_VERSION=KPM_VY +ninja nr-softmodem nr-cuup nr-uesoftmodem params_libconfig rfsimulator ``` +where `X`=`1`,`2`,`3`, and `Y`=`2_03`,`3_00`. + ## 2.2 FlexRIC +Important to note: OAI RAN and FlexRIC must be compiled with the same E2AP and E2SM-KPM versions. -By default, FlexRIC will build the nearRT-RIC with E2AP v2 and KPM v2. If you want a different version, edit the variable E2AP\_VERSION and KPM\_VERSION at FlexRIC's CMakeLists.txt file. Note that OAI's and FlexRIC's E2AP\_VERSION and KPM\_VERSION need to match due to O-RAN incompatibilities among versions. - - -### 2.2.1 Clone the FlexRIC repository +### 2.2.1 Case 1: OAI RAN and FlexRIC on the same machine +Instead of cloning the new FlexRIC repository, feel free to use FlexRIC submodule as a nearRT-RIC + xApp framework, apart from the E2 agent side. In order to achieve this, please follow the next steps: ```bash -git clone https://gitlab.eurecom.fr/mosaic5g/flexric flexric -cd flexric/ -git checkout f1c08ed2b9b1eceeda7941dd7bf435db0168dd56 +cd openairinterface5g/openair2/E2AP/flexric +git submodule init && git submodule update # only if OAI RAN wasn't previously compiled with --build-e2 or -DE2_AGENT options ``` +and continue as described in the [build FlexRIC section](https://gitlab.eurecom.fr/mosaic5g/flexric#22-build-flexric). -### 2.2.2 Build FlexRIC -```bash -mkdir build && cd build && cmake .. && make -j8 -``` +### 2.2.2 Case 2: OAI RAN and FlexRIC on different machines +The [FlexRIC submodule compilation step](#221-case-1-oai-ran-and-flexric-on-the-same-machine) is **mandatory** as the OAI RAN must use the Service Models (which are built as shared libraries). +To build FlexRIC on the other machine, follow the complete [FlexRIC installation](https://gitlab.eurecom.fr/mosaic5g/flexric#2-flexric-installation) process. -### 2.2.3 Installation of Service Models (SMs) -```bash -sudo make install -``` - -By default the service model libraries will be installed in the path `/usr/local/lib/flexric` while the configuration file in `/usr/local/etc/flexric`. # 3. Service Models available in OAI RAN ## 3.1 O-RAN +For a deeper understanding, we recommend that users of FlexRIC familiarize themselves with O-RAN WG3 specifications available at the [O-RAN specifications page](https://orandownloadsweb.azurewebsites.net/specifications). -We assume that user is familiar with O-RAN WG3 specifications that can be found at https://orandownloadsweb.azurewebsites.net/specifications. +The following specifications are recommended: +* `O-RAN.WG3.E2GAP-v02.00` - nearRT-RIC architecture & E2 General Aspects and Principles: important for a general understanding for E2 +* `O-RAN.WG3.E2AP-version` - E2AP protocol description +* `O-RAN.WG3.E2SM-KPM-version` - E2SM-KPM Service Model description +* `O-RAN.WG3.E2SM-RC-v01.03` - E2SM-RC Service Model description ### 3.1.1 E2SM-KPM - -As mentioned in section [2.1.2 Build OAI with E2 Agent](#212-build-oai-with-e2-agent), we support KPM v2.03/v3.00. Uses ASN.1 encoding. +As mentioned in section [2.1 OAI RAN](#21-oai-ran), we support KPM `v2.03/v3.00` which all use ASN.1 encoding. Per O-RAN specifications, 5G measurements supported by KPM are specified in 3GPP TS 28.552. From 3GPP TS 28.552, we support the following list: - * "DRB.PdcpSduVolumeDL" - * "DRB.PdcpSduVolumeUL" - * "DRB.RlcSduDelayDl" - * "DRB.UEThpDl" - * "DRB.UEThpUl" - * "RRU.PrbTotDl" - * "RRU.PrbTotUl" + * `DRB.PdcpSduVolumeDL` + * `DRB.PdcpSduVolumeUL` + * `DRB.RlcSduDelayDl` + * `DRB.UEThpDl` + * `DRB.UEThpUl` + * `RRU.PrbTotDl` + * `RRU.PrbTotUl` -From O-RAN.WG3.E2SM-KPM-version specification, we implemented: - * REPORT Service Style 4 ("Common condition-based, UE-level" - section 7.4.5) - fetch above measurements per each UE that matches common criteria (e.g. S-NSSAI). +From `O-RAN.WG3.E2SM-KPM-version` specification, we implemented: + * REPORT Service Style 4 ("Common condition-based, UE-level" - section 7.4.5) - fetch above measurements per each UE based on the common S-NSSAI `(1, 0xffffff)` condition ### 3.1.2 E2SM-RC +We support E2SM-RC `v1.03` which uses ASN.1 encoding. -We support RC v1.03. Uses ASN.1 encoding. - -From ORAN.WG3.E2SM-RC-v01.03 specification, we implemented: +From `O-RAN.WG3.E2SM-RC-v01.03` specification, we implemented: * REPORT Service Style 1 ("Message copy" - section 7.4.2) - aperiodic subscription for "RRC Message" and "UE ID" * REPORT Service Style 4 ("UE Information" - section 7.4.5) - aperiodic subscription for "UE RRC State Change" - * CONTROL Service Style 1 ("Radio Bearer Control" - section 7.6.2) - "QoS flow mapping configuration" (e.g creating a new DRB) + * CONTROL Service Style 1 ("Radio Bearer Control" - section 7.6.2) - "QoS flow mapping configuration"; please be aware that this functionality is defined as per O-RAN "To control the multiplexing of QoS flows to a DRB", + but OAI RAN doesn't support multiple QoS flows in one DRB. Therefore, this use case was adjusted for creation of new DRB, instead of creation of new QoS flow in the existing DRB. + More information can be found in the branch [qoe-e2](https://gitlab.eurecom.fr/oai/openairinterface5g/-/tree/qoe-e2?ref_type=heads). It's not merged due to incompliance with O-RAN specifications. + We showcased this demo in the O-RAN F2F Osaka meeting. Please feel free to download the [demo video](https://lf-o-ran-sc.atlassian.net/wiki/download/attachments/13566077/oai-flexric-demo-ric.mp4?api=v2) and [accompanying presentation](https://lf-o-ran-sc.atlassian.net/wiki/download/attachments/13566077/oai-FlexRIC-demo.pdf?api=v2). ## 3.2 Custom Service Models +In addition, we support custom Service Models for L2/L3. Please find the KPIs for each layer in the following structs: +* MAC: `mac_ue_stats_impl_t` +* RLC: `rlc_radio_bearer_stats_t` +* PDCP: `pdcp_radio_bearer_stats_t` +* GTP: `gtp_ngu_t_stats_t` -In addition, we support custom Service Models, such are MAC, RLC, PDCP, and GTP. Use plain encoding. +All use plain encoding, i.e., no ASN.1, but write the binary data into network messages. -If you are interested in TC and SLICE SMs, please follow the instructions at https://gitlab.eurecom.fr/mosaic5g/flexric. +There exist two additional custom Service Models, SLICE and TC (traffic control), but they are not supported in OAI RAN. They can only be tested with [E2 agent emulators](https://gitlab.eurecom.fr/mosaic5g/flexric#4-deployment) within FlexRIC framework. # 4. Start the process +At this point, we assume the 5G Core Network is already running in the background. For more information, please follow the [5GCN tutorial](../../doc/NR_SA_Tutorial_OAI_CN5G.md). -At this point, we assume the 5G Core Network is already running in the background. For more information, please follow the tutorial at https://gitlab.eurecom.fr/oai/openairinterface5g/-/blob/develop/doc/NR_SA_Tutorial_OAI_CN5G.md. +Optionally run Wireshark and capture E2AP traffic. -In order to configure E2 agent, please, add the following block in OAI's configuration file: +The E2 node (gNB-mono, DU, CU, CU-UP, CU-CP) configuration file must contain the `e2_agent` section. Please adjust the following example to your needs: ```bash e2_agent = { near_ric_ip_addr = "127.0.0.1"; - sm_dir = "/usr/local/lib/flexric/" + sm_dir = "/usr/local/lib/flexric/"; } ``` -* start E2 Node agents - As per O-RAN.WG3.E2SM-v02.00 specifications, UE ID (section 6.2.2.6) representation in OAI is: +* start the E2 nodes + + As per `O-RAN.WG3.E2SM-v02.00` specifications, `UE ID` (section 6.2.2.6) representation in OAI is: | | gNB-mono | CU | CU-CP | CU-UP | DU | |:----------------------|:----------------|:----------------|:----------------|:----------------------|:-------------------| | CHOICE UE ID case | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_UE_ID_E2SM | GNB_CU_UP_UE_ID_E2SM | GNB_DU_UE_ID_E2SM | @@ -179,68 +163,85 @@ e2_agent = { * start the gNB-mono ```bash - cd oai/cmake_targets/ran_build/build - sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --rfsim -E + cd /build + sudo ./nr-softmodem -O /targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf --gNBs.[0].min_rxtxtime 6 --rfsim ``` * if CU/DU split is used, start the gNB as follows ```bash - sudo ./nr-softmodem -O --rfsim -E - sudo ./nr-softmodem -O + cd /build + sudo ./nr-softmodem -O /targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf --rfsim + sudo ./nr-softmodem -O /targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-cu.sa.f1.conf ``` * if CU-CP/CU-UP/DU split is used, start the gNB as follows ```bash - sudo ./nr-softmodem -O --rfsim -E - sudo ./nr-softmodem -O - sudo ./nr-cuup -O + cd /build + sudo ./nr-softmodem -O /targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band78.106prb.rfsim.pci0.conf --rfsim + ./nr-softmodem -O /ci-scripts/conf_files/gnb-cucp.sa.f1.conf --gNBs.[0].plmn_list.[0].mcc 001 --gNBs.[0].plmn_list.[0].mnc 01 --gNBs.[0].local_s_address "127.0.0.3" --gNBs.[0].amf_ip_address.[0].ipv4 "192.168.70.132" --gNBs.[0].E1_INTERFACE.[0].ipv4_cucp "127.0.0.3" --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF "192.168.70.129" --e2_agent.near_ric_ip_addr "127.0.0.1" --e2_agent.sm_dir "/usr/local/lib/flexric/" + sudo ./nr-cuup -O /ci-scripts/conf_files/gnb-cuup.sa.f1.conf --gNBs.[0].plmn_list.[0].mcc 001 --gNBs.[0].plmn_list.[0].mnc 01 --gNBs.[0].local_s_address "127.0.0.6" --gNBs.[0].E1_INTERFACE.[0].ipv4_cucp "127.0.0.3" --gNBs.[0].E1_INTERFACE.[0].ipv4_cuup "127.0.0.6" --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF "192.168.70.129" --gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU "192.168.70.129" --e2_agent.near_ric_ip_addr "127.0.0.1" --e2_agent.sm_dir "/usr/local/lib/flexric/" --rfsim + ``` * start the nrUE ```bash - cd oai/cmake_targets/ran_build/build + cd /build + # for gNB-mono sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1 + # for CU/DU and CU-CP/CU-UP/DU split + sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3450720000 --rfsim --uicc0.imsi 001010000000001 --rfsimulator.serveraddr 127.0.0.1 ``` + Note: [multi-UE rfsim deployment tutorial](../../doc/NR_SA_Tutorial_OAI_multi_UE.md?ref_type=heads#run-multiple-ues-in-rfsimulator) * start the nearRT-RIC ```bash - cd flexric + cd flexric # or openairinterface5g/openair2/E2AP/flexric ./build/examples/ric/nearRT-RIC ``` * Start different xApps - - * start the KPM monitor xApp - measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) for each UE that matches S-NSSAI common criteria + Important to note: if no RIC INDICATION is received by any of the xApps, either the + * start the KPM monitor xApp - measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) for each UE that matches S-NSSAI `(1, 0xffffff)` common criteria ```bash - cd flexric + cd flexric # or openairinterface5g/openair2/E2AP/flexric ./build/examples/xApp/c/monitor/xapp_kpm_moni ``` - Note: we assume that each UE has only 1 DRB; CU-UP does not store the slices, therefore "coarse filtering" is used + Note: we assume that each UE has only 1 DRB; CU-UP does not store the slices, therefore "coarse filtering" is used; **if no RIC INDICATION message received**, please check if: + (1) UE is connected to the gNB + (2) UE has a PDU session (LCID 4) + (3) UE supports the slice `(1, 0xffffff)` * start the RC monitor xApp - aperiodic subscriptions for "UE RRC State Change", "RRC Message" copy (`RRC Reconfiguration`, `Measurement Report`, `Security Mode Complete`, `RRC Setup Complete`), and "UE ID" when `RRC Setup Complete` and/or `F1 UE Context Setup Request` detected ```bash - cd flexric + cd flexric # or openairinterface5g/openair2/E2AP/flexric ./build/examples/xApp/c/monitor/xapp_rc_moni ``` - * start the RC control xApp - RAN control function "QoS flow mapping configuration" (e.g. creating a new DRB) + * start the KPM monitor and RC control xApp - this xApp is only a PoC. It collects the measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) and sends the RC Control message + for "QoS flow mapping configuration". However, no control is being done within the RAN itself. Please refer to [3.1.2 E2SM-RC](#312-e2sm-rc) for detailed explanation. ```bash - cd flexric + cd flexric # or openairinterface5g/openair2/E2AP/flexric ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc ``` * start the (MAC + RLC + PDCP + GTP) monitor xApp ```bash - cd flexric + cd flexric # or openairinterface5g/openair2/E2AP/flexric ./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni ``` + Note: GTP is not yet implemented in CU-UP; **if no RIC INDICATION message received**, please check if: + (1) UE is connected to the gNB + (2) UE has a PDU session (LCID 4) - if no PDU session, only MAC/GTP stats will be sent + + * if `XAPP_MULTILANGUAGE` option is enabled, start the python xApps: + ```bash + python3 build/examples/xApp/python3/xapp_mac_rlc_pdcp_gtp_moni.py # only supported by the gNB-mono + ``` + The latency that you observe in your monitor xApp is the latency from the E2 Agent to the nearRT-RIC and xApp. Therefore, FlexRIC is well suited for use cases with ultra low-latency requirements. -Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is also written to /tmp/xapp_db in case that offline data processing is wanted (e.g., Machine Learning/Artificial Intelligence applications). You can browse the data using e.g., sqlitebrowser. +Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is also written to `/tmp/xapp_db_` in case that offline data processing is wanted (e.g., Machine Learning/Artificial Intelligence applications). You can browse the data using e.g., `sqlitebrowser`. + Please note: * KPM SM database is not been updated, therefore commented in `flexric/src/xApp/db/sqlite3/sqlite3_wrapper.c:1152` * RC SM database is not yet implemented. - -# Optional - Multiple UEs - -If you are interested in having multiple UEs in rfsim mode, please, follow the instructions at https://gitlab.eurecom.fr/oaiworkshop/summerworkshop2023/-/tree/main/ran#multiple-ues. From dfa1bd4efe7c3c58661f52d684cb3c0f94932987 Mon Sep 17 00:00:00 2001 From: Teodora Date: Tue, 29 Apr 2025 17:55:26 +0200 Subject: [PATCH 007/100] Add the NSSAI logging condition in KPM It is a periodic output, based on the reporting period. --- openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index e887740402..4468cdf0b9 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c @@ -173,6 +173,7 @@ static void capture_sst_sd(test_cond_value_t* test_cond_value, uint8_t *sst, uin *sd = malloc(**sd); **sd = buf[1] << 16 | buf[2] << 8 | buf[3]; } + printf("[E2 AGENT][E2SM-KPM] Condition NSSAI (%d, %x).\n", *sst, (*sd) ? **sd : 0xffffff); break; } default: @@ -408,7 +409,10 @@ bool read_kpm_sm(void* data) ue_type_matcher fp_match_cond_type = (*match_cond_arr[test_info.test_cond_type])[node_type]; arr_ue_id_t arr_ue_id = fp_match_cond_type(test_info); - if (arr_ue_id.sz == 0) return false; + if (arr_ue_id.sz == 0) { + printf("[E2 AGENT][E2SM-KPM] No UE matches the condition criteria.\n"); + return false; + } kpm->ind.msg.frm_3 = fill_kpm_ind_msg_frm_3(&arr_ue_id, &frm_4->action_def_format_1); } break; From 227f9e92f6b94291e85001a87b616d0ba88604ee Mon Sep 17 00:00:00 2001 From: Teodora Date: Tue, 29 Apr 2025 22:13:24 +0200 Subject: [PATCH 008/100] Properly fill RC RAN Function Name Follow-up for https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/143c0238e977035ce9cf5491ff41f06b29f6a278. --- .../E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c index 4dfddf6253..14c357496c 100644 --- a/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c +++ b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc.c @@ -27,6 +27,7 @@ #include "../../flexric/src/sm/rc_sm/ie/ir/ran_param_list.h" #include "../../flexric/src/agent/e2_agent_api.h" #include "openair2/E2AP/flexric/src/lib/sm/enc/enc_ue_id.h" +#include "openair2/E2AP/flexric/src/sm/rc_sm/rc_sm_id.h" #include #include @@ -379,10 +380,26 @@ static void fill_rc_control(ran_func_def_ctrl_t* ctrl) ctrl_style->ran_param_ctrl_out = NULL; } +static ran_function_name_t fill_rc_ran_func_name(void) +{ + ran_function_name_t dst = { + .name = cp_str_to_ba(SM_RAN_CTRL_SHORT_NAME), + .oid = cp_str_to_ba(SM_RAN_CTRL_OID), + .description = cp_str_to_ba(SM_RAN_CTRL_DESCRIPTION), + .instance = NULL + }; + return dst; +} + e2sm_rc_func_def_t fill_rc_ran_def_gnb(void) { e2sm_rc_func_def_t def = {0}; + // RAN Function Name + // Mandatory + // 9.3.2 + def.name = fill_rc_ran_func_name(); + // RAN Function Definition for EVENT TRIGGER // Optional // 9.2.2.2 @@ -421,6 +438,11 @@ static e2sm_rc_func_def_t fill_rc_ran_def_cu(void) { e2sm_rc_func_def_t def = {0}; + // RAN Function Name + // Mandatory + // 9.3.2 + def.name = fill_rc_ran_func_name(); + // RAN Function Definition for EVENT TRIGGER // Optional // 9.2.2.2 @@ -459,6 +481,11 @@ static e2sm_rc_func_def_t fill_rc_ran_def_null(void) { e2sm_rc_func_def_t def = {0}; + // RAN Function Name + // Mandatory + // 9.3.2 + def.name = fill_rc_ran_func_name(); + // RAN Function Definition for EVENT TRIGGER // Optional // 9.2.2.2 @@ -491,6 +518,11 @@ static e2sm_rc_func_def_t fill_rc_ran_def_cucp(void) { e2sm_rc_func_def_t def = {0}; + // RAN Function Name + // Mandatory + // 9.3.2 + def.name = fill_rc_ran_func_name(); + // RAN Function Definition for EVENT TRIGGER // Optional // 9.2.2.2 @@ -547,9 +579,6 @@ void read_rc_setup_sm(void* data) rc_e2_setup_t* rc = (rc_e2_setup_t*)data; /* Fill the RAN Function Definition with currently supported measurements */ - - // RAN Function Name is already filled in fill_ran_function_name() in rc_sm_agent.c - const ngran_node_t node_type = get_e2_node_type(); rc->ran_func_def = ran_def_rc[node_type](); From bd97d1165495b93ebff74e4279900a92f28cfb67 Mon Sep 17 00:00:00 2001 From: Teodora Date: Tue, 29 Apr 2025 22:16:29 +0200 Subject: [PATCH 009/100] Update FlexRIC submodule commit ID --- openair2/E2AP/flexric | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/E2AP/flexric b/openair2/E2AP/flexric index 2638b58e20..df754a8553 160000 --- a/openair2/E2AP/flexric +++ b/openair2/E2AP/flexric @@ -1 +1 @@ -Subproject commit 2638b58e201ab15200d0e02c6225e9aac35ab51b +Subproject commit df754a85537f6db255b5330b8d83eda6a2742f25 From 735bc2fa050c5d2dfb991fe1a26ecc7111bc835c Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 2 May 2025 01:10:24 +0200 Subject: [PATCH 010/100] Delete unnecessary test cases for OAI-FlexRIC CI pipeline Needless sleep time test case, and duplicated test case for the xApp with custom SMs. --- .../xml_files/container_5g_flexric_rfsim.xml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index d0d3446f41..05e050ab64 100644 --- a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml @@ -32,7 +32,6 @@ 000001 000002 000003 - 002001 010000 000004 333333 @@ -40,7 +39,6 @@ 010002 010003 020005 - 010013 002006 444444 100002 @@ -50,12 +48,6 @@ - - IdleSleep - Sleep - 10 - - Pull_Local_Registry Pull Images from Local Registry @@ -204,12 +196,4 @@ docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" > ../cmake_targets/log/5g_rfsimulator_flexric/sms-moni-010003.log - - Custom_Command - Custom SMs monitoring - localhost - yes - docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" > ../cmake_targets/log/5g_rfsimulator_flexric/sms-moni-010013.log - - From 498d2f8b374ca791fed2e14888d71320157bab68 Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 2 May 2025 01:18:19 +0200 Subject: [PATCH 011/100] Improve OAI-FlexRIC CI pipeline Instead of running xApps from oai-flexric container, create dedicated xApp containers. In addition, modify the flexric.conf: DB_PATH doesn't exist; DB_DIR is the correct name. --- .../xml_files/container_5g_flexric_rfsim.xml | 36 +++++----- .../5g_rfsimulator_flexric/conf/flexric.conf | 4 +- .../5g_rfsimulator_flexric/docker-compose.yml | 68 +++++++++++++++++++ 3 files changed, 90 insertions(+), 18 deletions(-) diff --git a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index 05e050ab64..a56248fe0e 100644 --- a/ci-scripts/xml_files/container_5g_flexric_rfsim.xml +++ b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml @@ -165,35 +165,39 @@ - Custom_Command + Deploy_Object RC monitoring - localhost - yes - docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_rc_moni" > ../cmake_targets/log/5g_rfsimulator_flexric/rc-moni-010000.log + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-rc-moni + 0 + 0 - Custom_Command + Deploy_Object KPM monitoring - localhost - yes - docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_kpm_moni" > ../cmake_targets/log/5g_rfsimulator_flexric/kpm-moni-010001.log + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-moni + 0 + 0 - Custom_Command + Deploy_Object KPM monitoring and RC control - localhost - yes - docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/kpm_rc/xapp_kpm_rc" > ../cmake_targets/log/5g_rfsimulator_flexric/kpm_rc-010002.log + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-kpm-rc + 0 + 0 - Custom_Command + Deploy_Object Custom SMs monitoring - localhost - yes - docker exec oai-flexric bash -c "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" > ../cmake_targets/log/5g_rfsimulator_flexric/sms-moni-010003.log + ci-scripts/yaml_files/5g_rfsimulator_flexric + xapp-gtp-mac-rlc-pdcp-moni + 0 + 0 diff --git a/ci-scripts/yaml_files/5g_rfsimulator_flexric/conf/flexric.conf b/ci-scripts/yaml_files/5g_rfsimulator_flexric/conf/flexric.conf index 5ffbf3d47f..481c4e68f9 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_flexric/conf/flexric.conf +++ b/ci-scripts/yaml_files/5g_rfsimulator_flexric/conf/flexric.conf @@ -1,5 +1,5 @@ [NEAR-RIC] NEAR_RIC_IP = 192.168.70.150 + [XAPP] -DB_PATH = /flexric/db/ -DB_NAME = xapp_rnis_db +DB_DIR = /tmp/ diff --git a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml index 9afdd02b60..899e02295f 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml @@ -13,6 +13,74 @@ services: interval: 10s timeout: 5s + xapp-rc-moni: + image: ${REGISTRY:-oaisoftwarealliance}/oai-flexric:${FLEXRIC_TAG:-develop} + command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_rc_moni" + container_name: xapp-rc-moni + depends_on: + - oai-flexric + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.70.154 + volumes: + - ./conf/flexric.conf:/usr/local/etc/flexric/flexric.conf + healthcheck: + test: /bin/bash -c "pgrep xapp_rc_moni" + interval: 10s + timeout: 5s + + xapp-kpm-moni: + image: ${REGISTRY:-oaisoftwarealliance}/oai-flexric:${FLEXRIC_TAG:-develop} + command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_kpm_moni" + container_name: xapp-kpm-moni + depends_on: + - oai-flexric + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.70.155 + volumes: + - ./conf/flexric.conf:/usr/local/etc/flexric/flexric.conf + healthcheck: + test: /bin/bash -c "pgrep xapp_kpm_moni" + interval: 10s + timeout: 5s + + xapp-kpm-rc: + image: ${REGISTRY:-oaisoftwarealliance}/oai-flexric:${FLEXRIC_TAG:-develop} + command: "stdbuf -o0 /usr/local/flexric/xApp/c/kpm_rc/xapp_kpm_rc" + container_name: xapp-kpm-rc + depends_on: + - oai-flexric + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.70.156 + volumes: + - ./conf/flexric.conf:/usr/local/etc/flexric/flexric.conf + healthcheck: + test: /bin/bash -c "pgrep xapp_kpm_rc" + interval: 10s + timeout: 5s + + xapp-gtp-mac-rlc-pdcp-moni: + image: ${REGISTRY:-oaisoftwarealliance}/oai-flexric:${FLEXRIC_TAG:-develop} + command: "stdbuf -o0 /usr/local/flexric/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni" + container_name: xapp-gtp-mac-rlc-pdcp-moni + depends_on: + - oai-flexric + - oai-gnb + networks: + public_net: + ipv4_address: 192.168.70.157 + volumes: + - ./conf/flexric.conf:/usr/local/etc/flexric/flexric.conf + healthcheck: + test: /bin/bash -c "pgrep -f xapp_gtp_mac_rlc_pdcp_moni" + interval: 10s + timeout: 5s + oai-gnb: image: ${REGISTRY:-oaisoftwarealliance}/${GNB_IMG:-oai-gnb}:${TAG:-develop} privileged: true From a84a5328f2fa0753b7be9cb55c63bb9fd4aec673 Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 2 May 2025 01:31:29 +0200 Subject: [PATCH 012/100] Make xApp duration flexible Improvement introduced in https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/0410c023726b18b9002f5adb39f7df95f49a7d7a. --- openair2/E2AP/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index ba742b2dda..7866467397 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -199,12 +199,13 @@ e2_agent = { ./build/examples/ric/nearRT-RIC ``` +`XAPP_DURATION` environment variable overwrites the default xApp duration of 20s. * Start different xApps Important to note: if no RIC INDICATION is received by any of the xApps, either the * start the KPM monitor xApp - measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) for each UE that matches S-NSSAI `(1, 0xffffff)` common criteria ```bash cd flexric # or openairinterface5g/openair2/E2AP/flexric - ./build/examples/xApp/c/monitor/xapp_kpm_moni + XAPP_DURATION=30 ./build/examples/xApp/c/monitor/xapp_kpm_moni ``` Note: we assume that each UE has only 1 DRB; CU-UP does not store the slices, therefore "coarse filtering" is used; **if no RIC INDICATION message received**, please check if: (1) UE is connected to the gNB @@ -214,20 +215,20 @@ e2_agent = { * start the RC monitor xApp - aperiodic subscriptions for "UE RRC State Change", "RRC Message" copy (`RRC Reconfiguration`, `Measurement Report`, `Security Mode Complete`, `RRC Setup Complete`), and "UE ID" when `RRC Setup Complete` and/or `F1 UE Context Setup Request` detected ```bash cd flexric # or openairinterface5g/openair2/E2AP/flexric - ./build/examples/xApp/c/monitor/xapp_rc_moni + XAPP_DURATION=30 ./build/examples/xApp/c/monitor/xapp_rc_moni ``` * start the KPM monitor and RC control xApp - this xApp is only a PoC. It collects the measurements stated in [3.1.1 E2SM-KPM](#311-e2sm-kpm) and sends the RC Control message for "QoS flow mapping configuration". However, no control is being done within the RAN itself. Please refer to [3.1.2 E2SM-RC](#312-e2sm-rc) for detailed explanation. ```bash cd flexric # or openairinterface5g/openair2/E2AP/flexric - ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc + XAPP_DURATION=30 ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc ``` * start the (MAC + RLC + PDCP + GTP) monitor xApp ```bash cd flexric # or openairinterface5g/openair2/E2AP/flexric - ./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni + XAPP_DURATION=30 ./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni ``` Note: GTP is not yet implemented in CU-UP; **if no RIC INDICATION message received**, please check if: (1) UE is connected to the gNB @@ -235,7 +236,7 @@ e2_agent = { * if `XAPP_MULTILANGUAGE` option is enabled, start the python xApps: ```bash - python3 build/examples/xApp/python3/xapp_mac_rlc_pdcp_gtp_moni.py # only supported by the gNB-mono + XAPP_DURATION=30 python3 build/examples/xApp/python3/xapp_mac_rlc_pdcp_gtp_moni.py # only supported by the gNB-mono ``` The latency that you observe in your monitor xApp is the latency from the E2 Agent to the nearRT-RIC and xApp. From 401ebe17b26cae5784db103fe59578a28783eafe Mon Sep 17 00:00:00 2001 From: Utku Ucak Date: Wed, 4 Jun 2025 13:31:46 +0000 Subject: [PATCH 013/100] fix config file --- .../GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf index 3d81eafd7a..d3852e236a 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.24PRB.usrpb210.conf @@ -29,7 +29,7 @@ gNBs = # downlinkConfigCommon #frequencyInfoDL # this is 3600 MHz + 12 PRBs@30kHz SCS (same as initial BWP) - absoluteFrequencySSB = 640288; + absoluteFrequencySSB = 640320; dl_frequencyBand = 78; # this is 3600 MHz dl_absoluteFrequencyPointA = 640000; @@ -82,7 +82,7 @@ gNBs = powerRampingStep = 1; #ra_ReponseWindow #1,2,4,8,10,20,40,80 - ra_ResponseWindow = 4; + ra_ResponseWindow = 5; #ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR #1=oneeighth,2=onefourth,3=half,4=one,5=two,6=four,7=eight,8=sixteen ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR = 4; From 93d9abd9b88a21ab4b216c4468d6810cffbbc984 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 14:42:06 +0200 Subject: [PATCH 014/100] increase max number of check values This will be needed for NR RLC and NR PDCP parameters. --- common/config/config_paramdesc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/config/config_paramdesc.h b/common/config/config_paramdesc.h index 6947f6531d..9d80c7050c 100644 --- a/common/config/config_paramdesc.h +++ b/common/config/config_paramdesc.h @@ -53,7 +53,7 @@ #define PARAMFLAG_PARAMSETDEF (1 << 17) // parameter has been set to default value in get functions /* checkedparam_t is possibly used in paramdef_t for specific parameter value validation */ -#define CONFIG_MAX_NUMCHECKVAL 20 +#define CONFIG_MAX_NUMCHECKVAL 64 typedef struct paramdef paramdef_t; typedef struct configmodule_interface configmodule_interface_t; typedef union checkedparam { From 1d0b8c1dc6c9bbf145d421e812f3eb6c91b015ea Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:06:58 +0200 Subject: [PATCH 015/100] add configuration values and structure for NR RLC --- openair2/LAYER2/nr_rlc/nr_rlc_configuration.h | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 openair2/LAYER2/nr_rlc/nr_rlc_configuration.h diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_configuration.h b/openair2/LAYER2/nr_rlc/nr_rlc_configuration.h new file mode 100644 index 0000000000..467e451152 --- /dev/null +++ b/openair2/LAYER2/nr_rlc/nr_rlc_configuration.h @@ -0,0 +1,160 @@ +/* + * 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 _NR_RLC_CONFIGURATION_H_ +#define _NR_RLC_CONFIGURATION_H_ + +#ifndef INT_LIST_SIZE +#define INT_LIST_SIZE(x) (sizeof((int[]){x})/sizeof(int)) +#endif + +/* values taken from 3GPP TS 38.331 version 17.3.0 */ + +#define VALUES_NR_RLC_T_POLL_RETRANSMIT \ + 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, \ + 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, \ + 145, 150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, \ + 215, 220, 225, 230, 235, 240, 245, 250, 300, 350, 400, 450, 500, 800, \ + 1000, 2000, 4000, 1, 2, 4 + +#define VALUES_NR_RLC_T_POLL_RETRANSMIT_STR \ + "ms5", "ms10", "ms15", "ms20", "ms25", "ms30", "ms35", "ms40", "ms45", "ms50", "ms55", "ms60", "ms65", "ms70", \ + "ms75", "ms80", "ms85", "ms90", "ms95", "ms100", "ms105", "ms110", "ms115", "ms120", "ms125", "ms130", "ms135", "ms140", \ + "ms145", "ms150", "ms155", "ms160", "ms165", "ms170", "ms175", "ms180", "ms185", "ms190", "ms195", "ms200", "ms205", "ms210", \ + "ms215", "ms220", "ms225", "ms230", "ms235", "ms240", "ms245", "ms250", "ms300", "ms350", "ms400", "ms450", "ms500", "ms800", \ + "ms1000", "ms2000", "ms4000", "ms1", "ms2", "ms4" + +#define SIZEOF_NR_RLC_T_POLL_RETRANSMIT INT_LIST_SIZE(VALUES_NR_RLC_T_POLL_RETRANSMIT) + +#define VALUES_NR_RLC_T_REASSEMBLY \ + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, \ + 80, 85, 90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200 + +#define VALUES_NR_RLC_T_REASSEMBLY_STR \ + "ms0", "ms5", "ms10", "ms15", "ms20", "ms25", "ms30", "ms35", "ms40", "ms45", "ms50", "ms55", "ms60", "ms65", "ms70", "ms75", \ + "ms80", "ms85", "ms90", "ms95", "ms100", "ms110", "ms120", "ms130", "ms140", "ms150", "ms160", "ms170", "ms180", "ms190", "ms200" + +#define SIZEOF_NR_RLC_T_REASSEMBLY INT_LIST_SIZE(VALUES_NR_RLC_T_REASSEMBLY) + +#define VALUES_NR_RLC_T_STATUS_PROHIBIT \ + 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, \ + 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, \ + 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, \ + 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, \ + 240, 245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, \ + 2000, 2400 + +#define VALUES_NR_RLC_T_STATUS_PROHIBIT_STR \ + "ms0", "ms5", "ms10", "ms15", "ms20", "ms25", "ms30", "ms35", "ms40", "ms45", "ms50", "ms55", \ + "ms60", "ms65", "ms70", "ms75", "ms80", "ms85", "ms90", "ms95", "ms100", "ms105", "ms110", "ms115", \ + "ms120", "ms125", "ms130", "ms135", "ms140", "ms145", "ms150", "ms155", "ms160", "ms165", "ms170", "ms175", \ + "ms180", "ms185", "ms190", "ms195", "ms200", "ms205", "ms210", "ms215", "ms220", "ms225", "ms230", "ms235", \ + "ms240", "ms245", "ms250", "ms300", "ms350", "ms400", "ms450", "ms500", "ms800", "ms1000", "ms1200", "ms1600", \ + "ms2000", "ms2400" + +#define SIZEOF_NR_RLC_T_STATUS_PROHIBIT INT_LIST_SIZE(VALUES_NR_RLC_T_STATUS_PROHIBIT) + +#define VALUES_NR_RLC_POLL_PDU \ + 4, 8, 16, 32, 64, 128, 256, 512, 1024, \ + 2048, 4096, 6144, 8192, 12288, 16384, 20480, 24576, 28672, \ + 32768, 40960, 49152, 57344, 65536, -1 /* -1 means infinity */ + +#define VALUES_NR_RLC_POLL_PDU_STR \ + "p4", "p8", "p16", "p32", "p64", "p128", "p256", "p512", "p1024", \ + "p2048", "p4096", "p6144", "p8192", "p12288", "p16384", "p20480", "p24576", "p28672", \ + "p32768", "p40960", "p49152", "p57344", "p65536", "infinity" + +#define SIZEOF_NR_RLC_POLL_PDU INT_LIST_SIZE(VALUES_NR_RLC_POLL_PDU) + +#define VALUES_NR_RLC_POLL_BYTE \ + /* KB */ \ + 1024 * 1, 1024 * 2, 1024 * 5, 1024 * 8, 1024 * 10, 1024 * 15, 1024 * 25, 1024 * 50, 1024 * 75, \ + 1024 * 100, 1024 * 125, 1024 * 250, 1024 * 375, 1024 * 500, 1024 * 750, 1024 * 1000, 1024 * 1250, \ + 1024 * 1500, 1024 * 2000, 1024 * 3000, 1024 * 4000, 1024 * 4500, 1024 * 5000, 1024 * 5500, \ + 1024 * 6000, 1024 * 6500, 1024 * 7000, 1024 * 7500, \ + /* MB */ \ + 1024 * 1024 * 8, 1024 * 1024 * 9, 1024 * 1024 * 10, 1024 * 1024 * 11, 1024 * 1024 * 12, \ + 1024 * 1024 * 13, 1024 * 1024 * 14, 1024 * 1024 * 15, 1024 * 1024 * 16, 1024 * 1024 * 17, \ + 1024 * 1024 * 18, 1024 * 1024 * 20, 1024 * 1024 * 25, 1024 * 1024 * 30, 1024 * 1024 * 40, \ + -1 /* -1 means infinity */ + +#define VALUES_NR_RLC_POLL_BYTE_STR \ + "kB1", "kB2", "kB5", "kB8", "kB10", "kB15", "kB25", "kB50", "kB75", \ + "kB100", "kB125", "kB250", "kB375", "kB500", "kB750", "kB1000", "kB1250", \ + "kB1500", "kB2000", "kB3000", "kB4000", "kB4500", "kB5000", "kB5500", \ + "kB6000", "kB6500", "kB7000", "kB7500", \ + "mB8", "mB9", "mB10", "mB11", "mB12", "mB13", "mB14", "mB15", \ + "mB16", "mB17", "mB18", "mB20", "mB25", "mB30", "mB40", \ + "infinity" + +#define SIZEOF_NR_RLC_POLL_BYTE INT_LIST_SIZE(VALUES_NR_RLC_POLL_BYTE) + +#define VALUES_NR_RLC_MAX_RETX_THRESHOLD \ + 1, 2, 3, 4, 6, 8, 16, 32 + +#define VALUES_NR_RLC_MAX_RETX_THRESHOLD_STR \ + "t1", "t2", "t3", "t4", "t6", "t8", "t16", "t32" + +#define SIZEOF_NR_RLC_MAX_RETX_THRESHOLD INT_LIST_SIZE(VALUES_NR_RLC_MAX_RETX_THRESHOLD) + +#define VALUES_NR_RLC_SN_FIELD_LENGTH_AM \ + 12, 18 + +#define VALUES_NR_RLC_SN_FIELD_LENGTH_AM_STR \ + "size12", "size18" + +#define SIZEOF_NR_RLC_SN_FIELD_LENGTH_AM INT_LIST_SIZE(VALUES_NR_RLC_SN_FIELD_LENGTH_AM) + +#define VALUES_NR_RLC_SN_FIELD_LENGTH_UM \ + 6, 12 + +#define VALUES_NR_RLC_SN_FIELD_LENGTH_UM_STR \ + "size6", "size12" + +#define SIZEOF_NR_RLC_SN_FIELD_LENGTH_UM INT_LIST_SIZE(VALUES_NR_RLC_SN_FIELD_LENGTH_UM) + +/* configuration of NR RLC, coming from configuration file */ +typedef struct { + struct { + int t_poll_retransmit; + int t_reassembly; + int t_status_prohibit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + int sn_field_length; + } srb; + struct { + int t_poll_retransmit; + int t_reassembly; + int t_status_prohibit; + int poll_pdu; + int poll_byte; + int max_retx_threshold; + int sn_field_length; + } drb_am; + struct { + int t_reassembly; + int sn_field_length; + } drb_um; +} nr_rlc_configuration_t; + +#endif /* _NR_RLC_CONFIGURATION_H_ */ From c7ce407a4b5e645ae12c9aca4f89d3dca83b2d21 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:08:46 +0200 Subject: [PATCH 016/100] add configuration values and structure for NR PDCP --- .../LAYER2/nr_pdcp/nr_pdcp_configuration.h | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h new file mode 100644 index 0000000000..f7eac08bd2 --- /dev/null +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h @@ -0,0 +1,70 @@ +/* + * 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 _NR_PDCP_CONFIGURATION_H_ +#define _NR_PDCP_CONFIGURATION_H_ + +#ifndef INT_LIST_SIZE +#define INT_LIST_SIZE(x) (sizeof((int[]){x})/sizeof(int)) +#endif + +/* values taken from 3GPP TS 38.331 version 17.3.0 */ + +#define VALUES_NR_PDCP_SN_SIZE \ + 12, 18 + +#define VALUES_NR_PDCP_SN_SIZE_STR \ + "len12bits", "len18bits" + +#define SIZEOF_NR_PDCP_SN_SIZE INT_LIST_SIZE(VALUES_NR_PDCP_SN_SIZE) + +#define VALUES_NR_PDCP_T_REORDERING \ + 0, 1, 2, 4, 5, 8, 10, 15, 20, 30, 40, 50, \ + 60, 80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, \ + 300, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000, \ + -1 /* -1 means infinity */ \ + +#define VALUES_NR_PDCP_T_REORDERING_STR \ + "ms0", "ms1", "ms2", "ms4", "ms5", "ms8", "ms10", "ms15", "ms20", "ms30", "ms40", "ms50", \ + "ms60", "ms80", "ms100", "ms120", "ms140", "ms160", "ms180", "ms200", "ms220", "ms240", "ms260", "ms280", \ + "ms300", "ms500", "ms750", "ms1000", "ms1250", "ms1500", "ms1750", "ms2000", "ms2250", "ms2500", "ms2750", "ms3000", \ + "infinity" + +#define SIZEOF_NR_PDCP_T_REORDERING INT_LIST_SIZE(VALUES_NR_PDCP_T_REORDERING) + +#define VALUES_NR_PDCP_DISCARD_TIMER \ + 10, 20, 30, 40, 50, 60, 75, 100, 150, 200, 250, 300, 500, 750, 1500, -1 /* -1 means infinity */ + +#define VALUES_NR_PDCP_DISCARD_TIMER_STR \ + "ms10", "ms20", "ms30", "ms40", "ms50", "ms60", "ms75", "ms100", "ms150", "ms200", "ms250", "ms300", "ms500", "ms750", "ms1500", "infinity" + +#define SIZEOF_NR_PDCP_DISCARD_TIMER INT_LIST_SIZE(VALUES_NR_PDCP_DISCARD_TIMER) + +/* configuration of NR PDCP, coming from configuration file */ +typedef struct { + struct { + int sn_size; + int t_reordering; + int discard_timer; + } drb; +} nr_pdcp_configuration_t; + +#endif /* _NR_PDCP_CONFIGURATION_H_ */ From f70d2f1312ff5d6fe6d81cf6810fd7411924926c Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:16:29 +0200 Subject: [PATCH 017/100] add NR RLC parameter definitions To be used in a later commit to retrieve NR RLC configuration parameters. To use, add the following to the configuration file (outside of other configurations). Adapt the values to your setup. The names ("ms45", "size12", etc.) come from 3GPP TS 38.331. rlc = { srb = { t_poll_retransmit = "ms45" t_reassembly = "ms25" t_status_prohibit = "ms0" poll_pdu = "infinity" poll_byte = "infinity" max_retx_threshold = "t8" sn_field_length = "size12" } drb_am = { t_poll_retransmit = "ms45" t_reassembly = "ms15" t_status_prohibit = "ms15" poll_pdu = "p64" poll_byte = "kB500" max_retx_threshold = "t32" sn_field_length = "size18" } drb_um = { t_reassembly = "ms15" sn_field_length = "size12" } } Default values are applied if the configuration is absent. The default values are the ones given above. --- openair2/GNB_APP/gnb_paramdef.h | 169 +++++++++++++++++++++++++++++++- 1 file changed, 168 insertions(+), 1 deletion(-) diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 99eb8847af..c8f6bc92fa 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -680,5 +680,172 @@ typedef enum { /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#endif +#define CONFIG_NR_RLC_T_POLL_RETRANSMIT "t_poll_retransmit" +#define CONFIG_NR_RLC_T_REASSEMBLY "t_reassembly" +#define CONFIG_NR_RLC_T_STATUS_PROHIBIT "t_status_prohibit" +#define CONFIG_NR_RLC_POLL_PDU "poll_pdu" +#define CONFIG_NR_RLC_POLL_BYTE "poll_byte" +#define CONFIG_NR_RLC_MAX_RETX_THRESHOLD "max_retx_threshold" +#define CONFIG_NR_RLC_SN_FIELD_LENGTH "sn_field_length" +/*----------------------------------------------------------------------*/ +/* nr rlc srb configuration */ +/*----------------------------------------------------------------------*/ + +#define CONFIG_STRING_NR_RLC_SRB "rlc.srb" + +#define CONFIG_NR_RLC_SRB_T_POLL_RETRANSMIT_IDX 0 +#define CONFIG_NR_RLC_SRB_T_REASSEMBLY_IDX 1 +#define CONFIG_NR_RLC_SRB_T_STATUS_PROHIBIT_IDX 2 +#define CONFIG_NR_RLC_SRB_POLL_PDU_IDX 3 +#define CONFIG_NR_RLC_SRB_POLL_BYTE_IDX 4 +#define CONFIG_NR_RLC_SRB_MAX_RETX_THRESHOLD_IDX 5 +#define CONFIG_NR_RLC_SRB_SN_FIELD_LENGTH_IDX 6 + +#define NR_RLC_SRB_GLOBALPARAMS_DESC { \ + { .optname = CONFIG_NR_RLC_T_POLL_RETRANSMIT, \ + .defstrval = "ms45", \ + .helpstr = "poll retransmit timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_POLL_RETRANSMIT_STR }, \ + .setintval = { VALUES_NR_RLC_T_POLL_RETRANSMIT }, \ + .num_okstrval = SIZEOF_NR_RLC_T_POLL_RETRANSMIT }}}, \ + { .optname = CONFIG_NR_RLC_T_REASSEMBLY, \ + .defstrval = "ms35", \ + .helpstr = "reassembly timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_REASSEMBLY_STR }, \ + .setintval = { VALUES_NR_RLC_T_REASSEMBLY }, \ + .num_okstrval = SIZEOF_NR_RLC_T_REASSEMBLY }}}, \ + { .optname = CONFIG_NR_RLC_T_STATUS_PROHIBIT, \ + .defstrval = "ms0", \ + .helpstr = "status prohibit timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_STATUS_PROHIBIT_STR }, \ + .setintval = { VALUES_NR_RLC_T_STATUS_PROHIBIT }, \ + .num_okstrval = SIZEOF_NR_RLC_T_STATUS_PROHIBIT }}}, \ + { .optname = CONFIG_NR_RLC_POLL_PDU, \ + .defstrval = "infinity", \ + .helpstr = "pollPDU", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_POLL_PDU_STR }, \ + .setintval = { VALUES_NR_RLC_POLL_PDU }, \ + .num_okstrval = SIZEOF_NR_RLC_POLL_PDU }}}, \ + { .optname = CONFIG_NR_RLC_POLL_BYTE, \ + .defstrval = "infinity", \ + .helpstr = "pollByte", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_POLL_BYTE_STR }, \ + .setintval = { VALUES_NR_RLC_POLL_BYTE }, \ + .num_okstrval = SIZEOF_NR_RLC_POLL_BYTE }}}, \ + { .optname = CONFIG_NR_RLC_MAX_RETX_THRESHOLD, \ + .defstrval = "t8", \ + .helpstr = "max reTX threshold", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_MAX_RETX_THRESHOLD_STR }, \ + .setintval = { VALUES_NR_RLC_MAX_RETX_THRESHOLD }, \ + .num_okstrval = SIZEOF_NR_RLC_MAX_RETX_THRESHOLD }}}, \ + { .optname = CONFIG_NR_RLC_SN_FIELD_LENGTH, \ + .defstrval = "size12", \ + .helpstr = "SN size", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_SN_FIELD_LENGTH_AM_STR }, \ + .setintval = { VALUES_NR_RLC_SN_FIELD_LENGTH_AM }, \ + .num_okstrval = SIZEOF_NR_RLC_SN_FIELD_LENGTH_AM }}}, \ +} + +/*----------------------------------------------------------------------*/ +/* nr rlc drb am configuration */ +/*----------------------------------------------------------------------*/ + +#define CONFIG_STRING_NR_RLC_DRB_AM "rlc.drb_am" + +#define CONFIG_NR_RLC_DRB_AM_T_POLL_RETRANSMIT_IDX 0 +#define CONFIG_NR_RLC_DRB_AM_T_REASSEMBLY_IDX 1 +#define CONFIG_NR_RLC_DRB_AM_T_STATUS_PROHIBIT_IDX 2 +#define CONFIG_NR_RLC_DRB_AM_POLL_PDU_IDX 3 +#define CONFIG_NR_RLC_DRB_AM_POLL_BYTE_IDX 4 +#define CONFIG_NR_RLC_DRB_AM_MAX_RETX_THRESHOLD_IDX 5 +#define CONFIG_NR_RLC_DRB_AM_SN_FIELD_LENGTH_IDX 6 + +#define NR_RLC_DRB_AM_GLOBALPARAMS_DESC { \ + { .optname = CONFIG_NR_RLC_T_POLL_RETRANSMIT, \ + .defstrval = "ms45", \ + .helpstr = "poll retransmit timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_POLL_RETRANSMIT_STR }, \ + .setintval = { VALUES_NR_RLC_T_POLL_RETRANSMIT }, \ + .num_okstrval = SIZEOF_NR_RLC_T_POLL_RETRANSMIT }}}, \ + { .optname = CONFIG_NR_RLC_T_REASSEMBLY, \ + .defstrval = "ms15", \ + .helpstr = "reassembly timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_REASSEMBLY_STR }, \ + .setintval = { VALUES_NR_RLC_T_REASSEMBLY }, \ + .num_okstrval = SIZEOF_NR_RLC_T_REASSEMBLY }}}, \ + { .optname = CONFIG_NR_RLC_T_STATUS_PROHIBIT, \ + .defstrval = "ms15", \ + .helpstr = "status prohibit timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_STATUS_PROHIBIT_STR }, \ + .setintval = { VALUES_NR_RLC_T_STATUS_PROHIBIT }, \ + .num_okstrval = SIZEOF_NR_RLC_T_STATUS_PROHIBIT }}}, \ + { .optname = CONFIG_NR_RLC_POLL_PDU, \ + .defstrval = "p64", \ + .helpstr = "pollPDU", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_POLL_PDU_STR }, \ + .setintval = { VALUES_NR_RLC_POLL_PDU }, \ + .num_okstrval = SIZEOF_NR_RLC_POLL_PDU }}}, \ + { .optname = CONFIG_NR_RLC_POLL_BYTE, \ + .defstrval = "kB500", \ + .helpstr = "pollByte", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_POLL_BYTE_STR }, \ + .setintval = { VALUES_NR_RLC_POLL_BYTE }, \ + .num_okstrval = SIZEOF_NR_RLC_POLL_BYTE }}}, \ + { .optname = CONFIG_NR_RLC_MAX_RETX_THRESHOLD, \ + .defstrval = "t32", \ + .helpstr = "max reTX threshold", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_MAX_RETX_THRESHOLD_STR }, \ + .setintval = { VALUES_NR_RLC_MAX_RETX_THRESHOLD }, \ + .num_okstrval = SIZEOF_NR_RLC_MAX_RETX_THRESHOLD }}}, \ + { .optname = CONFIG_NR_RLC_SN_FIELD_LENGTH, \ + .defstrval = "size18", \ + .helpstr = "SN size", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_SN_FIELD_LENGTH_AM_STR }, \ + .setintval = { VALUES_NR_RLC_SN_FIELD_LENGTH_AM }, \ + .num_okstrval = SIZEOF_NR_RLC_SN_FIELD_LENGTH_AM }}}, \ +} + +/*----------------------------------------------------------------------*/ +/* nr rlc drb um configuration */ +/*----------------------------------------------------------------------*/ + +#define CONFIG_STRING_NR_RLC_DRB_UM "rlc.drb_um" + +#define CONFIG_NR_RLC_DRB_UM_T_REASSEMBLY_IDX 0 +#define CONFIG_NR_RLC_DRB_UM_SN_FIELD_LENGTH_IDX 1 + +#define NR_RLC_DRB_UM_GLOBALPARAMS_DESC { \ + { .optname = CONFIG_NR_RLC_T_REASSEMBLY, \ + .defstrval = "ms15", \ + .helpstr = "reassembly timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_T_REASSEMBLY_STR }, \ + .setintval = { VALUES_NR_RLC_T_REASSEMBLY }, \ + .num_okstrval = SIZEOF_NR_RLC_T_REASSEMBLY }}}, \ + { .optname = CONFIG_NR_RLC_SN_FIELD_LENGTH, \ + .defstrval = "size12", \ + .helpstr = "SN size", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_RLC_SN_FIELD_LENGTH_UM_STR }, \ + .setintval = { VALUES_NR_RLC_SN_FIELD_LENGTH_UM }, \ + .num_okstrval = SIZEOF_NR_RLC_SN_FIELD_LENGTH_UM }}}, \ +} + +/*----------------------------------------------------------------------*/ + +#endif From 7852518bd355d4cfe0d9129e8ed83f46180abee1 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:20:39 +0200 Subject: [PATCH 018/100] add NR PDCP parameter definitions To be used in a later commit to retrieve NR PDCP configuration parameters. To use, add the following to the configuration file (outside of other configurations). Adapt the values to your setup. The names ("len18bits", "ms100", etc.) come from 3GPP TS 38.331. pdcp = { drb = { sn_size = "len18bits" t_reordering = "ms100" discard_timer = "infinity" } } Default values are applied if the configuration is absent. The default values are the ones given above. --- openair2/GNB_APP/gnb_paramdef.h | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index c8f6bc92fa..76ce814e88 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -848,4 +848,44 @@ typedef enum { /*----------------------------------------------------------------------*/ +#define CONFIG_NR_PDCP_SN_SIZE "sn_size" +#define CONFIG_NR_PDCP_T_REORDERING "t_reordering" +#define CONFIG_NR_PDCP_DISCARD_TIMER "discard_timer" + +/*----------------------------------------------------------------------*/ +/* nr pdcp drb configuration */ +/*----------------------------------------------------------------------*/ + +#define CONFIG_STRING_NR_PDCP_DRB "pdcp.drb" + +#define CONFIG_NR_PDCP_DRB_SN_SIZE_IDX 0 +#define CONFIG_NR_PDCP_DRB_T_REORDERING_IDX 1 +#define CONFIG_NR_PDCP_DRB_DISCARD_TIMER_IDX 2 + +#define NR_PDCP_DRB_GLOBALPARAMS_DESC { \ + { .optname = CONFIG_NR_PDCP_SN_SIZE, \ + .defstrval = "len18bits", \ + .helpstr = "SN size", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_PDCP_SN_SIZE_STR }, \ + .setintval = { VALUES_NR_PDCP_SN_SIZE }, \ + .num_okstrval = SIZEOF_NR_PDCP_SN_SIZE }}}, \ + { .optname = CONFIG_NR_PDCP_T_REORDERING, \ + .defstrval = "ms100", \ + .helpstr = "reordering timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_PDCP_T_REORDERING_STR }, \ + .setintval = { VALUES_NR_PDCP_T_REORDERING }, \ + .num_okstrval = SIZEOF_NR_PDCP_T_REORDERING }}}, \ + { .optname = CONFIG_NR_PDCP_DISCARD_TIMER, \ + .defstrval = "infinity", \ + .helpstr = "discard timer", .paramflags = 0, .strptr = NULL, .type = TYPE_STRING, .numelt = 0, \ + .chkPptr = &(checkedparam_t){ .s3a = { .f3a = config_checkstr_assign_integer, \ + .okstrval = { VALUES_NR_PDCP_DISCARD_TIMER_STR }, \ + .setintval = { VALUES_NR_PDCP_DISCARD_TIMER }, \ + .num_okstrval = SIZEOF_NR_PDCP_DISCARD_TIMER }}} \ +} + +/*----------------------------------------------------------------------*/ + #endif From 9845891ec43d2769d16a68df6ed937ff7cd5c5d5 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:38:00 +0200 Subject: [PATCH 019/100] simplify NR RLC ASN.1 decoding and add encoding for configuration values --- openair2/LAYER2/nr_rlc/asn1_utils.c | 176 +++------------------ openair2/LAYER2/nr_rlc/nr_rlc_asn1_utils.h | 9 ++ 2 files changed, 35 insertions(+), 150 deletions(-) diff --git a/openair2/LAYER2/nr_rlc/asn1_utils.c b/openair2/LAYER2/nr_rlc/asn1_utils.c index fd64d89481..f6b3422751 100644 --- a/openair2/LAYER2/nr_rlc/asn1_utils.c +++ b/openair2/LAYER2/nr_rlc/asn1_utils.c @@ -19,157 +19,33 @@ * contact@openairinterface.org */ +#include "nr_rlc_asn1_utils.h" #include "rlc.h" +#include "nr_rlc_configuration.h" -int decode_t_reassembly(int v) -{ - static const int tab[31] = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, - 80, 85, 90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200}; - - if (v < 0 || v > 30) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; +#define ENCODE_DECODE(a, b) \ +int decode_##a(int v) \ +{ \ + static const int tab[] = { VALUES_NR_RLC_##b }; \ + AssertFatal(v >= 0 && v < SIZEOF_NR_RLC_##b, \ + "bad encoded value " #a " %d\n", v); \ + return tab[v]; \ +} \ + \ +int encode_##a(int v) \ +{ \ + static const int tab[] = { VALUES_NR_RLC_##b }; \ + for (int ret = 0; ret < SIZEOF_NR_RLC_##b; ret++) \ + if (tab[ret] == v) \ + return ret; \ + AssertFatal(0, "bad " #a " value %d\n", v); \ } -int decode_t_status_prohibit(int v) -{ - static const int tab[62] = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, - 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, - 160, 165, 170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, - 240, 245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, 2000, 2400}; - - if (v < 0 || v > 61) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} - -int decode_t_poll_retransmit(int v) -{ - static const int tab[59] = {5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, - 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165, 170, 175, 180, 185, 190, 195, 200, - 205, 210, 215, 220, 225, 230, 235, 240, 245, 250, 300, 350, 400, 450, 500, 800, 1000, 2000, 4000}; - - if (v < 0 || v > 58) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} - -int decode_poll_pdu(int v) -{ - static const int tab[24] = { - 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 6144, - 8192, 12288, 16384, 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536, -1 /* -1 means infinity */ - }; - - if (v < 0 || v > 23) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} - -int decode_poll_byte(int v) -{ - static const int tab[44] = { - /* KB */ - 1024 * 1, - 1024 * 2, - 1024 * 5, - 1024 * 8, - 1024 * 10, - 1024 * 15, - 1024 * 25, - 1024 * 50, - 1024 * 75, - 1024 * 100, - 1024 * 125, - 1024 * 250, - 1024 * 375, - 1024 * 500, - 1024 * 750, - 1024 * 1000, - 1024 * 1250, - 1024 * 1500, - 1024 * 2000, - 1024 * 3000, - 1024 * 4000, - 1024 * 4500, - 1024 * 5000, - 1024 * 5500, - 1024 * 6000, - 1024 * 6500, - 1024 * 7000, - 1024 * 7500, - /* MB */ - 1024 * 1024 * 8, - 1024 * 1024 * 9, - 1024 * 1024 * 10, - 1024 * 1024 * 11, - 1024 * 1024 * 12, - 1024 * 1024 * 13, - 1024 * 1024 * 14, - 1024 * 1024 * 15, - 1024 * 1024 * 16, - 1024 * 1024 * 17, - 1024 * 1024 * 18, - 1024 * 1024 * 20, - 1024 * 1024 * 25, - 1024 * 1024 * 30, - 1024 * 1024 * 40, - -1 /* -1 means infinity */ - }; - - if (v < 0 || v > 43) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - if (tab[v] == -1) return -1; - return tab[v]; -} - -int decode_max_retx_threshold(int v) -{ - static const int tab[8] = {1, 2, 3, 4, 6, 8, 16, 32}; - - if (v < 0 || v > 7) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} - -int decode_sn_field_length_um(int v) -{ - static const int tab[2] = {6, 12}; - - if (v < 0 || v > 1) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} - -int decode_sn_field_length_am(int v) -{ - static const int tab[2] = {12, 18}; - - if (v < 0 || v > 1) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} +ENCODE_DECODE(t_reassembly, T_REASSEMBLY) +ENCODE_DECODE(t_status_prohibit, T_STATUS_PROHIBIT) +ENCODE_DECODE(t_poll_retransmit, T_POLL_RETRANSMIT) +ENCODE_DECODE(poll_pdu, POLL_PDU) +ENCODE_DECODE(poll_byte, POLL_BYTE) +ENCODE_DECODE(max_retx_threshold, MAX_RETX_THRESHOLD) +ENCODE_DECODE(sn_field_length_am, SN_FIELD_LENGTH_AM) +ENCODE_DECODE(sn_field_length_um, SN_FIELD_LENGTH_UM) diff --git a/openair2/LAYER2/nr_rlc/nr_rlc_asn1_utils.h b/openair2/LAYER2/nr_rlc/nr_rlc_asn1_utils.h index 6f010b02da..cbeb445105 100644 --- a/openair2/LAYER2/nr_rlc/nr_rlc_asn1_utils.h +++ b/openair2/LAYER2/nr_rlc/nr_rlc_asn1_utils.h @@ -31,4 +31,13 @@ int decode_max_retx_threshold(int v); int decode_sn_field_length_um(int v); int decode_sn_field_length_am(int v); +int encode_t_reassembly(int v); +int encode_t_status_prohibit(int v); +int encode_t_poll_retransmit(int v); +int encode_poll_pdu(int v); +int encode_poll_byte(int v); +int encode_max_retx_threshold(int v); +int encode_sn_field_length_um(int v); +int encode_sn_field_length_am(int v); + #endif /* _OPENAIR2_LAYER2_NR_RLC_ASN1_UTILS_H_ */ From 3f2eddd6ba24673c3b49f62bd7f6d527933f0c47 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:42:06 +0200 Subject: [PATCH 020/100] simplify NR PDCP ASN.1 decoding and add encoding for configuration values --- openair2/LAYER2/nr_pdcp/asn1_utils.c | 77 ++++++-------------- openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h | 11 ++- 2 files changed, 30 insertions(+), 58 deletions(-) diff --git a/openair2/LAYER2/nr_pdcp/asn1_utils.c b/openair2/LAYER2/nr_pdcp/asn1_utils.c index 6b45a73acf..5ec86be3c6 100644 --- a/openair2/LAYER2/nr_pdcp/asn1_utils.c +++ b/openair2/LAYER2/nr_pdcp/asn1_utils.c @@ -19,63 +19,30 @@ * contact@openairinterface.org */ +#include "nr_pdcp_asn1_utils.h" #include "common/utils/LOG/log.h" #include "nr_pdcp_entity.h" +#include "nr_pdcp_configuration.h" -int decode_t_reordering(int v) -{ - static const int tab[36] = {0, 1, 2, 4, 5, 8, 10, 15, 20, 30, 40, 50, 60, 80, 100, 120, 140, 160, - 180, 200, 220, 240, 260, 280, 300, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000}; - - if (v < 0 || v > 35) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; +#define ENCODE_DECODE(a, b) \ +int decode_##a(int v) \ +{ \ + static const int tab[] = { VALUES_NR_PDCP_##b }; \ + AssertFatal(v >= 0 && v < SIZEOF_NR_PDCP_##b, \ + "bad encoded value " #a " %d\n", v); \ + return tab[v]; \ +} \ + \ +int encode_##a(int v) \ +{ \ + static const int tab[] = { VALUES_NR_PDCP_##b }; \ + for (int ret = 0; ret < SIZEOF_NR_PDCP_##b; ret++) \ + if (tab[ret] == v) \ + return ret; \ + AssertFatal(0, "bad " #a " value %d\n", v); \ } -int decode_sn_size_ul(long s) -{ - if (s == 0) return SHORT_SN_SIZE; - if (s == 1) return LONG_SN_SIZE; - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); -} - -int decode_sn_size_dl(long s) -{ - if (s == 0) return SHORT_SN_SIZE; - if (s == 1) return LONG_SN_SIZE; - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); -} - -int decode_discard_timer(long v) -{ - static const int tab[16] = { - 10, - 20, - 30, - 40, - 50, - 60, - 75, - 100, - 150, - 200, - 250, - 300, - 500, - 750, - 1500, - -1, - }; - - if (v < 0 || v > 15) { - LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__); - exit(1); - } - - return tab[v]; -} +ENCODE_DECODE(t_reordering, T_REORDERING) +ENCODE_DECODE(sn_size_ul, SN_SIZE) +ENCODE_DECODE(sn_size_dl, SN_SIZE) +ENCODE_DECODE(discard_timer, DISCARD_TIMER) diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h index d525bce287..2628b29069 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h @@ -23,8 +23,13 @@ #define _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_ int decode_t_reordering(int v); -int decode_sn_size_ul(long s); -int decode_sn_size_dl(long s); -int decode_discard_timer(long v); +int decode_sn_size_ul(int v); +int decode_sn_size_dl(int v); +int decode_discard_timer(int v); + +int encode_t_reordering(int v); +int encode_sn_size_ul(int v); +int encode_sn_size_dl(int v); +int encode_discard_timer(int v); #endif /* _OPENAIR2_LAYER2_NR_PDCP_ASN1_UTILS_H_ */ From 82a3911971142cde85c2d434f4bafe2be144c63d Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:48:11 +0200 Subject: [PATCH 021/100] add configuration for NR RLC and NR PDCP to the RRC gNB structure A later commit will use them. --- openair2/RRC/NR/nr_rrc_defs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7e0789c4ad..e3f6722812 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -54,6 +54,8 @@ #include "NR_UE-MRDC-Capability.h" #include "NR_UE-NR-Capability.h" #include "intertask_interface.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" +#include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h" typedef enum { NR_RRC_OK=0, @@ -383,6 +385,8 @@ typedef struct gNB_RRC_INST_s { RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id size_t num_cuups; + nr_pdcp_configuration_t pdcp_config; + nr_rlc_configuration_t rlc_config; } gNB_RRC_INST; #define UE_LOG_FMT "(cellID %lx, UE ID %d RNTI %04x)" From e214ffc0f35dbced7fe4ff5d1dc7d9a8cc4bc50e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 16:49:49 +0200 Subject: [PATCH 022/100] add configuration for NR RLC to the MAC gNB structure A later commit will use it. --- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d97783604f..70b53552e7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -45,6 +45,7 @@ #include "common/utils/ds/seq_arr.h" #include "common/utils/nr/nr_common.h" #include "common/utils/ds/byte_array.h" +#include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h" #define NR_SCHED_LOCK(lock) \ do { \ @@ -899,6 +900,7 @@ typedef struct gNB_MAC_INST_s { nr_pp_impl_ul pre_processor_ul; nr_mac_config_t radio_config; + nr_rlc_configuration_t rlc_config; NR_UE_sched_ctrl_t *sched_ctrlCommon; NR_sched_pdcch_t *sched_pdcch_otherSI; From 178a5a66d411fbbfb8b7216ec2067512836dd827 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 17:02:35 +0200 Subject: [PATCH 023/100] add functions to retrieve configuration values for NR RLC and NR PDCP They will be used in a later commit. --- openair2/GNB_APP/gnb_config.c | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..317f1c6a91 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1467,6 +1467,55 @@ static seq_arr_t *fill_du_sibs(paramdef_t *GNBparamarray) return du_SIBs; } +void config_rlc(configmodule_interface_t *cfg, nr_rlc_configuration_t *rlc_config) +{ + /* SRB configuration */ + paramdef_t rlc_srb_params[] = NR_RLC_SRB_GLOBALPARAMS_DESC; + int ret = config_get(cfg, rlc_srb_params, sizeofArray(rlc_srb_params), CONFIG_STRING_NR_RLC_SRB); + AssertFatal(ret >= 0, "problem reading NR RLC configuration from configuration file\n"); + + rlc_config->srb.t_poll_retransmit = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_T_POLL_RETRANSMIT_IDX]); + rlc_config->srb.t_reassembly = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_T_REASSEMBLY_IDX]); + rlc_config->srb.t_status_prohibit = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_T_STATUS_PROHIBIT_IDX]); + rlc_config->srb.poll_pdu = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_POLL_PDU_IDX]); + rlc_config->srb.poll_byte = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_POLL_BYTE_IDX]); + rlc_config->srb.max_retx_threshold = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_MAX_RETX_THRESHOLD_IDX]); + rlc_config->srb.sn_field_length = config_get_processedint(cfg, &rlc_srb_params[CONFIG_NR_RLC_SRB_SN_FIELD_LENGTH_IDX]); + + /* DRB AM configuration */ + paramdef_t rlc_drb_am_params[] = NR_RLC_DRB_AM_GLOBALPARAMS_DESC; + ret = config_get(cfg, rlc_drb_am_params, sizeofArray(rlc_drb_am_params), CONFIG_STRING_NR_RLC_DRB_AM); + AssertFatal(ret >= 0, "problem reading NR RLC configuration from configuration file\n"); + + rlc_config->drb_am.t_poll_retransmit = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_T_POLL_RETRANSMIT_IDX]); + rlc_config->drb_am.t_reassembly = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_T_REASSEMBLY_IDX]); + rlc_config->drb_am.t_status_prohibit = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_T_STATUS_PROHIBIT_IDX]); + rlc_config->drb_am.poll_pdu = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_POLL_PDU_IDX]); + rlc_config->drb_am.poll_byte = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_POLL_BYTE_IDX]); + rlc_config->drb_am.max_retx_threshold = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_MAX_RETX_THRESHOLD_IDX]); + rlc_config->drb_am.sn_field_length = config_get_processedint(cfg, &rlc_drb_am_params[CONFIG_NR_RLC_DRB_AM_SN_FIELD_LENGTH_IDX]); + + /* DRB UM configuration */ + paramdef_t rlc_drb_um_params[] = NR_RLC_DRB_UM_GLOBALPARAMS_DESC; + ret = config_get(cfg, rlc_drb_um_params, sizeofArray(rlc_drb_um_params), CONFIG_STRING_NR_RLC_DRB_UM); + AssertFatal(ret >= 0, "problem reading NR RLC configuration from configuration file\n"); + + rlc_config->drb_um.t_reassembly = config_get_processedint(cfg, &rlc_drb_um_params[CONFIG_NR_RLC_DRB_UM_T_REASSEMBLY_IDX]); + rlc_config->drb_um.sn_field_length = config_get_processedint(cfg, &rlc_drb_um_params[CONFIG_NR_RLC_DRB_UM_SN_FIELD_LENGTH_IDX]); +} + +void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_config) +{ + /* DRB configuration */ + paramdef_t pdcp_params[] = NR_PDCP_DRB_GLOBALPARAMS_DESC; + int ret = config_get(cfg, pdcp_params, sizeofArray(pdcp_params), CONFIG_STRING_NR_PDCP_DRB); + AssertFatal(ret >= 0, "problem reading NR PDCP configuration from configuration file\n"); + + pdcp_config->drb.sn_size = config_get_processedint(cfg, &pdcp_params[CONFIG_NR_PDCP_DRB_SN_SIZE_IDX]); + pdcp_config->drb.t_reordering = config_get_processedint(cfg, &pdcp_params[CONFIG_NR_PDCP_DRB_T_REORDERING_IDX]); + pdcp_config->drb.discard_timer = config_get_processedint(cfg, &pdcp_params[CONFIG_NR_PDCP_DRB_DISCARD_TIMER_IDX]); +} + void RCconfig_nr_macrlc(configmodule_interface_t *cfg) { int j = 0; From b9dffde03ed32671e3e66c9ce05a6c6a46796c78 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Tue, 15 Apr 2025 17:20:44 +0200 Subject: [PATCH 024/100] adapt existing code to use NR RLC and NR PDCP values from configuration - remove hardcoded values - adapt gNB RRC code - adapt gNB MAC code - adapt physical simulators, where we put the hardcoded values that were everywhere else before; if there is a need for those simulators to get configurable values, more work is needed (but it's doubtful that it is needed) --- openair1/SIMULATION/NR_PHY/dlsim.c | 26 +++++++- openair1/SIMULATION/NR_PHY/ulsim.c | 26 +++++++- openair2/GNB_APP/gnb_config.c | 9 ++- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 2 +- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 4 +- .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 34 +++++++---- openair2/LAYER2/NR_MAC_gNB/main.c | 4 +- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 61 +++++++++++-------- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h | 15 ++++- openair2/RRC/NR/MESSAGES/asn1_msg.c | 12 ++-- openair2/RRC/NR/MESSAGES/asn1_msg.h | 4 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 3 +- openair2/RRC/NR/rrc_gNB_nsa.c | 4 +- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 19 +++--- openair2/RRC/NR/rrc_gNB_radio_bearers.h | 4 +- 15 files changed, 163 insertions(+), 64 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 6238c09a2e..b858945018 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -714,12 +714,36 @@ printf("%d\n", slot); .timer_config.n311 = 1, .timer_config.t319 = 400, .num_agg_level_candidates = {0, 0, 1, 1, 0}}; + const nr_rlc_configuration_t rlc_config = { + .srb = { + .t_poll_retransmit = 45, + .t_reassembly = 35, + .t_status_prohibit = 0, + .poll_pdu = -1, + .poll_byte = -1, + .max_retx_threshold = 8, + .sn_field_length = 12, + }, + .drb_am = { + .t_poll_retransmit = 45, + .t_reassembly = 15, + .t_status_prohibit = 15, + .poll_pdu = 64, + .poll_byte = 1024 * 500, + .max_retx_threshold = 32, + .sn_field_length = 18, + }, + .drb_um = { + .t_reassembly = 15, + .sn_field_length = 12, + } + }; RC.nb_nr_macrlc_inst = 1; RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(ngran_gNB, scc, NULL, &conf); + mac_top_init_gNB(ngran_gNB, scc, NULL, &conf, &rlc_config); gNB_mac = RC.nrmac[0]; nr_mac_config_scc(RC.nrmac[0], scc, &conf); diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 4c12530f30..4e127fe0b7 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -668,12 +668,36 @@ int main(int argc, char *argv[]) .timer_config.t311 = 3000, .timer_config.n311 = 1, .timer_config.t319 = 400}; + const nr_rlc_configuration_t rlc_config = { + .srb = { + .t_poll_retransmit = 45, + .t_reassembly = 35, + .t_status_prohibit = 0, + .poll_pdu = -1, + .poll_byte = -1, + .max_retx_threshold = 8, + .sn_field_length = 12, + }, + .drb_am = { + .t_poll_retransmit = 45, + .t_reassembly = 15, + .t_status_prohibit = 15, + .poll_pdu = 64, + .poll_byte = 1024 * 500, + .max_retx_threshold = 32, + .sn_field_length = 18, + }, + .drb_um = { + .t_reassembly = 15, + .sn_field_length = 12, + } + }; RC.nb_nr_macrlc_inst = 1; RC.nb_nr_mac_CC = (int*)malloc(RC.nb_nr_macrlc_inst*sizeof(int)); for (i = 0; i < RC.nb_nr_macrlc_inst; i++) RC.nb_nr_mac_CC[i] = 1; - mac_top_init_gNB(ngran_gNB, scc, NULL /* scd will be updated further below */, &conf); + mac_top_init_gNB(ngran_gNB, scc, NULL /* scd will be updated further below */, &conf, &rlc_config); nr_mac_config_scc(RC.nrmac[0], scc, &conf); NR_ServingCellConfig_t *scd = calloc(1,sizeof(NR_ServingCellConfig_t)); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 317f1c6a91..e1c04fa3f4 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1661,8 +1661,12 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) NR_ServingCellConfig_t *scd = get_scd_config(cfg); if (MacRLC_ParamList.numelt > 0) { + /* NR RLC config is needed by mac_top_init_gNB() */ + nr_rlc_configuration_t default_rlc_config; + config_rlc(cfg, &default_rlc_config); + ngran_node_t node_type = get_node_type(); - mac_top_init_gNB(node_type, scc, scd, &config); + mac_top_init_gNB(node_type, scc, scd, &config, &default_rlc_config); RC.nb_nr_mac_CC = (int *)malloc(RC.nb_nr_macrlc_inst * sizeof(int)); for (j = 0; j < RC.nb_nr_macrlc_inst; j++) { @@ -2196,6 +2200,9 @@ gNB_RRC_INST *RCconfig_NRRRC() if (!NODE_IS_DU(rrc->node_type)) config_security(rrc); + config_rlc(config_get_if(), &rrc->rlc_config); + config_pdcp(config_get_if(), &rrc->pdcp_config); + return rrc; } diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5ceff85296..2e6a778163 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3326,7 +3326,7 @@ bool prepare_initial_ul_rrc_message(gNB_MAC_INST *mac, NR_UE_info_t *UE) int srb_id = 1; const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon; const NR_ServingCellConfig_t *sccd = UE->is_redcap ? NULL : mac->common_channels[CC_id].pre_ServingCellConfig; - NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); + NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config, &mac->rlc_config); ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = cellGroupConfig; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f0b59c73de..a61e2f8f89 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -34,6 +34,7 @@ #include "LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "NR_TAG-Id.h" #include "common/ngran_types.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" void set_cset_offset(uint16_t); void get_K1_K2(int N1, int N2, int *K1, int *K2, int layers); @@ -52,7 +53,8 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca void mac_top_init_gNB(ngran_node_t node_type, NR_ServingCellConfigCommon_t *scc, NR_ServingCellConfig_t *scd, - const nr_mac_config_t *conf); + const nr_mac_config_t *conf, + const nr_rlc_configuration_t *default_rlc_config); void mac_top_destroy_gNB(gNB_MAC_INST *mac); void nr_mac_send_f1_setup_req(void); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 28c129cb58..a5999e50b1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -221,19 +221,21 @@ void gnb_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_upd LOG_I(MAC, "received gNB-DU configuration update acknowledge\n"); } -static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_be_setup_t *srb) +static NR_RLC_BearerConfig_t *get_bearerconfig_from_srb(const f1ap_srb_to_be_setup_t *srb, + const nr_rlc_configuration_t *rlc_config) { long priority = srb->srb_id == 2 ? 3 : 1; // see 38.331 sec 9.2.1 e_NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration bucket = NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5; - return get_SRB_RLC_BearerConfig(get_lcid_from_srbid(srb->srb_id), priority, bucket); + return get_SRB_RLC_BearerConfig(get_lcid_from_srbid(srb->srb_id), priority, bucket, rlc_config); } static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, int srbs_len, const f1ap_srb_to_be_setup_t *req_srbs, f1ap_srb_to_be_setup_t **resp_srbs, - NR_CellGroupConfig_t *cellGroupConfig) + NR_CellGroupConfig_t *cellGroupConfig, + const nr_rlc_configuration_t *rlc_config) { DevAssert(req_srbs != NULL && resp_srbs != NULL && cellGroupConfig != NULL); @@ -241,7 +243,7 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, AssertFatal(*resp_srbs != NULL, "out of memory\n"); for (int i = 0; i < srbs_len; i++) { const f1ap_srb_to_be_setup_t *srb = &req_srbs[i]; - NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_srb(srb); + NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_srb(srb, rlc_config); nr_rlc_add_srb(UE->rnti, srb->srb_id, rlc_BearerConfig); int priority = rlc_BearerConfig->mac_LogicalChannelConfig->ul_SpecificParameters->priority; @@ -265,11 +267,12 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, return srbs_len; } -static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb) +static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb, + const nr_rlc_configuration_t *rlc_config) { const NR_RLC_Config_PR rlc_conf = drb->rlc_mode == F1AP_RLC_MODE_AM ? NR_RLC_Config_PR_am : NR_RLC_Config_PR_um_Bi_Directional; long priority = 13; // hardcoded for the moment - return get_DRB_RLC_BearerConfig(get_lcid_from_drbid(drb->drb_id), drb->drb_id, rlc_conf, priority); + return get_DRB_RLC_BearerConfig(get_lcid_from_drbid(drb->drb_id), drb->drb_id, rlc_conf, priority, rlc_config); } static int get_non_dynamic_priority(int fiveqi) @@ -304,7 +307,8 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, int drbs_len, const f1ap_drb_to_be_setup_t *req_drbs, f1ap_drb_to_be_setup_t **resp_drbs, - NR_CellGroupConfig_t *cellGroupConfig) + NR_CellGroupConfig_t *cellGroupConfig, + const nr_rlc_configuration_t *rlc_config) { DevAssert(req_drbs != NULL && resp_drbs != NULL && cellGroupConfig != NULL); instance_t f1inst = get_f1_gtp_instance(); @@ -316,7 +320,7 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE, for (int i = 0; i < drbs_len; i++) { const f1ap_drb_to_be_setup_t *drb = &req_drbs[i]; f1ap_drb_to_be_setup_t *resp_drb = &(*resp_drbs)[i]; - NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb); + NR_RLC_BearerConfig_t *rlc_BearerConfig = get_bearerconfig_from_drb(drb, rlc_config); nr_rlc_add_drb(UE->rnti, drb->drb_id, rlc_BearerConfig); nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nssai}; @@ -557,7 +561,7 @@ static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_C const NR_ServingCellConfig_t *sccd = cc->pre_ServingCellConfig; const nr_mac_config_t *configuration = &mac->radio_config; if (is_SA) { - cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config); + cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config, &mac->rlc_config); cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc); } else { NR_UE_NR_Capability_t *cap = get_ue_nr_cap_from_cg_config_info(cgci); @@ -649,7 +653,8 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) req->srbs_to_be_setup_length, req->srbs_to_be_setup, &resp.srbs_to_be_setup, - new_CellGroup); + new_CellGroup, + &mac->rlc_config); } if (req->drbs_to_be_setup_length > 0) { @@ -657,7 +662,8 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req) req->drbs_to_be_setup_length, req->drbs_to_be_setup, &resp.drbs_to_be_setup, - new_CellGroup); + new_CellGroup, + &mac->rlc_config); } if (req->rrc_container != NULL) { @@ -747,7 +753,8 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) req->srbs_to_be_setup_length, req->srbs_to_be_setup, &resp.srbs_to_be_setup, - new_CellGroup); + new_CellGroup, + &mac->rlc_config); } if (req->drbs_to_be_setup_length > 0) { @@ -755,7 +762,8 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) req->drbs_to_be_setup_length, req->drbs_to_be_setup, &resp.drbs_to_be_setup, - new_CellGroup); + new_CellGroup, + &mac->rlc_config); } if (req->drbs_to_be_released_length > 0) { diff --git a/openair2/LAYER2/NR_MAC_gNB/main.c b/openair2/LAYER2/NR_MAC_gNB/main.c index 9c8e414f52..0acc6fe0d2 100644 --- a/openair2/LAYER2/NR_MAC_gNB/main.c +++ b/openair2/LAYER2/NR_MAC_gNB/main.c @@ -236,7 +236,8 @@ static void mac_rrc_init(gNB_MAC_INST *mac, ngran_node_t node_type) void mac_top_init_gNB(ngran_node_t node_type, NR_ServingCellConfigCommon_t *scc, NR_ServingCellConfig_t *scd, - const nr_mac_config_t *config) + const nr_mac_config_t *config, + const nr_rlc_configuration_t *default_rlc_config) { module_id_t i; gNB_MAC_INST *nrmac; @@ -272,6 +273,7 @@ void mac_top_init_gNB(ngran_node_t node_type, RC.nrmac[i]->common_channels[0].ServingCellConfigCommon = scc; RC.nrmac[i]->radio_config = *config; + RC.nrmac[i]->rlc_config = *default_rlc_config; RC.nrmac[i]->common_channels[0].pre_ServingCellConfig = scd; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 22c2207be1..d361352e9f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -40,6 +40,7 @@ #include "openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h" #include "openair3/UTILS/conversions.h" +#include "LAYER2/nr_rlc/nr_rlc_asn1_utils.h" #include "NR_MeasurementTimingConfiguration.h" #include "uper_decoder.h" @@ -3338,7 +3339,10 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid, return SpCellConfig; } -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration) +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, + long priority, + long bucketSizeDuration, + const nr_rlc_configuration_t *default_rlc_config) { NR_RLC_BearerConfig_t *rlc_BearerConfig = NULL; rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); @@ -3352,15 +3356,15 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, l rlc_Config->present = NR_RLC_Config_PR_am; rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms35; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms0; + *(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->srb.t_reassembly); + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->srb.t_status_prohibit); rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t)); - *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = NR_SN_FieldLengthAM_size12; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_infinity; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_infinity; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t8; + *(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length); + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->srb.t_poll_retransmit); + rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->srb.poll_pdu); + rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->srb.poll_byte); + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->srb.max_retx_threshold); rlc_BearerConfig->rlc_Config = rlc_Config; NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); @@ -3381,7 +3385,9 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, l return rlc_BearerConfig; } -static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc_config_pr) +static void nr_drb_config(struct NR_RLC_Config *rlc_Config, + NR_RLC_Config_PR rlc_config_pr, + const nr_rlc_configuration_t *default_rlc_config) { switch (rlc_config_pr) { case NR_RLC_Config_PR_um_Bi_Directional: @@ -3390,25 +3396,25 @@ static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc rlc_Config->choice.um_Bi_Directional = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional)); rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; + *rlc_Config->choice.um_Bi_Directional->ul_UM_RLC.sn_FieldLength = encode_sn_field_length_um(default_rlc_config->drb_um.sn_field_length); rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength)); - *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = NR_SN_FieldLengthUM_size12; - rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = NR_T_Reassembly_ms15; + *rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.sn_FieldLength = encode_sn_field_length_um(default_rlc_config->drb_um.sn_field_length); + rlc_Config->choice.um_Bi_Directional->dl_UM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->drb_um.t_reassembly); break; case NR_RLC_Config_PR_am: // RLC AM Bearer configuration rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am)); rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = NR_T_PollRetransmit_ms45; - rlc_Config->choice.am->ul_AM_RLC.pollPDU = NR_PollPDU_p64; - rlc_Config->choice.am->ul_AM_RLC.pollByte = NR_PollByte_kB500; - rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = NR_UL_AM_RLC__maxRetxThreshold_t32; + *rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = encode_sn_field_length_am(default_rlc_config->drb_am.sn_field_length); + rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->drb_am.t_poll_retransmit); + rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->drb_am.poll_pdu); + rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->drb_am.poll_byte); + rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->drb_am.max_retx_threshold); rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(*rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength)); - *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size18; - rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = NR_T_Reassembly_ms15; - rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = NR_T_StatusProhibit_ms15; + *rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = encode_sn_field_length_am(default_rlc_config->drb_am.sn_field_length); + rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->drb_am.t_reassembly); + rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->drb_am.t_status_prohibit); break; default: AssertFatal(false, "RLC config type %d not handled\n", rlc_config_pr); @@ -3417,7 +3423,11 @@ static void nr_drb_config(struct NR_RLC_Config *rlc_Config, NR_RLC_Config_PR rlc rlc_Config->present = rlc_config_pr; } -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority) +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, + long drbId, + NR_RLC_Config_PR rlc_conf, + long priority, + const nr_rlc_configuration_t *default_rlc_config) { NR_RLC_BearerConfig_t *rlc_BearerConfig = calloc(1, sizeof(NR_RLC_BearerConfig_t)); rlc_BearerConfig->logicalChannelIdentity = lcChannelId; @@ -3427,7 +3437,7 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR rlc_BearerConfig->reestablishRLC = NULL; NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t)); - nr_drb_config(rlc_Config, rlc_conf); + nr_drb_config(rlc_Config, rlc_conf, default_rlc_config); rlc_BearerConfig->rlc_Config = rlc_Config; NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t)); @@ -3451,7 +3461,8 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, const NR_ServingCellConfig_t *servingcellconfigdedicated, - const nr_mac_config_t *configuration) + const nr_mac_config_t *configuration, + const nr_rlc_configuration_t *default_rlc_config) { NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(*cellGroupConfig)); cellGroupConfig->cellGroupId = 0; @@ -3460,7 +3471,7 @@ NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, /* TS38.331 9.2.1 Default SRB configurations */ cellGroupConfig->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList)); NR_RLC_BearerConfig_t *rlc_BearerConfig = - get_SRB_RLC_BearerConfig(1, 1, NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000); + get_SRB_RLC_BearerConfig(1, 1, NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000, default_rlc_config); asn1cSeqAdd(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig); cellGroupConfig->rlc_BearerToReleaseList = NULL; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index d5a7f8d40a..cdb4f5b792 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -31,6 +31,7 @@ #include "NR_UL-CCCH-Message.h" #include "f1ap_messages_types.h" #include "common/platform_types.h" +#include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h" struct NR_MeasurementTimingConfiguration; struct NR_PDSCH_TimeDomainResourceAllocationList; @@ -84,7 +85,8 @@ NR_SIB19_r17_t *get_SIB19_NR(const NR_ServingCellConfigCommon_t *scc); NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid, const NR_ServingCellConfigCommon_t *scc, const NR_ServingCellConfig_t *servingcellconfigdedicated, - const nr_mac_config_t *configuration); + const nr_mac_config_t *configuration, + const nr_rlc_configuration_t *default_rlc_config); void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig, const int uid, NR_UE_NR_Capability_t *uecap, @@ -107,7 +109,14 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc); -NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, long priority, long bucketSizeDuration); -NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, long drbId, NR_RLC_Config_PR rlc_conf, long priority); +NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId, + long priority, + long bucketSizeDuration, + const nr_rlc_configuration_t *default_rlc_config); +NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId, + long drbId, + NR_RLC_Config_PR rlc_conf, + long priority, + const nr_rlc_configuration_t *default_rlc_config); #endif diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6a7ee77b52..37d92ae9e1 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -46,6 +46,7 @@ #include "LAYER2/nr_rlc/nr_rlc_oai_api.h" #include "asn1_msg.h" #include "../nr_rrc_proto.h" +#include "LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" #include "openair3/SECU/key_nas_deriver.h" @@ -273,7 +274,8 @@ int do_RRCReject(uint8_t *const buffer) NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, e_NR_CipheringAlgorithm ciphering_algorithm, - e_NR_SecurityConfig__keyToUse key_to_use) + e_NR_SecurityConfig__keyToUse key_to_use, + const nr_pdcp_configuration_t *pdcp_config) { NR_RadioBearerConfig_t *rbconfig = calloc(1, sizeof(*rbconfig)); rbconfig->srb_ToAddModList = NULL; @@ -288,9 +290,9 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, drb_ToAddMod->recoverPDCP = NULL; drb_ToAddMod->pdcp_Config = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config)); asn1cCalloc(drb_ToAddMod->pdcp_Config->drb, drb); - asn1cCallocOne(drb->discardTimer, NR_PDCP_Config__drb__discardTimer_infinity); - asn1cCallocOne(drb->pdcp_SN_SizeUL, NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits); - asn1cCallocOne(drb->pdcp_SN_SizeDL, NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits); + asn1cCallocOne(drb->discardTimer, encode_discard_timer(pdcp_config->drb.discard_timer)); + asn1cCallocOne(drb->pdcp_SN_SizeUL, encode_sn_size_ul(pdcp_config->drb.sn_size)); + asn1cCallocOne(drb->pdcp_SN_SizeDL, encode_sn_size_dl(pdcp_config->drb.sn_size)); drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; drb->headerCompression.choice.notUsed = 0; drb->integrityProtection = NULL; @@ -298,7 +300,7 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, drb->outOfOrderDelivery = NULL; drb_ToAddMod->pdcp_Config->moreThanOneRLC = NULL; - asn1cCallocOne(drb_ToAddMod->pdcp_Config->t_Reordering, NR_PDCP_Config__t_Reordering_ms100); + asn1cCallocOne(drb_ToAddMod->pdcp_Config->t_Reordering, encode_t_reordering(pdcp_config->drb.t_reordering)); drb_ToAddMod->pdcp_Config->ext1 = NULL; asn1cSeqAdd(&rbconfig->drb_ToAddModList->list,drb_ToAddMod); diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index afc9226b17..bec3e1d148 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -52,6 +52,7 @@ #include "NR_SecurityConfig.h" #include "ds/seq_arr.h" #include "rrc_messages_types.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList; struct asn_TYPE_descriptor_s; @@ -72,7 +73,8 @@ int do_RRCReject(uint8_t *const buffer); NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id, int rb_id, e_NR_CipheringAlgorithm ciphering_algorithm, - e_NR_SecurityConfig__keyToUse key_to_use); + e_NR_SecurityConfig__keyToUse key_to_use, + const nr_pdcp_configuration_t *pdcp_config); int do_RRCSetup(uint8_t *const buffer, size_t buffer_size, diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 82aa7b5a86..a0002b5a4d 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -397,7 +397,8 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession pduSession, rrc->configuration.enable_sdap, rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); + rrc->security.do_drb_ciphering, + &rrc->pdcp_config); pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding for (int j=0; j < pdu->numDRB2Setup; j++) { diff --git a/openair2/RRC/NR/rrc_gNB_nsa.c b/openair2/RRC/NR/rrc_gNB_nsa.c index deabe38327..8ac172a21e 100644 --- a/openair2/RRC/NR/rrc_gNB_nsa.c +++ b/openair2/RRC/NR/rrc_gNB_nsa.c @@ -141,7 +141,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ uint32_t cgci_len = 0; if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) { DevAssert(m == NULL); - UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master); + UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master, &rrc->pdcp_config); cgci_len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp); DevAssert(cgci_len > 0); cgci_buf = tmp; @@ -223,7 +223,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_ exit(1); } - UE->rb_config = get_default_rbconfig(m->e_rabs_tobeadded[0].e_rab_id, m->e_rabs_tobeadded[0].drb_ID, cipher_algo, NR_SecurityConfig__keyToUse_secondary); + UE->rb_config = get_default_rbconfig(m->e_rabs_tobeadded[0].e_rab_id, m->e_rabs_tobeadded[0].drb_ID, cipher_algo, NR_SecurityConfig__keyToUse_secondary, &rrc->pdcp_config); } if(m!=NULL) { diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 35ae278b2a..e22ee7ffd6 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -30,6 +30,7 @@ #include "common/utils/T/T.h" #include "ngap_messages_types.h" #include "oai_asn1.h" +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create) { @@ -71,13 +72,16 @@ drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id) return &ue->established_drbs[drb_id - 1]; } -void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config, int do_drb_integrity, int do_drb_ciphering) +void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config, + int do_drb_integrity, + int do_drb_ciphering, + const nr_pdcp_configuration_t *default_pdcp_config) { AssertError(pdcp_config != NULL, return, "Failed to set default PDCP configuration for DRB!\n"); - pdcp_config->discardTimer = NR_PDCP_Config__drb__discardTimer_infinity; - pdcp_config->pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len18bits; - pdcp_config->pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len18bits; - pdcp_config->t_Reordering = NR_PDCP_Config__t_Reordering_ms100; + pdcp_config->discardTimer = encode_discard_timer(default_pdcp_config->drb.discard_timer); + pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size); + pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size); + pdcp_config->t_Reordering = encode_t_reordering(default_pdcp_config->drb.t_reordering); pdcp_config->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed; pdcp_config->headerCompression.NotUsed = 0; pdcp_config->integrityProtection = do_drb_integrity ? NR_PDCP_Config__drb__integrityProtection_enabled : 1; @@ -99,7 +103,8 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, const rrc_pdu_session_param_t *pduSession, bool enable_sdap, int do_drb_integrity, - int do_drb_ciphering) + int do_drb_ciphering, + const nr_pdcp_configuration_t *pdcp_config) { DevAssert(ue != NULL); @@ -130,7 +135,7 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, est_drb->status = DRB_ACTIVE; } /* PDCP Configuration */ - set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering); + set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config); drb_t *rrc_drb = get_drb(ue, drb_id); DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */ diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 133e17627f..4a249496ff 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -49,13 +49,15 @@ drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id); /// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header. /// @param do_drb_integrity /// @param do_drb_ciphering +/// @param pdcp_config /// @return returns a pointer to the generated DRB structure drb_t *generateDRB(gNB_RRC_UE_t *ue, uint8_t drb_id, const rrc_pdu_session_param_t *pduSession, bool enable_sdap, int do_drb_integrity, - int do_drb_ciphering); + int do_drb_ciphering, + const nr_pdcp_configuration_t *pdcp_config); /// @brief return the next available (inactive) DRB ID of UE ue uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue); From 915f9d55d86dee101b5df9371bc2fd30eac85646 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 16 Apr 2025 11:22:26 +0200 Subject: [PATCH 025/100] fix asn1 test compilation encode_xx() are needed --- openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt b/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt index 3f7bf45c0e..980d6160e8 100644 --- a/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt +++ b/openair2/RRC/NR/MESSAGES/tests/CMakeLists.txt @@ -1,4 +1,7 @@ -add_executable(test_asn1_msg test_asn1_msg.cpp) +add_executable(test_asn1_msg + test_asn1_msg.cpp + ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c + ${OPENAIR2_DIR}/LAYER2/nr_rlc/asn1_utils.c) target_link_libraries(test_asn1_msg PRIVATE nr_rrc SECURITY minimal_lib GTest::gtest UTIL) add_dependencies(tests test_asn1_msg) add_test(NAME test_asn1_msg From bd05075ac6e42ede8cdad279d9bdb99ca3ef1aa1 Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 29 Jan 2025 14:20:53 +0100 Subject: [PATCH 026/100] code cosmetic improvement --- executables/nr-gnb.c | 19 +++---- executables/nr-ru.c | 55 ++++++++----------- openair1/PHY/INIT/nr_init_ru.c | 33 +++++------ openair1/PHY/NR_TRANSPORT/nr_prach.c | 5 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 7 +-- openair1/SCHED_NR/nr_ru_procedures.c | 18 +++--- openair1/SCHED_NR/sched_nr.h | 2 +- 7 files changed, 60 insertions(+), 79 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 9f20e6f409..24b835d419 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -360,13 +360,11 @@ void term_gNB_Tpool(int inst) { } /// eNB kept in function name for nffapi calls, TO FIX -void init_eNB_afterRU(void) { - int inst,ru_id,i,aa; - PHY_VARS_gNB *gNB; - - for (inst=0; instnum_RU, gNB->Mod_id); - for (ru_id=0,aa=0; ru_idnum_RU; ru_id++) { + int aa = 0; + for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) { AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); - for (i=0; iRU_list[ru_id]->nb_rx; aa++,i++) { - LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n",gNB->RU_list[ru_id]->idx,i,aa); + for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { + LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i]; // TODO hardcoded beam to 0, still need to understand how to handle this properly gNB->common_vars.rxdataF[0][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i]; } } - /* TODO: review this code, there is something wrong. * In monolithic mode, we come here with nb_antennas_rx == 0 * (not tested in other modes). @@ -393,7 +391,6 @@ void init_eNB_afterRU(void) { //init_precoding_weights(RC.gNB[inst]); init_gNB_Tpool(inst); } - } /** diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 6187c9bc2e..0ae303b4e8 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -240,20 +240,20 @@ int connect_rau(RU_t *ru) { void fh_if5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { if (ru == RC.ru[0]) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME( VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, ru->proc.timestamp_tx&0xffffffff ); int offset = ru->nr_frame_parms->get_samples_slot_timestamp(slot,ru->nr_frame_parms,0); - void *buffs[ru->nb_tx]; - for (int aid=0;aidnb_tx;aid++) buffs[aid] = (void*)&ru->common.txdata[aid][offset]; + void *buffs[ru->nb_tx]; + for (int aid = 0; aid < ru->nb_tx; aid++) + buffs[aid] = (void*)&ru->common.txdata[aid][offset]; struct timespec txmeas; clock_gettime(CLOCK_MONOTONIC, &txmeas); LOG_D(NR_PHY,"IF5 TX %d.%d, TS %llu, buffs[0] %p, buffs[1] %p ener0 %f dB, tx start %d\n",frame,slot,(unsigned long long)timestamp,buffs[0],buffs[1], 10*log10((double)signal_energy(buffs[0],ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms))),(int)txmeas.tv_nsec); ru->ifdevice.trx_write_func2(&ru->ifdevice, - timestamp, + timestamp, buffs, - 0, - ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms), - 0, - ru->nb_tx); - + 0, + ru->nr_frame_parms->get_samples_per_slot(slot,ru->nr_frame_parms), + 0, + ru->nb_tx); } // southbound IF4p5 fronthaul @@ -591,33 +591,27 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; openair0_config_t *cfg = &ru->openair0_cfg; - void *rxp[ru->nb_rx]; - unsigned int rxs; - int i; uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); - uint32_t samples_per_slot_prev ; - openair0_timestamp ts,old_ts; - AssertFatal(*slotslots_per_frame && *slot>=0, "slot %d is illegal (%d)\n",*slot,fp->slots_per_frame); + AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame); start_meas(&ru->rx_fhaul); - for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; + void *rxp[ru->nb_rx]; + for (int i = 0; i < ru->nb_rx; i++) + rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)]; - VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1 ); - old_ts = proc->timestamp_rx; - LOG_D(PHY,"Reading %d samples for slot %d (%p)\n",samples_per_slot,*slot,rxp[0]); + VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1); + openair0_timestamp old_ts = proc->timestamp_rx; + LOG_D(PHY,"Reading %d samples for slot %d (%p)\n", samples_per_slot, *slot, rxp[0]); + openair0_timestamp ts; + unsigned int rxs; if(emulate_rf) { wait_on_condition(&proc->mutex_emulateRF,&proc->cond_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); release_thread(&proc->mutex_emulateRF,&proc->instance_cnt_emulateRF,"emulatedRF_thread"); rxs = samples_per_slot; ts = old_ts + rxs; } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, - &ts, - rxp, - samples_per_slot, - ru->nb_rx); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); @@ -629,7 +623,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) LOG_E(PHY, "rx_rf: Asked for %d samples, got %d from USRP\n", samples_per_slot, rxs); if (proc->first_rx != 1) { - samples_per_slot_prev = fp->get_samples_per_slot((*slot-1)%fp->slots_per_frame,fp); + uint32_t samples_per_slot_prev = fp->get_samples_per_slot((*slot - 1) % fp->slots_per_frame, fp); if (proc->timestamp_rx - old_ts != samples_per_slot_prev) { LOG_D(PHY, @@ -752,8 +746,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *cfg = &ru->config; - void *txp[ru->nb_tx]; - int i; T(T_ENB_PHY_OUTPUT_SIGNAL, T_INT(0), T_INT(0), @@ -820,7 +812,8 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot); - for (i = 0; i < ru->nb_tx; i++) + void *txp[ru->nb_tx]; + for (int i = 0; i < ru->nb_tx; i++) txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff); @@ -830,12 +823,12 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) timestamp + ru->ts_offset - sf_extension, txp, siglen + sf_extension, - ru->nb_tx, flags); + ru->nb_tx, + flags); LOG_D(PHY, - "[TXPATH] RU %d aa %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " + "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " "returned %d, E %f\n", ru->idx, - i, (long long unsigned int)(timestamp + ru->ts_offset - sf_extension), frame, slot, diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 674c70cdc3..93964f3ee9 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -29,7 +29,7 @@ void init_prach_ru_list(RU_t *ru); -int nr_phy_init_RU(RU_t *ru) +void nr_phy_init_RU(RU_t *ru) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; @@ -53,30 +53,30 @@ int nr_phy_init_RU(RU_t *ru) if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals - ru->common.txdata = (int32_t**)malloc16(ru->nb_tx*sizeof(int32_t*)); - ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + ru->common.txdata = (int32_t**)malloc16(ru->nb_tx * sizeof(int32_t*)); + ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); for (int i = 0; i < ru->nb_tx; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not - ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame)*sizeof(int32_t)); + ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t)); LOG_D(PHY, "[INIT] common.txdata[%d] = %p (%lu bytes,sf_extension %d)\n", i, ru->common.txdata[i], (ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t), ru->sf_extension); - ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; + ru->common.txdata[i] = &ru->common.txdata[i][ru->sf_extension]; LOG_D(PHY, "[INIT] common.txdata[%d] = %p \n", i, ru->common.txdata[i]); } for (int i = 0; i < ru->nb_rx; i++) { - ru->common.rxdata[i] = (int32_t*)malloc16_clear( fp->samples_per_frame*sizeof(int32_t) ); + ru->common.rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame * sizeof(int32_t)); } } // IF5 or local RF else { - ru->common.txdata = (int32_t**)NULL; - ru->common.rxdata = (int32_t**)NULL; + ru->common.txdata = (int32_t**)NULL; + ru->common.rxdata = (int32_t**)NULL; } if (ru->function != NGFI_RRU_IF5) { // we need to do RX/TX RU processing LOG_D(PHY, "nb_tx %d\n", ru->nb_tx); @@ -85,7 +85,6 @@ int nr_phy_init_RU(RU_t *ru) ru->common.rxdata_7_5kHz[i] = (int32_t*)malloc16_clear( 2*fp->samples_per_subframe*2*sizeof(int32_t) ); LOG_D(PHY, "rxdata_7_5kHz[%d] %p for RU %d\n", i, ru->common.rxdata_7_5kHz[i], ru->idx); } - // allocate precoding input buffers (TX) ru->common.txdataF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); @@ -97,11 +96,11 @@ int nr_phy_init_RU(RU_t *ru) ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, ru->nb_tx * sizeof(int32_t *)); for (int i = 0; i < ru->nb_tx; i++) { - ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP*sizeof(int32_t) ); + ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t)); LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx); } // allocate FFT output buffers (RX) - ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx*sizeof(int32_t*) ); + ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); for (int i = 0; i < ru->nb_rx; i++) { // allocate 4 slots of I/Q signal data (frequency) int size = RU_RX_SLOT_DEPTH * fp->symbols_per_slot * fp->ofdm_symbol_size; @@ -117,21 +116,17 @@ int nr_phy_init_RU(RU_t *ru) for (int i = 0; i < ru->nb_rx; i++) { // largest size for PRACH FFT is 4x98304 (16*24576) - ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear( 4*98304*2*sizeof(int16_t) ); - LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n",i,ru->prach_rxsigF[j][i]); + ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t)); + LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); } } - - AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX,"gNB instances %d > %d\n", - ru->num_gNB,NUMBER_OF_gNB_MAX); + + AssertFatal(ru->num_gNB <= NUMBER_OF_gNB_MAX, "gNB instances %d > %d\n", ru->num_gNB,NUMBER_OF_gNB_MAX); LOG_D(PHY, "[INIT] %s() ru->num_gNB:%d \n", __FUNCTION__, ru->num_gNB); - } // !=IF5 init_prach_ru_list(ru); - - return(0); } void nr_phy_free_RU(RU_t *ru) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 858257893f..9094064fde 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -159,7 +159,6 @@ void rx_nr_prach_ru(RU_t *ru, { AssertFatal(ru != NULL,"ru is null\n"); - int16_t **rxsigF = NULL; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int slot2 = slot; int16_t *prach[ru->nb_rx]; @@ -191,12 +190,12 @@ void rx_nr_prach_ru(RU_t *ru, prachStartSymbol, prachOccasion); - rxsigF = ru->prach_rxsigF[prachOccasion]; + int16_t **rxsigF = ru->prach_rxsigF[prachOccasion]; AssertFatal(ru->if_south == LOCAL_RF || ru->if_south == REMOTE_IF5, "we shouldn't call this if if_south != LOCAL_RF or REMOTE_IF5\n"); - for (int aa=0; aanb_rx; aa++){ + for (int aa = 0; aa < ru->nb_rx; aa++) { if (prach_sequence_length == 0) slot2 = prachStartSlot; prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index 437a3c20db..c6d0ed1ef3 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -264,7 +264,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, - int prachOccasion, + int prachOccasion, int frame, int subframe, uint16_t *max_preamble, @@ -280,10 +280,7 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu); +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index a0b3a69ba8..0dc8c360b0 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -47,7 +47,7 @@ // RU OFDM Modulator gNodeB // OFDM modulation core routine, generates a first_symbol to first_symbol+num_symbols on a particular slot and TX antenna port -void nr_feptx0(RU_t *ru,int tti_tx,int first_symbol, int num_symbols, int aa) +void nr_feptx0(RU_t *ru, int tti_tx, int first_symbol, int num_symbols, int aa) { NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; @@ -345,24 +345,24 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) void nr_fep(void* arg) { feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg; - RU_t *ru = feprx_cmd->ru; - int aid = feprx_cmd->aid; - int tti_rx = feprx_cmd->slot; - int startSymbol = feprx_cmd->startSymbol; - int endSymbol = feprx_cmd->endSymbol; + RU_t *ru = feprx_cmd->ru; + int aid = feprx_cmd->aid; + int slot = feprx_cmd->slot; + int startSymbol = feprx_cmd->startSymbol; + int endSymbol = feprx_cmd->endSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; - LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, tti_rx, startSymbol, endSymbol); + LOG_D(PHY,"aid %d, frame %d slot %d, startSymbol %d, endSymbol %d\n", aid, ru->proc.frame_rx, slot, startSymbol, endSymbol); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1); - int offset = (tti_rx % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; + int offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (int l = startSymbol; l <= endSymbol; l++) nr_slot_fep_ul(fp, ru->common.rxdata[aid], &ru->common.rxdataF[aid][offset], l, - tti_rx, + slot, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0); diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index bf5a1eda3f..9f65819960 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -44,7 +44,7 @@ void nr_feptx_prec_control(RU_t *ru,int frame,int tti_tx); void nr_fep_tp(RU_t *ru, int slot); void nr_feptx_tp(RU_t *ru, int frame_tx, int slot); void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); -int nr_phy_init_RU(RU_t *ru); +void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols); From c1372a52c89860cffadec61c5da4d9af02b957ef Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 5 Jun 2025 10:13:09 +0200 Subject: [PATCH 027/100] bugfix: don't print '.' if no prefix It's confusing to read "Section ".rlc" not allowed" when it should be "Section "rlc" not allowed". --- openair2/GNB_APP/gnb_config.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index e1c04fa3f4..64f6bc8421 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -846,7 +846,11 @@ static void verify_section_notset(configmodule_interface_t *cfg, char *aprefix, paramlist_def_t pl = {0}; strncpy(pl.listname, secname, sizeof(pl.listname) - 1); config_getlist(cfg, &pl, NULL, 0, aprefix); - AssertFatal(pl.numelt == 0, "Section \"%s.%s\" not allowed in this config, please remove it\n", aprefix ? aprefix : "", secname); + AssertFatal(pl.numelt == 0, + "Section \"%s%s%s\" not allowed in this config, please remove it\n", + aprefix ? aprefix : "", + aprefix ? "." : "", + secname); } void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) { From 127ba6f0d996f75b4f0c7ebd39018fab65c62871 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Thu, 5 Jun 2025 10:14:58 +0200 Subject: [PATCH 028/100] add checks for allowed sections --- openair2/GNB_APP/gnb_config.c | 2 ++ openair2/GNB_APP/gnb_paramdef.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 64f6bc8421..3b071f6634 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -883,6 +883,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST); verify_section_notset(cfg, NULL, CONFIG_STRING_RU_LIST); verify_section_notset(cfg, NULL, CONFIG_STRING_MACRLC_LIST); + verify_section_notset(cfg, NULL, CONFIG_STRING_NR_RLC_LIST); } else if (NODE_IS_DU(node_type)) { // verify that there is no bearer config verify_gnb_param_notset(gnbp, GNB_ENABLE_SDAP_IDX, GNB_CONFIG_STRING_ENABLE_SDAP); @@ -890,6 +891,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type) verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS); verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY); + verify_section_notset(cfg, NULL, CONFIG_STRING_NR_PDCP_LIST); } // else nothing to be checked /* other possible verifications: PNF, VNF, CU-CP, CU-UP, ...? */ diff --git a/openair2/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 76ce814e88..cc2c412a81 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -680,6 +680,9 @@ typedef enum { /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CONFIG_STRING_NR_RLC_LIST "rlc" +#define CONFIG_STRING_NR_PDCP_LIST "pdcp" + #define CONFIG_NR_RLC_T_POLL_RETRANSMIT "t_poll_retransmit" #define CONFIG_NR_RLC_T_REASSEMBLY "t_reassembly" #define CONFIG_NR_RLC_T_STATUS_PROHIBIT "t_status_prohibit" From d851e7799c32aa9b0891f1cdaa294840490c1001 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 28 May 2025 14:05:46 +0100 Subject: [PATCH 029/100] Fix segmentation fault and LOGs for SRS usage NFAPI_NR_SRS_BEAMMANAGEMENT --- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- nfapi/open-nFAPI/nfapi/src/nfapi_p7.c | 3 +-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 13 ++++++++----- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 10 +++++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index a34796eeb3..2c7960d045 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -1829,7 +1829,7 @@ typedef struct { uint8_t num_symbols; // Number of symbols for SRS. Value: 1 -> 4. If a PHY does not report for individual symbols then this parameter should be set to 1. uint8_t wide_band_snr; // SNR value in dB measured within configured SRS bandwidth on each symbol. Value: 0 -> 255 representing -64 dB to 63 dB with a step size 0.5 dB. 0xff will be set if this field is invalid. uint8_t num_reported_symbols; // Number of symbols reported in this message. This allows PHY to report individual symbols or aggregated symbols where this field will be set to 1. Value: 1 -> 4. - nfapi_nr_srs_reported_symbol_t* reported_symbol_list; + nfapi_nr_srs_reported_symbol_t reported_symbol_list[4]; } nfapi_nr_srs_beamforming_report_t; // SRS indication diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c index 8cf42cf511..b6e15e294b 100644 --- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c +++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c @@ -4455,8 +4455,7 @@ int unpack_nr_srs_beamforming_report(void *pMessageBuf, uint32_t messageBufLen, && pull8(&pReadPackedMessage, &nr_srs_beamforming_report->num_reported_symbols, end))) { return -1; } - nr_srs_beamforming_report->reported_symbol_list = - calloc(nr_srs_beamforming_report->num_reported_symbols, sizeof(*nr_srs_beamforming_report->reported_symbol_list)); + for (int reported_symbol = 0; reported_symbol < nr_srs_beamforming_report->num_reported_symbols; ++reported_symbol) { if (!unpack_nr_srs_reported_symbol(&nr_srs_beamforming_report->reported_symbol_list[reported_symbol], &pReadPackedMessage, diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 095c41d0da..3e24d0a4eb 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -1046,6 +1046,9 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N nr_srs_bf_report.num_symbols = 1 << srs_pdu->num_symbols; nr_srs_bf_report.wide_band_snr = srs_est >= 0 ? (gNB->srs->snr + 64) << 1 : 0xFF; // 0xFF will be set if this field is invalid nr_srs_bf_report.num_reported_symbols = 1 << srs_pdu->num_symbols; + AssertFatal(nr_srs_bf_report.num_reported_symbols == 1, + "nr_srs_bf_report.num_reported_symbols %i not handled yet!\n", + nr_srs_bf_report.num_reported_symbols); fill_srs_reported_symbol(&nr_srs_bf_report.reported_symbol_list[0], srs_pdu, frame_parms->N_RB_UL, snr_per_rb, srs_est); #ifdef SRS_IND_DEBUG @@ -1053,13 +1056,13 @@ int phy_procedures_gNB_uespec_RX(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, N LOG_I(NR_PHY, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols); LOG_I(NR_PHY, "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", nr_srs_bf_report.wide_band_snr, (nr_srs_bf_report.wide_band_snr >> 1) - 64); LOG_I(NR_PHY, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols); - LOG_I(NR_PHY, "nr_srs_bf_report.prgs[0].num_prgs = %i\n", nr_srs_bf_report.prgs[0].num_prgs); - for (int prg_idx = 0; prg_idx < nr_srs_bf_report.prgs[0].num_prgs; prg_idx++) { + LOG_I(NR_PHY, "nr_srs_bf_report.reported_symbol_list[0].num_prgs = %i\n", nr_srs_bf_report.reported_symbol_list[0].num_prgs); + for (int prg_idx = 0; prg_idx < nr_srs_bf_report.reported_symbol_list[0].num_prgs; prg_idx++) { LOG_I(NR_PHY, - "nr_srs_beamforming_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n", + "nr_srs_beamforming_report.reported_symbol_list[0].prg_list[%3i].rb_snr = %i (%i dB)\n", prg_idx, - nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr, - (nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64); + nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr, + (nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr >> 1) - 64); } #endif diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 35c817b975..241b6203e9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -1442,13 +1442,13 @@ void handle_nr_srs_measurements(const module_id_t module_id, LOG_I(NR_MAC, "nr_srs_bf_report.num_symbols = %i\n", nr_srs_bf_report.num_symbols); LOG_I(NR_MAC, "nr_srs_bf_report.wide_band_snr = %i (%i dB)\n", nr_srs_bf_report.wide_band_snr, wide_band_snr_dB); LOG_I(NR_MAC, "nr_srs_bf_report.num_reported_symbols = %i\n", nr_srs_bf_report.num_reported_symbols); - LOG_I(NR_MAC, "nr_srs_bf_report.prgs[0].num_prgs = %i\n", nr_srs_bf_report.prgs[0].num_prgs); - for (int prg_idx = 0; prg_idx < nr_srs_bf_report.prgs[0].num_prgs; prg_idx++) { + LOG_I(NR_MAC, "nr_srs_bf_report.reported_symbol_list[0].num_prgs = %i\n", nr_srs_bf_report.reported_symbol_list[0].num_prgs); + for (int prg_idx = 0; prg_idx < nr_srs_bf_report.reported_symbol_list[0].num_prgs; prg_idx++) { LOG_I(NR_MAC, - "nr_srs_bf_report.prgs[0].prg_list[%3i].rb_snr = %i (%i dB)\n", + "nr_srs_bf_report.reported_symbol_list[0].prg_list[%3i].rb_snr = %i (%i dB)\n", prg_idx, - nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr, - (nr_srs_bf_report.prgs[0].prg_list[prg_idx].rb_snr >> 1) - 64); + nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr, + (nr_srs_bf_report.reported_symbol_list[0].prg_list[prg_idx].rb_snr >> 1) - 64); } #endif From 7080810e4987dcdb2b0b24c09069469c9745d260 Mon Sep 17 00:00:00 2001 From: rmagueta Date: Wed, 28 May 2025 17:04:39 +0100 Subject: [PATCH 030/100] Refactor SRS configuration --- openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c | 196 +++++++++++-------- 1 file changed, 115 insertions(+), 81 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 22c2207be1..70797f52ea 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -728,64 +728,58 @@ static struct NR_SRS_Resource__resourceType__periodic *configure_periodic_srs(co return periodic_srs; } -static NR_SetupRelease_SRS_Config_t *get_config_srs(const NR_ServingCellConfigCommon_t *scc, - const NR_UE_NR_Capability_t *uecap, - const int curr_bwp, - const int uid, - const int res_id, - const long maxMIMO_Layers, - const int minRXTXTIME, - int do_srs) +static NR_SRS_ResourceSet_t *get_srs_resourceset(const int resset_id, + const int res_id, + const long usage, + const int minRXTXTIME, + int do_srs) { - NR_SetupRelease_SRS_Config_t *setup_release_srs_Config = calloc(1,sizeof(*setup_release_srs_Config)); - setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; - setup_release_srs_Config->choice.setup = calloc(1,sizeof(*setup_release_srs_Config->choice.setup)); - NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; - - srs_Config->srs_ResourceSetToReleaseList = NULL; - - srs_Config->srs_ResourceSetToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceSetToAddModList)); - NR_SRS_ResourceSet_t *srs_resset0 = calloc(1,sizeof(*srs_resset0)); - srs_resset0->srs_ResourceSetId = res_id; - srs_resset0->srs_ResourceIdList = calloc(1,sizeof(*srs_resset0->srs_ResourceIdList)); - NR_SRS_ResourceId_t *srs_resset0_id = calloc(1,sizeof(*srs_resset0_id)); - *srs_resset0_id = res_id; - asn1cSeqAdd(&srs_resset0->srs_ResourceIdList->list, srs_resset0_id); - srs_Config->srs_ResourceToReleaseList=NULL; + NR_SRS_ResourceSet_t *srs_resset = calloc_or_fail(1, sizeof(*srs_resset)); + srs_resset->srs_ResourceSetId = resset_id; + srs_resset->srs_ResourceIdList = calloc_or_fail(1, sizeof(*srs_resset->srs_ResourceIdList)); + NR_SRS_ResourceId_t *srs_resset_id = calloc_or_fail(1, sizeof(*srs_resset_id)); + *srs_resset_id = res_id; + asn1cSeqAdd(&srs_resset->srs_ResourceIdList->list, srs_resset_id); if (do_srs) { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; - srs_resset0->resourceType.choice.periodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.periodic)); - srs_resset0->resourceType.choice.periodic->associatedCSI_RS = NULL; + srs_resset->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_periodic; + srs_resset->resourceType.choice.periodic = calloc_or_fail(1, sizeof(*srs_resset->resourceType.choice.periodic)); + srs_resset->resourceType.choice.periodic->associatedCSI_RS = NULL; } else { - srs_resset0->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; - srs_resset0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic)); - srs_resset0->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger = 1; - srs_resset0->resourceType.choice.aperiodic->csi_RS = NULL; - srs_resset0->resourceType.choice.aperiodic->slotOffset = calloc(1,sizeof(*srs_resset0->resourceType.choice.aperiodic->slotOffset)); - *srs_resset0->resourceType.choice.aperiodic->slotOffset = minRXTXTIME; - srs_resset0->resourceType.choice.aperiodic->ext1 = NULL; + srs_resset->resourceType.present = NR_SRS_ResourceSet__resourceType_PR_aperiodic; + srs_resset->resourceType.choice.aperiodic = calloc_or_fail(1, sizeof(*srs_resset->resourceType.choice.aperiodic)); + srs_resset->resourceType.choice.aperiodic->aperiodicSRS_ResourceTrigger = 1; + srs_resset->resourceType.choice.aperiodic->csi_RS = NULL; + srs_resset->resourceType.choice.aperiodic->slotOffset = + calloc_or_fail(1, sizeof(*srs_resset->resourceType.choice.aperiodic->slotOffset)); + *srs_resset->resourceType.choice.aperiodic->slotOffset = minRXTXTIME; + srs_resset->resourceType.choice.aperiodic->ext1 = NULL; } - srs_resset0->usage=NR_SRS_ResourceSet__usage_codebook; - srs_resset0->alpha = calloc(1,sizeof(*srs_resset0->alpha)); - *srs_resset0->alpha = NR_Alpha_alpha1; - srs_resset0->p0 = calloc(1,sizeof(*srs_resset0->p0)); - *srs_resset0->p0 =-80; - srs_resset0->pathlossReferenceRS = NULL; - srs_resset0->srs_PowerControlAdjustmentStates = NULL; - asn1cSeqAdd(&srs_Config->srs_ResourceSetToAddModList->list,srs_resset0); + srs_resset->usage = usage; + srs_resset->alpha = calloc_or_fail(1, sizeof(*srs_resset->alpha)); + *srs_resset->alpha = NR_Alpha_alpha1; + srs_resset->p0 = calloc_or_fail(1, sizeof(*srs_resset->p0)); + *srs_resset->p0 = -80; + srs_resset->pathlossReferenceRS = NULL; + srs_resset->srs_PowerControlAdjustmentStates = NULL; + return srs_resset; +} - srs_Config->srs_ResourceToReleaseList = NULL; - - srs_Config->srs_ResourceToAddModList = calloc(1,sizeof(*srs_Config->srs_ResourceToAddModList)); - NR_SRS_Resource_t *srs_res0=calloc(1,sizeof(*srs_res0)); - srs_res0->srs_ResourceId = res_id; - srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; +static NR_SRS_Resource_t *get_srs_resource(const NR_ServingCellConfigCommon_t *scc, + const NR_UE_NR_Capability_t *uecap, + const int curr_bwp, + const int uid, + const int res_id, + const long maxMIMO_Layers, + const NR_SRS_Resource__transmissionComb_PR tx_comb, + int do_srs) +{ + NR_SRS_Resource_t *srs_res = calloc_or_fail(1, sizeof(*srs_res)); + srs_res->srs_ResourceId = res_id; + srs_res->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; if (do_srs) { long nrofSRS_Ports = 1; - if (uecap && - uecap->featureSets && - uecap->featureSets->featureSetsUplink && - uecap->featureSets->featureSetsUplink->list.count > 0) { + if (uecap && uecap->featureSets && uecap->featureSets->featureSetsUplink + && uecap->featureSets->featureSetsUplink->list.count > 0) { NR_FeatureSetUplink_t *ul_feature_setup = uecap->featureSets->featureSetsUplink->list.array[0]; switch (ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource) { case NR_SRS_Resources__maxNumberSRS_Ports_PerResource_n1: @@ -798,55 +792,95 @@ static NR_SetupRelease_SRS_Config_t *get_config_srs(const NR_ServingCellConfigCo nrofSRS_Ports = 4; break; default: - LOG_E(NR_RRC, "Max Number of SRS Ports Per Resource %ld is invalid!\n", + LOG_E(NR_RRC, + "Max Number of SRS Ports Per Resource %ld is invalid!\n", ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource); } nrofSRS_Ports = min(nrofSRS_Ports, maxMIMO_Layers); switch (nrofSRS_Ports) { case 1: - srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; + srs_res->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_port1; break; case 2: - srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports2; + srs_res->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports2; break; case 4: - srs_res0->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports4; + srs_res->nrofSRS_Ports = NR_SRS_Resource__nrofSRS_Ports_ports4; break; default: - LOG_E(NR_RRC, "Number of SRS Ports Per Resource %ld is invalid!\n", + LOG_E(NR_RRC, + "Number of SRS Ports Per Resource %ld is invalid!\n", ul_feature_setup->supportedSRS_Resources->maxNumberSRS_Ports_PerResource); } } - LOG_I(NR_RRC, "SRS configured with %d ports\n", 1<nrofSRS_Ports); + LOG_I(NR_RRC, "SRS configured with %d ports\n", 1 << srs_res->nrofSRS_Ports); } - srs_res0->ptrs_PortIndex = NULL; - srs_res0->transmissionComb.present = NR_SRS_Resource__transmissionComb_PR_n2; - srs_res0->transmissionComb.choice.n2 = calloc(1,sizeof(*srs_res0->transmissionComb.choice.n2)); - srs_res0->transmissionComb.choice.n2->combOffset_n2 = 0; - srs_res0->transmissionComb.choice.n2->cyclicShift_n2 = 0; - srs_res0->resourceMapping.startPosition = 1; - srs_res0->resourceMapping.nrofSymbols = NR_SRS_Resource__resourceMapping__nrofSymbols_n1; - srs_res0->resourceMapping.repetitionFactor = NR_SRS_Resource__resourceMapping__repetitionFactor_n1; - srs_res0->freqDomainPosition = 0; - srs_res0->freqDomainShift = 0; - srs_res0->freqHopping.b_SRS = 0; - srs_res0->freqHopping.b_hop = 0; - srs_res0->freqHopping.c_SRS = rrc_get_max_nr_csrs(curr_bwp, srs_res0->freqHopping.b_SRS); - srs_res0->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; + srs_res->ptrs_PortIndex = NULL; + srs_res->transmissionComb.present = tx_comb; + switch (tx_comb) { + case NR_SRS_Resource__transmissionComb_PR_n2: + srs_res->transmissionComb.choice.n2 = calloc_or_fail(1, sizeof(*srs_res->transmissionComb.choice.n2)); + srs_res->transmissionComb.choice.n2->combOffset_n2 = 0; + srs_res->transmissionComb.choice.n2->cyclicShift_n2 = 0; + break; + case NR_SRS_Resource__transmissionComb_PR_n4: + srs_res->transmissionComb.choice.n4 = calloc_or_fail(1, sizeof(*srs_res->transmissionComb.choice.n4)); + srs_res->transmissionComb.choice.n4->combOffset_n4 = 0; + srs_res->transmissionComb.choice.n4->cyclicShift_n4 = 0; + break; + default: + AssertFatal(1 == 0, "Invalid transmission comb %d\n", tx_comb); + } + srs_res->resourceMapping.startPosition = 1; + srs_res->resourceMapping.nrofSymbols = NR_SRS_Resource__resourceMapping__nrofSymbols_n1; + srs_res->resourceMapping.repetitionFactor = NR_SRS_Resource__resourceMapping__repetitionFactor_n1; + srs_res->freqDomainPosition = 0; + srs_res->freqDomainShift = 0; + srs_res->freqHopping.b_SRS = 0; + srs_res->freqHopping.b_hop = 0; + srs_res->freqHopping.c_SRS = rrc_get_max_nr_csrs(curr_bwp, srs_res->freqHopping.b_SRS); + srs_res->groupOrSequenceHopping = NR_SRS_Resource__groupOrSequenceHopping_neither; if (do_srs) { - srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; - srs_res0->resourceType.choice.periodic = configure_periodic_srs(scc, uid); + srs_res->resourceType.present = NR_SRS_Resource__resourceType_PR_periodic; + srs_res->resourceType.choice.periodic = configure_periodic_srs(scc, uid); } else { - srs_res0->resourceType.present = NR_SRS_Resource__resourceType_PR_aperiodic; - srs_res0->resourceType.choice.aperiodic = calloc(1,sizeof(*srs_res0->resourceType.choice.aperiodic)); + srs_res->resourceType.present = NR_SRS_Resource__resourceType_PR_aperiodic; + srs_res->resourceType.choice.aperiodic = calloc_or_fail(1, sizeof(*srs_res->resourceType.choice.aperiodic)); } - srs_res0->sequenceId = 40; - srs_res0->spatialRelationInfo = calloc(1,sizeof(*srs_res0->spatialRelationInfo)); - srs_res0->spatialRelationInfo->servingCellId = NULL; + srs_res->sequenceId = 40; + srs_res->spatialRelationInfo = calloc_or_fail(1, sizeof(*srs_res->spatialRelationInfo)); + srs_res->spatialRelationInfo->servingCellId = NULL; // TODO include CSI as reference signal when BWPs are handled properly - srs_res0->spatialRelationInfo->referenceSignal.present = NR_SRS_SpatialRelationInfo__referenceSignal_PR_ssb_Index; - srs_res0->spatialRelationInfo->referenceSignal.choice.ssb_Index = 0; - asn1cSeqAdd(&srs_Config->srs_ResourceToAddModList->list,srs_res0); + srs_res->spatialRelationInfo->referenceSignal.present = NR_SRS_SpatialRelationInfo__referenceSignal_PR_ssb_Index; + srs_res->spatialRelationInfo->referenceSignal.choice.ssb_Index = 0; + return srs_res; +} + +static NR_SetupRelease_SRS_Config_t *get_config_srs(const NR_ServingCellConfigCommon_t *scc, + const NR_UE_NR_Capability_t *uecap, + const int curr_bwp, + const int uid, + const int res_id, + const long maxMIMO_Layers, + const int minRXTXTIME, + int do_srs) +{ + NR_SetupRelease_SRS_Config_t *setup_release_srs_Config = calloc_or_fail(1, sizeof(*setup_release_srs_Config)); + setup_release_srs_Config->present = NR_SetupRelease_SRS_Config_PR_setup; + setup_release_srs_Config->choice.setup = calloc_or_fail(1, sizeof(*setup_release_srs_Config->choice.setup)); + NR_SRS_Config_t *srs_Config = setup_release_srs_Config->choice.setup; + + srs_Config->srs_ResourceToAddModList = calloc_or_fail(1, sizeof(*srs_Config->srs_ResourceToAddModList)); + NR_SRS_Resource_t *srs_res0 = + get_srs_resource(scc, uecap, curr_bwp, uid, res_id, maxMIMO_Layers, NR_SRS_Resource__transmissionComb_PR_n2, do_srs); + asn1cSeqAdd(&srs_Config->srs_ResourceToAddModList->list, srs_res0); + + srs_Config->srs_ResourceSetToAddModList = calloc_or_fail(1, sizeof(*srs_Config->srs_ResourceSetToAddModList)); + NR_SRS_ResourceSet_t *srs_resset0 = get_srs_resourceset(res_id, res_id, NR_SRS_ResourceSet__usage_codebook, minRXTXTIME, do_srs); + asn1cSeqAdd(&srs_Config->srs_ResourceSetToAddModList->list, srs_resset0); + + srs_Config->srs_ResourceSetToReleaseList = NULL; + srs_Config->srs_ResourceToReleaseList = NULL; return setup_release_srs_Config; } From 5b837f925090041e572a297b647ee27c8d26fe99 Mon Sep 17 00:00:00 2001 From: Teodora Date: Wed, 4 Jun 2025 16:38:20 +0200 Subject: [PATCH 031/100] Remove unnecessary shared volume for SMs Follow-up for https://gitlab.eurecom.fr/mosaic5g/flexric/-/commit/497b4d345171ab92b7060b68c12f4e2e58621444. --- .../yaml_files/5g_rfsimulator_flexric/docker-compose.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml index 899e02295f..6b9771e1c1 100644 --- a/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml +++ b/ci-scripts/yaml_files/5g_rfsimulator_flexric/docker-compose.yml @@ -7,7 +7,6 @@ services: ipv4_address: 192.168.70.150 volumes: - ./conf/flexric.conf:/usr/local/etc/flexric/flexric.conf - - sharedXappLibs:/usr/local/lib/flexric/ healthcheck: test: /bin/bash -c "pgrep nearRT-RIC" interval: 10s @@ -95,7 +94,6 @@ services: ipv4_address: 192.168.70.151 volumes: - ../../conf_files/gnb.sa.band78.106prb.rfsim.flexric.conf:/opt/oai-gnb/etc/gnb.conf - - sharedXappLibs:/usr/local/lib/flexric/ healthcheck: test: /bin/bash -c "pgrep nr-softmodem" interval: 10s @@ -140,9 +138,6 @@ services: timeout: 5s retries: 5 -volumes: - sharedXappLibs: - networks: public_net: name: oai-cn5g-public-net From 4b2cd156bb6557d9fe7c8becc34a227d138c9ad1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 15:42:36 +0200 Subject: [PATCH 032/100] Adopt existing ngap_ambr_t in NGAP PDU Session Setup Request --- openair2/COMMON/ngap_messages_types.h | 7 ++----- openair2/RRC/NR/rrc_gNB_NGAP.c | 2 +- openair3/NGAP/ngap_gNB_handlers.c | 4 ++-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 52cd919338..b899bb33e2 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -664,11 +664,8 @@ typedef struct ngap_pdusession_setup_req_s { /* E RAB setup request */ pdusession_t pdusession_setup_params[NGAP_MAX_PDU_SESSION]; - /* UE Uplink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateUplink; - - /* UE Downlink Aggregated Max Bitrates */ - uint64_t ueAggMaxBitRateDownlink; + /* UE Aggregated Max Bitrates */ + ngap_ambr_t ueAggMaxBitRate; } ngap_pdusession_setup_req_t; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 82aa7b5a86..1ff31acae1 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -940,7 +940,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } - if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink)) { + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRate.br_dl)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index ad8efce5a3..efa717e719 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -985,9 +985,9 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &msg->ueAggMaxBitRateUplink); + &msg->ueAggMaxBitRate.br_ul); asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRateDownlink); + &msg->ueAggMaxBitRate.br_dl); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); From 615f5ef663c9624517c749f61b39061da3bc4c92 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 15:45:36 +0200 Subject: [PATCH 033/100] Add decoding functions for common NGAP IEs and use in stack * Functions added: decode_ngap_guami decode_ngap_UEAggregateMaximumBitRate decode_ngap_nssai decode_ngap_security_capabilities decode_ngap_mobility_restriction * Adopt these functions in the common NGAP library --- openair3/NGAP/ngap_common.c | 48 ++++++++++++ openair3/NGAP/ngap_common.h | 5 ++ openair3/NGAP/ngap_gNB_handlers.c | 124 ++++++++---------------------- 3 files changed, 83 insertions(+), 94 deletions(-) diff --git a/openair3/NGAP/ngap_common.c b/openair3/NGAP/ngap_common.c index 385730f70d..7b960fed0b 100644 --- a/openair3/NGAP/ngap_common.c +++ b/openair3/NGAP/ngap_common.c @@ -28,6 +28,7 @@ */ #include +#include "conversions.h" #include "ngap_common.h" int asn1_xer_print = 0; @@ -66,3 +67,50 @@ void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in) break; } } + +nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in) +{ + nr_guami_t out = {0}; + TBCD_TO_MCC_MNC(&in->pLMNIdentity, out.mcc, out.mnc, out.mnc_len); + OCTET_STRING_TO_INT8(&in->aMFRegionID, out.amf_region_id); + OCTET_STRING_TO_INT16(&in->aMFSetID, out.amf_set_id); + OCTET_STRING_TO_INT8(&in->aMFPointer, out.amf_pointer); + return out; +} + +ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in) +{ + ngap_ambr_t ambr = {0}; + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateUL, &ambr.br_ul); + asn_INTEGER2ulong(&in->uEAggregateMaximumBitRateDL, &ambr.br_dl); + return ambr; +} + +nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in) +{ + nssai_t nssai = {0}; + OCTET_STRING_TO_INT8(&in->sST, nssai.sst); + if (in->sD != NULL) { + BUFFER_TO_INT24(in->sD->buf, nssai.sd); + } else { + nssai.sd = 0xffffff; + } + return nssai; +} + +ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in) +{ + ngap_security_capabilities_t out = {0}; + out.nRencryption_algorithms = BIT_STRING_to_uint16(&in->nRencryptionAlgorithms); + out.nRintegrity_algorithms = BIT_STRING_to_uint16(&in->nRintegrityProtectionAlgorithms); + out.eUTRAencryption_algorithms = BIT_STRING_to_uint16(&in->eUTRAencryptionAlgorithms); + out.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&in->eUTRAintegrityProtectionAlgorithms); + return out; +} + +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in) +{ + ngap_mobility_restriction_t out = {0}; + TBCD_TO_MCC_MNC(&in->servingPLMN, out.serving_plmn.mcc, out.serving_plmn.mnc, out.serving_plmn.mnc_digit_length); + return out; +} diff --git a/openair3/NGAP/ngap_common.h b/openair3/NGAP/ngap_common.h index 259f0cbb18..82a8fe9234 100644 --- a/openair3/NGAP/ngap_common.h +++ b/openair3/NGAP/ngap_common.h @@ -85,6 +85,11 @@ extern int asn1_xer_print; typedef int (*ngap_message_decoded_callback)(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu); void encode_ngap_cause(NGAP_Cause_t *out, const ngap_cause_t *in); +nr_guami_t decode_ngap_guami(const NGAP_GUAMI_t *in); +ngap_ambr_t decode_ngap_UEAggregateMaximumBitRate(const NGAP_UEAggregateMaximumBitRate_t *in); +nssai_t decode_ngap_nssai(const NGAP_S_NSSAI_t *in); +ngap_security_capabilities_t decode_ngap_security_capabilities(const NGAP_UESecurityCapabilities_t *in); +ngap_mobility_restriction_t decode_ngap_mobility_restriction(const NGAP_MobilityRestrictionList_t *in); /** @}*/ diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index efa717e719..3f6b718861 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -747,30 +747,14 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 msg->gNB_ue_ngap_id = ue_desc_p->gNB_ue_ngap_id; msg->amf_ue_ngap_id = ue_desc_p->amf_ue_ngap_id; /* id-UEAggregateMaximumBitRate */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &(msg->ue_ambr.br_ul)); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &(msg->ue_ambr.br_dl)); - } else { - NGAP_WARN("could not find NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate\n"); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, false); + if (ie != NULL) { + msg->ue_ambr = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); } - /* id-GUAMI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_GUAMI, true); - - TBCD_TO_MCC_MNC(&ie->value.choice.GUAMI.pLMNIdentity, msg->guami.mcc, - msg->guami.mnc, msg->guami.mnc_len); - - msg->guami.amf_region_id = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFRegionID); - msg->guami.amf_set_id = BIT_STRING_to_uint16(&ie->value.choice.GUAMI.aMFSetID); - msg->guami.amf_pointer = BIT_STRING_to_uint8(&ie->value.choice.GUAMI.aMFPointer); - + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_GUAMI, true); + msg->guami = decode_ngap_guami(&ie->value.choice.GUAMI); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtReq, false); if (ie != NULL) { @@ -779,17 +763,7 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 for (i = 0; i < ie->value.choice.PDUSessionResourceSetupListCxtReq.list.count; i++) { NGAP_PDUSessionResourceSetupItemCxtReq_t *item_p = ie->value.choice.PDUSessionResourceSetupListCxtReq.list.array[i]; msg->pdusession_param[i].pdusession_id = item_p->pDUSessionID; - - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_param[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - uint8_t *sd_p = (uint8_t *)&msg->pdusession_param[i].nssai.sd; - sd_p[0] = item_p->s_NSSAI.sD->buf[0]; - sd_p[1] = item_p->s_NSSAI.sD->buf[1]; - sd_p[2] = item_p->s_NSSAI.sD->buf[2]; - } else { - msg->pdusession_param[i].nssai.sd = 0xffffff; - } - + msg->pdusession_param[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); if (item_p->nAS_PDU) { msg->pdusession_param[i].nas_pdu = create_byte_array(item_p->nAS_PDU->size, item_p->nAS_PDU->buf); } @@ -799,62 +773,31 @@ static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32 } /* id-AllowedNSSAI */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); - - //if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_AllowedNSSAI_Item_t *allow_nssai_item_p = NULL; - - //NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count > 0); - //DevAssert(ie->value.choice.AllowedNSSAI.list.count <= NGAP_maxnoofAllowedS_NSSAIs); - - AssertFatal(ie, "AllowedNSSAI not present, forging 2 NSSAI\n"); - - NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); - msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; - - for(i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { - allow_nssai_item_p = ie->value.choice.AllowedNSSAI.list.array[i]; - - OCTET_STRING_TO_INT8(&allow_nssai_item_p->s_NSSAI.sST, msg->allowed_nssai[i].sst); - - if(allow_nssai_item_p->s_NSSAI.sD != NULL) { - msg->allowed_nssai[i].sd = 0; - BUFFER_TO_INT24((uint8_t *)allow_nssai_item_p->s_NSSAI.sD->buf, msg->allowed_nssai[i].sd); - } else { - msg->allowed_nssai[i].sd = 0xffffff; - } - } + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AllowedNSSAI, true); + NGAP_DEBUG("AllowedNSSAI.list.count %d\n", ie->value.choice.AllowedNSSAI.list.count); + msg->nb_allowed_nssais = ie->value.choice.AllowedNSSAI.list.count; + for (i = 0; i < ie->value.choice.AllowedNSSAI.list.count; i++) { + msg->allowed_nssai[i] = decode_ngap_nssai(&ie->value.choice.AllowedNSSAI.list.array[i]->s_NSSAI); + } /* id-UESecurityCapabilities */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, - NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UESecurityCapabilities, true); + msg->security_capabilities = decode_ngap_security_capabilities(&ie->value.choice.UESecurityCapabilities); - msg->security_capabilities.nRencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRencryptionAlgorithms); - msg->security_capabilities.nRintegrity_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.nRintegrityProtectionAlgorithms); - msg->security_capabilities.eUTRAencryption_algorithms = - BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAencryptionAlgorithms); - msg->security_capabilities.eUTRAintegrity_algorithms = BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.eUTRAintegrityProtectionAlgorithms); - - /* id-SecurityKey : Copy the security key */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); - memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); - - /* id-MobilityRestrictionList */ - NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false); - - if (ie != NULL) { /* checked by macro but cppcheck doesn't see it */ - NGAP_MobilityRestrictionList_t *mobility_rest_list_p = NULL; - mobility_rest_list_p = &ie->value.choice.MobilityRestrictionList; - - msg->mobility_restriction_flag = 1; - TBCD_TO_MCC_MNC( - &mobility_rest_list_p->servingPLMN, msg->mobility_restriction.serving_plmn.mcc, msg->mobility_restriction.serving_plmn.mnc, msg->mobility_restriction.serving_plmn.mnc_digit_length); - } + /* id-SecurityKey : Copy the security key */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_SecurityKey, true); + memcpy(&msg->security_key, ie->value.choice.SecurityKey.buf, ie->value.choice.SecurityKey.size); + /* id-MobilityRestrictionList */ + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_MobilityRestrictionList, + false); + if (ie != NULL) { + msg->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList); + msg->mobility_restriction_flag = true; + } /* id-NAS-PDU */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_InitialContextSetupRequestIEs_t, ie, container, @@ -984,10 +927,7 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 /* UE Aggregated Maximum Bitrate */ NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate, true); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL), - &msg->ueAggMaxBitRate.br_ul); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRate.br_dl); + msg->ueAggMaxBitRate = decode_ngap_UEAggregateMaximumBitRate(&ie->value.choice.UEAggregateMaximumBitRate); NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_PDUSessionResourceSetupRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListSUReq, true); @@ -999,12 +939,8 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3 msg->pdusession_setup_params[i].pdusession_id = item_p->pDUSessionID; // S-NSSAI - OCTET_STRING_TO_INT8(&item_p->s_NSSAI.sST, msg->pdusession_setup_params[i].nssai.sst); - if (item_p->s_NSSAI.sD != NULL) { - BUFFER_TO_INT24((uint8_t *)item_p->s_NSSAI.sD->buf, msg->pdusession_setup_params[i].nssai.sd); - } else { - msg->pdusession_setup_params[i].nssai.sd = 0xffffff; - } + msg->pdusession_setup_params[i].nssai = decode_ngap_nssai(&item_p->s_NSSAI); + OCTET_STRING_t *transfer = &item_p->pDUSessionResourceSetupRequestTransfer; msg->pdusession_setup_params[i].nas_pdu = create_byte_array(item_p->pDUSessionNAS_PDU->size, item_p->pDUSessionNAS_PDU->buf); msg->pdusession_setup_params[i].pdusessionTransfer = create_byte_array(transfer->size, transfer->buf); From 5e2d7638d1e43cca1790c5e85bf87fe1863a506c Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 18:11:22 +0100 Subject: [PATCH 034/100] Move allocAddrCopy to NGAP utilities This function is needed also in upcoming NGAP libraries (i.e. N2 Handover) and therefore is moved to the NGAP utilities file. The function converts transport_layer_addr_t data struct to BIT_STRING_t by copying the content of its members. The naming is also updated to tnl_to_bitstring. --- openair3/NGAP/ngap_gNB_management_procedures.c | 12 ++++++++++++ openair3/NGAP/ngap_gNB_management_procedures.h | 3 +++ openair3/NGAP/ngap_gNB_nas_procedures.c | 14 ++------------ 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_management_procedures.c b/openair3/NGAP/ngap_gNB_management_procedures.c index e82fd1401b..6ffce99d9c 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.c +++ b/openair3/NGAP/ngap_gNB_management_procedures.c @@ -39,6 +39,8 @@ #include "queue.h" #include "tree.h" #include "ds/byte_array.h" +#include "BIT_STRING.h" +#include "common/utils/utils.h" static ngap_gNB_internal_data_t ngap_gNB_internal_data; @@ -188,3 +190,13 @@ void ngap_gNB_remove_amf_desc(ngap_gNB_instance_t * instance) free(amf); } } + +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in) +{ + if (in.length) { + out->buf = malloc_or_fail(in.length); + memcpy(out->buf, in.buffer, in.length); + out->size = in.length; + out->bits_unused = 0; + } +} diff --git a/openair3/NGAP/ngap_gNB_management_procedures.h b/openair3/NGAP/ngap_gNB_management_procedures.h index d71480da30..365fd0dd9d 100644 --- a/openair3/NGAP/ngap_gNB_management_procedures.h +++ b/openair3/NGAP/ngap_gNB_management_procedures.h @@ -29,6 +29,7 @@ */ #include "ds/byte_array.h" +#include "BIT_STRING.h" #ifndef NGAP_GNB_MANAGEMENT_PROCEDURES_H_ #define NGAP_GNB_MANAGEMENT_PROCEDURES_H_ @@ -47,4 +48,6 @@ uint16_t ngap_gNB_fetch_add_global_cnx_id(void); void ngap_gNB_prepare_internal_data(void); +void tnl_to_bitstring(BIT_STRING_t *out, const transport_layer_addr_t in); + #endif /* NGAP_GNB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7729ffa4f2..10ef36ec2a 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -58,16 +58,6 @@ #include "s1ap_messages_types.h" #include "xer_encoder.h" -static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in) -{ - if (in.length) { - out->buf = malloc(in.length); - memcpy(out->buf, in.buffer, in.length); - out->size = in.length; - out->bits_unused = 0; - } -} - /** @brief Selects the AMF instance for a given UE based on identity information. * It attempts to select an AMF using the following prioritized criteria: * 1. GUAMI, if provided and valid (via Region ID, Set ID, Pointer). @@ -621,7 +611,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(initial_ctxt_resp_p->pdusessions[i].gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, initial_ctxt_resp_p->pdusessions[i].gNB_addr); NGAP_DEBUG("initial_ctxt_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, @@ -936,7 +926,7 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.present = NGAP_UPTransportLayerInformation_PR_gTPTunnel; asn1cCalloc(pdusessionTransfer.dLQosFlowPerTNLInformation.uPTransportLayerInformation.choice.gTPTunnel, tmp); GTP_TEID_TO_ASN1(pdusession->gtp_teid, &tmp->gTP_TEID); - allocAddrCopy(&tmp->transportLayerAddress, pdusession->gNB_addr); + tnl_to_bitstring(&tmp->transportLayerAddress, pdusession->gNB_addr); NGAP_DEBUG("pdusession_setup_resp_p: pdusession ID %ld, gnb_addr %d.%d.%d.%d, SIZE %ld, TEID %u\n", item->pDUSessionID, tmp->transportLayerAddress.buf[0], From eb2facfa7613afa6c58764fb11bf28c04902033e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 May 2025 10:45:08 +0200 Subject: [PATCH 035/100] Add macro to iterate over seq_arr_t --- common/utils/ds/seq_arr.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/utils/ds/seq_arr.h b/common/utils/ds/seq_arr.h index 2fd049fa34..cb771405c5 100644 --- a/common/utils/ds/seq_arr.h +++ b/common/utils/ds/seq_arr.h @@ -34,6 +34,9 @@ SOFTWARE. #include #include +#define FOR_EACH_SEQ_ARR(type, var, arr) \ + for (type var = seq_arr_front(arr); var != seq_arr_end(arr); var = seq_arr_next(arr, var)) + typedef struct seq_arr_s { uint8_t* data; size_t size; From c1c4c65a936aa5fd09f935b50112ee0c107d77b5 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Mon, 19 May 2025 22:01:46 +0200 Subject: [PATCH 036/100] Unify setting default parameters in config libraries Add common function config_common_getdefault --- common/config/config_common.c | 60 +++++++++++++++++++ common/config/config_common.h | 1 + common/config/libconfig/config_libconfig.c | 14 ++--- common/config/yaml/config_yaml.cpp | 70 +--------------------- 4 files changed, 70 insertions(+), 75 deletions(-) diff --git a/common/config/config_common.c b/common/config/config_common.c index 2bca71d912..c617c426d7 100644 --- a/common/config/config_common.c +++ b/common/config/config_common.c @@ -308,3 +308,63 @@ void config_assign_int(configmodule_interface_t *cfg, paramdef_t *cfgoptions, ch break; } } + +/** + * @brief Assigns the default value to a configuration parameter if available. + * + * This function checks the type of the parameter and assigns its default value + * if it is defined. It handles various parameter types, including strings, integers, + * arrays, doubles, IPv4 addresses, and lists. If the parameter is marked with + * PARAMFLAG_DONOTREAD, it is ignored. + * + * @param[in] cfg Pointer to the configuration module interface. + * @param[in] cfgoption Pointer to the parameter definition structure. + * @param[in] prefix Optional prefix for the parameter name (can be NULL). + * @return 1 if the default value was set, 0 if ignored, or -1 on error/unsupported type. + */ +int config_common_getdefault(configmodule_interface_t *cfg, paramdef_t *cfgoption, char *prefix) +{ + if( (cfgoption->paramflags & PARAMFLAG_DONOTREAD) != 0) { + return 0; + } + + switch(cfgoption->type) { + case TYPE_STRING: + return config_setdefault_string(cfg, cfgoption, prefix); + + case TYPE_STRINGLIST: + return config_setdefault_stringlist(cfg, cfgoption, prefix); + + case TYPE_UINT8: + case TYPE_INT8: + case TYPE_UINT16: + case TYPE_INT16: + case TYPE_UINT32: + case TYPE_INT32: + case TYPE_MASK: + return config_setdefault_int(cfg, cfgoption, prefix); + + case TYPE_UINT64: + case TYPE_INT64: + return config_setdefault_int64(cfg, cfgoption, prefix); + + case TYPE_UINTARRAY: + case TYPE_INTARRAY: + return config_setdefault_intlist(cfg, cfgoption, prefix); + + case TYPE_DOUBLE: + return config_setdefault_double(cfg, cfgoption, prefix); + + case TYPE_IPV4ADDR: + return config_setdefault_ipv4addr(cfg, cfgoption, prefix); + + case TYPE_LIST: + // No default value for list type + fprintf(stderr,"[CONFIG] %s.%s TYPE_LIST has no default value\n", prefix, cfgoption->optname); + return -1; + + default: + fprintf(stderr,"[CONFIG] %s.%s type %i not supported\n", prefix, cfgoption->optname, cfgoption->type); + return -1; + } /* switch on param type */ +} diff --git a/common/config/config_common.h b/common/config/config_common.h index 8e595e4556..00211c9519 100644 --- a/common/config/config_common.h +++ b/common/config/config_common.h @@ -50,6 +50,7 @@ int config_setdefault_double(configmodule_interface_t *cfg, paramdef_t *cfgoptio int config_setdefault_ipv4addr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, char *prefix); void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree); void config_assign_int(configmodule_interface_t *cfg, paramdef_t *cfgoptions, char *fullname, int val); +int config_common_getdefault(configmodule_interface_t *cfg, paramdef_t *cfgoption, char *prefix); #ifdef __cplusplus } diff --git a/common/config/libconfig/config_libconfig.c b/common/config/libconfig/config_libconfig.c index 0934024391..0770fb2af8 100644 --- a/common/config/libconfig/config_libconfig.c +++ b/common/config/libconfig/config_libconfig.c @@ -356,7 +356,7 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, snprintf( *cfgoptions[i].strptr , cfgoptions[i].numelt, "%s", str); printf_params(cfg, "[LIBCONFIG] %s: \"%s\"\n", cfgpath, *cfgoptions[i].strptr); } else { - defval = config_setdefault_string(cfg, &cfgoptions[i], prefix); + defval = config_common_getdefault(cfg, &cfgoptions[i], prefix); } break; @@ -367,7 +367,7 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, if ( setting != NULL) { read_strlist(cfg, &cfgoptions[i], setting, cfgpath); } else { - defval = config_setdefault_stringlist(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } break; @@ -383,7 +383,7 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, config_check_valptr(cfg, &(cfgoptions[i]), sizeof(*cfgoptions[i].iptr), 1); config_assign_int(cfg, &(cfgoptions[i]), cfgpath, u); } else { - defval = config_setdefault_int(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } break; @@ -401,7 +401,7 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, printf_params(cfg, "[LIBCONFIG] %s: %ld\n", cfgpath, *cfgoptions[i].i64ptr); } } else { - defval = config_setdefault_int64(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } break; @@ -413,7 +413,7 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, if ( setting != NULL) { read_intarray(cfg, &cfgoptions[i], setting, cfgpath); } else { - defval = config_setdefault_intlist(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } break; @@ -424,14 +424,14 @@ int config_libconfig_get(configmodule_interface_t *cfg, paramdef_t *cfgoptions, *cfgoptions[i].dblptr = dbl; printf_params(cfg, "[LIBCONFIG] %s: %lf\n", cfgpath, *(cfgoptions[i].dblptr)); } else { - defval = config_setdefault_double(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } break; case TYPE_IPV4ADDR: if ( !config_lookup_string(&(libconfig_privdata.cfg),cfgpath, (const char **)&str)) { - defval = config_setdefault_ipv4addr(cfg, &(cfgoptions[i]), prefix); + defval = config_common_getdefault(cfg, &(cfgoptions[i]), prefix); } else { int rst = config_assign_ipv4addr(cfg, cfgoptions, str); diff --git a/common/config/yaml/config_yaml.cpp b/common/config/yaml/config_yaml.cpp index 138163ce0e..0da2d4bf56 100644 --- a/common/config/yaml/config_yaml.cpp +++ b/common/config/yaml/config_yaml.cpp @@ -25,8 +25,7 @@ extern "C" { #include "common/config/config_userapi.h" void *config_allocate_new(configmodule_interface_t *cfg, int sz, bool autoFree); void config_check_valptr(configmodule_interface_t *cfg, paramdef_t *cfgoptions, int elt_sz, int nb_elt); -#include "../config_userapi.h" -#include "../config_common.h" +int config_common_getdefault(configmodule_interface_t *cfg, paramdef_t *cfgoption, char *prefix); } #include #include @@ -44,71 +43,6 @@ class YamlConfig { } }; -void SetDefault(configmodule_interface_t *cfg, paramdef_t *param) -{ - switch (param->type) { - case TYPE_INT: - *param->iptr = param->defintval; - break; - case TYPE_UINT: - *param->uptr = param->defuintval; - break; - case TYPE_STRING: - if (param->defstrval != nullptr) { - if (param->numelt == 0) { - config_check_valptr(cfg, param, 1, strlen(param->defstrval) + 1); - } - sprintf(*param->strptr, "%s", param->defstrval); - } - break; - case TYPE_INT8: - *param->i8ptr = param->defintval; - break; - case TYPE_UINT8: - *param->u8ptr = param->defuintval; - break; - case TYPE_INT16: - *param->i16ptr = param->defintval; - break; - case TYPE_UINT16: - *param->u16ptr = param->defuintval; - break; - case TYPE_INT64: - *param->i64ptr = param->defint64val; - break; - case TYPE_UINT64: - *param->u64ptr = param->defint64val; - break; - case TYPE_DOUBLE: - *param->dblptr = param->defdblval; - break; - case TYPE_MASK: - *param->uptr = param->defuintval; - break; - case TYPE_STRINGLIST: - if (param->defstrlistval != nullptr) { - param->strlistptr = param->defstrlistval; - } - break; - case TYPE_INTARRAY: - if (param->defintarrayval) { - param->iptr = param->defintarrayval; - } - break; - case TYPE_UINTARRAY: - if (param->defintarrayval) { - param->uptr = (uint32_t *)param->defintarrayval; - } - break; - case TYPE_IPV4ADDR: - config_setdefault_ipv4addr(cfg, param, param->defstrval); - break; - default: - AssertFatal(false, "Unhandled type %d", param->type); - } - param->paramflags |= PARAMFLAG_PARAMSETDEF; -} - void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *param) { auto optname = std::string(param->optname); @@ -213,7 +147,7 @@ void GetParams(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t if (node && node[std::string(params[i].optname)]) { SetNonDefault(cfg, node, ¶ms[i]); } else { - SetDefault(cfg, ¶ms[i]); + config_common_getdefault(cfg, ¶ms[i], nullptr); } } } From 5cb1113674c51128b8bc822ebb2731178b9ed044 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Tue, 3 Jun 2025 08:54:45 +0200 Subject: [PATCH 037/100] Handle YAML Exceptions --- common/config/yaml/config_yaml.cpp | 54 ++++++++++++++----- common/config/yaml/tests/CMakeLists.txt | 2 + common/config/yaml/tests/malformed.yaml | 13 +++++ .../yaml/tests/test_read_str_as_int.yaml | 2 + common/config/yaml/tests/test_yaml_config.cpp | 42 ++++++++++++++- 5 files changed, 97 insertions(+), 16 deletions(-) create mode 100644 common/config/yaml/tests/malformed.yaml create mode 100644 common/config/yaml/tests/test_read_str_as_int.yaml diff --git a/common/config/yaml/config_yaml.cpp b/common/config/yaml/config_yaml.cpp index 0da2d4bf56..0b9139c407 100644 --- a/common/config/yaml/config_yaml.cpp +++ b/common/config/yaml/config_yaml.cpp @@ -141,14 +141,12 @@ void SetNonDefault(configmodule_interface_t *cfg, const YAML::Node &node, paramd param->paramflags |= PARAMFLAG_PARAMSET; } -void GetParams(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *params, int num_params) +void GetParam(configmodule_interface_t *cfg, const YAML::Node &node, paramdef_t *param) { - for (auto i = 0; i < num_params; i++) { - if (node && node[std::string(params[i].optname)]) { - SetNonDefault(cfg, node, ¶ms[i]); - } else { - config_common_getdefault(cfg, ¶ms[i], nullptr); - } + if (node && node[std::string(param->optname)]) { + SetNonDefault(cfg, node, param); + } else { + config_common_getdefault(cfg, param, nullptr); } } @@ -163,7 +161,15 @@ extern "C" int config_yaml_init(configmodule_interface_t *cfg) pthread_mutex_init(&cfg->memBlocks_mutex, NULL); memset(cfg->oneBlock, 0, sizeof(cfg->oneBlock)); - config_yaml::config = new config_yaml::YamlConfig(std::string(cfgP[0])); + try { + config_yaml::config = new config_yaml::YamlConfig(std::string(cfgP[0])); + } catch (const YAML::BadFile &e) { + fprintf(stderr, "[CONFIG] Error loading YAML file '%s': %s\n", cfgP[0], e.what()); + return -1; + } catch (const YAML::Exception &e) { + fprintf(stderr, "[CONFIG] Error parsing YAML file '%s': %s\n", cfgP[0], e.what()); + return -1; + } return 0; } @@ -183,14 +189,14 @@ YAML::Node find_node(const std::string &prefix, YAML::Node node) if (key.at(0) == '[' && key.back() == ']') { // The key is an index to a sequence if (!current.IsSequence()) { - throw std::invalid_argument("Incorrect yaml file structure"); + throw std::invalid_argument("Expected a sequence at " + key); } int index = std::stoi(key.substr(1, key.size() - 2)); current = current[index]; continue; } if (!current.IsMap()) { - throw std::invalid_argument("Incorrect yaml file structure"); + throw std::invalid_argument("Expected a map at " + key); } if (!current[key]) { return config_yaml::invalid_node; @@ -206,8 +212,14 @@ extern "C" int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgopt if (prefix != nullptr) { p = std::string(prefix); } - auto node = find_node(p, YAML::Clone(config_yaml::config->config)); - if (node == config_yaml::invalid_node) { + YAML::Node node; + try { + node = find_node(p, YAML::Clone(config_yaml::config->config)); + if (node == config_yaml::invalid_node) { + return -1; + } + } catch (const std::invalid_argument &e) { + fprintf(stderr, "[CONFIG] Error finding node '%s': %s\n", p.c_str(), e.what()); return -1; } for (auto i = 0; i < numoptions; i++) { @@ -216,7 +228,14 @@ extern "C" int config_yaml_get(configmodule_interface_t *cfg, paramdef_t *cfgopt config_check_valptr(cfg, &cfgoptions[i], sizeof(void *), 1); } } - config_yaml::GetParams(cfg, node, cfgoptions, numoptions); + for (int i = 0; i < numoptions; i++) { + try { + config_yaml::GetParam(cfg, node, &cfgoptions[i]); + } catch (const YAML::Exception &e) { + fprintf(stderr, "[CONFIG] Config error: prefix: %s, setting: %s, error: %s\n", p.c_str(), cfgoptions[i].optname, e.what()); + return -1; + } + } return numoptions; } @@ -257,7 +276,14 @@ extern "C" int config_yaml_getlist(configmodule_interface_t *cfg, } } - config_yaml::GetParams(cfg, node[i], ParamList->paramarray[i], numparams); + for (int j = 0; j < numparams; j++) { + try { + config_yaml::GetParam(cfg, node[i], &ParamList->paramarray[i][j]); + } catch (const YAML::Exception &e) { + fprintf(stderr, "[CONFIG] Config error: prefix: %s, setting: %s, error: %s\n", path, ParamList->paramarray[i][j].optname, e.what()); + return -1; + } + } } } diff --git a/common/config/yaml/tests/CMakeLists.txt b/common/config/yaml/tests/CMakeLists.txt index d33fa57658..e3f1002d79 100644 --- a/common/config/yaml/tests/CMakeLists.txt +++ b/common/config/yaml/tests/CMakeLists.txt @@ -11,3 +11,5 @@ configure_file(test_list_of_mappings.yml test_list_of_mappings.yml COPYONLY) configure_file(test_int_array.yaml test_int_array.yaml COPYONLY) configure_file(test_read_mapping_as_list.yaml test_read_mapping_as_list.yaml COPYONLY) configure_file(test_ipv4.yaml test_ipv4.yaml COPYONLY) +configure_file(test_read_str_as_int.yaml test_read_str_as_int.yaml COPYONLY) +configure_file(malformed.yaml malformed.yaml COPYONLY) diff --git a/common/config/yaml/tests/malformed.yaml b/common/config/yaml/tests/malformed.yaml new file mode 100644 index 0000000000..c7f5fff55b --- /dev/null +++ b/common/config/yaml/tests/malformed.yaml @@ -0,0 +1,13 @@ +test: + - +bad_file: + - "testvalue1" + - "testvalue2" + - "testvalue3" + - "testvalue4" + - "testvalue5" + - "testvalue6" + - "testvalue7" + - "testvalue8" + - "testvalue9" + - "testvalue10" - yaml error diff --git a/common/config/yaml/tests/test_read_str_as_int.yaml b/common/config/yaml/tests/test_read_str_as_int.yaml new file mode 100644 index 0000000000..a055e855d5 --- /dev/null +++ b/common/config/yaml/tests/test_read_str_as_int.yaml @@ -0,0 +1,2 @@ +test: + var: "test_var" diff --git a/common/config/yaml/tests/test_yaml_config.cpp b/common/config/yaml/tests/test_yaml_config.cpp index 384a1f406c..814e3a3635 100644 --- a/common/config/yaml/tests/test_yaml_config.cpp +++ b/common/config/yaml/tests/test_yaml_config.cpp @@ -78,8 +78,9 @@ TEST(yaml_config, yaml_get_existing_values) { uint16_t value; p.type = TYPE_UINT16; p.u16ptr = &value; + p.paramflags = PARAMFLAG_MANDATORY; char prefix[] = "test"; - config_yaml_get(cfg, &p, 1, prefix); + EXPECT_EQ(config_yaml_get(cfg, &p, 1, prefix), 1); EXPECT_EQ(value, i); } @@ -94,7 +95,7 @@ TEST(yaml_config, yaml_get_non_existing_values) { cfg->cfgP[0] = strdup("test1.yaml"); EXPECT_EQ(config_yaml_init(cfg), 0); - // Testing paremters present in the test node + // Testing parameters not present in the test node paramdef_t p = {0}; for (auto i = 4; i <= 5; i++) { sprintf(p.optname, "%s%d", "value", i); @@ -421,6 +422,43 @@ TEST(yaml_config, test_read_ipv4) { free(p.defstrval); } +TEST(yaml_config, yaml_read_str_as_int) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("test_read_str_as_int.yaml"); + EXPECT_EQ(config_yaml_init(cfg), 0); + + // Testing paremters present in the test node + paramdef_t p = {0}; + uint16_t value; + p.type = TYPE_UINT16; + p.u16ptr = &value; + p.paramflags = PARAMFLAG_MANDATORY; + char prefix[] = "test"; + sprintf(p.optname, "%s", "var"); + EXPECT_EQ(config_yaml_get(cfg, &p, 1, prefix), -1); + + + config_yaml_end(cfg); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, yaml_open_non_existing_file) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("non_existing_file.yaml"); + EXPECT_EQ(config_yaml_init(cfg), -1); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + +TEST(yaml_config, malformed_file) { + configmodule_interface_t *cfg = static_cast(calloc(1, sizeof(*cfg))); + cfg->cfgP[0] = strdup("malformed.yaml"); + EXPECT_EQ(config_yaml_init(cfg), -1); + free(cfg->cfgP[0]); + end_configmodule(cfg); +} + int main(int argc, char** argv) { logInit(); From c5f5ab2820e09ee493674d9d486ad80b6d52d7f2 Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 5 Jun 2025 14:58:37 +0200 Subject: [PATCH 038/100] CI: set NR RLC and NR PDCP parameters in the conf file Default values used. --- .../conf_files/gnb-cucp.sa.f1.quectel.conf | 8 ++++++ .../gnb-du.sa.band78.106prb.usrpb200.conf | 25 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf index 99a530ca39..8cebc8640a 100644 --- a/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf +++ b/ci-scripts/conf_files/gnb-cucp.sa.f1.quectel.conf @@ -58,6 +58,14 @@ gNBs = } ); +pdcp = { + drb = { + sn_size = "len18bits" + t_reordering = "ms100" + discard_timer = "infinity" + } +} + security = { # preferred ciphering algorithms # the first one of the list that an UE supports in chosen diff --git a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf index 3626cec227..45482642b9 100644 --- a/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf +++ b/ci-scripts/conf_files/gnb-du.sa.band78.106prb.usrpb200.conf @@ -163,6 +163,31 @@ gNBs = } ); +rlc = { + srb = { + t_poll_retransmit = "ms45" + t_reassembly = "ms25" + t_status_prohibit = "ms0" + poll_pdu = "infinity" + poll_byte = "infinity" + max_retx_threshold = "t8" + sn_field_length = "size12" + } + drb_am = { + t_poll_retransmit = "ms45" + t_reassembly = "ms15" + t_status_prohibit = "ms15" + poll_pdu = "p64" + poll_byte = "kB500" + max_retx_threshold = "t32" + sn_field_length = "size18" + } + drb_um = { + t_reassembly = "ms15" + sn_field_length = "size12" + } +} + MACRLCs = ( { num_cc = 1; From b7f00aa24041bf9185eb40a5b3e621df6f684e9e Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 07:53:49 +0200 Subject: [PATCH 039/100] SCTP: Provide more info on getaddrinfo() fail Upon failure, the error message was saying that something failed (i.e., the reason), but not parameters of the getaddrinfo(). Simplify root cause analysis by providing the parameters for the attempted getaddrinfo() call. --- openair3/SCTP/sctp_eNB_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index 6b83a7df6d..82afa451c0 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -464,7 +464,7 @@ static void sctp_handle_new_association_req(const instance_t instance, char port[12]; snprintf(port, sizeof(port), "%d", req->port); int status = getaddrinfo(remote, port, &hints, &serv); - AssertFatal(status == 0, "getaddrinfo() failed: %s\n", gai_strerror(status)); + AssertFatal(status == 0, "getaddrinfo(node %s service %s) failed: %s\n", remote, port, gai_strerror(status)); struct addrinfo *p = NULL; for (p = serv; p != NULL; p = p->ai_next) { From 302020028829e864740967a6b2824d459e2f841b Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 27 May 2025 16:07:48 +0200 Subject: [PATCH 040/100] in case of DCIX0 38.214 tells us to assume it is always type1 allocation --- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 6 ++---- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 4086588660..3303bb7362 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -399,8 +399,7 @@ static bwp_info_t get_pdsch_bwp_start_size(gNB_MAC_INST *nr_mac, NR_UE_info_t *U // 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. if (dl_bwp->dci_format == NR_DL_DCI_FORMAT_1_0 && sched_ctrl->search_space->searchSpaceType - && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common - && dl_bwp->pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1) { + && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { if (sched_ctrl->coreset->controlResourceSetId == 0) { bwp_info.bwpStart = nr_mac->cset0_bwp_start; } else { @@ -1183,8 +1182,7 @@ void nr_schedule_ue_spec(module_id_t module_id, // 3GPP TS 38.214 Section 5.1.2.2.2 Downlink resource allocation type 1 uint16_t riv_bwp_size = pdsch_pdu->BWPSize; if (current_BWP->dci_format == NR_DL_DCI_FORMAT_1_0 - && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common - && pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType1) { + && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { if (gNB_mac->cset0_bwp_size > 0) { riv_bwp_size = gNB_mac->cset0_bwp_size; } else { diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 35c817b975..3626599fe5 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -78,8 +78,7 @@ static bwp_info_t get_pusch_bwp_start_size(NR_UE_info_t *UE) // case when DCI format 0_0 is decoded in any common search space in which case the size of the initial UL bandwidth part shall // be used. if (ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_0 && sched_ctrl->search_space->searchSpaceType - && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common - && ul_bwp->pusch_Config->resourceAllocation == NR_PUSCH_Config__resourceAllocation_resourceAllocationType1) { + && sched_ctrl->search_space->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_common) { bwp_info.bwpSize = min(ul_bwp->BWPSize, UE->sc_info.initial_ul_BWPSize); } else { bwp_info.bwpSize = ul_bwp->BWPSize; From e6aeb47ea8c294e5a4986a0eef304f8b0bcb5e74 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 27 May 2025 16:08:19 +0200 Subject: [PATCH 041/100] correct order for releasing spCellConfig --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 28c129cb58..99a8439dc9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -960,10 +960,6 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) NR_UE_info_t *oldUE = find_nr_UE(&mac->UE_info, *dl_rrc->old_gNB_DU_ue_id); AssertFatal(oldUE, "CU claims we should know UE %04x, but we don't\n", *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_lock(&mac->sched_lock); - /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it - * from the current configuration. Also, expect the reconfiguration from - * the CU, so save the old UE's CellGroup for the new UE */ - UE->CellGroup->spCellConfig = NULL; uid_t temp_uid = UE->uid; UE->uid = oldUE->uid; oldUE->uid = temp_uid; @@ -975,6 +971,11 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) UE->CellGroup = oldUE->CellGroup; oldUE->CellGroup = NULL; UE->mac_stats = oldUE->mac_stats; + /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it + * from the current configuration. Also, expect the reconfiguration from + * the CU, so save the old UE's CellGroup for the new UE */ + ASN_STRUCT_FREE(asn_DEF_NR_SpCellConfig, UE->CellGroup->spCellConfig); + UE->CellGroup->spCellConfig = NULL; mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); From 842ab32c91a530bc4e5d8f82ab2d3cb196a067f5 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 08:14:12 +0200 Subject: [PATCH 042/100] ITTI: remove useless log_scheduler() function The primary motivation here is to remove a VLA, as in the parent commits. Closer inspection revealed that (1) it is only used by the LTE UE, and (2) it only logs some data which we likely don't need. So I simply removed this function. --- common/utils/ocp_itti/intertask_interface.cpp | 36 ------------------- common/utils/ocp_itti/intertask_interface.h | 1 - executables/lte-ue.c | 2 -- 3 files changed, 39 deletions(-) diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp index faf510712b..8ad5f63a50 100644 --- a/common/utils/ocp_itti/intertask_interface.cpp +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -475,41 +475,5 @@ typedef struct timer_elm_s { return 0; } -void log_scheduler(const char* label) -{ - int policy = sched_getscheduler(0); - struct sched_param param; - if (sched_getparam(0, ¶m) == -1) - { - LOG_E(HW, "sched_getparam: %s\n", strerror(errno)); - abort(); - } - - cpu_set_t cpu_set; - if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) == -1) - { - LOG_E(HW, "sched_getaffinity: %s\n", strerror(errno)); - abort(); - } - int num_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if (num_cpus < 1) - { - LOG_E(HW, "sysconf(_SC_NPROCESSORS_ONLN): %s\n", strerror(errno)); - abort(); - } - char buffer[num_cpus]; - for (int i = 0; i < num_cpus; i++) - { - buffer[i] = CPU_ISSET(i, &cpu_set) ? 'Y' : '-'; - } - - LOG_A(HW, "Scheduler policy=%d priority=%d affinity=[%d]%.*s label=%s\n", - policy, - param.sched_priority, - num_cpus, - num_cpus, - buffer, - label); -} } // extern "C" diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h index 2f2ad54174..84dbd15365 100644 --- a/common/utils/ocp_itti/intertask_interface.h +++ b/common/utils/ocp_itti/intertask_interface.h @@ -566,7 +566,6 @@ int timer_remove(long timer_id); int signal_handle(int *end); int signal_mask(void); -void log_scheduler(const char *label); #ifdef __cplusplus } #endif diff --git a/executables/lte-ue.c b/executables/lte-ue.c index e941690f26..2d7338c410 100644 --- a/executables/lte-ue.c +++ b/executables/lte-ue.c @@ -1740,8 +1740,6 @@ void *UE_thread(void *arg) { oai_exit=1; } - log_scheduler(__func__); - while (!oai_exit) { AssertFatal ( 0== pthread_mutex_lock(&UE->proc.mutex_synch), ""); int instance_cnt_synch = UE->proc.instance_cnt_synch; From 26b3b16aa51fe1c1e36f1f1c4543eb88dad6ffcd Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 23 May 2025 10:28:30 +0200 Subject: [PATCH 043/100] Move the OSC nearRT-RIC tutorial in OAI E2 agent from FlexRIC --- openair2/E2AP/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index 7866467397..43a39f5afd 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -246,3 +246,17 @@ Additionally, all the data received in the `xapp_gtp_mac_rlc_pdcp_moni` xApp is Please note: * KPM SM database is not been updated, therefore commented in `flexric/src/xApp/db/sqlite3/sqlite3_wrapper.c:1152` * RC SM database is not yet implemented. + +# 5. O-RAN SC nearRT-RIC interoperability + +The E2AP port for OSC nearRT-RIC is 36422, but the default value in E2 agent is 36421. Before proceeding with integration, please set the `e2ap_server_port` to 36422, and recompile the OAI. + +## 5.1 H release +We showcased the QoE use case during the O-RAN F2F meeting Phoenix, October 2023: +* [recorded presentation](https://zoom.us/rec/play/N5mnAQUcEVRf8HN6qLYa4k7kjNq3bK4hQiYqHGv9KUoLfcR6GHiE-GvnmAudT6xccmZSbkxxYHRwTaxk.Zi7d8Sl1kQ6Sk1SH?canPlayFromShare=true&from=share_recording_detail&continueMode=true&componentName=rec-play&originRequestUrl=https%3A%2F%2Fzoom.us%2Frec%2Fshare%2FwiYXulPlAqIIDY_vLPQSGqYIj-e5Ef_UCxveMjrDNGgXLLvEcDF4v1cmVBe8imb4.WPi-DA_dfPDBQ0FH). This use case is shown after 4 minutes (04:00). +* [accompanying flyer](https://openairinterface.org/wp-content/uploads/2023/10/demo2-phoenix.pdf) + +The same was shown in the following events: +* [Joint OSC/OSFG-OAI Workshop](https://openairinterface.org/joint-osc-oai-workshop-end-to-end-open-source-reference-designs-for-o-ran/) + +In order to reproduce this testbed, please follow the [O-RAN SC nearRT-RIC installation guide](https://lf-o-ran-sc.atlassian.net/wiki/spaces/GS/overview), and the [kpm-rc-xapp](https://github.com/mirazabal/kpm_rc-xapp) xApp used. Please note that we cannot give support for the O-RAN SC nearRT-RIC. From 8a544b9fbb64e65f549ea5958d68d5cbddca67f3 Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 6 Dec 2024 17:16:15 +0100 Subject: [PATCH 044/100] simpler RU beam management by storing RU beam index at L1 instead of FAPI beam index --- openair1/PHY/NR_TRANSPORT/nr_dci.c | 1 + openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 1 + openair1/PHY/NR_TRANSPORT/nr_prach.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 7 ++++++- openair1/PHY/NR_TRANSPORT/srs_rx.c | 7 ++++++- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 16 ++++++++++++---- openair1/SCHED_NR/sched_nr.h | 7 ++++++- 8 files changed, 44 insertions(+), 9 deletions(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 6cca7fcfcc..899432c37a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -82,6 +82,7 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + &gNB->gNB_config.dbt_config, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 6e68a459c9..ee93f78e45 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -681,6 +681,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &gNB->gNB_config.dbt_config, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 9094064fde..a5e6c86e86 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -85,7 +85,12 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p // TODO no idea how to compute final prach symbol here so for now we go til the end of the slot int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); - prach->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + prach->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 982b236b70..84656ba1d0 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -76,7 +76,12 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t if (gNB->common_vars.beam_id) { int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); - ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } ulsch->frame = frame; ulsch->slot = slot; diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index a66812b39e..c7dacd7104 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -73,7 +73,12 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, if (gNB->common_vars.beam_id) { int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); - pucch->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + pucch->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } memcpy((void *)&pucch->pucch_pdu, (void *)pucch_pdu, sizeof(nfapi_nr_pucch_pdu_t)); LOG_D(PHY, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 8ece090cc5..642095345d 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -59,7 +59,12 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu if (gNB->common_vars.beam_id) { int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(fapi_beam_idx, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, bitmap); + srs->beam_nb = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.dbt_config, + &gNB->common_vars, + slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); } memcpy((void *)&srs->srs_pdu, (void *)srs_pdu, sizeof(nfapi_nr_srs_pdu_t)); break; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 095c41d0da..19fdd4dca8 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,18 +45,24 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG -int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols) +int beam_index_allocation(int fapi_beam_index, + nfapi_nr_dbt_pdu_t *dbt_config, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols) { if (!common_vars->beam_id) return 0; int idx = -1; + int ru_beam_idx = dbt_config->dig_beam_list[fapi_beam_index].txru_list[0].dig_beam_weight_Re; for (int j = 0; j < common_vars->num_beams_period; j++) { for (int i = 0; i < symbols_per_slot; i++) { if (((bitmap_symbols >> i) & 0x01) == 0) continue; int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i]; - if (current_beam == -1 || current_beam == fapi_beam_index) + if (current_beam == -1 || current_beam == ru_beam_idx) idx = j; else { idx = -1; @@ -66,10 +72,10 @@ int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int s if (idx != -1) break; } - AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", fapi_beam_index); + AssertFatal(idx >= 0, "Couldn't allocate beam ID %d\n", ru_beam_idx); for (int j = 0; j < symbols_per_slot; j++) { if (((bitmap_symbols >> j) & 0x01)) - common_vars->beam_id[idx][slot * symbols_per_slot + j] = fapi_beam_index; + common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx; } LOG_D(PHY, "Allocating beam %d in slot %d\n", idx, slot); return idx; @@ -132,6 +138,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &cfg->dbt_config, &gNB->common_vars, slot, fp->symbols_per_slot, @@ -273,6 +280,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + &cfg->dbt_config, &gNB->common_vars, slot, fp->symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 9f65819960..72d2d96b4c 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -47,5 +47,10 @@ void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); -int beam_index_allocation(int fapi_beam_index, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, int bitmap_symbols); +int beam_index_allocation(int fapi_beam_index, + nfapi_nr_dbt_pdu_t *dbt_config, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols); #endif From 1d2fb5af9dfe9cbade5314014a80b0bc71462930 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 22:49:16 +0200 Subject: [PATCH 045/100] Fix FC value definition for NH (A.10 3GPP TS 33.501) --- openair3/SECU/key_nas_deriver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 20aba64e1e..1011eeb357 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -41,7 +41,7 @@ #include #define FC_KENB (0x11) -#define FC_NH (0x12) +#define FC_NH (0x6F) // A.10 3GPP TS 33.501 #define FC_KENB_STAR (0x13) /* 33401 #A.7 Algorithm for key derivation function. * This FC should be used for: From d06790fcf2ff7ec048b39071a6b04140cd55d99e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 29 Apr 2025 22:50:04 +0200 Subject: [PATCH 046/100] Move derive_kgnb to key_nas_deriver lib --- openair3/NAS/NR_UE/nr_nas_msg.c | 36 +-------------------------------- openair3/SECU/key_nas_deriver.c | 32 +++++++++++++++++++++++++++++ openair3/SECU/key_nas_deriver.h | 2 ++ 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d152a5d4a3..4c5d6fb717 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -71,6 +71,7 @@ #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" #include "ds/byte_array.h" +#include "key_nas_deriver.h" #define MAX_NAS_UE 4 @@ -444,41 +445,6 @@ void derive_knas(algorithm_type_dist_t nas_alg_type, uint8_t nas_alg_id, uint8_t memcpy(knas, out + 16, 16); } -static void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) -{ - /* Compute the KDF input parameter - * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 - */ - uint8_t input[32] = {0}; - // uint16_t length = 4; - // int offset = 0; - - LOG_TRACE(INFO, "%s with count= %d", __FUNCTION__, count); - memset(input, 0, 32); - input[0] = 0x6E; - // P0 - input[1] = count >> 24; - input[2] = (uint8_t)(count >> 16); - input[3] = (uint8_t)(count >> 8); - input[4] = (uint8_t)count; - // L0 - input[5] = 0; - input[6] = 4; - // P1 - input[7] = 0x01; - // L1 - input[8] = 0; - input[9] = 1; - - byte_array_t data = {.buf = input, .len = 10}; - kdf(kamf, data, 32, kgnb); - - printf("kgnb : "); - for (int pp = 0; pp < 32; pp++) - printf("%02x ", kgnb[pp]); - printf("\n"); -} - static void derive_ue_keys(uint8_t *buf, nr_ue_nas_t *nas) { uint8_t ak[6]; diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 1011eeb357..ec6da5e411 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -139,6 +139,38 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t * NOTE: knas is dynamically allocated by the KDF function */ +/** @brief KgNB derivation (A.9 3GPP TS 33.501) */ +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) +{ + /* Compute the KDF input parameter + * S = FC(0x6E) || UL NAS Count || 0x00 0x04 || 0x01 || 0x00 0x01 + */ + uint8_t input[32] = {0}; + + input[0] = 0x6E; + // P0 + input[1] = count >> 24; + input[2] = (uint8_t)(count >> 16); + input[3] = (uint8_t)(count >> 8); + input[4] = (uint8_t)count; + // L0 + input[5] = 0; + input[6] = 4; + // P1 + input[7] = 0x01; + // L1 + input[8] = 0; + input[9] = 1; + + byte_array_t data = {.buf = input, .len = 10}; + kdf(kamf, data, 32, kgnb); + + printf("kgnb : "); + for (int pp = 0; pp < 32; pp++) + printf("%02x ", kgnb[pp]); + printf("\n"); +} + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB) { uint8_t s[7] = {0}; diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 4e84c5f3be..99c5b20b51 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -14,6 +14,8 @@ typedef enum { UP_INT_ALG = 0x06 } algorithm_type_dist_t; +void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb); + void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB); void derive_keNB_star(const uint8_t *kenb_32, From bd1f266ab5426ff39b8b7ca6f5e9d5e119527511 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:26:26 +0200 Subject: [PATCH 047/100] Add utility to log hex buffer with size len (LOG_D) and remove unused legacy hex_dump * logging buffer is pretty useful for debugging purposes, e.g. derived key values --- common/utils/utils.c | 28 ------------------- common/utils/utils.h | 2 -- openair3/SECU/key_nas_deriver.c | 49 +++++++++++++++++++++------------ openair3/SECU/key_nas_deriver.h | 2 ++ 4 files changed, 33 insertions(+), 48 deletions(-) diff --git a/common/utils/utils.c b/common/utils/utils.c index 377c4512b7..33797b49df 100644 --- a/common/utils/utils.c +++ b/common/utils/utils.c @@ -7,34 +7,6 @@ #include #include "utils.h" - - -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len) -{ - char *p = out; - char *endp = out + out_len; - const uint8_t *q = data; - snprintf(p, endp - p, "[%zu]", data_len); - p += strlen(p); - for (size_t i = 0; i < data_len; ++i) - { - if (p >= endp) - { - static const char ellipses[] = "..."; - char *s = endp - sizeof(ellipses); - if (s >= p) - { - strcpy(s, ellipses); - } - break; - } - snprintf(p, endp - p, " %02X", *q++); - p += strlen(p); - } - return out; -} - - /**************************************************************************** ** ** ** Name: hex_char_to_hex_value() ** diff --git a/common/utils/utils.h b/common/utils/utils.h index 841cb2af9c..df188b812f 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -109,8 +109,6 @@ static inline void *malloc_or_fail(size_t size) #define PAGE_MASK 0xfffff000 #define virt_to_phys(x) (x) -const char *hexdump(const void *data, size_t data_len, char *out, size_t out_len); - // Converts an hexadecimal ASCII coded digit into its value. ** int hex_char_to_hex_value (char c); // Converts an hexadecimal ASCII coded string into its value.** diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index ec6da5e411..3c0b05dc50 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -57,14 +57,32 @@ #define NR_FC_ALG_KEY_DER (0x69) #define NR_FC_ALG_KEY_NG_RAN_STAR_DER (0x70) -// #define SECU_DEBUG 1 +static void log_hex_buffer(const char *label, const uint8_t *buf, const int len) +{ + char hex_str[len * 2 + 1]; + for (int i = 0; i < len; i++) { + snprintf(&hex_str[i * 2], 3, "%02x", buf[i]); + } + hex_str[len * 2] = '\0'; + LOG_D(UTIL, "%s: %s\n", label, hex_str); +} + +static const char* alg_type_to_str(algorithm_type_dist_t alg_type) +{ + switch (alg_type) { + case NAS_ENC_ALG: return "NAS_ENC_ALG"; + case NAS_INT_ALG: return "NAS_INT_ALG"; + case RRC_ENC_ALG: return "RRC_ENC_ALG"; + case RRC_INT_ALG: return "RRC_INT_ALG"; + case UP_ENC_ALG: return "UP_ENC_ALG"; + case UP_INT_ALG: return "UP_INT_ALG"; + default: return "UNKNOWN_ALG_TYPE"; + } +} static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t kasme[32], uint8_t FC, uint8_t out[32]) { uint8_t s[7]; -#if defined(SECU_DEBUG) - int i; -#endif /* FC */ s[0] = FC; @@ -83,18 +101,11 @@ static void derive_key_common(algorithm_type_dist_t alg_type, uint8_t alg_id, co s[5] = 0x00; s[6] = 0x01; -#if defined(SECU_DEBUG) - printf("%s FC %d nas_alg_type distinguisher %d nas_enc_alg_identity %d\n", __FUNCTION__, FC_ALG_KEY_DER, alg_type, alg_id); - - for (i = 0; i < 7; i ++) { - printf("0x%02x ", s[i]); - } - - printf("\n"); -#endif - byte_array_t data = {.len = 7, .buf = s}; kdf(kasme, data, 32, out); + log_hex_buffer("Input key (kgnb)", kasme, 32); + log_hex_buffer("Derivation string (s)", s, 7); + log_hex_buffer(alg_type_to_str(alg_type), out, 32); } /*! @@ -165,10 +176,9 @@ void derive_kgnb(uint8_t kamf[32], uint32_t count, uint8_t *kgnb) byte_array_t data = {.buf = input, .len = 10}; kdf(kamf, data, 32, kgnb); - printf("kgnb : "); - for (int pp = 0; pp < 32; pp++) - printf("%02x ", kgnb[pp]); - printf("\n"); + log_hex_buffer("KAMF", kamf, 32); + log_hex_buffer("KDF input for kgnb", input, 10); + log_hex_buffer("Derived kgnb", kgnb, 32); } void derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t *keNB) @@ -260,6 +270,9 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t byte_array_t data = {.buf = s, .len = 10}; const uint32_t len_key = 32; kdf(key, data, len_key, key_ng_ran_star); + log_hex_buffer("Input key", key, 32); + log_hex_buffer("KDF input for ng_ran*", s, 10); + log_hex_buffer("Derived key_ng_ran*", key_ng_ran_star, 32); } void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB) diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 99c5b20b51..4cb336bce9 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -5,6 +5,8 @@ #include #include +#define SECURITY_KEY_LEN 32 + typedef enum { NAS_ENC_ALG = 0x01, NAS_INT_ALG = 0x02, From 70eb09dc099a13f60d9980a122ecb01730ce5c70 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:28:45 +0200 Subject: [PATCH 048/100] Add NH derivation function (A.10 3GPP TS 33.501) --- openair3/SECU/key_nas_deriver.c | 24 ++++++++++++++++++++++++ openair3/SECU/key_nas_deriver.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 3c0b05dc50..a7cf27a1ff 100644 --- a/openair3/SECU/key_nas_deriver.c +++ b/openair3/SECU/key_nas_deriver.c @@ -293,3 +293,27 @@ void derive_skgNB(const uint8_t *keNB, const uint16_t sk_counter, uint8_t *skgNB byte_array_t data = {.buf = s, .len = 5}; kdf(keNB, data, 32, skgNB); } + +/** @brief NH derivation function (A.10 3GPP TS 33.501) + * @param k_amf: input key + * @param sync_input: pointer to the newly derived KgNB for the initial NH derivation, + * and the previous NH for all subsequent derivations + * @param nh: pointer to the derivated NH output */ +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh) +{ + uint8_t s[SECURITY_KEY_LEN + 3] = {0}; + // FC + s[0] = FC_NH; + // P0 = SYNC-input + memcpy(&s[1], sync_input, SECURITY_KEY_LEN); + // L0 = length of SYNC-input (i.e. 0x00 0x20) + s[SECURITY_KEY_LEN + 1] = 0x00; + s[SECURITY_KEY_LEN + 2] = 0x20; + + byte_array_t data = {.buf = s, .len = sizeof(s)}; + kdf(k_amf, data, SECURITY_KEY_LEN, nh); + + log_hex_buffer("KDF input (SYNC string)", s, SECURITY_KEY_LEN + 3); + log_hex_buffer("Derived NH", nh, SECURITY_KEY_LEN); + +} diff --git a/openair3/SECU/key_nas_deriver.h b/openair3/SECU/key_nas_deriver.h index 4cb336bce9..0ab14ad51a 100644 --- a/openair3/SECU/key_nas_deriver.h +++ b/openair3/SECU/key_nas_deriver.h @@ -34,4 +34,6 @@ void nr_derive_key(algorithm_type_dist_t alg_type, uint8_t alg_id, const uint8_t void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t key[32], uint8_t *key_ng_ran_star); +void nr_derive_nh(const uint8_t k_amf[SECURITY_KEY_LEN], const uint8_t *sync_input, uint8_t *nh); + #endif From 6de5b1d3debb2d47f8ad5463075981f1164b137f Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 7 Apr 2025 18:22:04 +0200 Subject: [PATCH 049/100] Store PCI received in reconfigurationWithSync According to 3GPP TS 38.331 5.3.5.5.2 (Reconfiguration with sync), the UE shall consider the target SpCell to be one with a physical cell identity indicated by the physCellId --- openair2/RRC/NR_UE/rrc_UE.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 4abc712507..bb58191e24 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -1030,11 +1030,16 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc, NR_Rec return; } - if (reconfigurationWithSync->spCellConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL && - reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB) - rrc->arfcn_ssb = *reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB; + if (reconfigurationWithSync->spCellConfigCommon) { + /* if the frequencyInfoDL is included, consider the target SpCell + to be one on the SSB frequency indicated by the frequencyInfoDL */ + const NR_DownlinkConfigCommon_t *dcc = reconfigurationWithSync->spCellConfigCommon->downlinkConfigCommon; + if (dcc && dcc->frequencyInfoDL && dcc->frequencyInfoDL->absoluteFrequencySSB) + rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB; + + // consider the target SpCell to be one with a physical cell identity indicated by the physCellId + rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId; + } NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants; nr_timer_stop(&tac->T310); From de0730a4e82c4f48e54f40720c7a167a6fa78df8 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Apr 2025 15:24:00 +0200 Subject: [PATCH 050/100] Use module_id in rrc_gNB_get_next_transaction_identifier call --- openair2/RRC/NR/rrc_gNB.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 78e472ed60..b8d37986cb 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2181,7 +2181,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance 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); + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); 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); From 9d951b109fff8c955dd96f11c7fc5622d5c64d75 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 26 May 2025 16:23:14 +0200 Subject: [PATCH 051/100] Return in nr_ue_get_sdu when mac->lc_ordered_list.count is 0 This count is used to size the dynamic array lcids_bj_pos. In case count is zero, this would lead to runtime error. With this change, the function will indicate to the caller that no SDUs are present and will print an error. --- openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c index 1922a3420e..b810bf8de6 100644 --- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c +++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c @@ -2703,6 +2703,10 @@ static uint8_t nr_ue_get_sdu(NR_UE_MAC_INST_t *mac, mac->lc_ordered_list.count); // variable used to build the lcids with positive Bj + if (!mac->lc_ordered_list.count) { + LOG_E(NR_MAC, "Failed to init lcids_bj_pos: mac->lc_ordered_list.count = 0\n"); + return 0; + } nr_lcordered_info_t lcids_bj_pos[mac->lc_ordered_list.count]; int avail_lcids_count = select_logical_channels(mac, lcids_bj_pos); From eb4cd38577aabd6f8a8bea9014ebaef59dacb07b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 14:53:20 +0100 Subject: [PATCH 052/100] Refactor handling of NGAP UE Context in ngap_gNB_handle_nas_first_req this commit is refactoring the function ngap_gNB_handle_nas_first_req to (1) fill first a local instance of ngap_gNB_ue_context_t and then (2) pass it to ngap_store_ue_context which will allocate memory for the instance to store in ngap --- openair3/NGAP/ngap_gNB_nas_procedures.c | 31 +++++++++++++------------ openair3/NGAP/ngap_gNB_ue_context.c | 5 +++- openair3/NGAP/ngap_gNB_ue_context.h | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 10ef36ec2a..74130e75f8 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -165,16 +165,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf head->value.present = NGAP_InitiatingMessage__value_PR_InitialUEMessage; NGAP_InitialUEMessage_t *out = &head->value.choice.InitialUEMessage; - /* Store the UE context in NGAP with: - * selected AMF, selected PLMN identity, gNB ID - * the unique gNB UE NGAP ID, used for the duration of the connectivity */ - struct ngap_gNB_ue_context_s *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); - DevAssert(ue_desc_p != NULL); - ue_desc_p->amf_ref = amf; - ue_desc_p->gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id; - ue_desc_p->gNB_instance = instance_p; - ue_desc_p->selected_plmn_identity = UEfirstReq->plmn; - ngap_store_ue_context(ue_desc_p); + /* Create and store NGAP UE context */ + ngap_gNB_ue_context_t ue_desc_p = { + .amf_ref = amf, + .gNB_ue_ngap_id = UEfirstReq->gNB_ue_ngap_id, + .gNB_instance = instance_p, + .selected_plmn_identity = UEfirstReq->plmn, + }; // RAN UE NGAP ID (M) { @@ -182,7 +179,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; ie->criticality = NGAP_Criticality_reject; ie->value.present = NGAP_InitialUEMessage_IEs__value_PR_RAN_UE_NGAP_ID; - ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p->gNB_ue_ngap_id; + ie->value.choice.RAN_UE_NGAP_ID = ue_desc_p.gNB_ue_ngap_id; } /* NAS-PDU (M): transferred transparently */ @@ -208,7 +205,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf 0, // Cell ID &userinfo_nr_p->nR_CGI.nRCellIdentity); - plmn_id_t *plmn = &ue_desc_p->selected_plmn_identity; + plmn_id_t *plmn = &ue_desc_p.selected_plmn_identity; MCC_MNC_TO_TBCD(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &userinfo_nr_p->nR_CGI.pLMNIdentity); /* In case of network sharing, @@ -255,7 +252,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf DevMessage("Failed to encode initial UE message\n"); /* Update the current NGAP UE state */ - ue_desc_p->ue_state = NGAP_UE_WAITING_CSR; + ue_desc_p.ue_state = NGAP_UE_WAITING_CSR; /* Assign a stream for this UE : * From 3GPP 38.412 7)Transport layers: * Within the SCTP association established between one AMF and gNB pair: @@ -272,9 +269,13 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf if ((amf->nextstream == 0) && (amf->out_streams > 1)) { amf->nextstream += 1; } - ue_desc_p->tx_stream = amf->nextstream; + ue_desc_p.tx_stream = amf->nextstream; + + /* Create and store UE context */ + ngap_store_ue_context(&ue_desc_p); + /* Send encoded message over sctp */ - ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p->tx_stream); + ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p.tx_stream); return 0; } diff --git a/openair3/NGAP/ngap_gNB_ue_context.c b/openair3/NGAP/ngap_gNB_ue_context.c index c4b7b012ef..d0949b88c2 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.c +++ b/openair3/NGAP/ngap_gNB_ue_context.c @@ -60,8 +60,11 @@ static int ngap_gNB_compare_gNB_ue_ngap_id(struct ngap_gNB_ue_context_s *p1, str RB_GENERATE(ngap_ue_map, ngap_gNB_ue_context_s, entries, ngap_gNB_compare_gNB_ue_ngap_id); -void ngap_store_ue_context(struct ngap_gNB_ue_context_s *ue_desc_p) +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue) { + LOG_I(NGAP, "Create UE context (ID %d) for AMF '%s' (assoc_id %d)\n", ue->gNB_ue_ngap_id, ue->amf_ref->amf_name, ue->amf_ref->assoc_id); + ngap_gNB_ue_context_t *ue_desc_p = calloc_or_fail(1, sizeof(*ue_desc_p)); + *ue_desc_p = *ue; if (RB_INSERT(ngap_ue_map, &ngap_ue_head, ue_desc_p)) LOG_E(NGAP, "Bug in UE uniq number allocation %u, we try to add a existing UE\n", ue_desc_p->gNB_ue_ngap_id); return; diff --git a/openair3/NGAP/ngap_gNB_ue_context.h b/openair3/NGAP/ngap_gNB_ue_context.h index 4c0c63239f..aaf9e83bbc 100644 --- a/openair3/NGAP/ngap_gNB_ue_context.h +++ b/openair3/NGAP/ngap_gNB_ue_context.h @@ -78,7 +78,7 @@ typedef struct ngap_gNB_ue_context_s { ngap_gNB_instance_t *gNB_instance; } ngap_gNB_ue_context_t; -void ngap_store_ue_context(ngap_gNB_ue_context_t *ue_desc_p); +void ngap_store_ue_context(const ngap_gNB_ue_context_t *ue_desc_p); ngap_gNB_ue_context_t *ngap_get_ue_context(uint32_t gNB_ue_ngap_id); ngap_gNB_ue_context_t *ngap_detach_ue_context(uint32_t gNB_ue_ngap_id); From 63b4a784a8913bb7df369c77d9f02a4658c985db Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 12 Mar 2025 16:10:36 +0100 Subject: [PATCH 053/100] Use byte_array_t in nr_initiate_handover --- openair2/RRC/NR/rrc_gNB_mobility.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index e6e50ffbf1..c1ab2862fe 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -73,8 +73,7 @@ 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, + byte_array_t *ho_prep_info, ho_req_ack_t ack, ho_success_t success, ho_cancel_t cancel) @@ -83,7 +82,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, DevAssert(ue != NULL); DevAssert(target_du != NULL); // source_du might be NULL -> inter-CU handover - DevAssert(ho_prep_buf != NULL && ho_prep_len > 0); + DevAssert(ho_prep_info->buf != NULL && ho_prep_info->len > 0); if (ue->ho_context != NULL) { LOG_E(NR_RRC, "handover for UE %u ongoing, cannot trigger new\n", ue->rrc_ue_id); @@ -130,8 +129,8 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, 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, + .handoverPreparationInfo = ho_prep_info->buf, + .handoverPreparationInfo_length = ho_prep_info->len, }; f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; @@ -327,7 +326,8 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain 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); + byte_array_t hpi = {.buf = buf, .len = size}; + nr_initiate_handover(rrc, ue, source_du, target_du, &hpi, ack, success, cancel); } void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue) From 75c7220345679c18eab0ce6d42c15de1874fa69f Mon Sep 17 00:00:00 2001 From: batuhan duyuler Date: Fri, 7 Mar 2025 12:14:05 +0100 Subject: [PATCH 054/100] Refactored code to populate DRBs to be setup list in nr_initiate_handover Co-authored-by: Guido Casati --- openair2/RRC/NR/rrc_gNB_mobility.c | 75 ++++++++++++++++-------------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index c1ab2862fe..54c0f6f17d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -61,6 +61,46 @@ static void free_ho_ctx(nr_handover_context_t *ho_ctx) free(ho_ctx); } +static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE]) +{ + int nb_drb = 0; + for (int i = 0; i < MAX_DRBS_PER_UE; ++i) { + 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_or_fail(1, sizeof(drb->drb_info.flows_mapped_to_drb[0])); + 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; + } + return nb_drb; +} + /* \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 @@ -134,40 +174,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc, }; f1ap_drb_to_be_setup_t drbs[MAX_DRBS_PER_UE] = {0}; - int nb_drb = 0; - for (int i = 0; i < sizeofArray(drbs); ++i) { - 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_or_fail(1, sizeof(f1ap_flows_mapped_to_drb_t)); - 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; - } + int nb_drb = fill_drb_to_be_setup(rrc, ue, drbs); 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; From d413cf969651001dacea43ddca47c3f55a1bfa73 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 16 May 2025 10:44:11 +0200 Subject: [PATCH 055/100] Refactor handover functions: get_neighbour_cell_information and get_neighbour_config * differentiate the 2 functions based on the input: either NR Cell ID or PCI * enhanced variables naming to distinguish the parameters * add logging for debugging purposes --- openair2/RRC/NR/rrc_gNB.c | 77 ++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b8d37986cb..b924bfd0d0 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -96,6 +96,7 @@ #include "E1AP/lib/e1ap_interface_management.h" #include "NR_DL-DCCH-Message.h" #include "ds/byte_array.h" +#include "alg/find.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -130,39 +131,47 @@ static void freeDRBlist(NR_DRB_ToAddModList_t *list) return; } -const neighbour_cell_configuration_t *get_neighbour_config(int serving_cell_nr_cellid) +static bool eq_cell_id(const void *vval, const void *vit) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - if (!neighbour_cell_configuration) - return NULL; + const int *cell_id = (const int *)vval; + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)vit; + return cell->nr_cell_id == *cell_id; +} - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (neighbour_config->nr_cell_id == serving_cell_nr_cellid) - return neighbour_config; +const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_INST *rrc, int cell_id) +{ + if (!rrc->neighbour_cell_configuration) + return NULL; + seq_arr_t *head = rrc->neighbour_cell_configuration; + LOG_D(NR_RRC, "Number of neighbour cell configurations: %ld\n", head->size); + elm_arr_t e = find_if(head, &cell_id, eq_cell_id); + if (e.found) { + const neighbour_cell_configuration_t *cell = (const neighbour_cell_configuration_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with Cell ID %ld\n", cell->nr_cell_id); + return cell; } return NULL; } -const nr_neighbour_gnb_configuration_t *get_neighbour_cell_information(int serving_cell_nr_cellid, int neighbour_cell_phy_id) +static bool eq_pci(const void *vval, const void *vit) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - for (int cellIdx = 0; cellIdx < neighbour_cell_configuration->size; cellIdx++) { - neighbour_cell_configuration_t *neighbour_config = - (neighbour_cell_configuration_t *)seq_arr_at(neighbour_cell_configuration, cellIdx); - if (!neighbour_config) - continue; + const int *pci = (const int *)vval; + const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)vit; + return neighbour->physicalCellId == *pci; +} - for (int neighbourIdx = 0; neighbourIdx < neighbour_config->neighbour_cells->size; neighbourIdx++) { - nr_neighbour_gnb_configuration_t *neighbour = - (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_config->neighbour_cells, neighbourIdx); - if (neighbour != NULL && neighbour->physicalCellId == neighbour_cell_phy_id) - return neighbour; - } +const nr_neighbour_gnb_configuration_t *get_neighbour_gnb_by_pci(const neighbour_cell_configuration_t *cell, int pci) +{ + seq_arr_t *head = cell->neighbour_cells; + DevAssert(head != NULL); + LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); + elm_arr_t e = find_if(head, &pci, eq_pci); + if (e.found) { + const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)e.it; + LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); + return neighbour; } + LOG_E(NR_RRC, "No matching neighbour cell found for Physical Cell ID: %d\n", pci); return NULL; } @@ -564,7 +573,7 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, 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); + const neighbour_cell_configuration_t *neighbour_config = get_neighbour_cell_config(rrc, cell_info->nr_cellid); seq_arr_t *neighbour_cells = NULL; if (neighbour_config) neighbour_cells = neighbour_config->neighbour_cells; @@ -1391,7 +1400,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, int servingCellRSRP = 0; int neighbourCellRSRP = 0; - int servingCellId = -1; + int scell_pci = -1; switch (event_triggered->eventId.present) { case NR_EventTriggerConfig__eventId_PR_eventA2: @@ -1408,7 +1417,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, for (int serving_cell_idx = 0; serving_cell_idx < measResults->measResultServingMOList.list.count; serving_cell_idx++) { const NR_MeasResultServMO_t *meas_result_serv_MO = measResults->measResultServingMOList.list.array[serving_cell_idx]; - servingCellId = *(meas_result_serv_MO->measResultServingCell.physCellId); + scell_pci = *(meas_result_serv_MO->measResultServingCell.physCellId); if (meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell) { servingCellRSRP = *(meas_result_serv_MO->measResultServingCell.measResult.cellResults.resultsSSB_Cell->rsrp) - 157; } else { @@ -1426,7 +1435,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, const NR_MeasResultListNR_t *measResultListNR = measResults->measResultNeighCells->choice.measResultListNR; for (int neigh_meas_idx = 0; neigh_meas_idx < measResultListNR->list.count; neigh_meas_idx++) { const NR_MeasResultNR_t *meas_result_neigh_cell = (measResultListNR->list.array[neigh_meas_idx]); - const int neighbourCellId = *(meas_result_neigh_cell->physCellId); + const int neighbour_pci = *(meas_result_neigh_cell->physCellId); // TS 138 133 Table 10.1.6.1-1: SS-RSRP and CSI-RSRP measurement report mapping const struct NR_MeasResultNR__measResult__cellResults *cellResults = &(meas_result_neigh_cell->measResult.cellResults); @@ -1439,13 +1448,13 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, LOG_I(NR_RRC, "HO LOG: Measurement Report for the neighbour %d with RSRP: %d\n", - neighbourCellId, + neighbour_pci, neighbourCellRSRP); - 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->nr_cellid, neighbourCellId); + const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbour_pci); + const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(scell_pci); + const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, serving_cell->nr_cellid); + const nr_neighbour_gnb_configuration_t *neighbour = get_neighbour_gnb_by_pci(cell, neighbour_pci); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. if (!neigh_cell && neighbour) { @@ -1465,7 +1474,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, 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); + 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, neighbour_pci); } } From a937eaec234ec05d20d9f383f31bbcd98b0ac3c7 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 25 Feb 2025 17:15:16 +0100 Subject: [PATCH 056/100] Rework RRCReconfiguration handling in RRC/ASN1 according to TS 38.331, RRCReconfiguration messages can be carried in a container by different RRC messages, e.g. HandoverPreparationInformation, HandoverCommand, RRCResume etc.. therefore before the introduction of new RRCReconfiguration messages, e.g. for handover, a new design seems to be necessary in order to improve modularity and maintainability of the code. The goal of this commit is to make the generation of RRCReconfiguration messages more modular by (1) preparing the RRCReconfiguration parameters data in RRC (2) pass it to ASN1 for IEs allocation (3) encode to buffer The following changes are introduced: (1) introduce struct nr_rrc_reconfig_param_t to store the RRC parameters relevant to encode the RRCReconfiguration IEs (2) add RRC function get_RRCReconfiguration_params to fetch nr_rrc_reconfig_param_t data from the UE context and (3) pass it to the ASN1 encoder, e.g. do_RRCReconfiguration (4) add a function build_RRCReconfiguration_IEs to allocate memory and build the ASN1 NR_RRCReconfiguration_IEs_t and (5) adopt it in do_RRCReconfiguration (4) add free_RRCReconfiguration_params for memory management of nr_rrc_reconfig_param_t data (6) add test for rrc_reconfiguration get_RRCReconfiguration_params: This function prepares RRCReconfigurationParams for RRC encoding. Motivation of this change: depending on the RRCReconfiguration message to be encoded, the ownership of ASN1 memory allocation should belong to the ASN1 layer, therefore this function is preparing the nr_rrc_reconfig_param_t data to pass to the ASN1 encoder to build the ASN1 message and encode to buffer The function is preparing the params for the IEs that are either mandatory or shared among different RRC messages. Specific fields that depend on the message to be encoded are then added afterwards in the caller. The input param to indicate re-establishment has been split between SRBs and DRBs, since depending on the scenario the PDCP re-establishment can vary. This will be addressed in a later commit. This function is also handling xid. build_RRCReconfiguration_IE: The long term goal is to transfer ownership of memory allocation in ASN1 encoding to build_RRCReconfiguration_IE, then by calling ASN_STRUCT_FREE_CONTENTS_ONLY on dl_dcch_msg, all IEs allocated in the context are freed after encoding to buffer. In the long term, createDRBlist, createSRBlist can also be brought into the context of build_RRCReconfiguration_IEs and free the ASN1 structure after encoding. This improves maintability and helps preventing memory leaks. Currently, what is not allocated in the context, is nulled and freed outside. free_RRCReconfiguration_params: this function frees memory allocated to build the nr_rrc_reconfig_param_t data, including the NR_DRB_ToAddModList_t and NR_SRB_ToAddModList_t. The function freeDRBlist has been removed since no longer necessary. dedicated_NAS_msg_list: dedicated_NAS_msg_list handling has also been refactored, by: (1) fetch the NAS PDUs from the UE context in get_RRCReconfiguration_params, which translates to (2) passing an array of dedicatedNAS-MessageList + size to the ASN1 encoding function where (3) the ASN1 encoding logic for the dedicated_NAS_msg_list IE has been moved Note, 3GPP TS 38.331: dedicatedNAS-MessageList: SEQUENCE (SIZE(1..maxDRB)) OF DedicatedNAS-Message --- openair2/RRC/NR/MESSAGES/asn1_msg.c | 183 ++++++----- openair2/RRC/NR/MESSAGES/asn1_msg.h | 28 +- .../RRC/NR/MESSAGES/tests/test_asn1_msg.cpp | 79 +++++ openair2/RRC/NR/nr_rrc_proto.h | 3 + openair2/RRC/NR/rrc_gNB.c | 288 ++++++++---------- 5 files changed, 315 insertions(+), 266 deletions(-) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6a7ee77b52..6ab4ffc2fc 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -143,6 +143,7 @@ #include "common/ran_context.h" #include "conversions.h" +#include "ds/byte_array.h" //#define XER_PRINT @@ -499,112 +500,108 @@ int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id return((enc_rval.encoded+7)/8); } -//------------------------------------------------------------------------------ -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig) -//------------------------------------------------------------------------------ +/** @brief Build RRCReconfiguration message (3GPP TS 38.331) */ +static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_reconfig_param_t *params) { - NR_DL_DCCH_Message_t dl_dcch_msg={0}; - asn_enc_rval_t enc_rval; - NR_RRCReconfiguration_IEs_t *ie; + NR_RRCReconfiguration_IEs_t *ie = calloc_or_fail(1, sizeof(*ie)); - dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; - asn1cCalloc(dl_dcch_msg.message.choice.c1, c1);// = CALLOC(1, sizeof(struct NR_DL_DCCH_MessageType__c1)); - c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + // radioBearerConfig + if ((params->srb_config_list && params->srb_config_list->list.size) + || (params->drb_config_list && params->drb_config_list->list.size)) { + ie->radioBearerConfig = calloc_or_fail(1, sizeof(*ie->radioBearerConfig)); + struct NR_RadioBearerConfig *cfg = ie->radioBearerConfig; + cfg->srb_ToAddModList = params->srb_config_list; + cfg->drb_ToAddModList = params->drb_config_list; + cfg->securityConfig = params->security_config; + cfg->srb3_ToRelease = NULL; + cfg->drb_ToReleaseList = params->drb_release_list; + } - asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); // = calloc(1, sizeof(NR_RRCReconfiguration_t)); - rrcReconf->rrc_TransactionIdentifier = Transaction_id; - rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + /* measConfig */ + ie->measConfig = params->meas_config; - /******************** Radio Bearer Config ********************/ - /* Configure Security */ - // security_config = CALLOC(1, sizeof(NR_SecurityConfig_t)); - // security_config->securityAlgorithmConfig = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->securityAlgorithmConfig)); - // security_config->securityAlgorithmConfig->cipheringAlgorithm = NR_CipheringAlgorithm_nea0; - // security_config->securityAlgorithmConfig->integrityProtAlgorithm = NULL; - // security_config->keyToUse = CALLOC(1, sizeof(*ie->radioBearerConfig->securityConfig->keyToUse)); - // *security_config->keyToUse = NR_SecurityConfig__keyToUse_master; + /* nonCriticalExtension, RRCReconfiguration-v1530-IEs */ + if (params->cell_group_config || params->num_nas_msg) { + // Allocate memory for extension IE + ie->nonCriticalExtension = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension)); + } - ie = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t)); - if ((SRB_configList && SRB_configList->list.size) || - (DRB_configList && DRB_configList->list.size)) { - ie->radioBearerConfig = calloc(1, sizeof(NR_RadioBearerConfig_t)); - ie->radioBearerConfig->srb_ToAddModList = SRB_configList; - ie->radioBearerConfig->drb_ToAddModList = DRB_configList; - ie->radioBearerConfig->securityConfig = security_config; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = DRB_releaseList; - } - - /******************** Meas Config ********************/ - // measConfig - ie->measConfig = meas_config; - // lateNonCriticalExtension - ie->lateNonCriticalExtension = NULL; - // nonCriticalExtension - - if (cellGroupConfig || dedicatedNAS_MessageList) { - ie->nonCriticalExtension = calloc(1, sizeof(NR_RRCReconfiguration_v1530_IEs_t)); - if (dedicatedNAS_MessageList) - ie->nonCriticalExtension->dedicatedNAS_MessageList = dedicatedNAS_MessageList; - } - - if (cellGroupConfig != NULL) { - uint8_t *buf = NULL; - ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, cellGroupConfig, (void **)&buf); - AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { - xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig); + // Configure Cell Group Config + if (ie->nonCriticalExtension) { + if (params->num_nas_msg) { + asn1cCalloc(ie->nonCriticalExtension->dedicatedNAS_MessageList, list); + /* dedicatedNAS-MessageList: The field is absent in case of reconfiguration with sync + otherwise it is optionally present */ + for (int i = 0; i < params->num_nas_msg; i++) { + asn1cSequenceAdd(list->list, NR_DedicatedNAS_Message_t, msg); + OCTET_STRING_fromBuf(msg, (char *)params->dedicated_NAS_msg_list[i].buf, params->dedicated_NAS_msg_list[i].len); } - ie->nonCriticalExtension->masterCellGroup = calloc(1,sizeof(OCTET_STRING_t)); - ie->nonCriticalExtension->masterCellGroup->buf = buf; - ie->nonCriticalExtension->masterCellGroup->size = len; } - dl_dcch_msg.message.choice.c1->choice.rrcReconfiguration->criticalExtensions.choice.rrcReconfiguration = ie; - - if (LOG_DEBUGFLAG(DEBUG_ASN1)) { - xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + /* masterCellGroup */ + if (params->cell_group_config) { + // Encode in extension IE (Master cell group) + uint8_t *buf = NULL; + ssize_t len = uper_encode_to_new_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, (void **)&buf); + AssertFatal(len > 0, "ASN1 message encoding failed (%lu)!\n", len); + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config); + } + ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup)); + *ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = len}; } - enc_rval = uper_encode_to_buffer(&asn_DEF_NR_DL_DCCH_Message, - NULL, - (void *)&dl_dcch_msg, - buffer, - buffer_size); - - AssertFatal(enc_rval.encoded >0, "ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - - // don't free what we did not allocate, so set fields with pointers to NULL - // if memory comes from outside - ie->measConfig = NULL; - if (ie->radioBearerConfig) { - ie->radioBearerConfig->srb_ToAddModList = NULL; - ie->radioBearerConfig->drb_ToAddModList = NULL; - ie->radioBearerConfig->securityConfig = NULL; - ie->radioBearerConfig->srb3_ToRelease = NULL; - ie->radioBearerConfig->drb_ToReleaseList = NULL; + /* masterKeyUpdate */ + if (params->masterKeyUpdate) { + ie->nonCriticalExtension->masterKeyUpdate = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterKeyUpdate)); + ie->nonCriticalExtension->masterKeyUpdate->keySetChangeIndicator = false; + ie->nonCriticalExtension->masterKeyUpdate->nextHopChainingCount = params->nextHopChainingCount; } - if (ie->nonCriticalExtension) - ie->nonCriticalExtension->dedicatedNAS_MessageList = NULL; + } + + return ie; +} + +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params) +{ + byte_array_t msg = {.buf = NULL, .len = 0}; + NR_RRCReconfiguration_IEs_t *ie = build_RRCReconfiguration_IEs(params); + + NR_DL_DCCH_Message_t dl_dcch_msg = {0}; + dl_dcch_msg.message.present = NR_DL_DCCH_MessageType_PR_c1; + + asn1cCalloc(dl_dcch_msg.message.choice.c1, c1); + c1->present = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; + asn1cCalloc(c1->choice.rrcReconfiguration, rrcReconf); + rrcReconf->rrc_TransactionIdentifier = params->transaction_id; + rrcReconf->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration; + rrcReconf->criticalExtensions.choice.rrcReconfiguration = ie; + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { + xer_fprint(stdout, &asn_DEF_NR_DL_DCCH_Message, (void *)&dl_dcch_msg); + } + + int val = uper_encode_to_new_buffer(&asn_DEF_NR_DL_DCCH_Message, NULL, &dl_dcch_msg, (void **)&msg.buf); + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode DL-DCCH message\n"); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); - LOG_D(NR_RRC, - "RRCReconfiguration for UE %d: Encoded %zd bits (%zd bytes)\n", - rrc_ue_id, - enc_rval.encoded, - (enc_rval.encoded + 7) / 8); + return msg; + } + msg.len = val; + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); - return((enc_rval.encoded+7)/8); + // Do not free what is not allocated in this context + ie->measConfig = NULL; + if (ie->radioBearerConfig) { + ie->radioBearerConfig->securityConfig = NULL; + ie->radioBearerConfig->drb_ToReleaseList = NULL; + ie->radioBearerConfig->srb_ToAddModList = NULL; + ie->radioBearerConfig->drb_ToAddModList = NULL; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_DL_DCCH_Message, &dl_dcch_msg); + + return msg; } int do_RRCSetupRequest(uint8_t *buffer, size_t buffer_size, uint8_t *rv, uint64_t fiveG_S_TMSI) diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index afc9226b17..83be12d87b 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -51,10 +51,24 @@ #include "NR_SRB-ToAddModList.h" #include "NR_SecurityConfig.h" #include "ds/seq_arr.h" +#include "ds/byte_array.h" #include "rrc_messages_types.h" -struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList; struct asn_TYPE_descriptor_s; +typedef struct { + uint8_t transaction_id; + NR_SRB_ToAddModList_t *srb_config_list; + NR_DRB_ToAddModList_t *drb_config_list; + NR_DRB_ToReleaseList_t *drb_release_list; + NR_SecurityConfig_t *security_config; + NR_MeasConfig_t *meas_config; + byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE]; + int num_nas_msg; + NR_CellGroupConfig_t *cell_group_config; + bool masterKeyUpdate; + int nextHopChainingCount; +} nr_rrc_reconfig_param_t; + /* * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) * output into the chosen string buffer. @@ -91,17 +105,7 @@ int do_NR_SA_UECapabilityEnquiry(uint8_t *const buffer, const uint8_t Transactio int do_NR_RRCRelease(uint8_t *buffer, size_t buffer_size, uint8_t Transaction_id); -int do_RRCReconfiguration(int rrc_ue_id, - uint8_t *buffer, - size_t buffer_size, - uint8_t Transaction_id, - NR_SRB_ToAddModList_t *SRB_configList, - NR_DRB_ToAddModList_t *DRB_configList, - NR_DRB_ToReleaseList_t *DRB_releaseList, - NR_SecurityConfig_t *security_config, - NR_MeasConfig_t *meas_config, - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList, - NR_CellGroupConfig_t *cellGroupConfig); +byte_array_t do_RRCReconfiguration(const nr_rrc_reconfig_param_t *params); int do_RRCSetupComplete(uint8_t *buffer, size_t buffer_size, diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index 347c35d3ea..1f92c5aae5 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -20,14 +20,22 @@ */ #include +#ifdef __cplusplus extern "C" { +#endif #include "openair2/RRC/NR/MESSAGES/asn1_msg.h" #include "common/ran_context.h" #include #include "common/utils/assertions.h" #include "common/utils/LOG/log.h" +#include "NR_DRB-ToAddMod.h" +#include "NR_DRB-ToAddModList.h" +#include "NR_SRB-ToAddModList.h" +#include "ds/byte_array.h" RAN_CONTEXT_t RC; +#ifdef __cplusplus } +#endif TEST(nr_asn1, rrc_reject) { @@ -77,6 +85,77 @@ TEST(nr_asn1, paging) EXPECT_GT(do_NR_Paging(0, buf, 0), 0); } +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) +{ + ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, params.meas_config); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +TEST(nr_asn1, rrc_reconfiguration) +{ + // SRB Configuration + NR_SRB_ToAddModList_t *srb_config_list = (NR_SRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*srb_config_list)); + for (int i = 0; i < 4; i++) { + if (i == 1 || i == 2) { + NR_SRB_ToAddMod_t *srb = (NR_SRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*srb)); + ASN_SEQUENCE_ADD(&srb_config_list->list, srb); + srb->srb_Identity = i; + if (i == 1 || i == 2) { + srb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*srb->reestablishPDCP)); + *srb->reestablishPDCP = 0; + } + } + } + + // DRB Configuration + NR_DRB_ToAddModList_t *drb_config_list = (NR_DRB_ToAddModList_t *)calloc_or_fail(1, sizeof(*drb_config_list)); + for (int i = 0; i < 32; i++) { + if (i == 1 || i == 2) { + NR_DRB_ToAddMod_t *drb = (NR_DRB_ToAddMod_t *)calloc_or_fail(1, sizeof(*drb)); + ASN_SEQUENCE_ADD(&drb_config_list->list, drb); + drb->drb_Identity = i; + drb->reestablishPDCP = (long *)calloc_or_fail(1, sizeof(*drb->reestablishPDCP)); + *drb->reestablishPDCP = 0; + } + } + + // nr_rrc_reconfig_param_t setup + nr_rrc_reconfig_param_t params = {}; + params.srb_config_list = srb_config_list; + params.drb_config_list = drb_config_list; + params.num_nas_msg = 2; + params.masterKeyUpdate = false; + params.nextHopChainingCount = 1; + + byte_array_t nas_pdu_1; + nas_pdu_1.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_1.buf, "NAS1", 4); + nas_pdu_1.len = 4; + + byte_array_t nas_pdu_2; + nas_pdu_2.buf = (uint8_t *)malloc_or_fail(4); + memcpy(nas_pdu_2.buf, "NAS2", 4); + nas_pdu_2.len = 4; + + params.dedicated_NAS_msg_list[0] = nas_pdu_1; + params.dedicated_NAS_msg_list[1] = nas_pdu_2; + + byte_array_t msg = do_RRCReconfiguration(¶ms); + + EXPECT_GT(msg.len, 0); + EXPECT_NE(msg.buf, nullptr); + + LOG_D(NR_RRC, "RRCReconfiguration: Encoded (%ld bytes)\n", msg.len); + + free_byte_array(msg); + free_RRCReconfiguration_params(params); +} + int main(int argc, char **argv) { logInit(); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 4546f59723..66f9911c8a 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -38,6 +38,7 @@ #include "NR_CG-Config.h" #include "NR_CG-ConfigInfo.h" #include "NR_RRCReconfiguration.h" +#include "RRC/NR/MESSAGES/asn1_msg.h" void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); @@ -112,6 +113,8 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, int n_rel_drbs, const f1ap_drb_to_be_released_t *rel_drbs); +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); + 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); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b924bfd0d0..e8c0edf441 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -125,12 +125,6 @@ static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_i data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd); } -static void freeDRBlist(NR_DRB_ToAddModList_t *list) -{ - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); - return; -} - static bool eq_cell_id(const void *vval, const void *vit) { const int *cell_id = (const int *)vval; @@ -551,15 +545,23 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a return rc_A3; } -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) +void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) { - NR_CellGroupConfig_t *cellGroupConfig = UE->masterCellGroup; + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list); + ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list); + ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config); + for (int i = 0; i < params.num_nas_msg; i++) + FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]); +} + +/** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ +static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, + gNB_RRC_UE_t *UE, + bool srb_reestablish, + bool drb_reestablish) +{ + uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); 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; @@ -617,71 +619,71 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, UE->measConfig = measconfig; - NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, reestablish); - NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, reestablish); + // Re-establish PDCP for SRB2 only + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reestablish); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, + .transaction_id = xid, + .drb_config_list = DRBs, + .drb_release_list = UE->DRB_ReleaseList, + .meas_config = UE->measConfig, + .srb_config_list = SRBs}; + UE->DRB_ReleaseList = NULL; // pointer transferred to params - int size = do_RRCReconfiguration(UE->rrc_ue_id, - 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; + for (int i = 0; i < UE->nb_of_pdusessions; i++) { + if (UE->pduSession[i].param.nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->pduSession[i].param.nas_pdu; + UE->pduSession[i].param.nas_pdu.buf = NULL; + UE->pduSession[i].param.nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld (pdusession idx %d) to RRCReconfiguration params\n", UE->pduSession[i].param.nas_pdu.len, i); + } + } + if (UE->nas_pdu.len > 0) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->nas_pdu; + UE->nas_pdu.buf = NULL; + UE->nas_pdu.len = 0; + LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", UE->nas_pdu.len); + } - return size; + return params; +} + +static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) +{ + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return msg; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + return msg; } 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); - ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + /* do not re-establish PDCP for any bearer */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, false, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buf, ue_p->pduSession[i].param.nas_pdu.len); - - LOG_D(NR_RRC, "add NAS info with size %ld (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.len, i); - ue_p->pduSession[i].xid = xid; + ue_p->pduSession[i].xid = params.transaction_id; } if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) { ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE; } } - if (ue_p->nas_pdu.len) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg); - OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buf, ue_p->nas_pdu.len); - } - - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; - } - - /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - // 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_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %d, xid %d)\n", size, xid); + LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) @@ -690,8 +692,8 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = - CALLOC(1, sizeof(*dedicatedNAS_MessageList)); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); + nr_rrc_reconfig_param_t params = {.drb_config_list = DRBs, .transaction_id = xid}; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; @@ -753,42 +755,27 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t session->status = PDU_SESSION_STATUS_DONE; session->xid = xid; - if (session->param.nas_pdu.buf != NULL) { - asn1cSequenceAdd(dedicatedNAS_MessageList->list,NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)session->param.nas_pdu.buf, session->param.nas_pdu.len); - LOG_I(NR_RRC, "add NAS info with size %ld (pdusession id %d)\n", session->param.nas_pdu.len, session->param.pdusession_id); + if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { + params.dedicated_NAS_msg_list[params.num_nas_msg++] = ue_p->pduSession[i].param.nas_pdu; } } - /* If list is empty free the list and reset the address */ - if (dedicatedNAS_MessageList->list.count == 0) { - free(dedicatedNAS_MessageList); - dedicatedNAS_MessageList = NULL; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - DRBs, - NULL, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - freeDRBlist(DRBs); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); /* Free all NAS PDUs */ for (int i = 0; i < ue_p->nb_of_pdusessions; i++) FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } //----------------------------------------------------------------------------- @@ -808,40 +795,22 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, } } - /* If list is empty free the list and reset the address */ - struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL; + nr_rrc_reconfig_param_t params = {.drb_release_list = DRB_Release_configList2, .transaction_id = xid}; if (nas_length > 0) { - dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); - asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, dedicatedNAS_Message); - OCTET_STRING_fromBuf(dedicatedNAS_Message, (char *)nas_buffer, nas_length); - LOG_I(NR_RRC,"add NAS info with size %d\n", nas_length); - } else { - LOG_W(NR_RRC,"dedlicated NAS list is empty\n"); + params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer; + params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length; } - - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - DRB_Release_configList2, - NULL, - NULL, - dedicatedNAS_MessageList, - NULL); - LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size, "[MSG] RRC Reconfiguration\n"); - - /* Free all NAS PDUs */ - if (nas_length > 0) { - /* Free the NAS PDU buffer and invalidate it */ - free(nas_buffer); + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; } - - LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %d)\n", ue_p->rrc_ue_id, size); + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) @@ -1081,32 +1050,26 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - new_xid, - SRBs, - DRBs, - NULL, - NULL, - NULL, // MeasObj_list, - NULL, - cellGroupConfig); - freeSRBlist(SRBs); - freeDRBlist(DRBs); - LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n"); - - AssertFatal(size > 0, "cannot encode RRC Reconfiguration\n"); + nr_rrc_reconfig_param_t params = {.cell_group_config = cellGroupConfig, + .drb_config_list = DRBs, + .srb_config_list = SRBs, + .transaction_id = new_xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return; + } + LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); LOG_I(NR_RRC, - "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %d)\n", + "UE %d RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %ld)\n", ue_p->rrc_ue_id, ue_p->rnti, - size); + msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_RRCReconfiguration_params(params); + free_byte_array(msg); } -//----------------------------------------------------------------------------- int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int dl_bwp_id, const int ul_bwp_id) { @@ -1123,22 +1086,16 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int *masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id; } - uint8_t buffer[NR_RRC_BUF_SIZE]; - int size = do_RRCReconfiguration(ue_p->rrc_ue_id, - buffer, - NR_RRC_BUF_SIZE, - xid, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - masterCellGroup); - + nr_rrc_reconfig_param_t params = {.cell_group_config = masterCellGroup, .transaction_id = xid}; + byte_array_t msg = do_RRCReconfiguration(¶ms); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id); + return -1; + } const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; - nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, buffer, size); - + nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); + free_byte_array(msg); + free_RRCReconfiguration_params(params); return 0; } @@ -2192,14 +2149,23 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); 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)); + /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key + * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection reestablishment + * in NR, do not re-establish PDCP */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, true, true); + params.transaction_id = xid; + + byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + if (msg.len <= 0) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // 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); + UE->ho_context->target->ho_req_ack(rrc, UE, msg.buf, msg.len); } } From d18830f359cb8bdfd96ad47db5a75b09fd845d52 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 1 Apr 2025 09:32:35 +0200 Subject: [PATCH 057/100] Enable PDCP re-establishment for SRB1/SRB2 based on bitmap in createSRBlist This is necessary because the function was re-establishing PDCP only for SRB2 however according to specs 3GPP TS 38.331 RadioBearerConfig, PDCP shall be re-established for SRB1 and/or SRB2 whenever the security key used for the radio bearer changes, with some exceptions for SRB1 (i.e. when resuming an RRC connection, or at the first reconfiguration after RRC connection reestablishment in NR, do not re-establish PDCP for SRB1). * the input param "reestablish" is converted into a bitmap to indicate whether PDCP should be re-established for the SRB1 and/or SRB2. * For convenience the bitmap is 0-based, with index 1 corresponding to SRB1, index 2 to SRB2. This commit is keeping the legacy re-establishment, that is re-establishment of PCDP for SRB2 only. --- openair2/RRC/NR/nr_rrc_proto.h | 3 +++ openair2/RRC/NR/rrc_gNB.c | 36 ++++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 66f9911c8a..fed265b0d6 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -40,6 +40,9 @@ #include "NR_RRCReconfiguration.h" #include "RRC/NR/MESSAGES/asn1_msg.h" +#define SRB1 1 +#define SRB2 2 + void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id); void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp); void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e8c0edf441..9a2039ebef 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -270,12 +270,17 @@ unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP) return tmp; } -/** - * @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages -*/ -static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) +/** @brief Create srb-ToAddModList for RRCSetup and RRCReconfiguration messages + * @param reestablish bitmap to indicates whether PDCP should be re-established + * for the SRB1 and/or SRB2. For convenience the bitmap is 0-based, with index 1 + * corresponding to SRB1, index 2 to SRB2. 3GPP TS 38.331 RadioBearerConfig + * specifies that PDCP shall be re-established whenever the security key used + * for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection + * reestablishment in NR, do not re-establish PDCP) */ +static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish) { - if (!ue->Srb[1].Active) { + if (!ue->Srb[SRB1].Active) { LOG_E(NR_RRC, "Call SRB list while SRB1 doesn't exist\n"); return NULL; } @@ -284,9 +289,11 @@ static NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, bool reestablish) if (ue->Srb[i].Active) { asn1cSequenceAdd(list->list, NR_SRB_ToAddMod_t, srb); srb->srb_Identity = i; - /* Set reestablishPDCP only for SRB2 */ - if (reestablish && i == 2) { + /* Based on the bitmap, set reestablishPDCP for SRB1 and SRB2 */ + if ((i == SRB1 || i == SRB2) && (reestablish & (1 << i))) { asn1cCallocOne(srb->reestablishPDCP, NR_SRB_ToAddMod__reestablishPDCP_true); + } else { + DevAssert(!(reestablish & (1 << i))); } } return list; @@ -558,7 +565,7 @@ void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) /** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, - bool srb_reestablish, + uint8_t srb_reest_bitmap, bool drb_reestablish) { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); @@ -620,8 +627,9 @@ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, UE->measConfig = measconfig; // Re-establish PDCP for SRB2 only - NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reestablish); + NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap); NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); + nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup, .transaction_id = xid, .drb_config_list = DRBs, @@ -662,7 +670,7 @@ static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { /* do not re-establish PDCP for any bearer */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, false, false); + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH; byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params); if (msg.len <= 0) { @@ -1043,8 +1051,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR /* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */ cuup_notify_reestablishment(rrc, ue_p); - /* Create srb-ToAddModList */ - NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, true); + /* Create srb-ToAddModList, 3GPP TS 38.331 RadioBearerConfig: + * do not re-establish PDCP for SRB1, when resuming an RRC connection, + * or at the first reconfiguration after RRC connection reestablishment in NR */ + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only /* Create drb-ToAddModList */ NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true); @@ -2153,7 +2163,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming * an RRC connection, or at the first reconfiguration after RRC connection reestablishment * in NR, do not re-establish PDCP */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, true, true); + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); params.transaction_id = xid; byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); From 60535aae9922790008e60a683166078185e2a8fd Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 19 May 2025 14:36:10 +0200 Subject: [PATCH 058/100] Use get_RRCReconfiguration_params in rrc_gNB_generate_dedicatedRRCReconfiguration --- openair2/RRC/NR/rrc_gNB.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 9a2039ebef..8851901c83 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -697,23 +697,20 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) { int qos_flow_index = 0; - uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); - ue_p->xids[xid] = RRC_PDUSESSION_MODIFY; - - NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); - nr_rrc_reconfig_param_t params = {.drb_config_list = DRBs, .transaction_id = xid}; + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false); + ue_p->xids[params.transaction_id] = RRC_PDUSESSION_MODIFY; for (int i = 0; i < ue_p->nb_of_pdusessions; i++) { rrc_pdu_session_param_t *session = &ue_p->pduSession[i]; // bypass the new and already configured pdu sessions if (session->status >= PDU_SESSION_STATUS_DONE) { - session->xid = xid; + session->xid = params.transaction_id; continue; } if (session->cause.type != NGAP_CAUSE_NOTHING) { // set xid of failure pdu session - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; continue; } @@ -728,7 +725,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t if (j == MAX_DRBS_PER_UE) { ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified}; - session->xid = xid; + session->xid = params.transaction_id; session->status = PDU_SESSION_STATUS_FAILED; session->cause = cause; continue; @@ -753,7 +750,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; session->status = PDU_SESSION_STATUS_FAILED; - session->xid = xid; + session->xid = params.transaction_id; session->cause = cause; continue; } @@ -761,11 +758,7 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t } session->status = PDU_SESSION_STATUS_DONE; - session->xid = xid; - - if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) { - params.dedicated_NAS_msg_list[params.num_nas_msg++] = ue_p->pduSession[i].param.nas_pdu; - } + session->xid = params.transaction_id; } byte_array_t msg = do_RRCReconfiguration(¶ms); @@ -774,11 +767,6 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t return; } LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); - - /* Free all NAS PDUs */ - for (int i = 0; i < ue_p->nb_of_pdusessions; i++) - FREE_AND_ZERO_BYTE_ARRAY(ue_p->pduSession[i].param.nas_pdu); - LOG_I(NR_RRC, "UE %d: Generate RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len); const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration; nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len); From 7fba453329677f087546b975b0ad8a328dde23c3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 11 Apr 2025 15:59:53 +0200 Subject: [PATCH 059/100] Pass byte_array_t to handover acknowledge function The byte_array reference contains the pointer to the encoded RRC buffer to be used in the handover acknowledge callback (e.g. in F1 to trigger RRCReconfiguration) --- openair2/RRC/NR/rrc_gNB.c | 2 +- openair2/RRC/NR/rrc_gNB_mobility.c | 4 ++-- openair2/RRC/NR/rrc_gNB_mobility.h | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8851901c83..a943b0d723 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2163,7 +2163,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance // 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, msg.buf, msg.len); + UE->ho_context->target->ho_req_ack(rrc, UE, msg); } } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 54c0f6f17d..df52a1bf6d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -258,7 +258,7 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ #endif } -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) +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t buffer) { // 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 @@ -266,7 +266,7 @@ static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_ // 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); + rrc_gNB_trigger_reconfiguration_for_handover(rrc, UE, buffer.buf, buffer.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 diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 5046176c1d..e49c8fb344 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -22,6 +22,7 @@ #define RRC_GNB_MOBILITY_H_ #include +#include "common/utils/ds/byte_array.h" /* forward declarations */ typedef struct gNB_RRC_INST_s gNB_RRC_INST; @@ -49,7 +50,7 @@ typedef struct nr_ho_source_cu { } 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_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, byte_array_t msg); 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 From dca7e6c95d212732f0abb4bed508cdaaee8a6888 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 6 May 2025 17:22:07 +0200 Subject: [PATCH 060/100] Rework handover ack callback Inside of passing the RRCReconfiguration buffer, call RRCReconfiguration message generation inside the F1 callback. This will simplify the code in the rrc_CU_process_ue_context_setup_response() function once the N2 handover case is introduced. In rrc_CU_process_ue_context_setup_response(), with presence of the HO context, the HO ACK callback is called only once and depending on the type of HO it will do either RRCReconfiguration for F1 and HandoverCommand for N2. --- openair2/RRC/NR/nr_rrc_proto.h | 4 ++++ openair2/RRC/NR/rrc_gNB.c | 28 +++------------------------- openair2/RRC/NR/rrc_gNB_mobility.c | 17 +++++++++++++---- openair2/RRC/NR/rrc_gNB_mobility.h | 2 +- 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index fed265b0d6..3a4fed6411 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -118,6 +118,10 @@ void rrc_gNB_generate_UeContextModificationRequest(const gNB_RRC_INST *rrc, void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params); +byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params); + +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish); + 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); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index a943b0d723..2fd479da91 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -563,10 +563,7 @@ void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) } /** @brief Prepare the instance of RRCReconfigurationParams to be pass to RRC encoding */ -static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, - gNB_RRC_UE_t *UE, - uint8_t srb_reest_bitmap, - bool drb_reestablish) +nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish) { uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id); nr_rrc_du_container_t *du = get_du_for_ue(rrc, UE->rrc_ue_id); @@ -656,7 +653,7 @@ static nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, return params; } -static byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) +byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, nr_rrc_reconfig_param_t params) { byte_array_t msg = do_RRCReconfiguration(¶ms); if (msg.len <= 0) { @@ -2144,26 +2141,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance 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(rrc->module_id); - UE->xids[xid] = RRC_DEDICATED_RECONF; - /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key - * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming - * an RRC connection, or at the first reconfiguration after RRC connection reestablishment - * in NR, do not re-establish PDCP */ - nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); - params.transaction_id = xid; - - byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); - if (msg.len <= 0) { - LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); - return; - } - - // 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, msg); + UE->ho_context->target->ho_req_ack(rrc, UE); } } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index df52a1bf6d..647f253989 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -258,11 +258,20 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_ #endif } -static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, byte_array_t buffer) +static void nr_rrc_f1_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE) { - // 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 + /* 3GPP TS 38.331 specifies that PDCP shall be re-established whenever the security key + * used for the radio bearer changes, with some expections for SRB1 (i.e. when resuming + * an RRC connection, or at the first reconfiguration after RRC connection reestablishment + * in NR, do not re-establish PDCP */ + nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, UE, (1 << SRB2), true); + UE->xids[params.transaction_id] = RRC_DEDICATED_RECONF; + byte_array_t buffer = rrc_gNB_encode_RRCReconfiguration(rrc, UE, params); + free_RRCReconfiguration_params(params); + if (!buffer.len) { + LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", UE->rrc_ue_id); + return; + } // F1 HO: handling of "source CU" information DevAssert(UE->ho_context->source != NULL); diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index e49c8fb344..6e9bcbcfe6 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -50,7 +50,7 @@ typedef struct nr_ho_source_cu { } 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, byte_array_t msg); +typedef void (*ho_req_ack_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); 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 From 70239c086c0f1269673e1ebde430ce29ad881534 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 16:41:46 +0200 Subject: [PATCH 061/100] Fix memory leak in fill_measurement_configuration seq_arr_push_back is doing a memcpy so locally allocated memory can be freed after. Allocate in stack. > Direct leak of 64 byte(s) in 2 object(s) allocated from: > #0 0x7ec4bb8b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x55895aae1b1f in fill_measurement_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2015 > #2 0x55895aae1b1f in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2112 > #3 0x55895a246112 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x55895a246112 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7ec4ba229d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..152e87bd20 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -2020,22 +2020,21 @@ static void fill_measurement_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc) measurementConfig->a3_event_list = malloc(sizeof(seq_arr_t)); seq_arr_init(measurementConfig->a3_event_list, sizeof(nr_a3_event_t)); for (int i = 0; i < A3_EventList.numelt; i++) { - nr_a3_event_t *a3_event = (nr_a3_event_t *)calloc(1, sizeof(nr_a3_event_t)); - AssertFatal(a3_event != NULL, "out of memory\n"); - a3_event->pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; - AssertFatal(a3_event->pci >= -1 && a3_event->pci < 1024, + nr_a3_event_t a3_event = {0}; + a3_event.pci = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_PCI_ID_IDX].i64ptr; + AssertFatal(a3_event.pci >= -1 && a3_event.pci < 1024, "entry %s.%s must be -1<=PCI<1024, but is %d\n", measurement_path, MEASUREMENT_EVENTS_PCI_ID, - a3_event->pci); - a3_event->timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; - a3_event->a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; - a3_event->hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; + a3_event.pci); + a3_event.timeToTrigger = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_TIMETOTRIGGER_IDX].i64ptr; + a3_event.a3_offset = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_OFFSET_IDX].i64ptr; + a3_event.hysteresis = *A3_EventList.paramarray[i][MEASUREMENT_EVENTS_HYSTERESIS_IDX].i64ptr; - if (a3_event->pci == -1) + if (a3_event.pci == -1) measurementConfig->is_default_a3_configuration_exists = true; - seq_arr_push_back(measurementConfig->a3_event_list, a3_event, sizeof(nr_a3_event_t)); + seq_arr_push_back(measurementConfig->a3_event_list, &a3_event, sizeof(nr_a3_event_t)); } } From abcc00945e3433b67a5c81235e8ee2d683cbcc2d Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:27:51 +0200 Subject: [PATCH 062/100] Fix memory leak in fill_neighbour_cell_configuration the dynamically allocated memory is pushed to the seq_arr that is doing a memcpy, so it can be either or better allocated in the stack instead > Direct leak of 48 byte(s) in 1 object(s) allocated from: > #0 0x7d4c934b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x577622a40137 in fill_neighbour_cell_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:1933 > #2 0x577622a40137 in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2109 > #3 0x5776221a30f2 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x5776221a30f2 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7d4c91e29d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 152e87bd20..8123f65dff 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1938,14 +1938,13 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!"); seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_gnb_configuration_t *neighbourCell = calloc(1, sizeof(nr_neighbour_gnb_configuration_t)); - AssertFatal(neighbourCell != NULL, "out of memory\n"); - neighbourCell->gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); - neighbourCell->nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); - neighbourCell->physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; - neighbourCell->subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; - neighbourCell->absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; - neighbourCell->tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; + nr_neighbour_gnb_configuration_t neighbourCell = {0}; + neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); + neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); + neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; + neighbourCell.subcarrierSpacing = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_SCS_IDX].uptr; + neighbourCell.absoluteFrequencySSB = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_ABS_FREQ_SSB_IDX].i64ptr; + neighbourCell.tac = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_TAC_IDX].uptr; char neighbour_plmn_path[CONFIG_MAXOPTLENGTH]; snprintf(neighbour_plmn_path, @@ -1957,10 +1956,10 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNB_CONFIG_STRING_NEIGHBOUR_PLMN); GET_PARAMS(NeighbourPlmn, GNBPLMNPARAMS_DESC, neighbour_plmn_path); - neighbourCell->plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; - neighbourCell->plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; - neighbourCell->plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell->neighbour_cells, neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); + neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; + neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; + neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; + seq_arr_push_back(cell->neighbour_cells, &neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); } seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t)); From 12d9e1f11675ef76bce45fc40cd2a70bd7fa841a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:49:47 +0200 Subject: [PATCH 063/100] Fix memory leak in fill_neighbour_cell_configuration dynamically allocated memory is pushed to the seq_arr that is doing a memcpy, so it can be either or better allocated in the stack instead > Direct leak of 16 byte(s) in 1 object(s) allocated from: > #0 0x7efd8f6b4a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154 > #1 0x577888f3457e in fill_neighbour_cell_configuration /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:1914 > #2 0x577888f3457e in RCconfig_NRRRC /openairinterface5g/n2-handover-preparation/openair2/GNB_APP/gnb_config.c:2108 > #3 0x57788869a0d2 in create_gNB_tasks /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:253 > #4 0x57788869a0d2 in main /openairinterface5g/n2-handover-preparation/executables/nr-softmodem.c:619 > #5 0x7efd8e029d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 --- openair2/GNB_APP/gnb_config.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 8123f65dff..d243421d2a 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1919,9 +1919,8 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc seq_arr_init(rrc->neighbour_cell_configuration, sizeof(neighbour_cell_configuration_t)); for (int elm = 0; elm < neighbour_list_param_list.numelt; ++elm) { - neighbour_cell_configuration_t *cell = calloc(1, sizeof(neighbour_cell_configuration_t)); - AssertFatal(cell != NULL, "out of memory\n"); - cell->nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; + neighbour_cell_configuration_t cell = {0}; + cell.nr_cell_id = (uint64_t)*neighbour_list_param_list.paramarray[elm][0].u64ptr; char neighbourpath[MAX_OPTNAME_SIZE + 8]; snprintf(neighbourpath, sizeof(neighbourpath), "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, gnb_idx, GNB_CONFIG_STRING_NEIGHBOUR_LIST, elm); @@ -1930,13 +1929,12 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc GNBNEIGHBOURCELLPARAMS_DESC, GNB_CONFIG_STRING_NEIGHBOUR_CELL_LIST, neighbourpath); - LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell->nr_cell_id, NeighbourCellParamList.numelt); + LOG_D(GNB_APP, "HO LOG: For the Cell: %ld Neighbour Cell ELM NUM: %d\n", cell.nr_cell_id, NeighbourCellParamList.numelt); if (NeighbourCellParamList.numelt < 1) continue; - cell->neighbour_cells = malloc(sizeof(seq_arr_t)); - AssertFatal(cell->neighbour_cells != NULL, "Memory exhausted!!!"); - seq_arr_init(cell->neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); + cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); + seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { nr_neighbour_gnb_configuration_t neighbourCell = {0}; neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); @@ -1959,10 +1957,9 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc neighbourCell.plmn.mcc = *NeighbourPlmn[GNB_MOBILE_COUNTRY_CODE_IDX].uptr; neighbourCell.plmn.mnc = *NeighbourPlmn[GNB_MOBILE_NETWORK_CODE_IDX].uptr; neighbourCell.plmn.mnc_digit_length = *NeighbourPlmn[GNB_MNC_DIGIT_LENGTH].uptr; - seq_arr_push_back(cell->neighbour_cells, &neighbourCell, sizeof(nr_neighbour_gnb_configuration_t)); + seq_arr_push_back(cell.neighbour_cells, &neighbourCell, sizeof(neighbourCell)); } - - seq_arr_push_back(rrc->neighbour_cell_configuration, cell, sizeof(neighbour_cell_configuration_t)); + seq_arr_push_back(rrc->neighbour_cell_configuration, &cell, sizeof(cell)); } void *base = seq_arr_front(rrc->neighbour_cell_configuration); size_t nmemb = seq_arr_size(rrc->neighbour_cell_configuration); From 114f833a7740103004756821c18c938ff905370a Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 5 May 2025 17:58:19 +0200 Subject: [PATCH 064/100] Fix memory leak in createSRBlist ASN_SEQUENCE_ADD is calling realloc which is allocating memory for the 'array' which was not freed. > Direct leak of 32 byte(s) in 1 object(s) allocated from: > #0 0x7ce97deb4c38 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164 > #1 0x5813fba02574 in asn_set_add /openairinterface5g/n2-handover-preparation/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/asn_SET_OF.c:27 > #2 0x5813faf6c672 in createSRBlist /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:331 > #3 0x5813faf9aa78 in rrc_gNB_generate_RRCSetup /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:421 > #4 0x5813fafba2ee in rrc_handle_RRCSetupRequest /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1243 > #5 0x5813fafba2ee in rrc_gNB_process_initial_ul_rrc_message /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2019 > #6 0x5813fafcdc3a in rrc_gnb_task /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2761 > #7 0x7ce97c894ac2 in start_thread nptl/pthread_create.c:442 > Direct leak of 32 byte(s) in 1 object(s) allocated from: > #0 0x7ce97deb4c38 in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:164 > #1 0x5813fba02574 in asn_set_add /openairinterface5g/n2-handover-preparation/cmake_targets/ran_build/build/openair2/RRC/LTE/MESSAGES/asn_SET_OF.c:27 > #2 0x5813faf6c672 in createSRBlist /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:331 > #3 0x5813faf7d89d in get_RRCReconfiguration_params /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:660 > #4 0x5813faf914b3 in rrc_gNB_generate_dedicatedRRCReconfiguration /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:716 > #5 0x5813faf96856 in rrc_CU_process_ue_context_setup_response /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2190 > #6 0x5813fafcd3ed in rrc_gnb_task /openairinterface5g/n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2796 > #7 0x7ce97c894ac2 in start_thread nptl/pthread_create.c:442 --- openair2/RRC/NR/rrc_gNB.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2fd479da91..ba324f4bad 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -322,12 +322,7 @@ static NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish) static void freeSRBlist(NR_SRB_ToAddModList_t *l) { - if (l) { - for (int i = 0; i < l->list.count; i++) - free(l->list.array[i]); - free(l); - } else - LOG_E(NR_RRC, "Call free SRB list on NULL pointer\n"); + ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, l); } static void activate_srb(gNB_RRC_UE_t *UE, int srb_id) From a06457bab62db2705d7e88c9113aad99ecbb48d9 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Thu, 5 Jun 2025 11:25:38 +0200 Subject: [PATCH 065/100] Fix direct leak in rrc_gNB_send_NGAP_NAS_FIRST_REQ Free memory allocated in NGAP after use in RRC. Direct leak of 29 byte(s) in 1 object(s) allocated from: > #0 0x7f11200b4887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145 > #1 0x558b7fcd0137 in malloc_or_fail /n2-handover-preparation/common/utils/utils.h:86 > #2 0x558b7fcd0137 in create_byte_array /n2-handover-preparation/common/utils/ds/byte_array.c:32 > #3 0x558b7fdb7a5c in rrc_gNB_send_NGAP_NAS_FIRST_REQ /n2-handover-preparation/openair2/RRC/NR/rrc_gNB_NGAP.c:183 > #4 0x558b7fd2ab30 in rrc_gNB_process_RRCSetupComplete /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:439 > #5 0x558b7fd2ab30 in handle_rrcSetupComplete /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1715 > #6 0x558b7fd63e23 in rrc_gNB_decode_dcch /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:1851 > #7 0x558b7fd8b4c3 in rrc_gnb_task /n2-handover-preparation/openair2/RRC/NR/rrc_gNB.c:2718 > #8 0x7f111ea94ac2 in start_thread nptl/pthread_create.c:442 --- openair3/NGAP/ngap_gNB.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 488345261d..ae8d806e18 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -313,6 +313,7 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { case NGAP_NAS_FIRST_REQ: ngap_gNB_handle_nas_first_req(instance, &NGAP_NAS_FIRST_REQ(received_msg)); + free_byte_array(NGAP_NAS_FIRST_REQ(received_msg).nas_pdu); break; case NGAP_UPLINK_NAS: From 90230078b40f2fe869b396c51b44bdcb60b5a160 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 9 Jun 2025 12:22:11 +0200 Subject: [PATCH 066/100] Select AMF by PLMN ID when no other ue_identity.presenceMask is present and/or matching The mask could be present, .e.g not zero, but the selection of the AMF could fail. This would lead to a skipping the selection of the AMF by PLMN ID, which is the last option when no UE identity is present and/or matching. --- openair3/NGAP/ngap_gNB_nas_procedures.c | 30 +++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/openair3/NGAP/ngap_gNB_nas_procedures.c b/openair3/NGAP/ngap_gNB_nas_procedures.c index 7729ffa4f2..96b33c332e 100644 --- a/openair3/NGAP/ngap_gNB_nas_procedures.c +++ b/openair3/NGAP/ngap_gNB_nas_procedures.c @@ -122,24 +122,26 @@ static ngap_gNB_amf_data_t *select_amf(ngap_gNB_instance_t *instance_p, const ng } // No UE identity (5G-S-TMSI or GUAMI) is present - if (msg->ue_identity.presenceMask == 0) { - // Select the AMF based on the selected PLMN identity received through RRCSetupComplete - amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn); + // Select the AMF based on the selected PLMN identity received through RRCSetupComplete + amf = ngap_gNB_nnsf_select_amf_by_plmn_id(instance_p, msg->establishment_cause, msg->plmn); + if (amf) { + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC=%03d MNC=%0*d\n", + msg->gNB_ue_ngap_id, + amf->amf_name, + amf->assoc_id, + msg->plmn.mcc, + msg->plmn.mnc_digit_length, + msg->plmn.mnc); + return amf; + } else { + // Select the AMF with the highest capacity + amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through selected PLMN MCC %d MNC %d\n", + NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, - amf->assoc_id, - msg->plmn.mcc, - msg->plmn.mnc); + amf->assoc_id); return amf; - } else { - // Select the AMF with the highest capacity - amf = ngap_gNB_nnsf_select_amf(instance_p, msg->establishment_cause); - if (amf) { - NGAP_INFO("UE %d: Chose AMF '%s' (assoc_id %d) through highest relative capacity\n", msg->gNB_ue_ngap_id, amf->amf_name, amf->assoc_id); - return amf; - } } } From f5f61162ff5eb334954b4ab95aac41f7901640f1 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 9 Jun 2025 12:25:11 +0200 Subject: [PATCH 067/100] Add mismatch warning in AMF selection utility functions --- openair3/NGAP/ngap_gNB_nnsf.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openair3/NGAP/ngap_gNB_nnsf.c b/openair3/NGAP/ngap_gNB_nnsf.c index 77cc7866e1..f895737a0d 100644 --- a/openair3/NGAP/ngap_gNB_nnsf.c +++ b/openair3/NGAP/ngap_gNB_nnsf.c @@ -30,6 +30,7 @@ #include "ngap_gNB_nnsf.h" #include #include "ngap_gNB_defs.h" +#include "ngap_common.h" #include "queue.h" #include "tree.h" @@ -222,6 +223,12 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_amf_setid(ngap_gNB_instance_t * } } + NGAP_WARN("No matching AMF found for PLMN (MCC=%03d MNC=%0*d) and AMF SetID=%u\n", + selected_plmn_identity.mcc, + selected_plmn_identity.mnc_digit_length, + selected_plmn_identity.mnc, + amf_setid); + /* At this point no AMF matches the selected PLMN and AMF code. In this case, * return NULL. That way the RRC layer should know about it and reject RRC * connectivity. */ @@ -314,6 +321,14 @@ ngap_gNB_amf_data_t *ngap_gNB_nnsf_select_amf_by_guami(ngap_gNB_instance_t *inst } } + NGAP_WARN("No matching AMF found for GUAMI (MCC=%03d MNC=%0*d RegionID=%d SetID=%d Pointer=%d)\n", + guami.mcc, + guami.mnc_len, + guami.mnc, + guami.amf_region_id, + guami.amf_set_id, + guami.amf_pointer); + /* At this point no AMF matches the provided GUAMI. In this case, return * NULL. That way the RRC layer should know about it and reject RRC * connectivity. */ From 03b6e32fdbfcc94d38070eaced42101d45f04278 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 10 Jun 2025 10:47:11 +0200 Subject: [PATCH 068/100] Rename nr_neighbour_gnb_configuration_t to nr_neighbour_cell_t for clarity --- openair2/GNB_APP/gnb_config.c | 4 ++-- openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 10 +++++----- openair2/RRC/NR/rrc_gNB_du.c | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d243421d2a..a2112d46eb 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1934,9 +1934,9 @@ static void fill_neighbour_cell_configuration(uint8_t gnb_idx, gNB_RRC_INST *rrc continue; cell.neighbour_cells = malloc_or_fail(sizeof(seq_arr_t)); - seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_gnb_configuration_t)); + seq_arr_init(cell.neighbour_cells, sizeof(nr_neighbour_cell_t)); for (int l = 0; l < NeighbourCellParamList.numelt; ++l) { - nr_neighbour_gnb_configuration_t neighbourCell = {0}; + nr_neighbour_cell_t neighbourCell = {0}; neighbourCell.gNB_ID = *(NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_GNB_ID_IDX].uptr); neighbourCell.nrcell_id = (uint64_t) * (NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_NR_CELLID_IDX].u64ptr); neighbourCell.physicalCellId = *NeighbourCellParamList.paramarray[l][GNB_CONFIG_N_CELL_PHYSICAL_ID_IDX].uptr; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7e0789c4ad..640803af2f 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -301,7 +301,7 @@ typedef struct { plmn_identity_t plmn; uint32_t tac; bool isIntraFrequencyNeighbour; -} nr_neighbour_gnb_configuration_t; +} nr_neighbour_cell_t; typedef struct neighbour_cell_configuration_s { uint64_t nr_cell_id; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index ba324f4bad..f69e03b810 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -150,18 +150,18 @@ const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_IN static bool eq_pci(const void *vval, const void *vit) { const int *pci = (const int *)vval; - const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)vit; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)vit; return neighbour->physicalCellId == *pci; } -const nr_neighbour_gnb_configuration_t *get_neighbour_gnb_by_pci(const neighbour_cell_configuration_t *cell, int pci) +const nr_neighbour_cell_t *get_neighbour_cell_by_pci(const neighbour_cell_configuration_t *cell, int pci) { seq_arr_t *head = cell->neighbour_cells; DevAssert(head != NULL); LOG_D(NR_RRC, "Number of neighbour cells: %ld\n", head->size); elm_arr_t e = find_if(head, &pci, eq_pci); if (e.found) { - const nr_neighbour_gnb_configuration_t *neighbour = (const nr_neighbour_gnb_configuration_t *)e.it; + const nr_neighbour_cell_t *neighbour = (const nr_neighbour_cell_t *)e.it; LOG_D(NR_RRC, "Found matching neighbour cell with PCI %d and Cell ID %ld\n", neighbour->physicalCellId, neighbour->nrcell_id); return neighbour; } @@ -593,7 +593,7 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC LOG_D(NR_RRC, "HO LOG: Preparing A3 Event Measurement Configuration!\n"); bool is_default_a3_added = false; for (int i = 0; i < neighbour_cells->size; i++) { - nr_neighbour_gnb_configuration_t *neighbourCell = (nr_neighbour_gnb_configuration_t *)seq_arr_at(neighbour_cells, i); + nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i); if (!neighbourCell->isIntraFrequencyNeighbour) continue; seq_arr_push_back(pci_seq, &neighbourCell->physicalCellId, sizeof(int)); @@ -1401,7 +1401,7 @@ static void process_Event_Based_Measurement_Report(gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *neigh_cell = get_cell_information_by_phycellId(neighbour_pci); const f1ap_served_cell_info_t *serving_cell = get_cell_information_by_phycellId(scell_pci); const neighbour_cell_configuration_t *cell = get_neighbour_cell_config(rrc, serving_cell->nr_cellid); - const nr_neighbour_gnb_configuration_t *neighbour = get_neighbour_gnb_by_pci(cell, neighbour_pci); + const nr_neighbour_cell_t *neighbour = get_neighbour_cell_by_pci(cell, neighbour_pci); // CU does not have f1 connection with neighbour cell context. So check does serving cell has this phyCellId as a // neighbour. if (!neigh_cell && neighbour) { diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 9e89766acb..a650a03604 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -202,7 +202,7 @@ const struct f1ap_served_cell_info_t *get_cell_information_by_phycellId(int phyC static void is_intra_frequency_neighbour(void *ssb_arfcn, void *neighbour_cell) { uint32_t *ssb_arfcn_ptr = (uint32_t *)ssb_arfcn; - nr_neighbour_gnb_configuration_t *neighbour_cell_ptr = (nr_neighbour_gnb_configuration_t *)neighbour_cell; + nr_neighbour_cell_t *neighbour_cell_ptr = (nr_neighbour_cell_t *)neighbour_cell; if (*ssb_arfcn_ptr == neighbour_cell_ptr->absoluteFrequencySSB) { LOG_D(NR_RRC, "HO LOG: found intra frequency neighbour %lu!\n", neighbour_cell_ptr->nrcell_id); @@ -237,7 +237,7 @@ static bool valid_du_in_neighbour_configs(const seq_arr_t *neighbour_cell_config for (int c = 0; c < neighbour_cell_configuration->size; c++) { const neighbour_cell_configuration_t *neighbour_config = seq_arr_at(neighbour_cell_configuration, c); for (int ni = 0; ni < neighbour_config->neighbour_cells->size; ni++) { - const nr_neighbour_gnb_configuration_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); + const nr_neighbour_cell_t *nc = seq_arr_at(neighbour_config->neighbour_cells, ni); if (nc->nrcell_id != cell->nr_cellid) continue; // current cell is in the nc config, check that config matches From 83df3c5e79f878c81091f5d26a90357c71fc8231 Mon Sep 17 00:00:00 2001 From: Teodora Date: Fri, 23 May 2025 11:00:06 +0200 Subject: [PATCH 069/100] Add OSC nearRT-RIC J release contribution and xDevSM framework --- openair2/E2AP/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index 43a39f5afd..5644d10cb5 100644 --- a/openair2/E2AP/README.md +++ b/openair2/E2AP/README.md @@ -260,3 +260,10 @@ The same was shown in the following events: * [Joint OSC/OSFG-OAI Workshop](https://openairinterface.org/joint-osc-oai-workshop-end-to-end-open-source-reference-designs-for-o-ran/) In order to reproduce this testbed, please follow the [O-RAN SC nearRT-RIC installation guide](https://lf-o-ran-sc.atlassian.net/wiki/spaces/GS/overview), and the [kpm-rc-xapp](https://github.com/mirazabal/kpm_rc-xapp) xApp used. Please note that we cannot give support for the O-RAN SC nearRT-RIC. + +## 5.2 J release +The OAI E2 Agent has been successfully integrated with the J release of the O-RAN OSC nearRT-RIC, leveraging the xDevSM framework developed by the MMWG at the University of Bologna and the WIoT at Northeastern University. + +xDevSM framework uses KPM SM (`libkpm_sm.so`) and RC SM (`librc_sm.so`) libraries from FlexRIC. Therefore, only E2AP is validated between OAI E2 Agent and OSC nearRT-RIC. + +Please follow [the xDevSM framework tutorial](https://openrangym.com/tutorials/xdevsm-tutorial) in order to reproduce this testbed, and try [the example xApps](https://github.com/wineslab/xDevSM-xapps-examples) built using this framework. From 675e1129b42dd863503a8e25656b5411ac5e45c4 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 9 Dec 2024 10:25:07 +0100 Subject: [PATCH 070/100] using the analog beamforming oai extension fapi fields instead of digital beamforming structure for analog beamforming --- doc/analog_beamforming.md | 2 ++ .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 ++ openair1/PHY/INIT/nr_init.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_dci.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 2 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 2 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 2 +- openair1/PHY/NR_TRANSPORT/srs_rx.c | 2 +- openair1/PHY/defs_gNB.h | 1 - openair1/SCHED_NR/phy_procedures_nr_gNB.c | 8 ++--- openair1/SCHED_NR/sched_nr.h | 2 +- openair2/GNB_APP/gnb_config.c | 2 +- openair2/LAYER2/NR_MAC_gNB/config.c | 34 ++++++++----------- 14 files changed, 31 insertions(+), 35 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 6d9e5bf71c..7943111f72 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -10,6 +10,8 @@ There are three main beamforming techinques: analog, digital and hybrid. The nam The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming. +To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. + # Configuration file fields for analog beamforming A set of parameters in configuration files controls the implementation of analog beamforming and instructs the scheduler on how to behave in such scenarios. Since most notably this technique in 5G is employed in FR2, the configuration file example currently available is a RFsim one for band 261. [Config file example](../ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index a34796eeb3..6ddb376bd3 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -496,6 +496,8 @@ typedef struct { typedef struct { nfapi_uint8_tlv_t num_beams_period_vendor_ext; nfapi_uint8_tlv_t analog_bf_vendor_ext; + nfapi_uint8_tlv_t total_num_beams_vendor_ext; + nfapi_uint8_tlv_t *analog_beam_list; } nfapi_nr_analog_beamforming_ve_t; // ERROR enums diff --git a/openair1/PHY/INIT/nr_init.c b/openair1/PHY/INIT/nr_init.c index d94d2ba493..ca453b6e65 100644 --- a/openair1/PHY/INIT/nr_init.c +++ b/openair1/PHY/INIT/nr_init.c @@ -172,8 +172,7 @@ void phy_init_nr_gNB(PHY_VARS_gNB *gNB) for (int i = 0; i < common_vars->num_beams_period; i++) common_vars->rxdataF[i] = (c16_t **)malloc16(Prx * sizeof(c16_t*)); - common_vars->num_beams = cfg->dbt_config.num_dig_beams; - if (common_vars->num_beams > 0) { + if (cfg->analog_beamforming_ve.analog_bf_vendor_ext.value) { common_vars->beam_id = (int **)malloc16(common_vars->num_beams_period * sizeof(int*)); for (int i = 0; i < common_vars->num_beams_period; i++) common_vars->beam_id[i] = (int*)malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 899432c37a..38a671d50c 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -82,7 +82,7 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index ee93f78e45..7e3d68f282 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -681,7 +681,7 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index a5e6c86e86..b01b35f502 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -86,7 +86,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); prach->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, Slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 84656ba1d0..f63bec4d5b 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -77,7 +77,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index c7dacd7104..a16b68f708 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -74,7 +74,7 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); pucch->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 642095345d..16b92be946 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -60,7 +60,7 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; srs->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.dbt_config, + &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, NR_NUMBER_OF_SYMBOLS_PER_SLOT, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 59d92444d5..d305197554 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -287,7 +287,6 @@ typedef struct { /// - first index: beam index (for concurrent beams) /// - second index: beam_id [0.. symbols_per_frame[ int **beam_id; - int num_beams; int num_beams_period; bool analog_bf; int32_t *debugBuff; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 19fdd4dca8..ca90965ebc 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -46,7 +46,7 @@ //#define SRS_IND_DEBUG int beam_index_allocation(int fapi_beam_index, - nfapi_nr_dbt_pdu_t *dbt_config, + nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, @@ -56,7 +56,7 @@ int beam_index_allocation(int fapi_beam_index, return 0; int idx = -1; - int ru_beam_idx = dbt_config->dig_beam_list[fapi_beam_index].txru_list[0].dig_beam_weight_Re; + int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; for (int j = 0; j < common_vars->num_beams_period; j++) { for (int i = 0; i < symbols_per_slot; i++) { if (((bitmap_symbols >> i) & 0x01) == 0) @@ -138,7 +138,7 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->dbt_config, + &cfg->analog_beamforming_ve, &gNB->common_vars, slot, fp->symbols_per_slot, @@ -280,7 +280,7 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, - &cfg->dbt_config, + &cfg->analog_beamforming_ve, &gNB->common_vars, slot, fp->symbols_per_slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 72d2d96b4c..7450518f19 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -48,7 +48,7 @@ void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); int beam_index_allocation(int fapi_beam_index, - nfapi_nr_dbt_pdu_t *dbt_config, + nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, int symbols_per_slot, diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 70e6c026ca..4b34c3858d 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1572,7 +1572,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) // each beam is described by a set of weights (one for each antenna) // on the other hand in case of analog beamforming an index to the RU beam identifier is provided config.nb_bfw[0] = num_tx; // number of tx antennas - config.nb_bfw[1] = n / num_tx; // number of beams + config.nb_bfw[1] = n; // number of beams weights/indices config.bw_list = malloc16_clear(n * sizeof(*config.bw_list)); for (int b = 0; b < n; b++) { config.bw_list[b] = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].iptr[b]; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 43d48eeeeb..59262c50d9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -715,36 +715,30 @@ static void config_common(gNB_MAC_INST *nrmac, if (cfg->cell_config.frame_duplex_type.value == TDD) set_tdd_config_nr(cfg, fs); - int nb_tx = config->nb_bfw[0]; // number of tx antennas - int nb_beams = config->nb_bfw[1]; // number of beams // precoding matrix configuration (to be improved) cfg->pmi_list = init_DL_MIMO_codebook(nrmac, pdsch_AntennaPorts); - // beamforming matrix configuration - cfg->dbt_config.num_dig_beams = nb_beams; - if (nb_beams > 0) { - cfg->dbt_config.num_txrus = nb_tx; - cfg->dbt_config.dig_beam_list = malloc16(nb_beams * sizeof(*cfg->dbt_config.dig_beam_list)); - AssertFatal(cfg->dbt_config.dig_beam_list, "out of memory\n"); - for (int i = 0; i < nb_beams; i++) { - nfapi_nr_dig_beam_t *beam = &cfg->dbt_config.dig_beam_list[i]; - beam->beam_idx = i; - beam->txru_list = malloc16(nb_tx * sizeof(*beam->txru_list)); - for (int j = 0; j < nb_tx; j++) { - nfapi_nr_txru_t *txru = &beam->txru_list[j]; - txru->dig_beam_weight_Re = config->bw_list[j + i * nb_tx] & 0xffff; - txru->dig_beam_weight_Im = (config->bw_list[j + i * nb_tx] >> 16) & 0xffff; - LOG_D(NR_MAC, "Beam %d Tx %d Weight (%d, %d)\n", i, j, txru->dig_beam_weight_Re, txru->dig_beam_weight_Im); - } - } - } + int nb_beams = config->nb_bfw[1]; // number of beams if (nrmac->beam_info.beam_allocation) { + LOG_I(NR_MAC, "Configuring analog beamforming in config_request message\n"); cfg->analog_beamforming_ve.num_beams_period_vendor_ext.tl.tag = NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.num_beams_period_vendor_ext.value = nrmac->beam_info.beams_per_period; cfg->num_tlv++; cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled cfg->num_tlv++; + //cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = ???; + cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams; + cfg->num_tlv++; + cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list)); + for (int i = 0; i < nb_beams; i++) + cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i]; + } else { + cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled + if (NFAPI_MODE == NFAPI_MONOLITHIC) { + cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; + cfg->num_tlv++; + } } } From f5072833b651e618bed6aa347f94ec6735315714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BAben=20Soares=20Silva?= Date: Mon, 9 Dec 2024 11:36:31 +0000 Subject: [PATCH 071/100] Add pack/unpack functionality for 2 new vendor extension TLVs. Add the ability to pack/unpack 2 new TLVs for analog beamforming total_num_beams_vendor_ext and analog_beam_list Add the unpack related changes for the first 2 vendor extension TLVs introduced related to beamforming. For the moment the packing is guarded by an Assert to ensure it is not used. Add the necessary utility function changes to support these VE TLVs Add the necessary changes to the corresponding unitary test for pack/unpack, commented for the moment, since the packing is disabled with an Assert. --- nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c | 47 +++++++++++++++++++ nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c | 30 ++++++++++++ .../nfapi/public_inc/nfapi_nr_interface.h | 2 + nfapi/tests/p5/nr_fapi_config_request_test.c | 27 +++++++++++ openair2/LAYER2/NR_MAC_gNB/config.c | 6 ++- 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c index 796f424abe..281043b6d3 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5.c @@ -1124,6 +1124,33 @@ uint8_t pack_nr_config_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e // only increase if it was set numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; + AssertFatal(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == 0, + "Total num beams Vendor extension shouldn't be set!"); + // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, + // so, it's safe to add the call to pack_nr_tlv even if it is not always set + retval &= pack_nr_tlv(NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + // only increase if it was set + numTLVs += + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; + + for (int beam = 0; beam < pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value; beam++) { + AssertFatal(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam].tl.tag == 0, + "Analog beams list Vendor extension shouldn't be set!"); + // The call to pack the TLV would be the same as any other TLV, it is only packed if the tag is set, + // so, it's safe to add the call to pack_nr_tlv even if it is not always set + retval &= pack_nr_tlv(NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, + &(pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam]), + ppWritePackedMsg, + end, + &pack_uint8_tlv_value); + // only increase if it was set + numTLVs += pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag == NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; + } + pNfapiMsg->num_tlv = numTLVs; retval &= push8(pNfapiMsg->num_tlv, &pNumTLVFields, end); return retval; @@ -1138,6 +1165,7 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * int config_beam_idx = 0; int tdd_periodicity_idx = 0; int symbol_per_slot_idx = 0; + int beam_ve_idx = 0; nfapi_nr_config_request_scf_t *pNfapiMsg = (nfapi_nr_config_request_scf_t *)msg; // unpack TLVs @@ -1188,6 +1216,10 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_TDD_PERIOD_TAG, &(pNfapiMsg->tdd_table.tdd_period), &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_SLOT_CONFIG_TAG, NULL, &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.num_beams_period_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.analog_bf_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, &(pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext), &unpack_uint8_tlv_value}, + {NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, NULL, &unpack_uint8_tlv_value}, {NFAPI_NR_CONFIG_RSSI_MEASUREMENT_TAG, &(pNfapiMsg->measurement_config.rssi_measurement), &unpack_uint8_tlv_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV4_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv4), &unpack_ipv4_address_value}, {NFAPI_NR_NFAPI_P7_VNF_ADDRESS_IPV6_TAG, &(pNfapiMsg->nfapi_config.p7_vnf_address_ipv6), &unpack_ipv6_address_value}, @@ -1221,6 +1253,21 @@ uint8_t unpack_nr_config_request(uint8_t **ppReadPackedMsg, uint8_t *end, void * } int result = 0; switch (generic_tl.tag) { + case NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG: + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = generic_tl.tag; + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.length = generic_tl.length; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext, ppReadPackedMsg, end); + pNfapiMsg->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( + pNfapiMsg->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + beam_ve_idx = 0; + break; + case NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG: + unpack_fns[idx].tlv = &pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx]; + pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.tag = generic_tl.tag; + pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx].tl.length = generic_tl.length; + result = (*unpack_fns[idx].unpack_func)(&pNfapiMsg->analog_beamforming_ve.analog_beam_list[beam_ve_idx], ppReadPackedMsg, end); + beam_ve_idx ++; + break; case NFAPI_NR_CONFIG_NUM_PRACH_FD_OCCASIONS_TAG: pNfapiMsg->prach_config.num_prach_fd_occasions.tl.tag = generic_tl.tag; pNfapiMsg->prach_config.num_prach_fd_occasions.tl.length = generic_tl.length; diff --git a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c index 4267992d07..1b5e3f0ad8 100644 --- a/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c +++ b/nfapi/open-nFAPI/fapi/src/nr_fapi_p5_utils.c @@ -276,6 +276,17 @@ bool eq_config_request(const nfapi_nr_config_request_scf_t *unpacked_req, const EQ_TLV(unpacked_req->nfapi_config.timing_info_mode, req->nfapi_config.timing_info_mode); EQ_TLV(unpacked_req->nfapi_config.timing_info_period, req->nfapi_config.timing_info_period); + + EQ_TLV(unpacked_req->analog_beamforming_ve.num_beams_period_vendor_ext, req->analog_beamforming_ve.num_beams_period_vendor_ext); + + EQ_TLV(unpacked_req->analog_beamforming_ve.analog_bf_vendor_ext, req->analog_beamforming_ve.analog_bf_vendor_ext); + + EQ_TLV(unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext, req->analog_beamforming_ve.total_num_beams_vendor_ext); + + for (int i = 0; i < unpacked_req->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + EQ_TLV(unpacked_req->analog_beamforming_ve.analog_beam_list[i], req->analog_beamforming_ve.analog_beam_list[i]); + } + return true; } @@ -422,6 +433,10 @@ void free_config_request(nfapi_nr_config_request_scf_t *msg) if (msg->pmi_list.pmi_pdu) { free(msg->pmi_list.pmi_pdu); } + + if (msg->analog_beamforming_ve.analog_beam_list) { + free(msg->analog_beamforming_ve.analog_beam_list); + } } void free_config_response(nfapi_nr_config_response_scf_t *msg) @@ -832,6 +847,21 @@ void copy_config_request(const nfapi_nr_config_request_scf_t *src, nfapi_nr_conf COPY_TLV(dst->nfapi_config.ul_dci_timing_offset, src->nfapi_config.ul_dci_timing_offset); COPY_TLV(dst->nfapi_config.tx_data_timing_offset, src->nfapi_config.tx_data_timing_offset); + + COPY_TLV(dst->analog_beamforming_ve.num_beams_period_vendor_ext, src->analog_beamforming_ve.num_beams_period_vendor_ext); + + COPY_TLV(dst->analog_beamforming_ve.analog_bf_vendor_ext, src->analog_beamforming_ve.analog_bf_vendor_ext); + + COPY_TLV(dst->analog_beamforming_ve.total_num_beams_vendor_ext, src->analog_beamforming_ve.total_num_beams_vendor_ext); + + if (dst->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { + dst->analog_beamforming_ve.analog_beam_list = (nfapi_uint8_tlv_t *)malloc( + dst->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + for (int i = 0; i < src->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + COPY_TLV(dst->analog_beamforming_ve.analog_beam_list[i], src->analog_beamforming_ve.analog_beam_list[i]); + } + } + } void copy_config_response(const nfapi_nr_config_response_scf_t *src, nfapi_nr_config_response_scf_t *dst) diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h index 39e9eca3e0..b7e6577fa2 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface.h @@ -31,6 +31,8 @@ #define NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG 0x0120 #define NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG 0xA000 #define NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG 0xA001 +#define NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG 0xA002 +#define NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG 0xA003 typedef struct { uint16_t phy_id; diff --git a/nfapi/tests/p5/nr_fapi_config_request_test.c b/nfapi/tests/p5/nr_fapi_config_request_test.c index 3b6ae99e94..93ff5b5f3a 100644 --- a/nfapi/tests/p5/nr_fapi_config_request_test.c +++ b/nfapi/tests/p5/nr_fapi_config_request_test.c @@ -229,6 +229,33 @@ static void fill_config_request_tlv_tdd_rand(nfapi_nr_config_request_scf_t *nfap FILL_TLV(nfapi_resp->nfapi_config.timing_info_period, NFAPI_NR_NFAPI_TIMING_INFO_PERIOD_TAG, rand8()); nfapi_resp->num_tlv++; +/* + // TODO: Uncomment this block when ready to enable the pack of the following VE TLVs in nr_fapi_p5.c + // NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG + // NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG + FILL_TLV(nfapi_resp->analog_beamforming_ve.num_beams_period_vendor_ext, + NFAPI_NR_FAPI_NUM_BEAMS_PERIOD_VENDOR_EXTENSION_TAG, + rand8()); + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_bf_vendor_ext, NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG, rand8()); + nfapi_resp->num_tlv++; + + FILL_TLV(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext, + NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG, + rand8()); + nfapi_resp->num_tlv++; + + if (nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value > 0) { + nfapi_resp->analog_beamforming_ve.analog_beam_list = + (nfapi_uint8_tlv_t *)malloc(nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value * sizeof(nfapi_uint8_tlv_t)); + for (int i = 0; i < nfapi_resp->analog_beamforming_ve.total_num_beams_vendor_ext.value; ++i) { + FILL_TLV(nfapi_resp->analog_beamforming_ve.analog_beam_list[i], NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG, rand8()); + nfapi_resp->num_tlv++; + } + }*/ } static void test_pack_unpack(nfapi_nr_config_request_scf_t *req) diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 59262c50d9..f87b4024b9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -727,12 +727,14 @@ static void config_common(gNB_MAC_INST *nrmac, cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 1; // analog BF enabled cfg->num_tlv++; - //cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = ???; + cfg->analog_beamforming_ve.total_num_beams_vendor_ext.tl.tag = NFAPI_NR_FAPI_TOTAL_NUM_BEAMS_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.total_num_beams_vendor_ext.value = nb_beams; cfg->num_tlv++; cfg->analog_beamforming_ve.analog_beam_list = malloc16(nb_beams * sizeof(*cfg->analog_beamforming_ve.analog_beam_list)); - for (int i = 0; i < nb_beams; i++) + for (int i = 0; i < nb_beams; i++) { + cfg->analog_beamforming_ve.analog_beam_list[i].tl.tag = NFAPI_NR_FAPI_ANALOG_BEAM_VENDOR_EXTENSION_TAG; cfg->analog_beamforming_ve.analog_beam_list[i].value = config->bw_list[i]; + } } else { cfg->analog_beamforming_ve.analog_bf_vendor_ext.value = 0; // analog BF disabled if (NFAPI_MODE == NFAPI_MONOLITHIC) { From 038247f0743e2a5b86e963470a6fdbc73b09907f Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 Dec 2024 16:13:21 +0100 Subject: [PATCH 072/100] RU analog beam management (not for 7.2) --- executables/nr-gnb.c | 9 +- executables/nr-ru.c | 17 ++- openair1/PHY/INIT/nr_init_ru.c | 40 +++--- openair1/PHY/NR_TRANSPORT/nr_prach.c | 10 +- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 8 +- openair1/PHY/defs_RU.h | 5 + openair1/SCHED_NR/fapi_nr_l1.c | 4 +- openair1/SCHED_NR/nr_ru_procedures.c | 123 +++++++++--------- openair1/SIMULATION/NR_PHY/prachsim.c | 2 +- 9 files changed, 115 insertions(+), 103 deletions(-) diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 24b835d419..acab30751b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -360,7 +360,6 @@ void term_gNB_Tpool(int inst) { } /// eNB kept in function name for nffapi calls, TO FIX - void init_eNB_afterRU(void) { for (int inst = 0; inst < RC.nb_nr_L1_inst; inst++) { @@ -371,17 +370,17 @@ void init_eNB_afterRU(void) if (0) AssertFatal(gNB->num_RU>0,"Number of RU attached to gNB %d is zero\n",gNB->Mod_id); LOG_D(NR_PHY, "Mapping RX ports from %d RUs to gNB %d\n", gNB->num_RU, gNB->Mod_id); - int aa = 0; for (int ru_id = 0; ru_id < gNB->num_RU; ru_id++) { AssertFatal(gNB->RU_list[ru_id]->common.rxdataF != NULL, "RU %d : common.rxdataF is NULL\n", gNB->RU_list[ru_id]->idx); AssertFatal(gNB->RU_list[ru_id]->prach_rxsigF != NULL, "RU %d : prach_rxsigF is NULL\n", gNB->RU_list[ru_id]->idx); - for (int i = 0; i < gNB->RU_list[ru_id]->nb_rx; aa++, i++) { LOG_I(PHY,"Attaching RU %d antenna %d to gNB antenna %d\n", gNB->RU_list[ru_id]->idx, i, aa); gNB->prach_vars.rxsigF[aa] = gNB->RU_list[ru_id]->prach_rxsigF[0][i]; - // TODO hardcoded beam to 0, still need to understand how to handle this properly - gNB->common_vars.rxdataF[0][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[i]; + for (int b = 0; b < gNB->RU_list[ru_id]->num_beams_period; b++) { + int idx = i + b * gNB->RU_list[ru_id]->nb_rx; + gNB->common_vars.rxdataF[b][aa] = (c16_t *)gNB->RU_list[ru_id]->common.rxdataF[idx]; + } } } /* TODO: review this code, there is something wrong. diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 0ae303b4e8..a8ef32485f 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -591,12 +591,13 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) RU_proc_t *proc = &ru->proc; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; openair0_config_t *cfg = &ru->openair0_cfg; - uint32_t samples_per_slot = fp->get_samples_per_slot(*slot,fp); + uint32_t samples_per_slot = fp->get_samples_per_slot(*slot, fp); AssertFatal(*slot < fp->slots_per_frame && *slot >= 0, "slot %d is illegal (%d)\n", *slot, fp->slots_per_frame); start_meas(&ru->rx_fhaul); - void *rxp[ru->nb_rx]; - for (int i = 0; i < ru->nb_rx; i++) + int nb = ru->nb_rx * ru->num_beams_period; + void *rxp[nb]; + for (int i = 0; i < nb; i++) rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot, fp, 0)]; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 1); @@ -611,7 +612,7 @@ static void rx_rf(RU_t *ru, int *frame, int *slot) rxs = samples_per_slot; ts = old_ts + rxs; } else { - rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, ru->nb_rx); + rxs = ru->rfdevice.trx_read_func(&ru->rfdevice, &ts, rxp, samples_per_slot, nb); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); @@ -812,8 +813,9 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_FRAME_NUMBER_TX0_RU, frame); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TTI_NUMBER_TX0_RU, slot); - void *txp[ru->nb_tx]; - for (int i = 0; i < ru->nb_tx; i++) + int nt = ru->nb_tx * ru->num_beams_period; + void *txp[nt]; + for (int i = 0; i < nt; i++) txp[i] = (void *)&ru->common.txdata[i][fp->get_samples_slot_timestamp(slot, fp, 0)] - sf_extension * sizeof(int32_t); VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_TRX_TST, (timestamp + ru->ts_offset) & 0xffffffff); @@ -823,7 +825,7 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) timestamp + ru->ts_offset - sf_extension, txp, siglen + sf_extension, - ru->nb_tx, + nt, flags); LOG_D(PHY, "[TXPATH] RU %d tx_rf, writing to TS %llu, %d.%d, unwrapped_frame %d, slot %d, flags %d, siglen+sf_extension %d, " @@ -1321,6 +1323,7 @@ void *ru_thread(void *param) rx_nr_prach_ru(ru, p->fmt, // could also use format p->numRA, + p->beam, prachStartSymbol, p->slot, prach_oc, diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 93964f3ee9..49d3890a0b 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -47,17 +47,21 @@ void nr_phy_init_RU(RU_t *ru) AssertFatal(ru->nb_log_antennas > 0 && ru->nb_log_antennas < 13, "ru->nb_log_antennas %d ! \n",ru->nb_log_antennas); - ru->common.beam_id = malloc16_clear(MAX_NUM_BEAM_PERIODS * sizeof(int*)); - for(int i = 0; i < MAX_NUM_BEAM_PERIODS; i++) + nfapi_nr_analog_beamforming_ve_t *analog_config = &cfg->analog_beamforming_ve; + ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1; + int nb_tx_streams = ru->nb_tx * ru->num_beams_period; + int nb_rx_streams = ru->nb_rx * ru->num_beams_period; + + ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*)); + for(int i = 0; i < ru->num_beams_period; i++) ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so allocate memory for time-domain signals // Time-domain signals - ru->common.txdata = (int32_t**)malloc16(ru->nb_tx * sizeof(int32_t*)); - ru->common.rxdata = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); + ru->common.txdata = (int32_t**)malloc16(nb_tx_streams * sizeof(int32_t*)); + ru->common.rxdata = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*)); - - for (int i = 0; i < ru->nb_tx; i++) { + for (int i = 0; i < nb_tx_streams; i++) { // Allocate 10 subframes of I/Q TX signal data (time) if not ru->common.txdata[i] = (int32_t*)malloc16_clear((ru->sf_extension + fp->samples_per_frame) * sizeof(int32_t)); LOG_D(PHY, @@ -70,7 +74,7 @@ void nr_phy_init_RU(RU_t *ru) LOG_D(PHY, "[INIT] common.txdata[%d] = %p \n", i, ru->common.txdata[i]); } - for (int i = 0; i < ru->nb_rx; i++) { + for (int i = 0; i < nb_rx_streams; i++) { ru->common.rxdata[i] = (int32_t*)malloc16_clear(fp->samples_per_frame * sizeof(int32_t)); } } // IF5 or local RF @@ -93,15 +97,15 @@ void nr_phy_init_RU(RU_t *ru) ru->common.txdataF[i] = (int32_t*)malloc16_clear(fp->samples_per_frame_wCP * sizeof(int32_t)); // allocate IFFT input buffers (TX) - ru->common.txdataF_BF = (int32_t **)malloc16(ru->nb_tx*sizeof(int32_t*)); - LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, ru->nb_tx * sizeof(int32_t *)); - for (int i = 0; i < ru->nb_tx; i++) { + ru->common.txdataF_BF = (int32_t **)malloc16(nb_tx_streams * sizeof(int32_t*)); + LOG_D(PHY, "[INIT] common.txdata_BF= %p (%lu bytes)\n", ru->common.txdataF_BF, nb_tx_streams * sizeof(int32_t *)); + for (int i = 0; i < nb_tx_streams; i++) { ru->common.txdataF_BF[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP * sizeof(int32_t)); LOG_D(PHY, "txdataF_BF[%d] %p for RU %d\n", i, ru->common.txdataF_BF[i], ru->idx); } // allocate FFT output buffers (RX) - ru->common.rxdataF = (int32_t**)malloc16(ru->nb_rx * sizeof(int32_t*)); - for (int i = 0; i < ru->nb_rx; i++) { + ru->common.rxdataF = (int32_t**)malloc16(nb_rx_streams * sizeof(int32_t*)); + for (int i = 0; i < nb_rx_streams; i++) { // allocate 4 slots of I/Q signal data (frequency) int size = RU_RX_SLOT_DEPTH * fp->symbols_per_slot * fp->ofdm_symbol_size; ru->common.rxdataF[i] = (int32_t*)malloc16_clear(sizeof(**ru->common.rxdataF) * size); @@ -132,16 +136,18 @@ void nr_phy_init_RU(RU_t *ru) void nr_phy_free_RU(RU_t *ru) { LOG_D(PHY, "Freeing RU signal buffers (if_south %s) nb_tx %d\n", ru_if_types[ru->if_south], ru->nb_tx); + int nb_tx_streams = ru->nb_tx * ru->num_beams_period; + int nb_rx_streams = ru->nb_rx * ru->num_beams_period; if (ru->if_south <= REMOTE_IF5) { // this means REMOTE_IF5 or LOCAL_RF, so free memory for time-domain signals // Hack: undo what is done at allocation - for (int i = 0; i < ru->nb_tx; i++) { + for (int i = 0; i < nb_tx_streams; i++) { int32_t *p = &ru->common.txdata[i][-ru->sf_extension]; free_and_zero(p); } free_and_zero(ru->common.txdata); - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->common.rxdata[i]); free_and_zero(ru->common.rxdata); } // else: IF5 or local RF -> nothing to free() @@ -157,12 +163,12 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.txdataF); // free IFFT input buffers (TX) - for (int i = 0; i < ru->nb_tx; i++) + for (int i = 0; i < nb_tx_streams; i++) free_and_zero(ru->common.txdataF_BF[i]); free_and_zero(ru->common.txdataF_BF); // free FFT output buffers (RX) - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->common.rxdataF[i]); free_and_zero(ru->common.rxdataF); @@ -171,7 +177,7 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->prach_rxsigF[j][i]); free_and_zero(ru->prach_rxsigF[j]); } - for(int i = 0; i < MAX_NUM_BEAM_PERIODS; ++i) + for(int i = 0; i < ru->num_beams_period; ++i) free_and_zero(ru->common.beam_id[i]); free_and_zero(ru->common.beam_id); } diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index b01b35f502..ed90a3e318 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -70,7 +70,7 @@ int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { return -1; } -void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) { int prach_id = find_nr_prach(gNB, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)), "illegal or no prach_id found!!! prach_id %d\n", prach_id); @@ -94,6 +94,7 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); + return prach_id; } void init_prach_ru_list(RU_t *ru) @@ -126,7 +127,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) return -1; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu) +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), @@ -140,6 +141,7 @@ void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_p ru->prach_list[prach_id].num_slots = (fmt < 4) ? get_long_prach_dur(fmt, ru->nr_frame_parms->numerology_index) : 1; ru->prach_list[prach_id].fmt = fmt; ru->prach_list[prach_id].numRA = prach_pdu->num_ra; + ru->prach_list[prach_id].beam = beam_id; ru->prach_list[prach_id].prachStartSymbol = prach_pdu->prach_start_symbol; ru->prach_list[prach_id].num_prach_ocas = prach_pdu->num_prach_ocas; pthread_mutex_unlock(&ru->prach_list_mutex); @@ -156,6 +158,7 @@ void free_nr_ru_prach_entry(RU_t *ru, int prach_id) void rx_nr_prach_ru(RU_t *ru, int prachFormat, int numRA, + int beam, int prachStartSymbol, int prachStartSlot, int prachOccasion, @@ -203,7 +206,8 @@ void rx_nr_prach_ru(RU_t *ru, for (int aa = 0; aa < ru->nb_rx; aa++) { if (prach_sequence_length == 0) slot2 = prachStartSlot; - prach[aa] = (int16_t*)&ru->common.rxdata[aa][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; + int idx = aa + beam * ru->nb_rx; + prach[aa] = (int16_t*)&ru->common.rxdata[idx][fp->get_samples_slot_timestamp(slot2, fp, 0) + sample_offset_slot - ru->N_TA_offset]; } int reps; diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index c6d0ed1ef3..ab1c9c2990 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -257,10 +257,7 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int slot, nfapi_nr_pusch_pdu_t *ulsch_pdu); -void nr_fill_prach(PHY_VARS_gNB *gNB, - int SFN, - int Slot, - nfapi_nr_prach_pdu_t *prach_pdu); +int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); void rx_nr_prach(PHY_VARS_gNB *gNB, nfapi_nr_prach_pdu_t *prach_pdu, @@ -274,13 +271,14 @@ void rx_nr_prach(PHY_VARS_gNB *gNB, void rx_nr_prach_ru(RU_t *ru, int prach_fmt, int numRA, + int beam, int prachStartSymbol, int prachStartSlot, int prachOccasion, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu); +void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdum, int beam_id); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 1417180cb3..95667943a2 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -172,6 +172,7 @@ typedef struct RU_prec_t_s{ typedef struct { int aid; + int beam; struct RU_t_s *ru; int startSymbol; int endSymbol; @@ -181,6 +182,7 @@ typedef struct { typedef struct { int aid; + int beam; struct RU_t_s *ru; int slot; int startSymbol; @@ -196,6 +198,7 @@ typedef struct { int prachStartSymbol; int num_prach_ocas; int num_slots; + int beam; } RU_PRACH_list_t; #define NUMBER_OF_NR_RU_PRACH_MAX 8 @@ -488,6 +491,8 @@ typedef struct RU_t_s { int nb_rx; /// number of TX paths on device int nb_tx; + /// number of concurrent analog beams in period + int num_beams_period; /// number of logical antennas at TX beamformer input int nb_log_antennas; /// maximum PDSCH RS EPRE diff --git a/openair1/SCHED_NR/fapi_nr_l1.c b/openair1/SCHED_NR/fapi_nr_l1.c index 5570b329fd..6b671abcfe 100644 --- a/openair1/SCHED_NR/fapi_nr_l1.c +++ b/openair1/SCHED_NR/fapi_nr_l1.c @@ -157,9 +157,9 @@ void nr_schedule_ul_tti_req(PHY_VARS_gNB *gNB, nfapi_nr_ul_tti_request_t *UL_tti UL_tti_req->SFN, UL_tti_req->Slot); nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[i].prach_pdu; - nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + int id = nr_fill_prach(gNB, UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); if (gNB->RU_list[0]->if_south == LOCAL_RF || gNB->RU_list[0]->if_south == REMOTE_IF5) - nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu); + nr_fill_prach_ru(gNB->RU_list[0], UL_tti_req->SFN, UL_tti_req->Slot, prach_pdu, gNB->prach_vars.list[id].beam_nb); break; case NFAPI_NR_UL_CONFIG_SRS_PDU_TYPE: LOG_D(NR_PHY, diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index 0dc8c360b0..cf0a1c6ee1 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -238,6 +238,7 @@ void nr_feptx(void *arg) RU_t *ru = feptx->ru; int slot = feptx->slot; int aa = feptx->aid; + int bb = feptx->beam; int startSymbol = feptx->startSymbol; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; int numSymbols = feptx->numSymbols; @@ -246,44 +247,32 @@ void nr_feptx(void *arg) int txdataF_BF_offset = startSymbol * fp->ofdm_symbol_size; VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 1); + int tx_idx = aa + bb * ru->nb_tx; - if (aa == 0) + if (tx_idx == 0) start_meas(&ru->precoding_stats); - if (ru->config.dbt_config.num_dig_beams != 0) { - for(int i = 0; i < ru->gNB_list[0]->common_vars.num_beams_period; i++) { - memcpy(&ru->common.beam_id[i][slot * fp->symbols_per_slot], - &ru->gNB_list[0]->common_vars.beam_id[i][slot * fp->symbols_per_slot], - (fp->symbols_per_slot) * sizeof(int)); - } + if (ru->gNB_list[0]->common_vars.analog_bf) { + memcpy(&ru->common.beam_id[bb][slot * fp->symbols_per_slot], + &ru->gNB_list[0]->common_vars.beam_id[bb][slot * fp->symbols_per_slot], + (fp->symbols_per_slot) * sizeof(int)); } // If there is no digital beamforming we just need to copy the data to RU if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) - memcpy((void*)&ru->common.txdataF_BF[aa][txdataF_BF_offset], - (void*)&ru->gNB_list[0]->common_vars.txdataF[0][aa][txdataF_offset], // TODO hardcoded beam to 0, still need to understand how to handle this properly + memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_BF_offset], + (void*)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset], numSamples * sizeof(int32_t)); else { AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); - for(int i = 0; i < fp->symbols_per_slot; ++i) { - nr_beam_precoding((c16_t **)ru->gNB_list[0]->common_vars.txdataF, - (c16_t **)ru->common.txdataF_BF, - fp, - ru->beam_weights[0], - slot, - i, - aa, - ru->nb_log_antennas, - txdataF_offset); - } } - if (aa==0) + if (tx_idx == 0) stop_meas(&ru->precoding_stats); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_PREC+feptx->aid , 0); ////////////FEPTX//////////// - nr_feptx0(ru, slot, startSymbol, numSymbols, aa); + nr_feptx0(ru, slot, startSymbol, numSymbols, tx_idx); // Task completed in // completed_task_ans(feptx->ans); @@ -299,39 +288,42 @@ void nr_feptx_tp(RU_t *ru, int frame_tx, int slot) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPTX_OFDM, 1); start_meas(&ru->ofdm_total_stats); - size_t const sz = ru->nb_tx + (ru->half_slot_parallelization > 0) * ru->nb_tx; + int nt = ru->nb_tx * ru->num_beams_period; + size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt; feptx_cmd_t arr[sz]; task_ans_t ans; init_task_ans(&ans, sz); int nbfeptx = 0; - for (int aid = 0; aid < ru->nb_tx; aid++) { - feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; - feptx_cmd->ans = &ans; - - feptx_cmd->aid = aid; - feptx_cmd->ru = ru; - feptx_cmd->slot = slot; - feptx_cmd->startSymbol = 0; - feptx_cmd->numSymbols = - (ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot; - - task_t t = {.func = nr_feptx, .args = feptx_cmd}; - pushTpool(ru->threadPool, t); - nbfeptx++; - if (ru->half_slot_parallelization > 0) { + for (int beam = 0; beam < ru->num_beams_period; beam++) { + for (int aid = 0; aid < ru->nb_tx; aid++) { feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; feptx_cmd->ans = &ans; - + feptx_cmd->beam = beam; feptx_cmd->aid = aid; feptx_cmd->ru = ru; feptx_cmd->slot = slot; - feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; - feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1; + feptx_cmd->startSymbol = 0; + feptx_cmd->numSymbols = + (ru->half_slot_parallelization > 0) ? ru->nr_frame_parms->symbols_per_slot >> 1 : ru->nr_frame_parms->symbols_per_slot; task_t t = {.func = nr_feptx, .args = feptx_cmd}; pushTpool(ru->threadPool, t); nbfeptx++; + if (ru->half_slot_parallelization > 0) { + feptx_cmd_t *feptx_cmd = &arr[nbfeptx]; + feptx_cmd->ans = &ans; + feptx_cmd->beam = beam; + feptx_cmd->aid = aid; + feptx_cmd->ru = ru; + feptx_cmd->slot = slot; + feptx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; + feptx_cmd->numSymbols = ru->nr_frame_parms->symbols_per_slot >> 1; + + task_t t = {.func = nr_feptx, .args = feptx_cmd}; + pushTpool(ru->threadPool, t); + nbfeptx++; + } } } join_task_ans(&ans); @@ -347,6 +339,7 @@ void nr_fep(void* arg) feprx_cmd_t *feprx_cmd = (feprx_cmd_t *)arg; RU_t *ru = feprx_cmd->ru; int aid = feprx_cmd->aid; + int beam = feprx_cmd->beam; int slot = feprx_cmd->slot; int startSymbol = feprx_cmd->startSymbol; int endSymbol = feprx_cmd->endSymbol; @@ -356,11 +349,12 @@ void nr_fep(void* arg) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 1); + int idx = aid + beam * ru->nb_rx; int offset = (slot % RU_RX_SLOT_DEPTH) * fp->symbols_per_slot * fp->ofdm_symbol_size; for (int l = startSymbol; l <= endSymbol; l++) nr_slot_fep_ul(fp, - ru->common.rxdata[aid], - &ru->common.rxdataF[aid][offset], + ru->common.rxdata[idx], + &ru->common.rxdataF[idx][offset], l, slot, ru->N_TA_offset); @@ -377,39 +371,42 @@ void nr_fep_tp(RU_t *ru, int slot) { if (ru->idx == 0) VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX, 1 ); start_meas(&ru->ofdm_demod_stats); - size_t const sz = ru->nb_rx + (ru->half_slot_parallelization > 0) * ru->nb_rx; + int nt = ru->nb_rx * ru->num_beams_period; + size_t const sz = nt + (ru->half_slot_parallelization > 0) * nt; feprx_cmd_t arr[sz]; task_ans_t ans; init_task_ans(&ans, sz); - for (int aid=0;aidnb_rx;aid++) { - feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; - feprx_cmd->ans = &ans; - - feprx_cmd->aid = aid; - feprx_cmd->ru = ru; - feprx_cmd->slot = ru->proc.tti_rx; - feprx_cmd->startSymbol = 0; - feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1 - : (ru->nr_frame_parms->symbols_per_slot - 1); - - task_t t = {.func = nr_fep, .args = feprx_cmd}; - pushTpool(ru->threadPool, t); - nbfeprx++; - if (ru->half_slot_parallelization > 0) { + for (int beam = 0; beam < ru->num_beams_period; beam++) { + for (int aid = 0; aid < ru->nb_rx; aid++) { feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; feprx_cmd->ans = &ans; - + feprx_cmd->beam = beam; feprx_cmd->aid = aid; feprx_cmd->ru = ru; feprx_cmd->slot = ru->proc.tti_rx; - feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; - feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1; + feprx_cmd->startSymbol = 0; + feprx_cmd->endSymbol = (ru->half_slot_parallelization > 0) ? (ru->nr_frame_parms->symbols_per_slot >> 1) - 1 + : (ru->nr_frame_parms->symbols_per_slot - 1); task_t t = {.func = nr_fep, .args = feprx_cmd}; pushTpool(ru->threadPool, t); - nbfeprx++; + if (ru->half_slot_parallelization > 0) { + feprx_cmd_t *feprx_cmd = &arr[nbfeprx]; + feprx_cmd->ans = &ans; + feprx_cmd->beam = beam; + feprx_cmd->aid = aid; + feprx_cmd->ru = ru; + feprx_cmd->slot = ru->proc.tti_rx; + feprx_cmd->startSymbol = ru->nr_frame_parms->symbols_per_slot >> 1; + feprx_cmd->endSymbol = ru->nr_frame_parms->symbols_per_slot - 1; + + task_t t = {.func = nr_fep, .args = feprx_cmd}; + pushTpool(ru->threadPool, t); + + nbfeprx++; + } } } join_task_ans(&ans); diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c index aebfe4997f..a13918a606 100644 --- a/openair1/SIMULATION/NR_PHY/prachsim.c +++ b/openair1/SIMULATION/NR_PHY/prachsim.c @@ -773,7 +773,7 @@ int main(int argc, char **argv){ } } - rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, slot, prachOccasion, frame, slot); + rx_nr_prach_ru(ru, prach_format, numRA, 0, prachStartSymbol, slot, prachOccasion, frame, slot); for (int i = 0; i < ru->nb_rx; ++i) gNB->prach_vars.rxsigF[i] = ru->prach_rxsigF[prachOccasion][i]; From 93b08c5f20445c27e0d80b9a51fb1efc83fe8a9c Mon Sep 17 00:00:00 2001 From: francescomani Date: Fri, 20 Dec 2024 11:30:55 +0100 Subject: [PATCH 073/100] bugfix in L1 analog beam allocation the allocation in L1 is done symbol-wise but the L2 is scheduling beams slot-based this means we need to check for beam availability in the whole slot --- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index ca90965ebc..b626aa59cd 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -58,9 +58,8 @@ int beam_index_allocation(int fapi_beam_index, int idx = -1; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; for (int j = 0; j < common_vars->num_beams_period; j++) { + // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot for (int i = 0; i < symbols_per_slot; i++) { - if (((bitmap_symbols >> i) & 0x01) == 0) - continue; int current_beam = common_vars->beam_id[j][slot * symbols_per_slot + i]; if (current_beam == -1 || current_beam == ru_beam_idx) idx = j; @@ -77,7 +76,7 @@ int beam_index_allocation(int fapi_beam_index, if (((bitmap_symbols >> j) & 0x01)) common_vars->beam_id[idx][slot * symbols_per_slot + j] = ru_beam_idx; } - LOG_D(PHY, "Allocating beam %d in slot %d\n", idx, slot); + LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot); return idx; } From bf6ddb70c4d3da4a0ac660dc73f853dc989484a0 Mon Sep 17 00:00:00 2001 From: francescomani Date: Sat, 18 Jan 2025 10:37:48 +0100 Subject: [PATCH 074/100] extension of analog beamforming doc to lower layers --- doc/analog_beamforming.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 7943111f72..6bdb99b82d 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -30,3 +30,24 @@ This matrix contains the beams already allocated in a given slot, to flag the sc To this goal, we extended the virtual resource block (VRB) map by one dimension to also contain information per allocated beam. As said, the scheduler can independently schedule users in a number of beams up to `beams_per_period` concurrently. It is important to note that in current implementation, there are several periodical channels, e.g. PRACH or PUCCH for CSI et cetera, that have the precendence in being assigned a beam, that is because the scheduling is automatic, set in RRC configuration, and not up to the scheduler. For these instances, we assume the beam is available (if not there are assertions to stop the process). For data channels, the currently implemented PF scheduler is used. The only modification is that a UE can be served only if there is a free beam available or the one of the beams already in use correspond to that UE beam. + +# FAPI implementation + +In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: +- `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming +- `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period` +- `total_num_beams_vendor_ext` which corresponds to the number of beams configured in `beam_weights` +- `analog_beam_list` which contains the RU beamforming indices configured in `beam_weights` + +Additionally, L2 provides in each channel FAPI message information about the beam index. Small Cell Forum (SCF) FAPI provides in its PHY API specifications for the channels only a field for digital beamforming as part of the `precoding_and_beamforming` stucture. Therefore without a better option, we are currently using that one to store the internal analog beamforming index. This is the index used internally by the code to progressively identify the beam with a value from 0 to `total_num_beams_vendor_ext`. + +# L1 implementation + +To handle multiple concurrent beams, the buffers containing Tx and Rx data in frequency domain (`txdataF` and `rxdataF`) have been extended by one dimension to contain multiple concurrent beams to be transmitted/received. +The function `beam_index_allocation`, called by every L1 channel, is responsible to match the FAPI analog beam index to the RU beam index and to store the latter `beam_id` structure, which allocates the beams per symbol, despite L2 only supporting beam change at slot level. At the same time, the function returns the concurrent beam index, to be used to store data in frequency domain buffers. While doing so, the function also checks if there is room for current beam in the list of concurrent beams, which should always be the case, if L2 properly allocated the channels. + +# RU implementation + +The implementation is still work in progress. + +The first dimension of the Tx and Rx buffers that used to contain the number of Tx/Rx antennas, it is now extended to contain the number of parallel streams which is the number of antennas multiplied by the number of concurrent beams. From be8771189ee73e5ed05d84f7425cd40a5d7119e8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 3 Feb 2025 18:57:15 +0100 Subject: [PATCH 075/100] moving beam weigths to MACRLC config file section and requiring only a single beam index per beam in analog beamforming --- .../gnb.sa.band261.u3.32prb.rfsim.conf | 2 +- doc/analog_beamforming.md | 3 +- openair2/GNB_APP/MACRLC_nr_paramdef.h | 8 +++-- openair2/GNB_APP/gnb_config.c | 29 ++++++++++--------- openair2/GNB_APP/gnb_paramdef.h | 12 +++----- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf index 7cc7a9e3f9..d5b1695d5c 100644 --- a/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf +++ b/ci-scripts/conf_files/gnb.sa.band261.u3.32prb.rfsim.conf @@ -21,7 +21,6 @@ gNBs = sib1_tda = 15; min_rxtxtime = 6; - beam_weights = [0]; // single SSB -> one analog beam servingCellConfigCommon = ( { @@ -179,6 +178,7 @@ MACRLCs = ({ set_analog_beamforming = 1; beam_duration = 1; beams_per_period = 1; + beam_weights = [0]; // single SSB -> one analog beam }); L1s = ( diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 6bdb99b82d..3c695c5464 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -20,8 +20,7 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) - `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) - -In the `gNBs` section of the configuration file, under the phyisical parameters, a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. This field is called `beam_weights`. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. # Implementation in OAI scheduler diff --git a/openair2/GNB_APP/MACRLC_nr_paramdef.h b/openair2/GNB_APP/MACRLC_nr_paramdef.h index e682c559fa..c1382d7b70 100644 --- a/openair2/GNB_APP/MACRLC_nr_paramdef.h +++ b/openair2/GNB_APP/MACRLC_nr_paramdef.h @@ -76,6 +76,7 @@ #define CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING "set_analog_beamforming" #define CONFIG_STRING_MACRLC_BEAM_DURATION "beam_duration" #define CONFIG_STRING_MACRLC_BEAMS_PERIOD "beams_per_period" +#define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights" #define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold" #define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold" @@ -143,6 +144,7 @@ {CONFIG_STRING_MACRLC_ANALOG_BEAMFORMING, HLP_MACRLC_AB, PARAMFLAG_BOOL, .u8ptr=NULL, .defintval=0, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAM_DURATION, HLP_MACRLC_BEAM_DURATION, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ {CONFIG_STRING_MACRLC_BEAMS_PERIOD, HLP_MACRLC_BEAMS_PERIOD, 0, .u8ptr=NULL, .defintval=1, TYPE_UINT8, 0}, \ + {CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY,0}, \ {CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD, HLP_MACRLC_PUSCH_RSSI_THRESHOLD, \ 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \ @@ -189,8 +191,9 @@ #define MACRLC_ANALOG_BEAMFORMING_IDX 36 #define MACRLC_ANALOG_BEAM_DURATION_IDX 37 #define MACRLC_ANALOG_BEAMS_PERIOD_IDX 38 -#define MACRLC_PUSCH_RSSI_THRES_IDX 39 -#define MACRLC_PUCCH_RSSI_THRES_IDX 40 +#define MACRLC_BEAMWEIGHTS_IDX 39 +#define MACRLC_PUSCH_RSSI_THRES_IDX 40 +#define MACRLC_PUCCH_RSSI_THRES_IDX 41 #define MACRLCPARAMS_CHECK { \ { .s5 = { NULL } }, \ @@ -232,6 +235,7 @@ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ + { .s5 = { NULL } }, \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \ { .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \ } diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 4b34c3858d..aab1ca831c 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1566,19 +1566,6 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) config.timer_config.n311, config.timer_config.t319); - if (config_isparamset(GNBParamList.paramarray[0], GNB_BEAMWEIGHTS_IDX)) { - int n = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].numelt; - AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n"); - // each beam is described by a set of weights (one for each antenna) - // on the other hand in case of analog beamforming an index to the RU beam identifier is provided - config.nb_bfw[0] = num_tx; // number of tx antennas - config.nb_bfw[1] = n; // number of beams weights/indices - config.bw_list = malloc16_clear(n * sizeof(*config.bw_list)); - for (int b = 0; b < n; b++) { - config.bw_list[b] = GNBParamList.paramarray[0][GNB_BEAMWEIGHTS_IDX].iptr[b]; - } - } - // Construct default aggragation level list or read from config int uess_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS]; uess_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0; @@ -1711,6 +1698,22 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) beam_info->beams_per_period = beams_per_period; beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration } + if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) { + int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; + int num_beam = n; + if (!ab) { + AssertFatal(n % num_tx == 0, "Error! Number of beam input needs to be multiple of TX antennas\n"); + num_beam = n / num_tx; + } + // each beam is described by a set of weights (one for each antenna) + // in case of analog beamforming an index to the RU beam identifier is provided + // (one for each beam regardless of the number of antennas per beam) + config.nb_bfw[0] = num_tx; // number of tx antennas + config.nb_bfw[1] = num_beam; // number of beams weights/indices + config.bw_list = calloc_or_fail(n, sizeof(*config.bw_list)); + for (int b = 0; b < n; b++) + config.bw_list[b] = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].iptr[b]; + } // triggers also PHY initialization in case we have L1 via FAPI nr_mac_config_scc(RC.nrmac[j], scc, &config); } // for (j=0;j Date: Tue, 4 Feb 2025 19:46:27 +0100 Subject: [PATCH 076/100] fix beam allocation for multiple TD prach occasions in a slot --- executables/nr-ru.c | 3 +- .../nfapi/public_inc/nfapi_nr_interface_scf.h | 2 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 29 ++++---- .../PHY/NR_TRANSPORT/nr_transport_proto.h | 4 +- openair1/PHY/defs_RU.h | 2 +- openair1/PHY/defs_gNB.h | 2 +- openair1/SCHED_NR/nr_prach_procedures.c | 7 +- openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c | 72 ++++++++++--------- 8 files changed, 64 insertions(+), 57 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a8ef32485f..a2b7fc858d 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -1319,11 +1319,12 @@ void *ru_thread(void *param) for (int prach_oc = 0; prach_oc < p->num_prach_ocas; prach_oc++) { int prachStartSymbol = p->prachStartSymbol + prach_oc * N_dur; + int beam_id = ru->prach_list[prach_id].beam ? ru->prach_list[prach_id].beam[prach_oc] : 0; //comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}. rx_nr_prach_ru(ru, p->fmt, // could also use format p->numRA, - p->beam, + beam_id, prachStartSymbol, p->slot, prach_oc, diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index 6ddb376bd3..6698ba9f29 100644 --- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h +++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h @@ -24,7 +24,7 @@ #define NFAPI_MAX_NUM_GROUPS 8 #define NFAPI_MAX_NUM_CB 8 #define NFAPI_MAX_NUM_PRGS 1 -#define NFAPI_MAX_NUM_BG_IF 1 +#define NFAPI_MAX_NUM_BG_IF 6 #define NFAPI_MAX_NUM_PERIODS 8 // Extension to the generic structures for single tlv values diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index ed90a3e318..55a235737a 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -42,7 +42,6 @@ void init_prach_list(PHY_VARS_gNB *gNB) for (int i = 0; i < NUMBER_OF_NR_PRACH_MAX; i++){ gNB->prach_vars.list[i].frame = -1; gNB->prach_vars.list[i].slot = -1; - gNB->prach_vars.list[i].beam_nb = -1; gNB->prach_vars.list[i].num_slots = -1; } } @@ -51,8 +50,8 @@ void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id) { gNB->prach_vars.list[prach_id].frame = -1; gNB->prach_vars.list[prach_id].slot = -1; - gNB->prach_vars.list[prach_id].beam_nb = -1; gNB->prach_vars.list[prach_id].num_slots = -1; + free_and_zero(gNB->prach_vars.list[prach_id].beam_nb); } int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame, int slot, find_type_t type) { @@ -79,18 +78,20 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr prach->slot = Slot; const int format = prach_pdu->prach_format; prach->num_slots = (format < 4) ? get_long_prach_dur(format, gNB->frame_parms.numerology_index) : 1; - prach->beam_nb = 0; if (gNB->common_vars.beam_id) { - int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - // TODO no idea how to compute final prach symbol here so for now we go til the end of the slot - int temp_nb_symbols = NR_NUMBER_OF_SYMBOLS_PER_SLOT - prach_pdu->prach_start_symbol; - int bitmap = SL_to_bitmap(prach_pdu->prach_start_symbol, temp_nb_symbols); - prach->beam_nb = beam_index_allocation(fapi_beam_idx, - &gNB->gNB_config.analog_beamforming_ve, - &gNB->common_vars, - Slot, - NR_NUMBER_OF_SYMBOLS_PER_SLOT, - bitmap); + int n_symb = get_nr_prach_duration(prach_pdu->prach_format); + prach->beam_nb = calloc(prach_pdu->beamforming.dig_bf_interface, sizeof(*prach->beam_nb)); + for (int i = 0; i < prach_pdu->beamforming.dig_bf_interface; i++) { + int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; + int start_symb = prach_pdu->prach_start_symbol + i * n_symb; + int bitmap = SL_to_bitmap(start_symb, n_symb); + prach->beam_nb[i] = beam_index_allocation(fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &gNB->common_vars, + Slot, + NR_NUMBER_OF_SYMBOLS_PER_SLOT, + bitmap); + } } LOG_D(NR_PHY,"Copying prach pdu %d bytes to index %d\n", (int)sizeof(*prach_pdu), prach_id); memcpy(&prach->pdu, prach_pdu, sizeof(*prach_pdu)); @@ -127,7 +128,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) return -1; } -void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int beam_id) +void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), diff --git a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h index ab1c9c2990..db49237a9e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -278,7 +278,7 @@ void rx_nr_prach_ru(RU_t *ru, int frame, int subframe); -void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdum, int beam_id); +void nr_fill_prach_ru(RU_t *ru,int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_nb); int16_t find_nr_prach(PHY_VARS_gNB *gNB,int frame,int slot, find_type_t type); int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type); @@ -304,7 +304,7 @@ int nr_get_srs_signal(PHY_VARS_gNB *gNB, void init_prach_list(PHY_VARS_gNB *gNB); void init_prach_ru_list(RU_t *ru); void free_nr_ru_prach_entry(RU_t *ru, int prach_id); -uint8_t get_nr_prach_duration(uint8_t prach_format); +int get_nr_prach_duration(uint8_t prach_format); void free_nr_prach_entry(PHY_VARS_gNB *gNB, int prach_id); diff --git a/openair1/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 95667943a2..a2c39852f5 100644 --- a/openair1/PHY/defs_RU.h +++ b/openair1/PHY/defs_RU.h @@ -198,7 +198,7 @@ typedef struct { int prachStartSymbol; int num_prach_ocas; int num_slots; - int beam; + int *beam; } RU_PRACH_list_t; #define NUMBER_OF_NR_RU_PRACH_MAX 8 diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index d305197554..975588ec65 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -138,9 +138,9 @@ typedef struct { int frame; int slot; // identifier for concurrent beams - int beam_nb; // prach duration in slots int num_slots; + int *beam_nb; nfapi_nr_prach_pdu_t pdu; } gNB_PRACH_list_t; diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index c9f6a9c8cc..ece4482137 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -42,8 +42,9 @@ #include "assertions.h" #include -uint8_t get_nr_prach_duration(uint8_t prach_format){ +int get_nr_prach_duration(uint8_t prach_format) +{ switch(prach_format){ case 0: // format 0 @@ -117,14 +118,14 @@ void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rac nfapi_nr_prach_pdu_t *prach_pdu = &gNB->prach_vars.list[prach_id].pdu; const int prach_start_slot = gNB->prach_vars.list[prach_id].slot; uint8_t prachStartSymbol; - uint8_t N_dur = get_nr_prach_duration(prach_pdu->prach_format); + int N_dur = get_nr_prach_duration(prach_pdu->prach_format); for(int prach_oc = 0; prach_oc < prach_pdu->num_prach_ocas; prach_oc++) { for (ru_aa=0,aa=0;ru_aanb_rx;ru_aa++,aa++) { gNB->prach_vars.rxsigF[aa] = ru->prach_rxsigF[prach_oc][ru_aa]; } - prachStartSymbol = prach_pdu->prach_start_symbol+prach_oc*N_dur; + prachStartSymbol = prach_pdu->prach_start_symbol + prach_oc * N_dur; //comment FK: the standard 38.211 section 5.3.2 has one extra term +14*N_RA_slot. This is because there prachStartSymbol is given wrt to start of the 15kHz slot or 60kHz slot. Here we work slot based, so this function is anyway only called in slots where there is PRACH. Its up to the MAC to schedule another PRACH PDU in the case there are there N_RA_slot \in {0,1}. rx_nr_prach(gNB, diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c index e67a30e67a..e398da1eaf 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c @@ -356,10 +356,11 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) NR_COMMON_channels_t *cc = gNB->common_channels; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup; + NR_BWP_UplinkCommon_t *initialUplinkBWP = scc->uplinkConfigCommon->initialUplinkBWP; + NR_RACH_ConfigCommon_t *rach_ConfigCommon = initialUplinkBWP->rach_ConfigCommon->choice.setup; NR_MsgA_ConfigCommon_r16_t *msgacc = NULL; - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) - msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; + if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16) + msgacc = initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup; int slots_frame = gNB->frame_structure.numb_slots_frame; int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size); nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index]; @@ -371,7 +372,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) int slot_index = 0; uint16_t prach_occasion_id = -1; - int bwp_start = NRRIV2PRBOFFSET(scc->uplinkConfigCommon->initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); + int bwp_start = NRRIV2PRBOFFSET(initialUplinkBWP->genericParameters.locationAndBandwidth, MAX_BWP_SIZE); uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value; const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; @@ -399,6 +400,16 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) uint32_t N_t_slot = cc->prach_info.N_t_slot; uint32_t start_symb = cc->prach_info.start_symbol; for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion + AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), + "Invalid UL_tti_req->n_pdus %d\n", + UL_tti_req->n_pdus); + + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE; + UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t); + nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu; + memset(prach_pdu, 0, sizeof(nfapi_nr_prach_pdu_t)); + UL_tti_req->n_pdus += 1; + int num_td_occ = 0; for (int td_index = 0; td_index < N_t_slot; td_index++) { uint32_t config_period = cc->prach_info.x; prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) + @@ -407,6 +418,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) if (prach_occasion_id >= cc->total_prach_occasions) // to be confirmed: unused occasion? continue; + num_td_occ++; float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value]; int beam_index = 0; if(num_ssb_per_RO <= 1) { @@ -417,8 +429,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) // multi-beam allocation structure beam = beam_allocation_procedure(&gNB->beam_info, frameP, slotP, beam_index, slots_frame); AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to %d SSB transmitted in any available beam\n", n_ssb + 1); - } - else { + } else { int first_ssb_index = (prach_occasion_id * (int)num_ssb_per_RO) % cc->num_active_ssb; for(int j = first_ssb_index; j < first_ssb_index + num_ssb_per_RO; j++) { // fapi beam index @@ -428,40 +439,15 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) AssertFatal(beam.idx >= 0, "Cannot allocate PRACH corresponding to SSB %d in any available beam\n", j); } } - if(td_index == 0) { - AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]), - "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus); - - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE; - UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t); - nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu; - memset(prach_pdu,0,sizeof(nfapi_nr_prach_pdu_t)); - UL_tti_req->n_pdus+=1; - + if(num_td_occ == 1) { // filling the prach fapi structure prach_pdu->phys_cell_id = *scc->physCellId; - prach_pdu->num_prach_ocas = N_t_slot; - gNB->num_scheduled_prach_rx += N_t_slot; prach_pdu->prach_start_symbol = start_symb; prach_pdu->num_ra = fdm_index; prach_pdu->num_cs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, rach_ConfigCommon->restrictedSetConfig); - prach_pdu->beamforming.num_prgs = 0; - prach_pdu->beamforming.prg_size = 0; - prach_pdu->beamforming.dig_bf_interface = 1; - prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx = beam_index; - - LOG_D(NR_MAC, - "Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n", - frameP, - slotP, - prach_occasion_id, - prach_pdu->num_ra, - start_symb, - slot_index, - RA_sfn_index); // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities // We added 9 = A1/B1 10 = A2/B2 11 A3/B3 if (format1!=0xff) { @@ -518,8 +504,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) AssertFatal(1==0,"Invalid PRACH format"); } } - if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 - && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { + if (initialUplinkBWP->ext1 && initialUplinkBWP->ext1->msgA_ConfigCommon_r16) { if (gNB->UE_info.connected_ue_list[0] == NULL) schedule_nr_MsgA_pusch(scc->uplinkConfigCommon, gNB, @@ -531,7 +516,26 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP) *scc->physCellId); } } + prach_pdu->num_prach_ocas = num_td_occ; + prach_pdu->beamforming.num_prgs = 0; + prach_pdu->beamforming.prg_size = 0; + prach_pdu->beamforming.dig_bf_interface = num_td_occ; + prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[num_td_occ - 1].beam_idx = beam_index; + + LOG_D(NR_MAC, + "Frame %d, Slot %d: Prach Occasion id = %u fdm index = %u start symbol = %u slot index = %u subframe index = %u \n", + frameP, + slotP, + prach_occasion_id, + prach_pdu->num_ra, + prach_pdu->prach_start_symbol, + slot_index, + RA_sfn_index); } + if (num_td_occ == 0) // no TD PRACH occasion -> no PRACH PDU + UL_tti_req->n_pdus -= 1; + else + gNB->num_scheduled_prach_rx += num_td_occ; } // block resources in vrb_map_UL From 964c737b7d3ad6b9249a3322c4cd2190f9b610c6 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 10 Jun 2025 11:12:44 +0200 Subject: [PATCH 077/100] simplify get_nr_prach_duration function --- openair1/SCHED_NR/nr_prach_procedures.c | 55 ++----------------------- 1 file changed, 3 insertions(+), 52 deletions(-) diff --git a/openair1/SCHED_NR/nr_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index ece4482137..c56a37ca1d 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -37,63 +37,14 @@ #include "nfapi_pnf.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" - - #include "assertions.h" - #include int get_nr_prach_duration(uint8_t prach_format) { - switch(prach_format){ - - case 0: // format 0 - return 0; - - case 1: // format 1 - return 0; - - case 2: // format 2 - return 0; - - case 3: // format 3 - return 0; - - case 4: // format A1 - return 2; - - case 5: // format A2 - return 4; - - case 6: // format A3 - return 6; - - case 7: // format B1 - return 2; - - case 8: // format B4 - return 12; - - case 9: // format C0 - return 2; - - case 10: // format C2 - return 6; - - case 11: // format A1/B1 - return 2; - - case 12: // format A2/B2 - return 4; - - case 13: // format A3/B3 - return 6; - - default : - AssertFatal(1==0,"Invalid Prach format\n"); - break; - - } + const int val[14] = {0, 0, 0, 0, 2, 4, 6, 2, 12, 2, 6, 2, 4, 6}; + AssertFatal(prach_format < sizeofArray(val), "Invalid Prach format %d\n", prach_format); + return val[prach_format]; } void L1_nr_prach_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_rach_indication_t *rach_ind) From f555bf2957245b3f53050b166d286606d6e49d3c Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 10 Feb 2025 09:46:49 +0100 Subject: [PATCH 078/100] analog beamforming based distributed antenna system --- doc/analog_beamforming.md | 8 ++++- executables/nr-ru.c | 37 +++++++++++------------ openair1/PHY/NR_TRANSPORT/nr_dci.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_dlsch.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_prach.c | 3 +- openair1/PHY/NR_TRANSPORT/nr_ulsch.c | 3 +- openair1/PHY/NR_TRANSPORT/pucch_rx.c | 8 ++--- openair1/PHY/NR_TRANSPORT/srs_rx.c | 3 +- openair1/PHY/defs_gNB.h | 2 ++ openair1/SCHED_NR/phy_procedures_nr_gNB.c | 13 +++++--- openair1/SCHED_NR/sched_nr.h | 3 +- openair2/GNB_APP/L1_nr_paramdef.h | 10 ++++-- openair2/GNB_APP/gnb_config.c | 1 + 13 files changed, 59 insertions(+), 38 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index 3c695c5464..e953e02fb3 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -10,7 +10,7 @@ There are three main beamforming techinques: analog, digital and hybrid. The nam The presence of a limited number of predefined beams at RU poses constraints to the scheduler at gNB. As a matter of fact, the scheduler can serve only a limited number of beams, depending on the RU characteristics (possibly only 1), in a given time scale, that also depends on the RU characteristics (e.g. 1 slot or 1 symbol). This limitation doesn't exist for digital beamforming. -To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. +Analog beamforming implementation also allows to enable distributed antenna systems (DAS), where each beam corrisponds to one antenna (or a set of antennas) of the system. In this scenario, the scheduler constaint is alleviated because normally the number of concurrent beams allowed equals the total number of beams. # Configuration file fields for analog beamforming @@ -22,6 +22,8 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) - `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. + # Implementation in OAI scheduler A new MAC structure `NR_beam_info_t` controls the behavior of the scheduler in presence of analog beamforming. Besides the already mentioned parameters `beam_duration` and `beams_per_period`, the structure also holds a matrix `beam_allocation[i][j]`, whose indices `i` and `j` stands respectively for the number of beams in the period and the slot index (the size of the latter depends on the frame characteristics). @@ -32,6 +34,8 @@ It is important to note that in current implementation, there are several period # FAPI implementation +To be noted that in our implementation analog beamforming is only supported in non-split/monolithic mode because we don't support yet SCF P19 interface that would be needed to manage these procedure in a split scenario with SCF FAPI. + In `config_request` structure, a vendor extension (`nfapi_nr_analog_beamforming_ve_t`) configures the lower layers at initialization with the following information: - `analog_bf_vendor_ext` which can assume values 1 or 0 for enabling or disabling analog beamforming - `num_beams_period_vendor_ext` which corresponds to the configuration parameter `beams_per_period` @@ -45,6 +49,8 @@ Additionally, L2 provides in each channel FAPI message information about the bea To handle multiple concurrent beams, the buffers containing Tx and Rx data in frequency domain (`txdataF` and `rxdataF`) have been extended by one dimension to contain multiple concurrent beams to be transmitted/received. The function `beam_index_allocation`, called by every L1 channel, is responsible to match the FAPI analog beam index to the RU beam index and to store the latter `beam_id` structure, which allocates the beams per symbol, despite L2 only supporting beam change at slot level. At the same time, the function returns the concurrent beam index, to be used to store data in frequency domain buffers. While doing so, the function also checks if there is room for current beam in the list of concurrent beams, which should always be the case, if L2 properly allocated the channels. +In case of DAS, since each beam corresponds to a specific antenna port, the `beam_index_allocation` function is simplified in the sense that the beam index corresponds to the antenna port index of the frequency domain buffers. + # RU implementation The implementation is still work in progress. diff --git a/executables/nr-ru.c b/executables/nr-ru.c index a2b7fc858d..910de225b7 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -846,7 +846,6 @@ void tx_rf(RU_t *ru, int frame,int slot, uint64_t timestamp) static void fill_rf_config(RU_t *ru, char *rf_config_file) { - int i; NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; nfapi_nr_config_request_scf_t *config = &ru->config; //tmp index openair0_config_t *cfg = &ru->openair0_cfg; @@ -872,13 +871,13 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) AssertFatal(ru->nb_rx > 0 && ru->nb_rx <= 8, "openair0 does not support more than 8 antennas\n"); cfg->Mod_id = 0; - cfg->num_rb_dl=N_RB; - cfg->tx_num_channels=ru->nb_tx; - cfg->rx_num_channels=ru->nb_rx; + cfg->num_rb_dl = N_RB; + cfg->tx_num_channels = ru->nb_tx * ru->num_beams_period; + cfg->rx_num_channels = ru->nb_rx * ru->num_beams_period; LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels); LOG_I(PHY,"tune_offset %.0f Hz, sample_rate %.0f Hz\n",cfg->tune_offset,cfg->sample_rate); - for (i=0; inb_tx; i++) { + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { cfg->tx_freq[i] = (double)fp->dl_CarrierFreq; } else if (ru->if_freq_offset) { @@ -893,7 +892,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) i, cfg->tx_gain[i],cfg->tx_freq[i]); } - for (i=0; inb_rx; i++) { + for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { if (ru->if_frequency == 0) { cfg->rx_freq[i] = (double)fp->ul_CarrierFreq; } else if (ru->if_freq_offset) { @@ -939,8 +938,8 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_ Each rf chain is is addressed by the card number and the chain on the card. The rf_map specifies for each antenna port, on which rf chain the mapping should start. Multiple antennas are mapped to successive RF chains on the same card. */ -int setup_RU_buffers(RU_t *ru) { - int i,j; +int setup_RU_buffers(RU_t *ru) +{ int card,ant; //uint16_t N_TA_offset = 0; NR_DL_FRAME_PARMS *fp; @@ -962,27 +961,27 @@ int setup_RU_buffers(RU_t *ru) { if (ru->openair0_cfg.mmapped_dma == 1) { // replace RX signal buffers with mmaped HW versions - for (i=0; inb_rx; i++) { - card = i/4; - ant = i%4; + for (int i = 0; i < ru->nb_rx * ru->num_beams_period; i++) { + card = i / 4; + ant = i % 4; LOG_D(PHY, "Mapping RU id %u, rx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.rxdata[i]); ru->common.rxdata[i] = ru->openair0_cfg.rxbase[ru->rf_map.chain + ant]; - for (j = 0; j < 16; j++) { - ru->common.rxdata[i][j] = 16-j; + for (int j = 0; j < 16; j++) { + ru->common.rxdata[i][j] = 16 - j; } } - for (i=0; inb_tx; i++) { - card = i/4; - ant = i%4; + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { + card = i / 4; + ant = i % 4; LOG_D(PHY, "Mapping RU id %u, tx_ant %d, on card %d, chain %d\n", ru->idx, i, ru->rf_map.card + card, ru->rf_map.chain + ant); free(ru->common.txdata[i]); ru->common.txdata[i] = ru->openair0_cfg.txbase[ru->rf_map.chain + ant]; - for (j = 0; j < 16; j++) { - ru->common.txdata[i][j] = 16-j; + for (int j = 0; j < 16; j++) { + ru->common.txdata[i][j] = 16 - j; } } } else { // not memory-mapped DMA @@ -1049,7 +1048,7 @@ void ru_tx_func(void *param) ru->fh_north_out(ru); } else { if(frame_tx == print_frame) { - for (int i=0; inb_tx; i++) { + for (int i = 0; i < ru->nb_tx * ru->num_beams_period; i++) { if(slot_tx == 0) { sprintf(filename,"gNBdataF_frame%d_sl%d.m", print_frame, slot_tx); LOG_M(filename,"txdataF_frame",&ru->gNB_list[0]->common_vars.txdataF[i][0],fp->samples_per_frame_wCP, 1, 1); diff --git a/openair1/PHY/NR_TRANSPORT/nr_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 38a671d50c..bea9cb63c5 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -81,7 +81,8 @@ static void nr_generate_dci(PHY_VARS_gNB *gNB, int dci_idx = 0; // multi-beam number (for concurrent beams) int bitmap = SL_to_bitmap(cset_start_symb, pdcch_pdu_rel15->DurationSymbols); - int beam_nb = beam_index_allocation(dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + dci_pdu->precodingAndBeamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c index 7e3d68f282..58d11413f4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -680,7 +680,8 @@ static int do_one_dlsch(unsigned char *input_ptr, PHY_VARS_gNB *gNB, NR_gNB_DLSC nfapi_nr_tx_precoding_and_beamforming_t *pb = &rel15->precodingAndBeamforming; // beam number in multi-beam scenario (concurrent beams) int bitmap = SL_to_bitmap(rel15->StartSymbolIndex, rel15->NrOfSymbols); - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 55a235737a..6398c59faa 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -85,7 +85,8 @@ int nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *pr int fapi_beam_idx = prach_pdu->beamforming.prgs_list[0].dig_bf_interface_list[i].beam_idx; int start_symb = prach_pdu->prach_start_symbol + i * n_symb; int bitmap = SL_to_bitmap(start_symb, n_symb); - prach->beam_nb[i] = beam_index_allocation(fapi_beam_idx, + prach->beam_nb[i] = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, Slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index f63bec4d5b..4621e184a6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -76,7 +76,8 @@ void nr_fill_ulsch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pusch_pdu_t if (gNB->common_vars.beam_id) { int fapi_beam_idx = ulsch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(ulsch_pdu->start_symbol_index, ulsch_pdu->nr_of_symbols); - ulsch->beam_nb = beam_index_allocation(fapi_beam_idx, + ulsch->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/pucch_rx.c b/openair1/PHY/NR_TRANSPORT/pucch_rx.c index a16b68f708..a9639ce0d7 100644 --- a/openair1/PHY/NR_TRANSPORT/pucch_rx.c +++ b/openair1/PHY/NR_TRANSPORT/pucch_rx.c @@ -57,10 +57,7 @@ //#define DEBUG_NR_PUCCH_RX 1 -void nr_fill_pucch(PHY_VARS_gNB *gNB, - int frame, - int slot, - nfapi_nr_pucch_pdu_t *pucch_pdu) +void nr_fill_pucch(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_nr_pucch_pdu_t *pucch_pdu) { bool found = false; for (int i = 0; i < gNB->max_nb_pucch; i++) { @@ -73,7 +70,8 @@ void nr_fill_pucch(PHY_VARS_gNB *gNB, if (gNB->common_vars.beam_id) { int fapi_beam_idx = pucch_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; int bitmap = SL_to_bitmap(pucch_pdu->start_symbol_index, pucch_pdu->nr_of_symbols); - pucch->beam_nb = beam_index_allocation(fapi_beam_idx, + pucch->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/NR_TRANSPORT/srs_rx.c b/openair1/PHY/NR_TRANSPORT/srs_rx.c index 16b92be946..c8b6d99c30 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -59,7 +59,8 @@ void nr_fill_srs(PHY_VARS_gNB *gNB, frame_t frame, slot_t slot, nfapi_nr_srs_pdu if (gNB->common_vars.beam_id) { int bitmap = SL_to_bitmap(srs_pdu->time_start_position, 1 << srs_pdu->num_symbols); int fapi_beam_idx = srs_pdu->beamforming.prgs_list[0].dig_bf_interface_list[0].beam_idx; - srs->beam_nb = beam_index_allocation(fapi_beam_idx, + srs->beam_nb = beam_index_allocation(gNB->enable_analog_das, + fapi_beam_idx, &gNB->gNB_config.analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 975588ec65..ad17c243ae 100644 --- a/openair1/PHY/defs_gNB.h +++ b/openair1/PHY/defs_gNB.h @@ -492,6 +492,8 @@ typedef struct PHY_VARS_gNB_s { int num_ulprbbl; uint16_t ulprbbl [MAX_BWP_SIZE]; + bool enable_analog_das; + time_stats_t phy_proc_tx; time_stats_t phy_proc_rx; time_stats_t rx_prach; diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index b626aa59cd..ad75cc733e 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,7 +45,8 @@ //#define DEBUG_RXDATA //#define SRS_IND_DEBUG -int beam_index_allocation(int fapi_beam_index, +int beam_index_allocation(bool das, + int fapi_beam_index, nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, @@ -55,8 +56,10 @@ int beam_index_allocation(int fapi_beam_index, if (!common_vars->beam_id) return 0; - int idx = -1; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; + if (das) + return ru_beam_idx; + int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot for (int i = 0; i < symbols_per_slot; i++) { @@ -136,7 +139,8 @@ void nr_common_signal_procedures(PHY_VARS_gNB *gNB, int frame, int slot, nfapi_n int txdataF_offset = slot * fp->samples_per_slot_wCP; // beam number in a scenario with multiple concurrent beams int bitmap = SL_to_bitmap(ssb_start_symbol, 4); // 4 ssb symbols - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &cfg->analog_beamforming_ve, &gNB->common_vars, slot, @@ -278,7 +282,8 @@ void phy_procedures_gNB_TX(processingData_L1tx_t *msgTx, int lprime_num = mapping_parms.lprime + 1; for (int j = 0; j < mapping_parms.size; j++) csi_bitmap |= ((1 << lprime_num) - 1) << mapping_parms.loverline[j]; - int beam_nb = beam_index_allocation(pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, + int beam_nb = beam_index_allocation(gNB->enable_analog_das, + pb->prgs_list[0].dig_bf_interface_list[0].beam_idx, &cfg->analog_beamforming_ve, &gNB->common_vars, slot, diff --git a/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index 7450518f19..40c32c2199 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -47,7 +47,8 @@ void feptx_prec(RU_t *ru,int frame_tx,int tti_tx); void nr_phy_init_RU(RU_t *ru); void nr_phy_free_RU(RU_t *ru); void clear_slot_beamid(PHY_VARS_gNB *gNB, int slot); -int beam_index_allocation(int fapi_beam_index, +int beam_index_allocation(bool das, + int fapi_beam_index, nfapi_nr_analog_beamforming_ve_t *analog_bf, NR_gNB_COMMON *common_vars, int slot, diff --git a/openair2/GNB_APP/L1_nr_paramdef.h b/openair2/GNB_APP/L1_nr_paramdef.h index e313818ad2..b2b4ab93c1 100644 --- a/openair2/GNB_APP/L1_nr_paramdef.h +++ b/openair2/GNB_APP/L1_nr_paramdef.h @@ -61,6 +61,8 @@ #define HLP_L1_PHASE_COMP "Apply NR symbolwise phase rotation" #define CONFIG_STRING_NUM_ANTENNAS_PER_THREAD "dmrs_num_antennas_per_thread" #define HLP_NUM_ARX "Number of antennas per thread for PUSCH channel estimation" +#define CONFIG_STRING_ANALOG_DAS "enable_das" + /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ /* L1 configuration parameters */ /* optname helpstr paramflags XXXptr defXXXval type numelt */ @@ -81,12 +83,13 @@ {CONFIG_STRING_L1_PRACH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=150, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=50, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_SRS_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=30, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ - {CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ + {CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \ {CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \ {CONFIG_STRING_NUM_ANTENNAS_PER_THREAD, HLP_NUM_ARX,0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \ + {CONFIG_STRING_ANALOG_DAS, NULL, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \ } // clang-format on #define L1_CC_IDX 0 @@ -109,6 +112,7 @@ #define L1_TX_AMP_BACKOFF_dB 17 #define L1_PHASE_COMP 18 #define NUM_ANTENNAS_PER_THREAD 19 +#define L1_ANALOG_DAS 20 /*----------------------------------------------------------------------------------------------------------------------------------------------------*/ #endif diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index aab1ca831c..4a68aa1f78 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1061,6 +1061,7 @@ void RCconfig_NR_L1(void) gNB->TX_AMP = min(32767.0 / pow(10.0, .05 * (double)(*L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr)), INT16_MAX); gNB->phase_comp = *L1_ParamList.paramarray[j][L1_PHASE_COMP].uptr; gNB->dmrs_num_antennas_per_thread = *(L1_ParamList.paramarray[j][NUM_ANTENNAS_PER_THREAD].uptr); + gNB->enable_analog_das = *(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr); LOG_I(NR_PHY, "TX_AMP = %d (-%d dBFS)\n", gNB->TX_AMP, *L1_ParamList.paramarray[j][L1_TX_AMP_BACKOFF_dB].uptr); AssertFatal(gNB->TX_AMP > 300, "TX_AMP is too small, must be larger than 300 (is %d)\n", gNB->TX_AMP); // Midhaul configuration From 3743719b88a1bfd7a35c0fb8f86d00f02783de55 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 7 Jan 2025 14:44:19 +0100 Subject: [PATCH 079/100] fix wrong assertion in nr_fill_prach_ru --- openair1/PHY/NR_TRANSPORT/nr_prach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 6398c59faa..76d9b1185f 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_prach.c +++ b/openair1/PHY/NR_TRANSPORT/nr_prach.c @@ -132,7 +132,7 @@ int16_t find_nr_prach_ru(RU_t *ru,int frame,int slot, find_type_t type) void nr_fill_prach_ru(RU_t *ru, int SFN, int Slot, nfapi_nr_prach_pdu_t *prach_pdu, int *beam_id) { int prach_id = find_nr_prach_ru(ru, SFN, Slot, SEARCH_EXIST_OR_FREE); - AssertFatal(((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX)) || (prach_id < 0), + AssertFatal((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX), "illegal or no prach_id found!!! prach_id %d\n", prach_id); From e15631b23c835464db5a9b76956aad1699ee1068 Mon Sep 17 00:00:00 2001 From: francescomani Date: Mon, 3 Feb 2025 15:58:10 +0100 Subject: [PATCH 080/100] adapting nr_feptx_prec function to analog beam management --- openair1/SCHED_NR/nr_ru_procedures.c | 66 ++++++++++------------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index cf0a1c6ee1..c455e5ac76 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -175,57 +175,39 @@ void nr_feptx_ofdm(RU_t *ru,int frame_tx,int tti_tx) { } -void nr_feptx_prec(RU_t *ru, int frame_tx, int tti_tx) +void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) { - PHY_VARS_gNB **gNB_list = ru->gNB_list,*gNB; - NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + PHY_VARS_gNB **gNB_list = ru->gNB_list; + AssertFatal(ru->num_gNB == 1, "Cannot handle more than 1 gNB\n"); + PHY_VARS_gNB *gNB = gNB_list[0]; nfapi_nr_config_request_scf_t *cfg = &ru->gNB_list[0]->gNB_config; - int slot_tx = tti_tx; - int txdataF_offset = (tti_tx*fp->samples_per_slot_wCP); - + NR_DL_FRAME_PARMS *fp = ru->nr_frame_parms; + int txdataF_offset = slot_tx * fp->samples_per_slot_wCP; start_meas(&ru->precoding_stats); - AssertFatal(ru->nb_log_antennas > 0, "ru->nb_log_antennas is 0!\n"); if (nr_slot_select(cfg,frame_tx,slot_tx) == NR_UPLINK_SLOT) return; - if (ru->num_gNB == 1) { - gNB = gNB_list[0]; + if (gNB->common_vars.analog_bf) { + for (int i = 0; i < ru->num_beams_period; i++) { + memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot], + (void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot], + (fp->symbols_per_slot) * sizeof(int)); + } + } - if (ru->config.dbt_config.num_dig_beams != 0) { - for(int i = 0; i < gNB->common_vars.num_beams_period; ++i) { - memcpy((void*) &ru->common.beam_id[i][slot_tx * fp->symbols_per_slot], - (void*) &gNB->common_vars.beam_id[i][slot_tx * fp->symbols_per_slot], - (fp->symbols_per_slot) * sizeof(int)); - } - } - - if (ru->config.dbt_config.num_dig_beams == 0 || gNB->common_vars.analog_bf) { - for (int i = 0; i < ru->nb_log_antennas; ++i) { - // TODO hardcoded beam to 0, still need to understand how to handle this properly - memcpy(ru->common.txdataF_BF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); - } - } - else { - for(int i = 0; i < ru->nb_log_antennas; ++i) { - // TODO hardcoded beam to 0, still need to understand how to handle this properly - memcpy(ru->common.txdataF[i], &gNB->common_vars.txdataF[0][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); - } - for (int l = 0; l < fp->symbols_per_slot; l++) { - for (int aa = 0; aa < ru->nb_tx; aa++) { - AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); - nr_beam_precoding((c16_t **)ru->common.txdataF, - (c16_t **)ru->common.txdataF_BF, - fp, - ru->beam_weights[0], - tti_tx, - l, - aa, - ru->nb_log_antennas, - 0); - } + // If there is no digital beamforming we just need to copy the data to RU + if (ru->config.dbt_config.num_dig_beams == 0 || ru->gNB_list[0]->common_vars.analog_bf) { + for (int b = 0; b < ru->num_beams_period; b++) { + for (int i = 0; i < ru->nb_tx; ++i) { + int tx_idx = i + b * ru->nb_tx; + memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_offset], + (void*)&gNB->common_vars.txdataF[b][i][txdataF_offset], + fp->samples_per_slot_wCP * sizeof(int32_t)); } } + } else { + AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } stop_meas(&ru->precoding_stats); } @@ -264,7 +246,7 @@ void nr_feptx(void *arg) (void*)&ru->gNB_list[0]->common_vars.txdataF[bb][aa][txdataF_offset], numSamples * sizeof(int32_t)); else { - AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); + AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } if (tx_idx == 0) From a1a4f24d0f0aaf51d79d2ee07421ef6bc607f310 Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Wed, 12 Feb 2025 21:05:31 +0100 Subject: [PATCH 081/100] hotfix for F. Mani's update to nr_feptx_prec handling of multiple beams --- openair1/PHY/INIT/nr_init_ru.c | 2 +- openair1/SCHED_NR/nr_ru_procedures.c | 2 +- radio/fhi_72/oran_isolate.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 49d3890a0b..d96a279b9b 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -51,7 +51,7 @@ void nr_phy_init_RU(RU_t *ru) ru->num_beams_period = analog_config->analog_bf_vendor_ext.value ? analog_config->num_beams_period_vendor_ext.value : 1; int nb_tx_streams = ru->nb_tx * ru->num_beams_period; int nb_rx_streams = ru->nb_rx * ru->num_beams_period; - + LOG_I(NR_PHY, "nb_tx_streams %d, nb_rx_streams %d, num_Beams_period %d\n", nb_tx_streams, nb_rx_streams, ru->num_beams_period); ru->common.beam_id = malloc16_clear(ru->num_beams_period * sizeof(int*)); for(int i = 0; i < ru->num_beams_period; i++) ru->common.beam_id[i] = malloc16_clear(fp->symbols_per_slot * fp->slots_per_frame * sizeof(int)); diff --git a/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index c455e5ac76..0546455e36 100644 --- a/openair1/SCHED_NR/nr_ru_procedures.c +++ b/openair1/SCHED_NR/nr_ru_procedures.c @@ -201,7 +201,7 @@ void nr_feptx_prec(RU_t *ru, int frame_tx, int slot_tx) for (int b = 0; b < ru->num_beams_period; b++) { for (int i = 0; i < ru->nb_tx; ++i) { int tx_idx = i + b * ru->nb_tx; - memcpy((void*)&ru->common.txdataF_BF[tx_idx][txdataF_offset], + memcpy((void*)ru->common.txdataF_BF[tx_idx], (void*)&gNB->common_vars.txdataF[b][i][txdataF_offset], fp->samples_per_slot_wCP * sizeof(int32_t)); } diff --git a/radio/fhi_72/oran_isolate.c b/radio/fhi_72/oran_isolate.c index 0a200a39a0..7ceec513c6 100644 --- a/radio/fhi_72/oran_isolate.c +++ b/radio/fhi_72/oran_isolate.c @@ -208,7 +208,7 @@ int trx_oran_ctlrecv(openair0_device *device, void *msg, ssize_t msg_len) void oran_fh_if4p5_south_in(RU_t *ru, int *frame, int *slot) { ru_info_t ru_info; - ru_info.nb_rx = ru->nb_rx; + ru_info.nb_rx = ru->nb_rx * ru->num_beams_period; ru_info.rxdataF = ru->common.rxdataF; ru_info.prach_buf = ru->prach_rxsigF[0]; // index: [prach_oca][ant_id] @@ -262,7 +262,7 @@ void oran_fh_if4p5_south_out(RU_t *ru, int frame, int slot, uint64_t timestamp) { start_meas(&ru->tx_fhaul); ru_info_t ru_info; - ru_info.nb_tx = ru->nb_tx; + ru_info.nb_tx = ru->nb_tx * ru->num_beams_period; ru_info.txdataF_BF = ru->common.txdataF_BF; // printf("south_out:\tframe=%d\tslot=%d\ttimestamp=%ld\n",frame,slot,timestamp); From 1153721b19c032287880d5a5afbe3815860fce3f Mon Sep 17 00:00:00 2001 From: Raymond Knopp Date: Fri, 21 Mar 2025 12:22:29 +0100 Subject: [PATCH 082/100] changes for multi-RU DAS scenario, handling of antenna ports in 7.2 (memory allocations for PRACH and neAxc in fh_config) --- executables/nr-ru.c | 1 + openair1/PHY/INIT/nr_init_ru.c | 6 +++--- radio/COMMON/common_lib.h | 2 ++ radio/fhi_72/oran-config.c | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/executables/nr-ru.c b/executables/nr-ru.c index 910de225b7..411caf9a63 100644 --- a/executables/nr-ru.c +++ b/executables/nr-ru.c @@ -874,6 +874,7 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file) cfg->num_rb_dl = N_RB; cfg->tx_num_channels = ru->nb_tx * ru->num_beams_period; cfg->rx_num_channels = ru->nb_rx * ru->num_beams_period; + cfg->num_distributed_ru = ru->num_beams_period; LOG_I(PHY,"Setting RF config for N_RB %d, NB_RX %d, NB_TX %d\n",cfg->num_rb_dl,cfg->rx_num_channels,cfg->tx_num_channels); LOG_I(PHY,"tune_offset %.0f Hz, sample_rate %.0f Hz\n",cfg->tune_offset,cfg->sample_rate); diff --git a/openair1/PHY/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index d96a279b9b..a0766c348f 100644 --- a/openair1/PHY/INIT/nr_init_ru.c +++ b/openair1/PHY/INIT/nr_init_ru.c @@ -116,9 +116,9 @@ void nr_phy_init_RU(RU_t *ru) // AssertFatal(ru->nb_rx <= sizeof(ru->prach_rxsigF) / sizeof(ru->prach_rxsigF[0]), // "nb_antennas_rx too large"); for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - ru->prach_rxsigF[j] = (int16_t**)malloc(ru->nb_rx * sizeof(int16_t*)); + ru->prach_rxsigF[j] = (int16_t**)malloc(nb_rx_streams * sizeof(int16_t*)); - for (int i = 0; i < ru->nb_rx; i++) { + for (int i = 0; i < nb_rx_streams; i++) { // largest size for PRACH FFT is 4x98304 (16*24576) ru->prach_rxsigF[j][i] = (int16_t*)malloc16_clear(4 * 98304 * 2 * sizeof(int16_t)); LOG_D(PHY,"[INIT] prach_vars->rxsigF[%d] = %p\n", i, ru->prach_rxsigF[j][i]); @@ -173,7 +173,7 @@ void nr_phy_free_RU(RU_t *ru) free_and_zero(ru->common.rxdataF); for (int j = 0; j < NUMBER_OF_NR_RU_PRACH_OCCASIONS_MAX; j++) { - for (int i = 0; i < ru->nb_rx; i++) + for (int i = 0; i < nb_rx_streams; i++) free_and_zero(ru->prach_rxsigF[j][i]); free_and_zero(ru->prach_rxsigF[j]); } diff --git a/radio/COMMON/common_lib.h b/radio/COMMON/common_lib.h index a33e65c150..86d09b00fb 100644 --- a/radio/COMMON/common_lib.h +++ b/radio/COMMON/common_lib.h @@ -225,6 +225,8 @@ typedef struct openair0_config { int rx_num_channels; //! number of TX channels (=TX antennas) int tx_num_channels; + //! number of distributed radio-units + int num_distributed_ru; //! rx daughter card char* rx_subdev; //! tx daughter card diff --git a/radio/fhi_72/oran-config.c b/radio/fhi_72/oran-config.c index 71804c5298..891634dbfc 100644 --- a/radio/fhi_72/oran-config.c +++ b/radio/fhi_72/oran-config.c @@ -834,7 +834,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c { AssertFatal(num_rus == 1 || num_rus == 2, "only support 1 or 2 RUs as of now\n"); AssertFatal(ru_idx < num_rus, "illegal ru_idx %d: must be < %d\n", ru_idx, num_rus); - DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0); + DevAssert(oai0->tx_num_channels > 0 && oai0->rx_num_channels > 0 && oai0->num_distributed_ru > 0); DevAssert(oai0->tx_bw > 0 && oai0->rx_bw > 0); DevAssert(oai0->tx_freq[0] > 0); for (int i = 1; i < oai0->tx_num_channels; ++i) @@ -879,7 +879,7 @@ static bool set_fh_config(void *mplane_api, int ru_idx, int num_rus, enum xran_c fh_config->dpdk_port = ru_idx; // DPDK port number used for FH fh_config->sector_id = 0; // Band sector ID for FH; not used in xran fh_config->nCC = 1; // number of Component carriers supported on FH; M-plane info - fh_config->neAxc = RTE_MAX(oai0->tx_num_channels / num_rus, oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) + fh_config->neAxc = RTE_MAX(oai0->num_distributed_ru * oai0->tx_num_channels / num_rus, oai0->num_distributed_ru * oai0->rx_num_channels / num_rus); // number of eAxc supported on one CC = max(PDSCH, PUSCH) fh_config->neAxcUl = 0; // number of eAxc supported on one CC for UL direction = PUSCH; used only if XRAN_CATEGORY_B fh_config->nAntElmTRx = 0; // number of antenna elements for TX and RX = SRS; used only if XRAN_CATEGORY_B fh_config->nDLFftSize = 0; // DL FFT size; not used in xran From 405d12293735db582c20b08ac306435a7c556d32 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 18:28:57 +0200 Subject: [PATCH 083/100] GTP: check that packets are not larger than max UDP size --- openair3/ocp-gtpu/gtp_itf.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 3036565fad..0ac9f95fa1 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -224,6 +224,7 @@ static int gtpv1uCreateAndSendMsg(int h, uint8_t extensionHeader_length) { LOG_D(GTPU, "Peer IP:%u peer port:%u outgoing teid:%u \n", peerIp, peerPort, teid); + DevAssert(msgLen + HDR_MAX < 65536); // maximum size of UDP packet uint8_t buffer[msgLen+HDR_MAX]; uint8_t *curPtr=buffer; Gtpv1uMsgHeaderT *msgHdr = (Gtpv1uMsgHeaderT *)buffer ; From 0f78aade97667073c588dd0131490a9bef3f896b Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 08:22:52 +0200 Subject: [PATCH 084/100] Remove useless printf in config reading This printf just shows which config sections are being read, but this has no useful information for a user. It was introduced in 7731f5bd2d8 but was not present prior to this commit, either. --- common/config/config_paramdesc.h | 1 - 1 file changed, 1 deletion(-) diff --git a/common/config/config_paramdesc.h b/common/config/config_paramdesc.h index 6947f6531d..3341162da7 100644 --- a/common/config/config_paramdesc.h +++ b/common/config/config_paramdesc.h @@ -169,7 +169,6 @@ typedef struct paramlist_def { /* Macros to get parameters with the config module API */ #define GET_PARAMS(param_def, param_desc, prefix) \ - printf("Reading '%s' section from the config file\n", #param_def); \ paramdef_t param_def[] = param_desc; \ config_get(config_get_if(), param_def, sizeofArray(param_def), prefix); From 986b212fe905f0983d5ae36b380e02458bce1383 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 08:22:02 +0200 Subject: [PATCH 085/100] GTP: fix memory leak when socket binding fails Avoid leaking memory upon failed socket binding by calling freeaddrinfo() before exiting in error cases. Fixes leak: Direct leak of 64 byte(s) in 1 object(s) allocated from: #0 0x0000004ac038 in malloc (/home/richie/oai/cmake_targets/ran_build/build/nr-softmodem+0x4ac038) (BuildId: 875d6e5bc54d7c89bdcf151452f12703cb6fd110) #1 0x7f0fdd92e2a6 in getaddrinfo (/lib64/libc.so.6+0x1202a6) (BuildId: 2b3c02fe7e4d3811767175b6f323692a10a4e116) #2 0x00000043d7ad in getaddrinfo (/home/richie/oai/cmake_targets/ran_build/build/nr-softmodem+0x43d7ad) (BuildId: 875d6e5bc54d7c89bdcf151452f12703cb6fd110) #3 0x000000700c73 in udpServerSocket(openAddr_s) /home/richie/oai/openair3/ocp-gtpu/gtp_itf.cpp:486:17 #4 0x000000700c73 in gtpv1Init /home/richie/oai/openair3/ocp-gtpu/gtp_itf.cpp:546:10 #5 0x000000c692b8 in cuup_init_n3 /home/richie/oai/openair2/E1AP/e1ap.c:744:61 #6 0x000000549ea1 in create_gNB_tasks /home/richie/oai/executables/nr-softmodem.c:320:7 #7 0x000000549ea1 in main /home/richie/oai/executables/nr-softmodem.c:619:15 #8 0x7f0fdd8115f4 in __libc_start_call_main (/lib64/libc.so.6+0x35f4) (BuildId: 2b3c02fe7e4d3811767175b6f323692a10a4e116) #9 0x7f0fdd8116a7 in __libc_start_main@GLIBC_2.2.5 (/lib64/libc.so.6+0x36a7) (BuildId: 2b3c02fe7e4d3811767175b6f323692a10a4e116) #10 0x000000408524 in _start (/home/richie/oai/cmake_targets/ran_build/build/nr-softmodem+0x408524) (BuildId: 875d6e5bc54d7c89bdcf151452f12703cb6fd110) --- openair3/ocp-gtpu/gtp_itf.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 0ac9f95fa1..fd571e8d0e 100644 --- a/openair3/ocp-gtpu/gtp_itf.cpp +++ b/openair3/ocp-gtpu/gtp_itf.cpp @@ -526,14 +526,14 @@ static int udpServerSocket(openAddr_s addr) { break; // if we get here, we must have connected successfully } + freeaddrinfo(servinfo); // all done with this structure + if (p == NULL) { // looped off the end of the list with no successful bind LOG_E(GTPU,"failed to bind socket: %s %s \n", addr.originHost, addr.originService); return -1; } - freeaddrinfo(servinfo); // all done with this structure - int sendbuff = 1000*1000*10; AssertFatal(0==setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, sizeof(sendbuff)),""); LOG_D(GTPU,"[%d] Created listener for paquets to: %s:%s, send buffer size: %d\n", sockfd, addr.originHost, addr.originService,sendbuff); From f0ca66adcddcc71b9a02175d306146fff6b2d1fb Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 08:58:05 +0200 Subject: [PATCH 086/100] Remove unused MAC types and includes Using the USIM interface in the MAC is non-sensical (violates layer separation). Add header include in nr-softmodem.c, which previously came through nr_mac_gNB.h -> usim_interface.h. --- executables/nr-softmodem.c | 1 + openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c index b9302392ab..332e06e7af 100644 --- a/executables/nr-softmodem.c +++ b/executables/nr-softmodem.c @@ -23,6 +23,7 @@ #define _GNU_SOURCE /* See feature_test_macros(7) */ #include "common/config/config_userapi.h" +#include "common/utils/load_module_shlib.h" #include "RRC/LTE/rrc_vars.h" #ifdef SMBV #include "PHY/TOOLS/smbv.h" diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d97783604f..8d42b7cc02 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -89,9 +89,6 @@ #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h" #include "NR_TAG.h" -#include - - /* Defs */ #define MAX_NUM_BWP 5 #define MAX_NUM_CORESET 12 @@ -100,7 +97,6 @@ #define NR_NB_RA_PROC_MAX 4 #define MAX_NUM_OF_SSB 64 #define MAX_NUM_NR_PRACH_PREAMBLES 64 -#define MIN_NUM_PRBS_TO_SCHEDULE 5 uint8_t nr_get_rv(int rel_round); @@ -677,10 +673,6 @@ typedef struct { float pdcch_cl_adjust; } NR_UE_sched_ctrl_t; -typedef struct { - uicc_t *uicc; -} NRUEcontext_t; - typedef struct NR_mac_dir_stats { uint64_t lc_bytes[64]; uint64_t rounds[8]; From ded31877343d2d32acd0fa2b7abd0b46c0a5ddd8 Mon Sep 17 00:00:00 2001 From: francescomani Date: Tue, 22 Apr 2025 17:54:51 +0200 Subject: [PATCH 087/100] omitting beam weigths in case of DAS --- doc/analog_beamforming.md | 4 ++-- openair1/SCHED_NR/phy_procedures_nr_gNB.c | 4 ++-- openair2/GNB_APP/gnb_config.c | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/analog_beamforming.md b/doc/analog_beamforming.md index e953e02fb3..4ff208343e 100644 --- a/doc/analog_beamforming.md +++ b/doc/analog_beamforming.md @@ -20,9 +20,9 @@ In the `MACRLC` section of configuration files, there are three new parameters: - `set_analog_beamforming` can be set to 1 or 0 to activate or desactivate analog beamforming (default value is 0) - `beam_duration` is the number of slots (currently minimum duration of a beam) the scheduler is tied to a beam (default value is 1) - `beams_per_period` is the number of concurrent beams the RU can handle in the beam duration (default value is 1) -- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted. +- `beam_weights` is a vector field containing the set of beam indices to be provided by the OAI L1 to the RU is also required. In current implementation, the number of beam indices should be equal to the number of SSBs transmitted -DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. +DAS is enabled by setting to 1 the parameter `enable_das` in the L1 section of the configuration file. In case of DAS enabled, the field `beam_weights` in `MACRLC` section can be omitted. # Implementation in OAI scheduler diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index ad75cc733e..d21674edaf 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -55,10 +55,10 @@ int beam_index_allocation(bool das, { if (!common_vars->beam_id) return 0; + if (das) + return fapi_beam_index; int ru_beam_idx = analog_bf->analog_beam_list[fapi_beam_index].value; - if (das) - return ru_beam_idx; int idx = -1; for (int j = 0; j < common_vars->num_beams_period; j++) { // L2 analog beam implementation is slot based, so we need to verify occupancy for the whole slot diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 4a68aa1f78..44ea5648bf 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1700,6 +1700,10 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) beam_info->beam_allocation_size = -1; // to be initialized once we have information on frame configuration } if (config_isparamset(MacRLC_ParamList.paramarray[j], MACRLC_BEAMWEIGHTS_IDX)) { + if (NFAPI_MODE == NFAPI_MONOLITHIC) { + GET_PARAMS_LIST(L1_ParamList, L1_Params, L1PARAMS_DESC, CONFIG_STRING_L1_LIST, NULL); + AssertFatal(*(L1_ParamList.paramarray[j][L1_ANALOG_DAS].uptr) == 0, "No need to set beam weights in case of DAS\n"); + } int n = MacRLC_ParamList.paramarray[j][MACRLC_BEAMWEIGHTS_IDX].numelt; int num_beam = n; if (!ab) { From 73a2ba3894c662699e285cf2c43df49f54a13b1c Mon Sep 17 00:00:00 2001 From: francescomani Date: Wed, 11 Jun 2025 10:22:23 +0200 Subject: [PATCH 088/100] assertion to avoid using analog beamforming in split scenario --- openair2/GNB_APP/gnb_config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 44ea5648bf..e9d0099340 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1692,6 +1692,7 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) } bool ab = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMFORMING_IDX].u8ptr; if (ab) { + AssertFatal(NFAPI_MODE == NFAPI_MONOLITHIC, "Analog beamforming only supported for monolithic scenario\n"); NR_beam_info_t *beam_info = &RC.nrmac[j]->beam_info; int beams_per_period = *MacRLC_ParamList.paramarray[j][MACRLC_ANALOG_BEAMS_PERIOD_IDX].u8ptr; beam_info->beam_allocation = malloc16(beams_per_period * sizeof(int *)); From 4262203e2de1df6635a5daed6815b5915c009633 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 18 Feb 2025 07:27:57 +0000 Subject: [PATCH 089/100] Add NAS Security Mode Reject enc/dec lib and unit test This 5GMM message is required for an invalid security mode command, e.g. when the MAC integrity fails, or the wrong Security Header is set. * Add encode/decode functions for common IEs in fgmm_lib: this library provides encoding/decoding helpers for IEs shared across multiple NAS messages. The goal is to avoid the legacy approach of creating separate files per IE * add NAS Cause enc/dec lib * Adopted byte_array_t to handle the buffer Co-authored-by: Eduard Vlad --- .../NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt | 1 + .../5GS/5GMM/MSG/FGSNASSecurityModeReject.c | 50 +++++++++++++++++++ .../5GS/5GMM/MSG/FGSNASSecurityModeReject.h | 47 +++++++++++++++++ openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c | 33 ++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c create mode 100644 openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt index bf47e478b9..0f4445c353 100644 --- a/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/CMakeLists.txt @@ -9,6 +9,7 @@ add_library(fgs_5gmm_lib OBJECT FGSIdentityResponse.c FGSAuthenticationResponse.c FGSNASSecurityModeComplete.c + FGSNASSecurityModeReject.c RegistrationComplete.c FGSUplinkNasTransport.c FGSDeregistrationRequestUEOriginating.c diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c b/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c new file mode 100644 index 0000000000..3f61b14ad7 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.c @@ -0,0 +1,50 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include "FGSNASSecurityModeReject.h" +#include "common/utils/ds/byte_array.h" +#include "fgmm_lib.h" + +int encode_fgs_security_mode_reject(byte_array_t *buffer, const fgs_security_mode_reject_msg *msg) +{ + if (buffer->len < 1) + return -1; // nothing to encode + + // 5GMM cause (Mandatory) + return encode_fgs_nas_cause(buffer, &msg->cause); +} + +/** @brief Decode Security Mode Reject (8.2.18 of 3GPP TS 24.501) */ +int decode_fgs_security_mode_reject(fgs_security_mode_reject_msg *msg, const byte_array_t *buffer) +{ + if (buffer->len < 1) + return -1; // nothing to decode + + // 5GMM cause (Mandatory) + return decode_fgs_nas_cause(&msg->cause, buffer); +} + +bool eq_sec_mode_reject(const fgs_security_mode_reject_msg *a, const fgs_security_mode_reject_msg *b) +{ + _NAS_EQ_CHECK_INT(a->cause, b->cause); + return true; +} diff --git a/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h b/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h new file mode 100644 index 0000000000..28c10e3700 --- /dev/null +++ b/openair3/NAS/NR_UE/5GS/5GMM/MSG/FGSNASSecurityModeReject.h @@ -0,0 +1,47 @@ +/* + * 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 FGS_NAS_security_mode_reject_H_ +#define FGS_NAS_security_mode_reject_H_ + +#include +#include "fgmm_lib.h" + +/* + * Message name: security mode reject + * Description: The SECURITY MODE REJECT message is sent by the UE to the AMF to + * indicate that the corresponding security mode command has been rejected. + * See 3GPP TS 24.501 table 8.2.27.1.1 + * + * Significance: dual + * Direction: UE to AMF + */ + +typedef struct { + // 5GMM cause (Mandatory) + cause_id_t cause; +} fgs_security_mode_reject_msg; + +int encode_fgs_security_mode_reject(byte_array_t *buffer, const fgs_security_mode_reject_msg *msg); +int decode_fgs_security_mode_reject(fgs_security_mode_reject_msg *msg, const byte_array_t *buffer); +bool eq_sec_mode_reject(const fgs_security_mode_reject_msg *a, const fgs_security_mode_reject_msg *b); + +#endif /* ! defined(FGS_NAS_security_mode_reject_H_) */ diff --git a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c index 88de4f13aa..f733bdd3a5 100644 --- a/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c +++ b/openair3/NAS/NR_UE/5GS/tests/nas_lib_test.c @@ -8,6 +8,7 @@ #include "fgmm_service_accept.h" #include "fgmm_service_reject.h" #include "fgmm_authentication_failure.h" +#include "FGSNASSecurityModeReject.h" #include "nr_nas_msg.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) @@ -266,6 +267,37 @@ static void test_auth_failure(void) free_fgmm_auth_failure(&dec); } +/** @brief Test NAS Security Mode Reject enc/dec */ +static void test_security_mode_reject(void) +{ + // Dummy NAS Security Mode Reject message + const fgs_security_mode_reject_msg orig = { + .cause = Illegal_UE, + }; + + // Expected encoded data + uint8_t expected_enc[] = {0x03}; + + // Buffer + uint8_t buf[8] = {0}; + byte_array_t buffer = {.buf = buf, .len = sizeof(buf)}; + + // Encode + int encoded_length = encode_fgs_security_mode_reject(&buffer, &orig); + AssertFatal(encoded_length == sizeofArray(expected_enc), "encode_fgs_security_mode_reject() failed\n"); + + // Compare the raw encoded buffer with expected encoded data + AssertFatal(memcmp(buffer.buf, expected_enc, encoded_length) == 0, "Encoding mismatch!\n"); + + // Decode + fgs_security_mode_reject_msg dec = {0}; + int decoded_length = decode_fgs_security_mode_reject(&dec, &buffer); + AssertFatal(decoded_length >= 0, "decode_fgs_security_mode_reject() failed\n"); + + // Compare original and decoded messages + AssertFatal(eq_sec_mode_reject(&orig, &dec), "test_sec_mode_reject() failed: original and decoded messages do not match\n"); +} + int main() { test_regression_registration_accept(); @@ -273,5 +305,6 @@ int main() test_service_accept(); test_service_reject(); test_auth_failure(); + test_security_mode_reject(); return 0; } From 98c458fa2c98bf2df8cc0e599921bd5876b37c67 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Wed, 28 May 2025 10:13:28 +0200 Subject: [PATCH 090/100] FGS NAS lib: enable encoding of Security Mode Reject Signed-off-by: Eduard Vlad Co-authored-by: Guido Casati --- openair3/NAS/NR_UE/5GS/NR_NAS_defs.h | 2 ++ openair3/NAS/NR_UE/5GS/fgs_nas_lib.c | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/openair3/NAS/NR_UE/5GS/NR_NAS_defs.h b/openair3/NAS/NR_UE/5GS/NR_NAS_defs.h index ab94925f09..2c8ecdf150 100644 --- a/openair3/NAS/NR_UE/5GS/NR_NAS_defs.h +++ b/openair3/NAS/NR_UE/5GS/NR_NAS_defs.h @@ -31,6 +31,7 @@ #include "FGSIdentityResponse.h" #include "FGSMobileIdentity.h" #include "FGSNASSecurityModeComplete.h" +#include "FGSNASSecurityModeReject.h" #include "FGSUplinkNasTransport.h" #include "RegistrationComplete.h" #include "RegistrationRequest.h" @@ -226,6 +227,7 @@ typedef struct { fgmm_auth_failure_t fgmm_auth_failure; fgs_deregistration_request_ue_originating_msg fgs_deregistration_request_ue_originating; fgs_security_mode_complete_msg fgs_security_mode_complete; + fgs_security_mode_reject_msg fgs_security_mode_reject; registration_complete_msg registration_complete; fgs_uplink_nas_transport_msg uplink_nas_transport; } mm_msg; /* 5GS Mobility Management messages */ diff --git a/openair3/NAS/NR_UE/5GS/fgs_nas_lib.c b/openair3/NAS/NR_UE/5GS/fgs_nas_lib.c index ca40131af6..3fcd82aa9b 100644 --- a/openair3/NAS/NR_UE/5GS/fgs_nas_lib.c +++ b/openair3/NAS/NR_UE/5GS/fgs_nas_lib.c @@ -81,6 +81,11 @@ int mm_msg_encode(const fgmm_nas_message_plain_t *p, uint8_t *buffer, uint32_t l case FGS_SECURITY_MODE_COMPLETE: enc_msg = encode_fgs_security_mode_complete(&p->mm_msg.fgs_security_mode_complete, buffer, len); break; + case FGS_SECURITY_MODE_REJECT: { + byte_array_t ba = {.buf = buffer, .len = len}; + enc_msg = encode_fgs_security_mode_reject(&ba, &p->mm_msg.fgs_security_mode_reject); + break; + } case FGS_UPLINK_NAS_TRANSPORT: enc_msg = encode_fgs_uplink_nas_transport(&p->mm_msg.uplink_nas_transport, buffer, len); break; From 6399d93be844195843b480833f1b914a13352632 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Wed, 28 May 2025 10:23:07 +0200 Subject: [PATCH 091/100] Add callback for generation of NAS Security Mode Reject message This is necessary to indicate to the Core network, that the security mode command procedure has failed. Check for the security context presence when generating the Security Mode reject message: according to 3GPP TS 24.501 5.4.2.5 "NAS security mode command not accepted by the UE" The UE shall send a SECURITY MODE REJECT containing a 5GMM cause that typically indicates one of the following cause values: (23) UE security capabilities mismatch (24) security mode rejected, unspecified The message shall be protected if a security context is available Signed-off-by: Eduard Vlad Co-authored-by: Guido Casati --- openair3/NAS/NR_UE/nr_nas_msg.c | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d152a5d4a3..5b23c4a041 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1042,6 +1042,68 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia } } +/** @brief Generates the Security Mode Reject message to be sent by the UE to the AMF + * to indicate that the corresponding security mode command has been rejected */ +static void generateSecurityModeReject(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, cause_id_t cause) +{ + LOG_I(NAS, "Send Security Mode Reject\n"); + fgmm_msg_header_t plain_header = set_mm_header(FGS_SECURITY_MODE_REJECT, PLAIN_5GS_MSG); + int size = sizeof(plain_header); + fgs_security_mode_reject_msg msg = {.cause = cause}; + size += 1; + + /** The UE shall apply the 5G NAS security context in use + * before the initiation of the security mode control procedure, + * if any, to protect the SECURITY MODE REJECT message */ + bool has_security_context = nas->security_container && nas->security_container->integrity_context; + if (has_security_context) { + fgmm_nas_msg_security_protected_t sp = {0}; + sp.header.protocol_discriminator = FGS_MOBILITY_MANAGEMENT_MESSAGE; + sp.header.security_header_type = INTEGRITY_PROTECTED; + sp.header.sequence_number = nas->security.nas_count_ul & 0xff; + size += sizeof(sp.header); + sp.plain.header = plain_header; + sp.plain.mm_msg.fgs_security_mode_reject = msg; + // Security protected header encoding + int security_header_len = nas_protected_security_header_encode(initialNasMsg->nas_data, &sp.header, size); + initialNasMsg->length = + security_header_len + mm_msg_encode(&sp.plain, initialNasMsg->nas_data + security_header_len, size - security_header_len); + /* ciphering */ + uint8_t buf[initialNasMsg->length - 7]; + nas_stream_cipher_t stream_cipher; + stream_cipher.context = nas->security_container->ciphering_context; + AssertFatal(nas->security.nas_count_ul <= 0xffffff, "fatal: NAS COUNT UL too big (todo: fix that)\n"); + stream_cipher.count = nas->security.nas_count_ul; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->nas_data + 7); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 7) << 3; + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); + memcpy(stream_cipher.message, buf, initialNasMsg->length - 7); + /* integrity protection */ + uint8_t mac[4]; + stream_cipher.context = nas->security_container->integrity_context; + stream_cipher.count = nas->security.nas_count_ul++; + stream_cipher.bearer = 1; + stream_cipher.direction = 0; + stream_cipher.message = (unsigned char *)(initialNasMsg->nas_data + 6); + /* length in bits */ + stream_cipher.blength = (initialNasMsg->length - 6) << 3; + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); + LOG_D(NAS, "Integrity protected initial NAS message: mac = %x %x %x %x \n", mac[0], mac[1], mac[2], mac[3]); + for (int i = 0; i < 4; i++) + initialNasMsg->nas_data[2 + i] = mac[i]; + } else { + fgmm_nas_message_plain_t plain = {0}; + plain.header = plain_header; + plain.mm_msg.fgs_security_mode_reject = msg; + // encode the message + initialNasMsg->nas_data = malloc_or_fail(size); + initialNasMsg->length = mm_msg_encode(&plain, initialNasMsg->nas_data, size); + } +} + static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length) { /* retrieve integrity and ciphering algorithms */ From 896698dab5eaf95c0ab1a21a9cc30be6343b3649 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Fri, 31 Jan 2025 10:49:04 +0000 Subject: [PATCH 092/100] SMC: reject NULL integrity for non emergency cases Signed-off-by: Eduard Vlad --- openair3/NAS/NR_UE/nr_nas_msg.c | 6 ++++++ openair3/SECU/secu_defs.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 5b23c4a041..e647857336 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1134,6 +1134,12 @@ static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initia /* todo: stream_security_container_delete() is not called anywhere, deal with that */ nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int); + /* Handle the invalid container with a reject message */ + if(nas->security_container == NULL) { + LOG_W(NAS, "Could not create security container!\n"); + return; + } + nas_itti_kgnb_refresh_req(nas->UE_id, nas->security.kgnb); generateSecurityModeComplete(nas, initialNasMsg); } diff --git a/openair3/SECU/secu_defs.c b/openair3/SECU/secu_defs.c index 17e3ca96ec..f8edf167df 100644 --- a/openair3/SECU/secu_defs.c +++ b/openair3/SECU/secu_defs.c @@ -118,6 +118,12 @@ stream_security_container_t *stream_security_container_init(int ciphering_algori container->integrity_context = stream_integrity_init(integrity_algorithm, integrity_key); container->ciphering_context = stream_ciphering_init(ciphering_algorithm, ciphering_key); + /* Reject invalid configurations, i.e. ones that set NIA0 */ + if (container->integrity_context == NULL) { + stream_security_container_delete(container); + return NULL; + } + return container; } From 6c8a3796ae56909e4d753a2caf9b84f69a2de5e6 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Tue, 10 Jun 2025 14:11:03 +0200 Subject: [PATCH 093/100] nas security: Implement reusable procedures for Security Mode Command handling Retrieving the mac is necessary during the handling of the SMC, since the context is generated from the specified keys therein. Therefore, it is necessary to check the MAC right after generation and ensure the authenticity of the message. If it is not given, the message must be rejected. Signed-off-by: Eduard Vlad Co-authored-by: Guido Casati --- openair3/NAS/NR_UE/nr_nas_msg.c | 147 ++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index e647857336..109037e9b1 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -151,6 +151,153 @@ static bool unprotected_allowed(byte_array_t buffer, fgs_nas_msg_t msg_type) } } +/** + * @brief Get the MAC of a Security Protected NAS message + * @param[in] pdu_buffer The buffer containing the NAS message + * @param[in] pdu_length The length of the NAS message + * @param[out] mac The MAC of the NAS message + * @return true if the MAC was successfully extracted, false otherwise + */ +bool nas_security_get_mac(uint8_t *pdu_buffer, int pdu_length, uint8_t *mac) +{ + /* Check for Security Protected Header */ + /* at least 8 bytes for Security Protected MM Message */ + if (pdu_length < 8) + return false; + + /* Only message type, that is not protected (c.f. + TS 24.501 9.3 Security Header Type) */ + if ((Security_header_t)pdu_buffer[1] == PLAIN_5GS_MSG) + return false; + + /* Get the MAC [EPD][SecHdr][MAC0]..[MAC3] - success */ + for (int i = 0; i < 4; i++) + mac[i] = pdu_buffer[2 + i]; + return true; +} + +/* + * @brief Get the Security Header of a NAS message + * @param[in] msg The buffer containing the NAS message + * @param[in] msg_length The length of the NAS message + * @param[out] sec_hdr The Security Header of the NAS message + * @return true if the Security Header was successfully extracted, false otherwise + */ +bool nas_security_get_sec_hdr(uint8_t *msg, int msg_length, Security_header_t *sec_hdr) +{ + /* Shortest message is [EPD][SecHdrType][Payl]*/ + if (msg_length < 3) { + LOG_E(NAS, "Invalid NAS message length %d\n", msg_length); + return false; + } + + /* Get the SecHdr and check for validity */ + uint8_t sec_hdr_type = msg[1] & 0x0f; + if (sec_hdr_type > INTEGRITY_PROTECTED_AND_CIPHERED_WITH_NEW_SECU_CTX) { + LOG_E(NAS, "Invalid Security Header Type %d\n", sec_hdr_type); + return false; + } + + /* Check ok. */ + *sec_hdr = (Security_header_t)sec_hdr_type; + return true; +} + +/* + * @brief Compute the MAC of a NAS message + * @param[in] nas The NAS context + * @param[in] pdu_buffer The buffer containing the NAS message + * @param[in] is_uplink True if the message is uplink, false Downlink + * @param[in] is3gpp_access True if the message is 3GPP access, false otherwise + * @param[in] pdu_length The length of the NAS message + * @param[out] mac The MAC of the NAS message + */ +static void nas_security_compute_mac(nr_ue_nas_t *nas, + byte_array_t buffer, + const bool is_uplink, + const bool is3gpp_access, + uint8_t *mac) +{ + uint8_t *buf = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH - 1; + int len = buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH + 1; + + /* Compute the MAC */ + nas_stream_cipher_t stream_cipher; + stream_cipher.context = nas->security_container->integrity_context; + + /* Select the right count in the context */ + if (is_uplink) + stream_cipher.count = nas->security.nas_count_ul; + else + stream_cipher.count = nas->security.nas_count_dl; + + /* 3GPP access is 1, non-3GPP access is 2 - see 3GPP TS 33.501 6.4.2.2 */ + stream_cipher.bearer = is3gpp_access ? 1 : 2; + + /* Configure Direction for MAC protection */ + stream_cipher.direction = is_uplink ? 0 : 1; + + /* Possibly encrypted message */ + stream_cipher.message = buf; + + /* length in bits */ + stream_cipher.blength = len << 3; + + stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, mac); +} + +/* + * @brief: Decrypt the payload of a NAS message. The buffer is modified in place + * @param[in] nas The NAS context + * @param[in] pdu_buffer The buffer containing the full (header + payload) NAS message + * @param[in] is_uplink True if the message is uplink, false Downlink + * @param[in] is3gpp_access True if the message is 3GPP access, false otherwise + * @param[in] pdu_length The length of the NAS message + */ +static void nas_security_decrypt_payload(nr_ue_nas_t *nas, byte_array_t buffer, const bool is_uplink, const bool is3gpp_access) +{ + Security_header_t sec_hdr; + + if (!nas_security_get_sec_hdr(buffer.buf, buffer.len, &sec_hdr)) { + LOG_E(NAS, "Failed to get Security Header\n"); + return; + } + + /* Nothing to do for unencrypted msgs */ + if (sec_hdr == PLAIN_5GS_MSG || sec_hdr == INTEGRITY_PROTECTED) { + return; + } + + /* Get integrity keys, and algorithms */ + nas_stream_cipher_t stream_cipher; + stream_cipher.context = nas->security_container->ciphering_context; + + /* Use the estimated count the right count in the context */ + stream_cipher.count = nas->security.nas_count_dl; + /* 3GPP access is 1, non-3GPP access is 2 - see 3GPP TS 33.501 6.4.2.2 */ + stream_cipher.bearer = is3gpp_access ? 1 : 2; + + /* Decryption only in downlink direction */ + stream_cipher.direction = 1; + + /* [EPD][SHR][MAC0]..[MAC3][PDU...]*/ + uint8_t *plain_payload = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; + stream_cipher.message = plain_payload; + + /* length in bits */ + int plain_length = buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; + stream_cipher.blength = plain_length << 3; + + /* Allocate output buffer for body only */ + uint8_t *decrypted = malloc_or_fail(plain_length); + + stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, decrypted); + + /* Override and free the decrypted payload */ + memcpy(plain_payload, decrypted, plain_length); + free(decrypted); +} + static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t buffer, fgs_nas_msg_t msg_type) { if (nas->security_container == NULL) From a2a8e3ba6d2886e05ef9e94a22630bf349567fd5 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Wed, 28 May 2025 10:25:09 +0200 Subject: [PATCH 094/100] Security Mode Command: Handle incorrect authentication It is not allowed to accept an unauthenticated SMC message, as this effectively bypasses all security measures and enables a malicioius attacker to compromise the confidentiality and integrity of exchanged messages. Signed-off-by: Eduard Vlad Co-authored-by: Guido Casati --- openair3/NAS/NR_UE/nr_nas_msg.c | 83 ++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index 109037e9b1..f2e3b8dd07 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -356,35 +356,22 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b } /* check integrity */ - uint8_t computed_mac[NAS_INTEGRITY_SIZE]; - nas_stream_cipher_t stream_cipher; - stream_cipher.context = nas->security_container->integrity_context; - stream_cipher.count = nas->security.nas_count_dl; - stream_cipher.bearer = 1; /* todo: don't hardcode */ - stream_cipher.direction = 1; - stream_cipher.message = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH - 1; - /* length in bits */ - stream_cipher.blength = (buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH + 1) << 3; - stream_compute_integrity(nas->security_container->integrity_algorithm, &stream_cipher, computed_mac); - + /* [EPD][SHD][MAC0]...[MAC3][SEQNO][PAYL]*/ uint8_t *received_mac = buffer.buf + 2; + uint8_t computed_mac[NAS_INTEGRITY_SIZE]; + nas_security_compute_mac(nas, + buffer, + false, + true, + computed_mac); if (memcmp(received_mac, computed_mac, NAS_INTEGRITY_SIZE) != 0) return NAS_SECURITY_INTEGRITY_FAILED; /* decipher */ - uint8_t payload_len = buffer.len - SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; - uint8_t buf[payload_len]; - stream_cipher.context = nas->security_container->ciphering_context; - stream_cipher.count = nas->security.nas_count_dl; - stream_cipher.bearer = 1; /* todo: don't hardcode */ - stream_cipher.direction = 1; - stream_cipher.message = buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH; - /* length in bits */ - stream_cipher.blength = (payload_len) << 3; - stream_compute_encrypt(nas->security_container->ciphering_algorithm, &stream_cipher, buf); - memcpy(buffer.buf + SECURITY_PROTECTED_5GS_NAS_MESSAGE_HEADER_LENGTH, buf, payload_len); + nas_security_decrypt_payload(nas, buffer, false, true); + /* update estimated DL Counter */ nas->security.nas_count_dl++; return NAS_SECURITY_INTEGRITY_PASSED; @@ -1253,8 +1240,39 @@ static void generateSecurityModeReject(nr_ue_nas_t *nas, as_nas_info_t *initialN static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *pdu, int pdu_length) { + /* Handle security mode command: must be authenticated, especially if no security + context has been previously established. */ + uint8_t recv_mac[4]; + Security_header_t sec_hdr; + + /* Must have valid security header*/ + if(!nas_security_get_sec_hdr(pdu, pdu_length, &sec_hdr)) { + LOG_E(NAS, "Received Security Mode Command without integrity protection.\n"); + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); + return; + } + + /* Must be integrity protected with new context (=3), see 3GPP TS 24.501 5.4.2.2 */ + if(sec_hdr != INTEGRITY_PROTECTED_WITH_NEW_SECU_CTX) { + LOG_E(NAS, "Received Security Mode Command with invalid security header type %d.\n", sec_hdr); + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); + return; + } + + /* Must have a MAC - checked after deriving keys */ + if(!nas_security_get_mac(pdu, pdu_length, recv_mac)) { + LOG_E(NAS, "Received Security Mode Command with invalid MAC.\n"); + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); + return; + } + /* retrieve integrity and ciphering algorithms */ - AssertFatal(pdu_length > 10, "nas: bad pdu\n"); + if (pdu_length < 10) { + LOG_E(NAS, "Invalid pdu_length=%d : send Security Mode Reject\n", pdu_length); + // 3GPP TS 24.501 5.4.2.5 NAS security mode command not accepted by the UE + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); + } + int ciphering_algorithm = (pdu[10] >> 4) & 0x0f; int integrity_algorithm = pdu[10] & 0x0f; @@ -1284,6 +1302,25 @@ static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initia /* Handle the invalid container with a reject message */ if(nas->security_container == NULL) { LOG_W(NAS, "Could not create security container!\n"); + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); + return; + } + + /* Check MAC and delete context if it does not match */ + uint8_t computed_mac[NAS_INTEGRITY_SIZE]; + byte_array_t ba = {.buf = pdu, .len = pdu_length}; + nas_security_compute_mac(nas, ba, false, true, computed_mac); + + /* Teardown security container if mismatch. */ + if(memcmp(computed_mac, recv_mac, NAS_INTEGRITY_SIZE) != 0) { + LOG_W(NAS, "MAC does not match\n"); + LOG_W(NAS, "Expected: %x %x %x %x\n", computed_mac[0], computed_mac[1], computed_mac[2], computed_mac[3]); + LOG_W(NAS, "Received: %x %x %x %x\n", recv_mac[0], recv_mac[1], recv_mac[2], recv_mac[3]); + stream_security_container_delete(nas->security_container); + nas->security_container = NULL; + + /* Signal rejection */ + generateSecurityModeReject(nas, initialNasMsg, Security_mode_rejected_unspecified); return; } From 5e45ecb1239ac5241cefbff6030087255f3ade94 Mon Sep 17 00:00:00 2001 From: Eduard Vlad Date: Thu, 22 May 2025 14:31:34 +0200 Subject: [PATCH 095/100] Security Mode Command: Perform Algorithm Rejection in NAS Handler This change performs the algorithm rejection in the corresponding NAS handler for 5G, since the protocol definitions differ between LTE and 5G, regarding NIA0/EIA0 user plane traffic. Therefore, for 5G NIA0 is rejected, since it is not allowed under normal circumstances, while LTE user plane traffic can indeed have EIA0 selected. Signed-off-by: Eduard Vlad --- openair3/NAS/NR_UE/nr_nas_msg.c | 9 +++++++-- openair3/SECU/secu_defs.c | 6 ------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index f2e3b8dd07..1a88b03205 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg.c +++ b/openair3/NAS/NR_UE/nr_nas_msg.c @@ -1296,8 +1296,13 @@ static void handle_security_mode_command(nr_ue_nas_t *nas, as_nas_info_t *initia } printf("\n"); - /* todo: stream_security_container_delete() is not called anywhere, deal with that */ - nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int); + if (integrity_algorithm != EIA0_ALG_ID) { + nas->security_container = stream_security_container_init(ciphering_algorithm, integrity_algorithm, knas_enc, knas_int); + } else { + LOG_E(NAS, "Rejecting Invalid NULL integrity %d for 5G!\n", + integrity_algorithm); + nas->security_container = NULL; + } /* Handle the invalid container with a reject message */ if(nas->security_container == NULL) { diff --git a/openair3/SECU/secu_defs.c b/openair3/SECU/secu_defs.c index f8edf167df..17e3ca96ec 100644 --- a/openair3/SECU/secu_defs.c +++ b/openair3/SECU/secu_defs.c @@ -118,12 +118,6 @@ stream_security_container_t *stream_security_container_init(int ciphering_algori container->integrity_context = stream_integrity_init(integrity_algorithm, integrity_key); container->ciphering_context = stream_ciphering_init(ciphering_algorithm, ciphering_key); - /* Reject invalid configurations, i.e. ones that set NIA0 */ - if (container->integrity_context == NULL) { - stream_security_container_delete(container); - return NULL; - } - return container; } From 27ece7e7f56323607be0b43b7975a2dfe1b324fb Mon Sep 17 00:00:00 2001 From: Jaroslava Fiedlerova Date: Thu, 12 Jun 2025 11:42:27 +0200 Subject: [PATCH 096/100] CI: update AmariUE configuration file, add RF configuration --- ci-scripts/as_ue/aw2s-multi-00102-20.cfg | 5 +-- ci-scripts/as_ue/config.cfg | 47 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 ci-scripts/as_ue/config.cfg diff --git a/ci-scripts/as_ue/aw2s-multi-00102-20.cfg b/ci-scripts/as_ue/aw2s-multi-00102-20.cfg index 48901cf6f0..5fc05d6301 100644 --- a/ci-scripts/as_ue/aw2s-multi-00102-20.cfg +++ b/ci-scripts/as_ue/aw2s-multi-00102-20.cfg @@ -8,13 +8,13 @@ #define DL_ARFCN 631296 #define TDD 1 -log_options: "all.level=warn,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1", +log_options: "all.level=debug,all.max_size=0,nas.level=debug,nas.max_size=1,rrc.level=debug,rrc.max_size=1", log_filename: "/tmp/ue.log", /* Enable remote API and Web interface */ com_addr: "0.0.0.0:9002", -include "rf_driver_20/1chan.cfg", +include "rf_driver/config.cfg", /* If true, allow the simulation of several UEs at the same time and allow dynamic UE creation from remote API */ @@ -22,7 +22,6 @@ allow dynamic UE creation from remote API */ cell_groups: [{ group_type: "nr", multi_ue: true, - ldpc_max_its:8, cells: [{ rf_port: 0, bandwidth: 20, diff --git a/ci-scripts/as_ue/config.cfg b/ci-scripts/as_ue/config.cfg new file mode 100644 index 0000000000..1c71b752c1 --- /dev/null +++ b/ci-scripts/as_ue/config.cfg @@ -0,0 +1,47 @@ +/* Parameters for SDR device version 2023-06-10 + * Copyright (C) 2015-2023 Amarisoft + */ + +#if !defined(N_CELL) + #define N_CELL 1 +#endif + +#if N_ANTENNA_DL <= 2 + #define N_CHAN N_CELL +#else + #define N_CHAN 2*N_CELL +#endif + +rf_driver: { + name: "sdr", + + /* list of devices. 'dev0' is always the master. */ +#if N_CHAN == 1 + args: "dev0=/dev/sdr0", +#elif N_CHAN == 2 + args: "dev0=/dev/sdr0,dev1=/dev/sdr1", +#elif N_CHAN == 3 + args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2", +#elif N_CHAN == 4 + args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2,dev3=/dev/sdr3", +#elif N_CHAN == 6 + args: "dev0=/dev/sdr0,dev1=/dev/sdr1,dev2=/dev/sdr2,dev3=/dev/sdr3,dev4=/dev/sdr4,dev5=/dev/sdr5", +#else + args: "", +#endif + + /* synchronisation source: internal, gps, external (default = internal) */ + // sync: "gps", + //rx_antenna:"rx", // force to use the RX connector in TDD as RX antenna + + /* PCIe jitter. decrease it to reduce latency */ + fifo_tx_time: 50, + //rx_latency: 30, +}, + +#if 0 + tx_pad_duration:300, +#endif + +tx_gain: 75.0, /* TX gain (in dB) */ +rx_gain: 55.0, /* RX gain (in dB) */ From 15370e7192f2259fb7ed0389ec9d117261431526 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Fri, 6 Jun 2025 07:50:14 +0200 Subject: [PATCH 097/100] Implement RB suspend at gNB MAC Add a flag for each RB that tracks suspension state. Mark all RBs (except SRB1) as suspended on reestablishment, and de-suspend on reconfiguration. Only check RLC status for non-suspended RBs. For UL data traffic, check that DRB/SRB2 exist (SRB1 should be there as soon as the UE context exists). --- .../LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c | 3 ++ .../NR_MAC_gNB/gNB_scheduler_primitives.c | 10 ++++++ .../LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c | 32 ++++++++++++------- openair2/LAYER2/NR_MAC_gNB/mac_proto.h | 1 + .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 8 ++++- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 2 ++ 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 3303bb7362..cb3c1bf801 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c @@ -335,6 +335,9 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, slot_t s 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); + memset(&sched_ctrl->rlc_status[lcid], 0, sizeof(sched_ctrl->rlc_status[lcid])); + if (c->suspended) + continue; if (lcid == DL_SCH_LCID_DTCH && nr_timer_is_active(&sched_ctrl->transm_interrupt)) continue; start_meas(&RC.nrmac[module_id]->rlc_status_ind); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5ceff85296..79c266bce7 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -3477,6 +3477,16 @@ static int cmp_lc_config(const void *va, const void *vb) return 1; } +nr_lc_config_t *nr_mac_get_lc_config(NR_UE_sched_ctrl_t* sched_ctrl, int lcid) +{ + nr_lc_config_t c = {.lcid = lcid}; + elm_arr_t elm = find_if(&sched_ctrl->lc_config, &c, eq_lcid_config); + if (elm.found) + return elm.it; + else + return NULL; +} + bool nr_mac_add_lcid(NR_UE_sched_ctrl_t* sched_ctrl, const nr_lc_config_t *c) { elm_arr_t elm = find_if(&sched_ctrl->lc_config, (void *) c, eq_lcid_config); diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c index 3626599fe5..b4297c230f 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c @@ -390,10 +390,15 @@ static int nr_process_mac_pdu(instance_t module_idP, slot, lcid); - nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len); + const nr_lc_config_t *srbc = nr_mac_get_lc_config(sched_ctrl, lcid); + if (!srbc || srbc->suspended) { + LOG_I(NR_MAC, "RNTI %04x LCID %d: ignoring %d bytes\n", UE->rnti, lcid, mac_len); + } else { + nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len); - UE->mac_stats.ul.total_sdu_bytes += mac_len; - UE->mac_stats.ul.lc_bytes[lcid] += mac_len; + UE->mac_stats.ul.total_sdu_bytes += mac_len; + UE->mac_stats.ul.lc_bytes[lcid] += mac_len; + } break; case UL_SCH_LCID_DTCH ...(UL_SCH_LCID_DTCH + 28): @@ -406,16 +411,21 @@ static int nr_process_mac_pdu(instance_t module_idP, lcid, module_idP, mac_len); - UE->mac_stats.ul.lc_bytes[lcid] += mac_len; + const nr_lc_config_t *c = nr_mac_get_lc_config(sched_ctrl, lcid); + if (!c || c->suspended) { + LOG_I(NR_MAC, "RNTI %04x LCID %d: ignoring %d bytes\n", UE->rnti, lcid, mac_len); + } else { + UE->mac_stats.ul.lc_bytes[lcid] += mac_len; - nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len); + nr_mac_rlc_data_ind(module_idP, UE->rnti, true, lcid, (char *)(pduP + mac_subheader_len), mac_len); - sdus += 1; - /* Updated estimated buffer when receiving data */ - if (sched_ctrl->estimated_ul_buffer >= mac_len) - sched_ctrl->estimated_ul_buffer -= mac_len; - else - sched_ctrl->estimated_ul_buffer = 0; + sdus += 1; + /* Updated estimated buffer when receiving data */ + if (sched_ctrl->estimated_ul_buffer >= mac_len) + sched_ctrl->estimated_ul_buffer -= mac_len; + else + sched_ctrl->estimated_ul_buffer = 0; + } break; case UL_SCH_LCID_RECOMMENDED_BITRATE_QUERY: diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f0b59c73de..c24baad097 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -451,6 +451,7 @@ void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod); bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c); +nr_lc_config_t *nr_mac_get_lc_config(NR_UE_sched_ctrl_t* sched_ctrl, int lcid); bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid); bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 99a8439dc9..90dc604471 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -777,6 +777,10 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) // we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1 nr_mac_clean_cellgroup(UE->CellGroup); configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); + for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { + nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); + c->suspended = false; + } } if (ue_cap != NULL) { @@ -965,7 +969,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) oldUE->uid = temp_uid; for (int i = 1; i < seq_arr_size(&oldUE->UE_sched_ctrl.lc_config); ++i) { const nr_lc_config_t *c = seq_arr_at(&oldUE->UE_sched_ctrl.lc_config, i); - nr_mac_add_lcid(&UE->UE_sched_ctrl, c); + nr_lc_config_t new = *c; + new.suspended = true; + nr_mac_add_lcid(&UE->UE_sched_ctrl, &new); } ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); UE->CellGroup = oldUE->CellGroup; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d97783604f..f7f034cd97 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -564,6 +564,8 @@ typedef struct NR_QoS_config_s { typedef struct nr_lc_config { uint8_t lcid; + /// flag if corresponding RB is suspended + bool suspended; /// priority as specified in 38.321 int priority; /// associated NSSAI for DRB From 81dbaf0aad7b544b6e77845fe2f63bb41ecf39e6 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 10 Jun 2025 16:02:00 +0200 Subject: [PATCH 098/100] Add comment on reestablishment in MAC-RRC DL handler --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 90dc604471..28472ac957 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -954,6 +954,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) UE->reestablish_rlc = false; } + /* if we get the old-gNB-DU-UE-ID, this means there is a reestablishment + * ongoing. */ if (dl_rrc->old_gNB_DU_ue_id != NULL) { AssertFatal(*dl_rrc->old_gNB_DU_ue_id != dl_rrc->gNB_DU_ue_id, "logic bug: current and old gNB DU UE ID cannot be the same\n"); From dfadcab45888c463141f2159cb46ba1ebe11f481 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Tue, 27 May 2025 19:37:46 +0200 Subject: [PATCH 099/100] Store spCellConfig during reestablishment for reconfiguration The spCellConfig is to be dropped during reestablishment and to be applied after reconfiguration. Implement this using the RRCReconfigurationComplete acknowledgment from the CU to the DU, applying the spCellConfig if present (which signals a prior reestablishment). Remove a prior flag that is not needed anymore, and do not "guess" when is the reconfiguration, because it is now handled in the case of the ack. The spCellConfig is not relevant as long as we use a common search space for DCIs (and the activation of dedicated search space happens after applying spCellConfig). For PUCCH, there is the PDSCH transmission of RRCReconfiguration which gets ack'ed in the default PUCCH. RRCReconfigurationComplete is sent in PUSCH (again through common search space). In theory, there cannot be another PUCCH before the application of spCellConfig, as all bearers are still suspended, and there should not be another SRB1 transmission in the meantime, as only one RRC transaction can be active at a time. Co-authored-by: francescomani --- .../NR_MAC_gNB/gNB_scheduler_primitives.c | 1 + .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 24 ++++++++----------- openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h | 5 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 79c266bce7..f204603af1 100644 --- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c +++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c @@ -2104,6 +2104,7 @@ NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP) void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia) { ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup); + ASN_STRUCT_FREE(asn_DEF_NR_SpCellConfig, UE->reconfigSpCellConfig); ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability); NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl; seq_arr_free(&sched_ctrl->lc_config, NULL); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 28472ac957..beea478998 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -774,12 +774,19 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) "RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n"); } else if (req->ReconfigComplOutcome == RRCreconf_success) { LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n"); + if (UE->reconfigSpCellConfig) { + // in case of reestablishment, the spCellConfig had to be released + // temporarily. Reapply now before doing the reconfiguration. + UE->CellGroup->spCellConfig = UE->reconfigSpCellConfig; + UE->reconfigSpCellConfig = NULL; + } // we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1 nr_mac_clean_cellgroup(UE->CellGroup); configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); c->suspended = false; + nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid); } } @@ -945,14 +952,6 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) DevAssert(success); } - if (UE->reestablish_rlc && dl_rrc->srb_id == 1) { - // we expected a reconfiguration to re-establish RLC, and this is on DCCH. We assume this is the reconfiguration. - for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { - nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); - nr_rlc_reestablish_entity(dl_rrc->gNB_DU_ue_id, lc_config->lcid); - } - UE->reestablish_rlc = false; - } /* if we get the old-gNB-DU-UE-ID, this means there is a reestablishment * ongoing. */ @@ -980,9 +979,9 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) oldUE->CellGroup = NULL; UE->mac_stats = oldUE->mac_stats; /* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it - * from the current configuration. Also, expect the reconfiguration from - * the CU, so save the old UE's CellGroup for the new UE */ - ASN_STRUCT_FREE(asn_DEF_NR_SpCellConfig, UE->CellGroup->spCellConfig); + * from the current configuration. It will be reapplied when the + * reconfiguration has succeeded (indicated by the CU) */ + UE->reconfigSpCellConfig = UE->CellGroup->spCellConfig; UE->CellGroup->spCellConfig = NULL; mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id); pthread_mutex_unlock(&mac->sched_lock); @@ -990,9 +989,6 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc) nr_rlc_update_id(*dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); /* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */ nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL); - /* Set flag to trigger RLC re-establishment - * for remaining RBs in next RRCReconfiguration */ - UE->reestablish_rlc = true; instance_t f1inst = get_f1_gtp_instance(); if (f1inst >= 0) // we actually use F1-U gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index f7f034cd97..be9566d3a4 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h @@ -746,8 +746,9 @@ typedef struct { NR_mac_stats_t mac_stats; /// currently active CellGroupConfig NR_CellGroupConfig_t *CellGroup; - /// reestablishRLC has to be signaled in RRCreconfiguration - bool reestablish_rlc; + /// in case of reestablishment, old spCellConfig to apply after + /// reconfiguration + NR_SpCellConfig_t *reconfigSpCellConfig; interrupt_followup_action_t interrupt_action; NR_UE_NR_Capability_t *capability; // UE selected beam index From 736ea530f73bd03bd4951f4ae6ff5167c4e6e14d Mon Sep 17 00:00:00 2001 From: luis_pereira87 Date: Fri, 13 Jun 2025 12:05:34 +0100 Subject: [PATCH 100/100] Only reestablish RLC while processing reconfiguration complete after a RRCReestablishment and not for every RRCReconfiguration --- openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index bcb69f5824..5d7642c815 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -787,15 +787,15 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req) // temporarily. Reapply now before doing the reconfiguration. UE->CellGroup->spCellConfig = UE->reconfigSpCellConfig; UE->reconfigSpCellConfig = NULL; + for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { + nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); + c->suspended = false; + nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid); + } } // we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1 nr_mac_clean_cellgroup(UE->CellGroup); configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1); - for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) { - nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i); - c->suspended = false; - nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid); - } } if (ue_cap != NULL) {