diff --git a/CMakeLists.txt b/CMakeLists.txt index 16dac5f2fe..38168ae460 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) 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) */ 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 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; 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/ci-scripts/xml_files/container_5g_flexric_rfsim.xml b/ci-scripts/xml_files/container_5g_flexric_rfsim.xml index d0d3446f41..a56248fe0e 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 @@ -173,43 +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 - - - - 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 + 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..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,12 +7,79 @@ 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 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 @@ -27,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 @@ -72,9 +138,6 @@ services: timeout: 5s retries: 5 -volumes: - sharedXappLibs: - networks: public_net: name: oai-cn5g-public-net 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/config_paramdesc.h b/common/config/config_paramdesc.h index 6947f6531d..8ddd507ee6 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 { @@ -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); 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..0b9139c407 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); @@ -207,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 { - SetDefault(cfg, ¶ms[i]); - } + if (node && node[std::string(param->optname)]) { + SetNonDefault(cfg, node, param); + } else { + config_common_getdefault(cfg, param, nullptr); } } @@ -229,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; } @@ -249,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; @@ -272,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++) { @@ -282,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; } @@ -323,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(); 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; 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/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/doc/analog_beamforming.md b/doc/analog_beamforming.md index 6d9e5bf71c..4ff208343e 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. +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 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) @@ -18,8 +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 -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. +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 @@ -28,3 +31,28 @@ 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 + +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` +- `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. + +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. + +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. 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 \ 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; diff --git a/executables/nr-gnb.c b/executables/nr-gnb.c index 9f20e6f409..acab30751b 100644 --- a/executables/nr-gnb.c +++ b/executables/nr-gnb.c @@ -360,32 +360,29 @@ 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>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); - - 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]; + 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. * In monolithic mode, we come here with nb_antennas_rx == 0 * (not tested in other modes). @@ -393,7 +390,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..411caf9a63 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,28 @@ 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); + 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); - for (i=0; inb_rx; i++) - rxp[i] = (void *)&ru->common.rxdata[i][fp->get_samples_slot_timestamp(*slot,fp,0)]; + 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 ); - 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, nb); } VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_TRX_READ, 0 ); @@ -629,7 +624,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 +747,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 +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); - for (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); @@ -830,12 +825,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); + nt, + 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, @@ -851,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; @@ -877,13 +871,14 @@ 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; + 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); - 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) { @@ -898,7 +893,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) { @@ -944,8 +939,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; @@ -967,27 +962,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 @@ -1054,7 +1049,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); @@ -1324,10 +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, + beam_id, prachStartSymbol, p->slot, prach_oc, 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/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/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_nr_interface_scf.h index a34796eeb3..0533a76c6d 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 @@ -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 @@ -1829,7 +1831,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/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/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/INIT/nr_init_ru.c b/openair1/PHY/INIT/nr_init_ru.c index 674c70cdc3..a0766c348f 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; @@ -47,36 +47,40 @@ int 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; + 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)); 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)); + 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) ); + 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 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 +89,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*)); @@ -94,15 +97,15 @@ int 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[i] = (int32_t*)malloc16_clear(fp->samples_per_subframe_wCP*sizeof(int32_t) ); + 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); @@ -113,40 +116,38 @@ int 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]); + 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) { 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() @@ -162,21 +163,21 @@ 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); 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]); } - 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_dci.c b/openair1/PHY/NR_TRANSPORT/nr_dci.c index 6cca7fcfcc..bea9cb63c5 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dci.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dci.c @@ -81,7 +81,9 @@ 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, 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..58d11413f4 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_dlsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch.c @@ -680,7 +680,9 @@ 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, frame_parms->symbols_per_slot, diff --git a/openair1/PHY/NR_TRANSPORT/nr_prach.c b/openair1/PHY/NR_TRANSPORT/nr_prach.c index 858257893f..76d9b1185f 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) { @@ -70,7 +69,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); @@ -79,16 +78,25 @@ void nr_fill_prach(PHY_VARS_gNB *gNB, int SFN, int Slot, nfapi_nr_prach_pdu_t *p 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->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(gNB->enable_analog_das, + 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)); + return prach_id; } void init_prach_ru_list(RU_t *ru) @@ -121,10 +129,10 @@ 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), + AssertFatal((prach_id >= 0) && (prach_id < NUMBER_OF_NR_PRACH_MAX), "illegal or no prach_id found!!! prach_id %d\n", prach_id); @@ -135,6 +143,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); @@ -151,6 +160,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, @@ -159,7 +169,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,15 +200,16 @@ 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]; + 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 437a3c20db..db49237a9e 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h +++ b/openair1/PHY/NR_TRANSPORT/nr_transport_proto.h @@ -257,14 +257,11 @@ 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, - int prachOccasion, + int prachOccasion, int frame, int subframe, uint16_t *max_preamble, @@ -274,16 +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_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); @@ -309,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/NR_TRANSPORT/nr_ulsch.c b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c index 982b236b70..4621e184a6 100644 --- a/openair1/PHY/NR_TRANSPORT/nr_ulsch.c +++ b/openair1/PHY/NR_TRANSPORT/nr_ulsch.c @@ -76,7 +76,13 @@ 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(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &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..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,13 @@ 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(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &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..c8b6d99c30 100644 --- a/openair1/PHY/NR_TRANSPORT/srs_rx.c +++ b/openair1/PHY/NR_TRANSPORT/srs_rx.c @@ -59,7 +59,13 @@ 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(gNB->enable_analog_das, + fapi_beam_idx, + &gNB->gNB_config.analog_beamforming_ve, + &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/PHY/defs_RU.h b/openair1/PHY/defs_RU.h index 1417180cb3..a2c39852f5 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/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h index 59d92444d5..ad17c243ae 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; @@ -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; @@ -493,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/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_prach_procedures.c b/openair1/SCHED_NR/nr_prach_procedures.c index c9f6a9c8cc..c56a37ca1d 100644 --- a/openair1/SCHED_NR/nr_prach_procedures.c +++ b/openair1/SCHED_NR/nr_prach_procedures.c @@ -37,62 +37,14 @@ #include "nfapi_pnf.h" #include "common/utils/LOG/log.h" #include "common/utils/LOG/vcd_signal_dumper.h" - - #include "assertions.h" - #include -uint8_t 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; - - } +int get_nr_prach_duration(uint8_t prach_format) +{ + 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) @@ -117,14 +69,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/openair1/SCHED_NR/nr_ru_procedures.c b/openair1/SCHED_NR/nr_ru_procedures.c index a0b3a69ba8..0546455e36 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; @@ -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], + (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); } @@ -238,6 +220,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 +229,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); - } + AssertFatal(false, "This needs to be fixed by using appropriate beams from config\n"); } - 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 +270,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); @@ -345,24 +319,26 @@ 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 beam = feprx_cmd->beam; + 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 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, - tti_rx, + slot, ru->N_TA_offset); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_RU_FEPRX+aid, 0); @@ -377,39 +353,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/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c index 095c41d0da..8da471f4c1 100644 --- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c +++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c @@ -45,18 +45,26 @@ //#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(bool das, + int fapi_beam_index, + nfapi_nr_analog_beamforming_ve_t *analog_bf, + NR_gNB_COMMON *common_vars, + int slot, + int symbols_per_slot, + int bitmap_symbols) { 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; 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++) { - 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,12 +74,12 @@ 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); + LOG_D(PHY, "Allocating beam_id[%d] %d in slot %d\n", idx, ru_beam_idx, slot); return idx; } @@ -131,7 +139,9 @@ 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, fp->symbols_per_slot, @@ -272,7 +282,9 @@ 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, fp->symbols_per_slot, @@ -1046,6 +1058,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 +1068,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/openair1/SCHED_NR/sched_nr.h b/openair1/SCHED_NR/sched_nr.h index bf5a1eda3f..40c32c2199 100644 --- a/openair1/SCHED_NR/sched_nr.h +++ b/openair1/SCHED_NR/sched_nr.h @@ -44,8 +44,14 @@ 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); +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, + int symbols_per_slot, + int bitmap_symbols); #endif 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/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]; 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/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/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c b/openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_kpm.c index aaf46797ac..4468cdf0b9 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 */ @@ -171,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: @@ -406,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; 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](); diff --git a/openair2/E2AP/README.md b/openair2/E2AP/README.md index 9b2b2716fb..5644d10cb5 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,107 @@ 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 ``` +`XAPP_DURATION` environment variable overwrites the default xApp duration of 20s. * 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 - ./build/examples/xApp/c/monitor/xapp_kpm_moni + cd flexric # or openairinterface5g/openair2/E2AP/flexric + 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 + 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 - ./build/examples/xApp/c/monitor/xapp_rc_moni + cd flexric # or openairinterface5g/openair2/E2AP/flexric + XAPP_DURATION=30 ./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 - ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc + cd flexric # or openairinterface5g/openair2/E2AP/flexric + XAPP_DURATION=30 ./build/examples/xApp/c/kpm_rc/xapp_kpm_rc ``` * start the (MAC + RLC + PDCP + GTP) monitor xApp ```bash - cd flexric - ./build/examples/xApp/c/monitor/xapp_gtp_mac_rlc_pdcp_moni + cd flexric # or openairinterface5g/openair2/E2AP/flexric + 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 + (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 + 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. 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 +# 5. O-RAN SC nearRT-RIC interoperability -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. +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. + +## 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. 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 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/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 70e6c026ca..0ddd097ca6 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) { @@ -879,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); @@ -886,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, ...? */ @@ -1061,6 +1067,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 @@ -1467,6 +1474,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; @@ -1566,19 +1622,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 / num_tx; // number of beams - 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; @@ -1612,8 +1655,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++) { @@ -1704,6 +1751,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 *)); @@ -1711,6 +1759,26 @@ 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)) { + 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) { + 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;jneighbour_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,22 +1997,20 @@ 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_cell_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_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; + 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,13 +2022,12 @@ 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(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); @@ -2020,22 +2084,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)); } } @@ -2147,6 +2210,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/GNB_APP/gnb_paramdef.h b/openair2/GNB_APP/gnb_paramdef.h index 99eb8847af..db04c5a8da 100644 --- a/openair2/GNB_APP/gnb_paramdef.h +++ b/openair2/GNB_APP/gnb_paramdef.h @@ -137,7 +137,6 @@ typedef enum { #define GNB_CONFIG_STRING_GNB_CU_UP_ID "gNB_CU_UP_ID" #define GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES "num_dlharq" #define GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES "num_ulharq" -#define GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST "beam_weights" #define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels" #define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs" #define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs" @@ -198,7 +197,6 @@ typedef enum { {GNB_CONFIG_STRING_DISABLE_HARQ, GNB_CONFIG_HLP_DISABLE_HARQ, PARAMFLAG_BOOL, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_DL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \ {GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES, GNB_CONFIG_HLP_NUM_UL_HARQ, 0, .iptr=NULL, .defintval=16, TYPE_INT, 0}, \ -{GNB_CONFIG_STRING_BEAM_WEIGHTS_LIST, NULL, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST, \ GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \ {GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \ @@ -243,11 +241,10 @@ typedef enum { #define GNB_DISABLE_HARQ_IDX 32 #define GNB_NUM_DL_HARQ_IDX 33 #define GNB_NUM_UL_HARQ_IDX 34 -#define GNB_BEAMWEIGHTS_IDX 35 -#define GNB_UESS_AGG_LEVEL_LIST_IDX 36 -#define GNB_CU_SIBS_IDX 37 -#define GNB_DU_SIBS_IDX 38 -#define GNB_DO_SINR_IDX 39 +#define GNB_UESS_AGG_LEVEL_LIST_IDX 35 +#define GNB_CU_SIBS_IDX 36 +#define GNB_DU_SIBS_IDX 37 +#define GNB_DO_SINR_IDX 38 #define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD} #define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32} @@ -293,7 +290,6 @@ typedef enum { { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ { .s5 = { NULL } }, \ - { .s5 = { NULL } }, \ } /*-------------------------------------------------------------------------------------------------------------------------------------------------*/ @@ -680,5 +676,215 @@ typedef enum { /*----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#endif +#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" +#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 }}}, \ +} + +/*----------------------------------------------------------------------*/ + +#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 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); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 43d48eeeeb..f87b4024b9 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -715,36 +715,32 @@ 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.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++) { + 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) { + cfg->analog_beamforming_ve.analog_bf_vendor_ext.tl.tag = NFAPI_NR_FAPI_ANALOG_BF_VENDOR_EXTENSION_TAG; + cfg->num_tlv++; + } } } 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 diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c index 4086588660..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); @@ -399,8 +402,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 +1185,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_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c index 5ceff85296..a447d9f91c 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); @@ -3326,7 +3327,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; @@ -3477,6 +3478,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 35c817b975..3fa16f6a51 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; @@ -391,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): @@ -407,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: @@ -1442,13 +1451,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 diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index f0b59c73de..6acf4ae1d8 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); @@ -451,6 +453,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 28c129cb58..5d7642c815 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) { @@ -774,6 +782,17 @@ 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; + 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); @@ -941,15 +960,9 @@ 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. */ 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"); @@ -960,30 +973,30 @@ 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; 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; 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. 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); nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id); 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/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_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h index d97783604f..3918e0215c 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 { \ @@ -89,9 +90,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 +98,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); @@ -564,6 +561,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 @@ -677,10 +676,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]; @@ -744,8 +739,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 @@ -899,6 +895,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; diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 22c2207be1..41ace5014b 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" @@ -728,64 +729,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 +793,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; } @@ -3338,7 +3373,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 +3390,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 +3419,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 +3430,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 +3457,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 +3471,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 +3495,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 +3505,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/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_ */ 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_ */ 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_ */ 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_ */ diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 6a7ee77b52..ad973bdc5f 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" @@ -143,6 +144,7 @@ #include "common/ran_context.h" #include "conversions.h" +#include "ds/byte_array.h" //#define XER_PRINT @@ -273,7 +275,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 +291,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 +301,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); @@ -499,112 +502,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..3ac4695eba 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -51,10 +51,25 @@ #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; +#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" 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. @@ -72,7 +87,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, @@ -91,17 +107,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/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 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_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7e0789c4ad..f2434eceaf 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, @@ -301,7 +303,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; @@ -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)" diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 4546f59723..3a4fed6411 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -38,6 +38,10 @@ #include "NR_CG-Config.h" #include "NR_CG-ConfigInfo.h" #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); @@ -112,6 +116,12 @@ 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); + +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 78e472ed60..f69e03b810 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" @@ -124,45 +125,47 @@ 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) +static bool eq_cell_id(const void *vval, const void *vit) { - ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list); - return; + 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; } -const neighbour_cell_configuration_t *get_neighbour_config(int serving_cell_nr_cellid) +const neighbour_cell_configuration_t *get_neighbour_cell_config(const gNB_RRC_INST *rrc, int cell_id) { - const gNB_RRC_INST *rrc = RC.nrrrc[0]; - seq_arr_t *neighbour_cell_configuration = rrc->neighbour_cell_configuration; - if (!neighbour_cell_configuration) + if (!rrc->neighbour_cell_configuration) return NULL; - - 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; + 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_cell_t *neighbour = (const nr_neighbour_cell_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_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_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; } + LOG_E(NR_RRC, "No matching neighbour cell found for Physical Cell ID: %d\n", pci); return NULL; } @@ -267,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; } @@ -281,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; @@ -312,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) @@ -542,15 +547,20 @@ 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 */ +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); DevAssert(du != NULL); f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; @@ -564,7 +574,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; @@ -583,7 +593,7 @@ static int rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *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)); @@ -608,93 +618,91 @@ 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_reest_bitmap); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish); - 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; + 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 - return size; + 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 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) { + 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, 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) { + 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) { int qos_flow_index = 0; - 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_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; } @@ -709,7 +717,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; @@ -734,7 +742,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; } @@ -742,44 +750,20 @@ 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); - } + session->xid = params.transaction_id; } - /* 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); - - /* 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_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n"); + 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); } //----------------------------------------------------------------------------- @@ -799,40 +783,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) @@ -1065,39 +1031,35 @@ 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); 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) { @@ -1114,22 +1076,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; } @@ -1391,7 +1347,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 +1364,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 +1382,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 +1395,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_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) { @@ -1465,7 +1421,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); } } @@ -2180,17 +2136,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(0); - UE->xids[xid] = RRC_DEDICATED_RECONF; - uint8_t buffer[NR_RRC_BUF_SIZE] = {0}; - int size = rrc_gNB_encode_RRCReconfiguration(rrc, UE, xid, NULL, buffer, sizeof(buffer), true); - DevAssert(size > 0 && size <= sizeof(buffer)); - - // TODO N2 38.413 sec 9.3.1.21: admitted PDU sessions (in UE), Target to - // Source Transparent Container (9.3.1.21) which encodes the RRC - // reconfiguration above - UE->ho_context->target->ho_req_ack(rrc, UE, buffer, size); + UE->ho_context->target->ho_req_ack(rrc, UE); } } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 82aa7b5a86..9fd4306962 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++) { @@ -940,7 +941,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/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 diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index e6e50ffbf1..647f253989 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 @@ -73,8 +113,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 +122,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,45 +169,12 @@ 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}; - 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; @@ -252,15 +258,24 @@ 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) { - // 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); - 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 @@ -327,7 +342,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) diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index 5046176c1d..6e9bcbcfe6 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); 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 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); 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); 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/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; 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; } diff --git a/openair3/NAS/NR_UE/nr_nas_msg.c b/openair3/NAS/NR_UE/nr_nas_msg.c index d152a5d4a3..5709d482c6 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 @@ -151,6 +152,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) @@ -209,35 +357,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; @@ -444,41 +579,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]; @@ -1042,10 +1142,103 @@ 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) { + /* 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; @@ -1069,8 +1262,38 @@ 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) { + 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; + } nas_itti_kgnb_refresh_req(nas->UE_id, nas->security.kgnb); generateSecurityModeComplete(nas, initialNasMsg); 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.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: diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index ad8efce5a3..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->ueAggMaxBitRateUplink); - asn_INTEGER2ulong(&(ie->value.choice.UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL), - &msg->ueAggMaxBitRateDownlink); + 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); 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..b00ce13f32 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). @@ -122,24 +112,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; - } } } @@ -175,16 +167,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) { @@ -192,7 +181,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 */ @@ -218,7 +207,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, @@ -265,7 +254,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: @@ -282,9 +271,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; } @@ -621,7 +614,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 +929,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], 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. */ 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); 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) { diff --git a/openair3/SECU/key_nas_deriver.c b/openair3/SECU/key_nas_deriver.c index 20aba64e1e..a7cf27a1ff 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: @@ -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); } /*! @@ -139,6 +150,37 @@ 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); + + 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) { uint8_t s[7] = {0}; @@ -228,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) @@ -248,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 4e84c5f3be..0ab14ad51a 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, @@ -14,6 +16,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, @@ -30,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 diff --git a/openair3/ocp-gtpu/gtp_itf.cpp b/openair3/ocp-gtpu/gtp_itf.cpp index 3036565fad..fd571e8d0e 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 ; @@ -525,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); 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 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); 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/" +}; 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;