From 06f2ab6d7cc56b9884d668b9d2941a39bed54908 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 9 Jun 2022 14:09:05 +0200 Subject: [PATCH 01/16] ctest: PDCCH test skips 100PRB for non AVX2 machines The current 8-bit Viterbi decoder implementation for SSE (non-AVX2) is not accurate enough to reliably decode all messages with a code rate ~0.9 or higher, e.g. DCI format 2/2A messages in 100 PRB cell at aggregation level 0. --- lib/src/phy/phch/test/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/phy/phch/test/CMakeLists.txt b/lib/src/phy/phch/test/CMakeLists.txt index 10175e2a2..c0e87239b 100644 --- a/lib/src/phy/phch/test/CMakeLists.txt +++ b/lib/src/phy/phch/test/CMakeLists.txt @@ -199,8 +199,9 @@ add_executable(pdcch_test pdcch_test.c) target_link_libraries(pdcch_test srsran_phy) foreach (nof_prb 6 15 25 50 75 100) - # Currently, the ARM platforms srsRAN has been tested are not capable of running 100PRB. So, skip 100 PRB in ARM - if (HAVE_NEON AND (${nof_prb} EQUAL 100)) + # Currently, the ARM and SSE platforms srsRAN has been tested are not capable of running 100PRB. So, skip 100 PRB in + # ARM and SSE. + if ((HAVE_NEON OR NOT HAVE_AVX2) AND (${nof_prb} EQUAL 100)) continue() endif () foreach (nof_ports 1 2) From 7e7eceda156dee1ee96c4f4aad435623c0aef39c Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Thu, 9 Jun 2022 14:44:54 +0200 Subject: [PATCH 02/16] ctest: Viterbi test skips 0dB for non AVX2 machines The accuracy of the 8-bit implementation of the Viterbi decoder used on non-AVX2 machines falls below the theoretical accuracy at 0dB. --- lib/src/phy/fec/convolutional/test/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/src/phy/fec/convolutional/test/CMakeLists.txt b/lib/src/phy/fec/convolutional/test/CMakeLists.txt index 23607bc78..59ed06791 100644 --- a/lib/src/phy/fec/convolutional/test/CMakeLists.txt +++ b/lib/src/phy/fec/convolutional/test/CMakeLists.txt @@ -18,7 +18,11 @@ add_test(viterbi_40_2 viterbi_test -n 1000 -s 1 -l 40 -t -e 2.0) add_test(viterbi_40_3 viterbi_test -n 1000 -s 1 -l 40 -t -e 3.0) add_test(viterbi_40_4 viterbi_test -n 1000 -s 1 -l 40 -t -e 4.5) -add_test(viterbi_1000_0 viterbi_test -n 100 -s 1 -l 1000 -t -e 0.0) +if (HAVE_AVX2) + # The accuracy of the 8-bit implementation of the Viterbi decoder used on + # non-AVX2 machines falls below the theoretical accuracy at 0dB. + add_test(viterbi_1000_0 viterbi_test -n 100 -s 1 -l 1000 -t -e 0.0) +endif() add_test(viterbi_1000_2 viterbi_test -n 100 -s 1 -l 1000 -t -e 2.0) add_test(viterbi_1000_3 viterbi_test -n 100 -s 1 -l 1000 -t -e 3.0) add_test(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -t -e 4.5) From 68fe21928e6b4eb7d5ce0e041321a5d2739b50b2 Mon Sep 17 00:00:00 2001 From: David Rupprecht Date: Sun, 12 Jun 2022 16:41:22 +0200 Subject: [PATCH 03/16] Added initialization of nas5g logger --- srsue/hdr/stack/ue_stack_lte.h | 1 + srsue/src/stack/ue_stack_lte.cc | 3 +++ 2 files changed, 4 insertions(+) diff --git a/srsue/hdr/stack/ue_stack_lte.h b/srsue/hdr/stack/ue_stack_lte.h index ef8a2b99f..199de428d 100644 --- a/srsue/hdr/stack/ue_stack_lte.h +++ b/srsue/hdr/stack/ue_stack_lte.h @@ -215,6 +215,7 @@ private: srslog::basic_logger& rrc_logger; srslog::basic_logger& usim_logger; srslog::basic_logger& nas_logger; + srslog::basic_logger& nas5g_logger; // UE NR stack logging srslog::basic_logger& mac_nr_logger; diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 2b67bed1d..15c66cf26 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -33,6 +33,7 @@ ue_stack_lte::ue_stack_lte() : rrc_logger(srslog::fetch_basic_logger("RRC", false)), usim_logger(srslog::fetch_basic_logger("USIM", false)), nas_logger(srslog::fetch_basic_logger("NAS", false)), + nas5g_logger(srslog::fetch_basic_logger("NAS5G", false)), mac_nr_logger(srslog::fetch_basic_logger("MAC-NR")), rrc_nr_logger(srslog::fetch_basic_logger("RRC-NR", false)), rlc_nr_logger(srslog::fetch_basic_logger("RLC-NR", false)), @@ -119,6 +120,8 @@ int ue_stack_lte::init(const stack_args_t& args_) nas_logger.set_level(srslog::str_to_basic_level(args.log.nas_level)); nas_logger.set_hex_dump_max_size(args.log.nas_hex_limit); + nas5g_logger.set_level(srslog::str_to_basic_level(args.log.nas_level)); + nas5g_logger.set_hex_dump_max_size(args.log.nas_hex_limit); mac_nr_logger.set_level(srslog::str_to_basic_level(args.log.mac_level)); mac_nr_logger.set_hex_dump_max_size(args.log.mac_hex_limit); rrc_nr_logger.set_level(srslog::str_to_basic_level(args.log.rrc_level)); From 436235b92cb959eed4b7dc3057abc3e0f6035a4c Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Thu, 26 May 2022 13:21:14 +0300 Subject: [PATCH 04/16] enb,cfg_parser: Fix log typo. --- srsenb/src/enb_cfg_parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 909362ad8..d8f372eb3 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -166,7 +166,7 @@ int field_carrier_freqs_info_list::parse(libconfig::Setting& root) field_asn1_bitstring_number, uint8_t> ncc_permitted( "ncc_permitted", &data->carrier_freqs_info_list[i].common_info.ncc_permitted); if (ncc_permitted.parse(root[i])) { - ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_lsit=%d", i); + ERROR("Error parsing `ncc_permitted` in carrier_freqs_info_list=%d", i); return SRSRAN_ERROR; } From 88998385eb3b0fa68eff205a2be3068f0cad0dab Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Sun, 29 May 2022 14:09:25 +0300 Subject: [PATCH 05/16] NAS: Add configuration for LAC. --- srsepc/epc.conf.example | 2 ++ srsepc/hdr/mme/nas.h | 2 ++ srsepc/hdr/mme/s1ap_common.h | 1 + srsepc/src/main.cc | 7 +++++++ srsepc/src/mme/nas.cc | 5 +++-- srsepc/src/mme/s1ap_nas_transport.cc | 1 + 6 files changed, 16 insertions(+), 2 deletions(-) diff --git a/srsepc/epc.conf.example b/srsepc/epc.conf.example index 73183a63f..e0aa15393 100644 --- a/srsepc/epc.conf.example +++ b/srsepc/epc.conf.example @@ -21,6 +21,7 @@ # (supported: EIA0 (rejected by most UEs), EIA1 (default), EIA2, EIA3 # paging_timer: Value of paging timer in seconds (T3413) # request_imeisv: Request UE's IMEI-SV in security mode command +# lac: 16-bit Location Area Code. # ##################################################################### [mme] @@ -36,6 +37,7 @@ encryption_algo = EEA0 integrity_algo = EIA1 paging_timer = 2 request_imeisv = false +lac = 0x0006 ##################################################################### # HSS configuration diff --git a/srsepc/hdr/mme/nas.h b/srsepc/hdr/mme/nas.h index bd29e889f..9c55460fb 100644 --- a/srsepc/hdr/mme/nas.h +++ b/srsepc/hdr/mme/nas.h @@ -133,6 +133,7 @@ typedef struct { srsran::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; srsran::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; bool request_imeisv; + uint16_t lac; } nas_init_t; typedef struct { @@ -271,6 +272,7 @@ private: std::string m_full_net_name; std::string m_short_net_name; bool m_request_imeisv = false; + uint16_t m_lac = 0; // Timers timeout values uint16_t m_t3413 = 0; diff --git a/srsepc/hdr/mme/s1ap_common.h b/srsepc/hdr/mme/s1ap_common.h index 3c38d6929..d4952730f 100644 --- a/srsepc/hdr/mme/s1ap_common.h +++ b/srsepc/hdr/mme/s1ap_common.h @@ -43,6 +43,7 @@ typedef struct { srsran::CIPHERING_ALGORITHM_ID_ENUM encryption_algo; srsran::INTEGRITY_ALGORITHM_ID_ENUM integrity_algo; bool request_imeisv; + uint16_t lac; } s1ap_args_t; typedef struct { diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index d0d5c76f2..43bfbfed3 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -88,6 +88,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) string hss_db_file; string hss_auth_algo; string log_filename; + string lac; // Command line only options bpo::options_description general("General options"); @@ -115,6 +116,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("mme.integrity_algo", bpo::value(&integrity_algo)->default_value("EIA1"), "Set preferred integrity protection algorithm for NAS") ("mme.paging_timer", bpo::value(&paging_timer)->default_value(2), "Set paging timer value in seconds (T3413)") ("mme.request_imeisv", bpo::value(&request_imeisv)->default_value(false), "Enable IMEISV request in Security mode command") + ("mme.lac", bpo::value(&lac)->default_value("0x01"), "Location Area Code") ("hss.db_file", bpo::value(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys") ("spgw.gtpu_bind_addr", bpo::value(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection") ("spgw.sgi_if_addr", bpo::value(&sgi_if_addr)->default_value("176.16.0.1"), "IP address of TUN interface for the SGi connection") @@ -218,6 +220,11 @@ void parse_args(all_args_t* args, int argc, char* argv[]) sstr << std::hex << vm["mme.tac"].as(); sstr >> args->mme_args.s1ap_args.tac; } + { + std::stringstream sstr; + sstr << std::hex << vm["mme.lac"].as(); + sstr >> args->mme_args.s1ap_args.lac; + } // Convert MCC/MNC strings if (!srsran::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) { diff --git a/srsepc/src/mme/nas.cc b/srsepc/src/mme/nas.cc index e7164422b..aa0f4d97d 100644 --- a/srsepc/src/mme/nas.cc +++ b/srsepc/src/mme/nas.cc @@ -37,7 +37,8 @@ nas::nas(const nas_init_t& args, const nas_if_t& itf) : m_full_net_name(args.full_net_name), m_short_net_name(args.short_net_name), m_t3413(args.paging_timer), - m_request_imeisv(args.request_imeisv) + m_request_imeisv(args.request_imeisv), + m_lac(args.lac) { m_sec_ctx.integ_algo = args.integ_algo; m_sec_ctx.cipher_algo = args.cipher_algo; @@ -1541,7 +1542,7 @@ bool nas::pack_attach_accept(srsran::byte_buffer_t* nas_buffer) attach_accept.lai_present = true; attach_accept.lai.mcc = mcc; attach_accept.lai.mnc = mnc; - attach_accept.lai.lac = 001; + attach_accept.lai.lac = m_lac; attach_accept.ms_id_present = true; attach_accept.ms_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_TMSI; diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc index 54888e833..4e7e70baa 100644 --- a/srsepc/src/mme/s1ap_nas_transport.cc +++ b/srsepc/src/mme/s1ap_nas_transport.cc @@ -72,6 +72,7 @@ void s1ap_nas_transport::init() m_nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo; m_nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo; m_nas_init.request_imeisv = m_s1ap->m_s1ap_args.request_imeisv; + m_nas_init.lac = m_s1ap->m_s1ap_args.lac; // Init NAS interface m_nas_if.s1ap = s1ap::get_instance(); From f571d46cf83c8a59075d0356d503a86ad78c64fd Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Sun, 22 May 2022 16:38:32 +0300 Subject: [PATCH 06/16] enb,cfg_parser: Add GERAN speed state scale factors --- srsenb/sib.conf.example | 3 +++ srsenb/src/enb_cfg_parser.cc | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 0d4e60aa4..7ca5dafba 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -143,6 +143,9 @@ sib3 = # Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted # # t_resel_geran: Cell reselection timer (seconds) +# t_resel_geran_sf: Optional speed dependent ScalingFactor for t_resel_geran. +# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0". +# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0". # carrier_freqs_info_list: A list of carrier frequency groups. # cell_resel_prio: Absolute priority of the carrier frequency group # ncc_permitted: 8-bit bitmap of NCC carriers permitted for monitoring diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index d8f372eb3..7f4f1f303 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -2236,7 +2236,13 @@ int parse_sib7(std::string filename, sib_type7_s* data) parser::section sib7("sib7"); sib7.add_field(new parser::field("t_resel_geran", &data->t_resel_geran)); - // TODO: t_resel_geran_sf + + parser::section t_resel_geran_sf("t_resel_geran_sf"); + sib7.add_subsection(&t_resel_geran_sf); + t_resel_geran_sf.set_optional(&data->t_resel_geran_sf_present); + + t_resel_geran_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &data->t_resel_geran_sf.sf_medium)); + t_resel_geran_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &data->t_resel_geran_sf.sf_high)); data->carrier_freqs_info_list_present = true; parser::section geran_neigh("carrier_freqs_info_list"); From 602bca70a4ab11a7d557ade98774481c149a1856 Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Mon, 23 May 2022 08:41:04 +0300 Subject: [PATCH 07/16] enb,cfg_parser: Allow sib4 to contain black cell list only. --- srsenb/src/enb_cfg_parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 7f4f1f303..2bd58c6b2 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -124,7 +124,7 @@ int field_intra_neigh_cell_list::parse(libconfig::Setting& root) int field_intra_black_cell_list::parse(libconfig::Setting& root) { data->intra_freq_black_cell_list.resize((uint32_t)root.getLength()); - data->intra_freq_black_cell_list_present = data->intra_freq_neigh_cell_list.size() > 0; + data->intra_freq_black_cell_list_present = data->intra_freq_black_cell_list.size() > 0; for (uint32_t i = 0; i < data->intra_freq_black_cell_list.size() && i < ASN1_RRC_MAX_CELL_BLACK; i++) { if (not parse_enum_by_number(data->intra_freq_black_cell_list[i].range, "range", root[i])) { fprintf(stderr, "Missing field range in black_cell=%d\n", i); From 375709b449bfb4a9c17f186b675bdfcf3e9038c0 Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Mon, 23 May 2022 08:32:51 +0300 Subject: [PATCH 08/16] enb,cfg_parser: Add SIB6 parsing. --- srsenb/sib.conf.example | 50 ++++++++++++ srsenb/src/enb_cfg_parser.cc | 143 +++++++++++++++++++++++++++++++++++ srsenb/src/enb_cfg_parser.h | 23 ++++++ 3 files changed, 216 insertions(+) diff --git a/srsenb/sib.conf.example b/srsenb/sib.conf.example index 7ca5dafba..69bc9c077 100644 --- a/srsenb/sib.conf.example +++ b/srsenb/sib.conf.example @@ -137,6 +137,56 @@ sib3 = } }; +##################################################################### +# sib6 configuration options (See TS 36.331) +# Contains UTRA neighbor information for inter-rat handover. +# Must be added to sib1::sched_info::si_mapping_info array parameter to be transmitted +# +# t_resel_utra: Cell reselection timer (seconds) +# t_resel_utra_sf: Optional speed dependent ScalingFactor for t_resel_utra. +# sf_medium: Scaling factor if the UE is in Medium Mobility state, one of "0.25", "0.5", "0.75" or "1.0". +# sf_high: Scaling factor if the UE is in High Mobility state, one of "0.25", "0.5", "0.75" or "1.0". +# carrier_freq_list_utra_fdd / carrier_freq_list_utra_tdd: A list of carrier frequencies of UTRA FDD / TDD. +# carrier_freq: The UARFCN for the UTRA carrier frequency. +# cell_resel_prio: Optional absolute priority of the carrier frequency group. +# thresh_x_high: Srclev threshold (dB) to select to a higher-priority RAT/Frequency. +# thresh_x_low: Srclev threshold (dB) to select to a lower-priority RAT/Frequency. +# q_rx_lev_min: Minimum receive level in UTRA cell, ([field_val] * 2) + 1 = [level in dBm]. +# p_max_utra: The maximum allowed transmission power on the (uplink) carrier frequency. +# q_qual_min: Minimum required quality leve in UTRA cell, applicable only for FDD cells. +# +##################################################################### +sib6 = +{ + t_resel_utra = 1; + t_resel_utra_sf = { + sf_medium = "0.25"; + sf_high = "1.0"; + } + carrier_freq_list_utra_fdd = + ( + { + carrier_freq = 9613; + cell_resel_prio = 6; + thresh_x_high = 3; + thresh_x_low = 2; + q_rx_lev_min = -50; + p_max_utra = 4; + q_qual_min = -10; + } + ); + carrier_freq_list_utra_tdd = + ( + { + carrier_freq = 9505; + thresh_x_high = 1; + thresh_x_low = 2; + q_rx_lev_min = -50; + p_max_utra = -3; + } + ); +}; + ##################################################################### # sib7 configuration options (See TS 36.331) # Contains GERAN neighbor information for CSFB and inter-rat handover. diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 2bd58c6b2..94aee179b 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -142,6 +142,111 @@ int field_intra_black_cell_list::parse(libconfig::Setting& root) return 0; } +int field_carrier_freq_list_utra_fdd::parse(libconfig::Setting& root) +{ + data->carrier_freq_list_utra_fdd.resize((uint32_t)root.getLength()); + data->carrier_freq_list_utra_fdd_present = data->carrier_freq_list_utra_fdd.size() > 0; + for (uint32_t i = 0; i < data->carrier_freq_list_utra_fdd.size() && i < ASN1_RRC_MAX_UTRA_FDD_CARRIER; i++) { + unsigned int carrier_freq = 0; + if (!root[i].lookupValue("carrier_freq", carrier_freq)) { + fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_fdd=%d\n", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].carrier_freq = carrier_freq; + + unsigned int cell_resel_prio = 0; + if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) { + data->carrier_freq_list_utra_fdd[i].cell_resel_prio_present = true; + data->carrier_freq_list_utra_fdd[i].cell_resel_prio = cell_resel_prio; + } + + unsigned int thresh_x_high = 0; + if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) { + ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].thresh_x_high = thresh_x_high; + + unsigned int thresh_x_low = 0; + if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) { + ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].thresh_x_low = thresh_x_low; + + int q_rx_lev_min = 0; + if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) { + ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].q_rx_lev_min = q_rx_lev_min; + + int p_max_utra = 0; + if (!root[i].lookupValue("p_max_utra", p_max_utra)) { + ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].p_max_utra = p_max_utra; + + int q_qual_min = 0; + if (!root[i].lookupValue("q_qual_min", q_qual_min)) { + ERROR("Missing field `q_qual_min` in carrier_freq_list_utra_fdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_fdd[i].q_qual_min = q_qual_min; + } + return 0; +} + +int field_carrier_freq_list_utra_tdd::parse(libconfig::Setting& root) +{ + data->carrier_freq_list_utra_tdd.resize((uint32_t)root.getLength()); + data->carrier_freq_list_utra_tdd_present = data->carrier_freq_list_utra_tdd.size() > 0; + for (uint32_t i = 0; i < data->carrier_freq_list_utra_tdd.size() && i < ASN1_RRC_MAX_UTRA_TDD_CARRIER; i++) { + unsigned int carrier_freq = 0; + if (!root[i].lookupValue("carrier_freq", carrier_freq)) { + fprintf(stderr, "Missing field `carrier_freq` in carrier_freq_list_utra_tdd=%d\n", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].carrier_freq = carrier_freq; + + unsigned int cell_resel_prio = 0; + if (root[i].lookupValue("cell_resel_prio", cell_resel_prio)) { + data->carrier_freq_list_utra_tdd[i].cell_resel_prio_present = true; + data->carrier_freq_list_utra_tdd[i].cell_resel_prio = cell_resel_prio; + } + + unsigned int thresh_x_high = 0; + if (!root[i].lookupValue("thresh_x_high", thresh_x_high)) { + ERROR("Missing field `thresh_x_high` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].thresh_x_high = thresh_x_high; + + unsigned int thresh_x_low = 0; + if (!root[i].lookupValue("thresh_x_low", thresh_x_low)) { + ERROR("Missing field `thresh_x_low` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].thresh_x_low = thresh_x_low; + + int q_rx_lev_min = 0; + if (!root[i].lookupValue("q_rx_lev_min", q_rx_lev_min)) { + ERROR("Missing field `q_rx_lev_min` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].q_rx_lev_min = q_rx_lev_min; + + int p_max_utra = 0; + if (!root[i].lookupValue("p_max_utra", p_max_utra)) { + ERROR("Missing field `p_max_utra` in carrier_freq_list_utra_tdd=%d", i); + return SRSRAN_ERROR; + } + data->carrier_freq_list_utra_tdd[i].p_max_utra = p_max_utra; + } + return 0; +} + int field_carrier_freqs_info_list::parse(libconfig::Setting& root) { data->carrier_freqs_info_list.resize((uint32_t)root.getLength()); @@ -2231,6 +2336,36 @@ int parse_sib4(std::string filename, sib_type4_s* data) return parser::parse_section(std::move(filename), &sib4); } +int parse_sib6(std::string filename, sib_type6_s* data) +{ + parser::section sib6("sib6"); + + // t-ReselectionUTRA + sib6.add_field(new parser::field("t_resel_utra", &data->t_resel_utra)); + + // t-ReselectionUTRA-SF + parser::section t_resel_utra_sf("t_resel_utra_sf"); + sib6.add_subsection(&t_resel_utra_sf); + t_resel_utra_sf.set_optional(&data->t_resel_utra_sf_present); + t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_medium", &data->t_resel_utra_sf.sf_medium)); + t_resel_utra_sf.add_field(make_asn1_enum_number_str_parser("sf_high", &data->t_resel_utra_sf.sf_high)); + + // carrierFreqListUTRA-FDD + parser::section carrier_freq_list_utra_fdd("carrier_freq_list_utra_fdd"); + sib6.add_subsection(&carrier_freq_list_utra_fdd); + bool dummy_bool = false; + carrier_freq_list_utra_fdd.set_optional(&dummy_bool); + carrier_freq_list_utra_fdd.add_field(new field_carrier_freq_list_utra_fdd(data)); + + // carrierFreqListUTRA-TDD + parser::section carrier_freq_list_utra_tdd("carrier_freq_list_utra_tdd"); + sib6.add_subsection(&carrier_freq_list_utra_tdd); + carrier_freq_list_utra_tdd.set_optional(&dummy_bool); + carrier_freq_list_utra_tdd.add_field(new field_carrier_freq_list_utra_tdd(data)); + + return parser::parse_section(std::move(filename), &sib6); +} + int parse_sib7(std::string filename, sib_type7_s* data) { parser::section sib7("sib7"); @@ -2314,6 +2449,7 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co sib_type2_s* sib2 = &rrc_cfg_->sibs[1].set_sib2(); sib_type3_s* sib3 = &rrc_cfg_->sibs[2].set_sib3(); sib_type4_s* sib4 = &rrc_cfg_->sibs[3].set_sib4(); + sib_type6_s* sib6 = &rrc_cfg_->sibs[5].set_sib6(); sib_type7_s* sib7 = &rrc_cfg_->sibs[6].set_sib7(); sib_type9_s* sib9 = &rrc_cfg_->sibs[8].set_sib9(); sib_type13_r9_s* sib13 = &rrc_cfg_->sibs[12].set_sib13_v920(); @@ -2383,6 +2519,13 @@ int parse_sibs(all_args_t* args_, rrc_cfg_t* rrc_cfg_, srsenb::phy_cfg_t* phy_co } } + // Generate SIB6 if defined in mapping info + if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type6)) { + if (sib_sections::parse_sib6(args_->enb_files.sib_config, sib6) != SRSRAN_SUCCESS) { + return SRSRAN_ERROR; + } + } + // Generate SIB7 if defined in mapping info if (sib_is_present(sib1->sched_info_list, sib_type_e::sib_type7)) { if (sib_sections::parse_sib7(args_->enb_files.sib_config, sib7) != SRSRAN_SUCCESS) { diff --git a/srsenb/src/enb_cfg_parser.h b/srsenb/src/enb_cfg_parser.h index d1f0ae0ae..494217c2f 100644 --- a/srsenb/src/enb_cfg_parser.h +++ b/srsenb/src/enb_cfg_parser.h @@ -54,6 +54,7 @@ int parse_sib1(std::string filename, asn1::rrc::sib_type1_s* data); int parse_sib2(std::string filename, asn1::rrc::sib_type2_s* data); int parse_sib3(std::string filename, asn1::rrc::sib_type3_s* data); int parse_sib4(std::string filename, asn1::rrc::sib_type4_s* data); +int parse_sib6(std::string filename, asn1::rrc::sib_type6_s* data); int parse_sib7(std::string filename, asn1::rrc::sib_type7_s* data); int parse_sib9(std::string filename, asn1::rrc::sib_type9_s* data); int parse_sib13(std::string filename, asn1::rrc::sib_type13_r9_s* data); @@ -140,6 +141,28 @@ private: asn1::rrc::sib_type4_s* data; }; +class field_carrier_freq_list_utra_fdd final : public parser::field_itf +{ +public: + explicit field_carrier_freq_list_utra_fdd(asn1::rrc::sib_type6_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "carrier_freq_list_utra_fdd"; } + +private: + asn1::rrc::sib_type6_s* data; +}; + +class field_carrier_freq_list_utra_tdd final : public parser::field_itf +{ +public: + explicit field_carrier_freq_list_utra_tdd(asn1::rrc::sib_type6_s* data_) { data = data_; } + int parse(Setting& root) override; + const char* get_name() override { return "carrier_freq_list_utra_tdd"; } + +private: + asn1::rrc::sib_type6_s* data; +}; + class field_carrier_freqs_info_list final : public parser::field_itf { public: From 218bf1c9162e486a86dfbf47b3a07163b7d14ad5 Mon Sep 17 00:00:00 2001 From: Matan Perelman Date: Thu, 23 Jun 2022 11:22:33 +0300 Subject: [PATCH 09/16] enb,cfg_parser: Fix ac_barring_for_mo_data time typo. --- srsenb/src/enb_cfg_parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsenb/src/enb_cfg_parser.cc b/srsenb/src/enb_cfg_parser.cc index 94aee179b..40d74c44b 100644 --- a/srsenb/src/enb_cfg_parser.cc +++ b/srsenb/src/enb_cfg_parser.cc @@ -2099,7 +2099,7 @@ int parse_sib2(std::string filename, sib_type2_s* data) acbarring_data.add_field( make_asn1_enum_number_str_parser("factor", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_factor)); - acbarring_data.add_field(make_asn1_enum_number_parser("fime", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time)); + acbarring_data.add_field(make_asn1_enum_number_parser("time", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_time)); acbarring_data.add_field(make_asn1_bitstring_number_parser( "for_special_ac", &data->ac_barr_info.ac_barr_for_mo_data.ac_barr_for_special_ac)); From 2e4b1aceaf50211182e73f4ba5544c5a7874844a Mon Sep 17 00:00:00 2001 From: Zishuai CHENG <5786734+WingPig99@users.noreply.github.com> Date: Wed, 22 Jun 2022 18:19:15 +0100 Subject: [PATCH 10/16] Parse tmsi type of mobile id and fixed the content length of network feature support --- lib/src/asn1/liblte_mme.cc | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 2d32f310e..e3d1cff84 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -319,6 +319,7 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_MOBI { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8* id; + uint32* id32; uint32 length; uint32 i; bool odd = false; @@ -338,22 +339,35 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_mobile_id_ie(uint8** ie_ptr, LIBLTE_MME_MOBI } else if (LIBLTE_MME_MOBILE_ID_TYPE_IMEISV == mobile_id->type_of_id) { id = mobile_id->imeisv; odd = false; + } else if (LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id) { + id32 = &mobile_id->tmsi; + odd = false; } else { // TODO: Not handling these IDs return (err); } - id[0] = **ie_ptr >> 4; - *ie_ptr += 1; - for (i = 0; i < 7; i++) { - id[i * 2 + 1] = (*ie_ptr)[i] & 0x0F; - id[i * 2 + 2] = (*ie_ptr)[i] >> 4; - } - if (odd) { - *ie_ptr += 7; + if (mobile_id->type_of_id != LIBLTE_MME_MOBILE_ID_TYPE_TMSI) { + id[0] = **ie_ptr >> 4; + *ie_ptr += 1; + for (i = 0; i < 7; i++) { + id[i * 2 + 1] = (*ie_ptr)[i] & 0x0F; + id[i * 2 + 2] = (*ie_ptr)[i] >> 4; + } + if (odd) { + *ie_ptr += 7; + } else { + id[i * 2 + 1] = (*ie_ptr)[i] & 0xF; + *ie_ptr += 8; + } } else { - id[i * 2 + 1] = (*ie_ptr)[i] & 0xF; - *ie_ptr += 8; + *ie_ptr += 1; + uint32 tmsi = 0; + for (i = 0; i < 4; i++) { + tmsi += ((*ie_ptr)[i] & 0xFF) << ((3 - i) * 8); + } + *id32 = tmsi; + *ie_ptr += 4; } err = LIBLTE_SUCCESS; @@ -1380,12 +1394,13 @@ liblte_mme_unpack_eps_network_feature_support_ie(uint8** ie_ptr, LIBLTE_MME_EPS_ LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; if (ie_ptr != NULL && eps_nfs != NULL) { + int ie_len = *ie_ptr[0]; eps_nfs->esrps = ((*ie_ptr)[1] >> 5) & 0x01; eps_nfs->cs_lcs = (LIBLTE_MME_CS_LCS_ENUM)(((*ie_ptr)[1] >> 3) & 0x03); eps_nfs->epc_lcs = ((*ie_ptr)[1] >> 2) & 0x01; eps_nfs->emc_bs = ((*ie_ptr)[1] >> 1) & 0x01; eps_nfs->ims_vops = (*ie_ptr)[1] & 0x01; - *ie_ptr += 2; + *ie_ptr += (ie_len + 1); err = LIBLTE_SUCCESS; } From 9d6385c84f013bf438779fe1a0e85d362f007021 Mon Sep 17 00:00:00 2001 From: Shubham Tatvamasi Date: Sat, 30 Apr 2022 08:53:39 +0530 Subject: [PATCH 11/16] ci: use matrix-keyword for x86/aarch64 builds Cherry-picked from Shubham Tatvamasi (https://github.com/ShubhamTatvamasi) initial commit --- .github/workflows/ccpp.yml | 47 +++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index c8459e96b..8f7445d2e 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -1,35 +1,44 @@ name: C/C++ CI on: push jobs: - x86_ubuntu18_build: - name: Build and test on x86 Ubuntu 18.04 + x86_ubuntu_build: + name: Build on x86 + runs-on: ${{ matrix.os }} strategy: - matrix: - compiler: [gcc, clang] - runs-on: ubuntu-18.04 + fail-fast: false + matrix: + os: [ubuntu-20.04, ubuntu-18.04] + compiler: [gcc, clang] steps: - - uses: actions/checkout@v1 - - name: Build srsRAN on x86 Ubuntu 18.04 - run: | - sudo apt update - sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind - mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest - - aarch64_ubuntu18_build: - runs-on: ubuntu-18.04 + - uses: actions/checkout@v3 + - name: Build srsRAN on x86 ${{ matrix.os }} + run: | + sudo apt update + sudo apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev colordiff ninja-build valgrind + mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja && ctest + + aarch64_ubuntu_build: name: Build on aarch64 + runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: + os: [ubuntu-20.04, ubuntu-18.04] compiler: [gcc, clang] + include: + - os: ubuntu-20.04 + distro: ubuntu20.04 + - os: ubuntu-18.04 + distro: ubuntu18.04 steps: - - uses: actions/checkout@v1 - - name: Build srsRAN on aarch64 + - uses: actions/checkout@v3 + - name: Build srsRAN on aarch64 ${{ matrix.os }} uses: uraimo/run-on-arch-action@master with: - architecture: aarch64 - distribution: ubuntu18.04 + arch: aarch64 + distro: ${{ matrix.distro }} run: | export CTEST_PARALLEL_LEVEL=$(nproc --all) apt update apt install -y build-essential cmake libfftw3-dev libmbedtls-dev libpcsclite-dev libboost-program-options-dev libconfig++-dev libsctp-dev ninja-build - ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja \ No newline at end of file + ls -l && pwd && mkdir build && cd build && cmake -DRF_FOUND=True -GNinja .. && ninja From 51fdfa334dd422f2b5a90379ab7904e369dde6d4 Mon Sep 17 00:00:00 2001 From: Piotr Gawlowicz Date: Fri, 3 Jun 2022 11:09:54 +0200 Subject: [PATCH 12/16] epc: fix example usage text in the srsepc_if_masq.sh script --- srsepc/srsepc_if_masq.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/srsepc/srsepc_if_masq.sh b/srsepc/srsepc_if_masq.sh index b6ab769c5..83b648fb5 100755 --- a/srsepc/srsepc_if_masq.sh +++ b/srsepc/srsepc_if_masq.sh @@ -14,7 +14,7 @@ sudo -v || exit #Check if outbound interface was specified if [ ! $# -eq 1 ] then - echo "Usage :'sudo ./if_masq.sh ' " + echo "Usage :'sudo ./srsepc_if_masq.sh ' " exit fi From 6f2c64194148370e79aea41e9aaa2f8d269cee3f Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 19 Jul 2022 12:19:18 +0200 Subject: [PATCH 13/16] ue,sa: enable PCAP writing for NAS-5G --- srsue/src/stack/ue_stack_lte.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/srsue/src/stack/ue_stack_lte.cc b/srsue/src/stack/ue_stack_lte.cc index 15c66cf26..f7100e727 100644 --- a/srsue/src/stack/ue_stack_lte.cc +++ b/srsue/src/stack/ue_stack_lte.cc @@ -195,6 +195,7 @@ int ue_stack_lte::init(const stack_args_t& args_) if (args.pkt_trace.nas_pcap.enable) { if (nas_pcap.open(args.pkt_trace.nas_pcap.filename.c_str()) == SRSRAN_SUCCESS) { nas.start_pcap(&nas_pcap); + nas_5g.start_pcap(&nas_pcap); stack_logger.info("Open nas pcap file %s", args.pkt_trace.nas_pcap.filename.c_str()); } else { stack_logger.error("Can not open pcap file %s", args.pkt_trace.nas_pcap.filename.c_str()); From 72220aa811087e8f4ee49639ff1798995d127ae5 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 19 Jul 2022 12:44:06 +0200 Subject: [PATCH 14/16] enb,phy: do not start start plots if LTE workers don't exist this was causing a segfault when the GUI was enabled in SA mode, i.e. without LTE cells we only support the GUI with LTE enabled. --- srsenb/src/phy/phy.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/srsenb/src/phy/phy.cc b/srsenb/src/phy/phy.cc index e211b157c..db0f75831 100644 --- a/srsenb/src/phy/phy.cc +++ b/srsenb/src/phy/phy.cc @@ -349,7 +349,9 @@ void phy::configure_mbsfn(srsran::sib2_mbms_t* sib2, srsran::sib13_t* sib13, con // Start GUI void phy::start_plot() { - lte_workers[0]->start_plot(); + if (lte_workers.get_nof_workers() > 0) { + lte_workers[0]->start_plot(); + } } int phy::init_nr(const phy_args_t& args, const phy_cfg_t& cfg, stack_interface_phy_nr& stack) From b001d6c10e253745f1f45f6bf83cddd5d3fdb67d Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Fri, 15 Jul 2022 12:22:00 +0100 Subject: [PATCH 15/16] lib,rlc_am_lte: fix checkers for the TX window full --- lib/include/srsran/rlc/rlc_am_lte.h | 1 + lib/src/rlc/rlc_am_lte.cc | 21 +++- lib/test/rlc/rlc_am_lte_test.cc | 175 ++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+), 6 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_lte.h b/lib/include/srsran/rlc/rlc_am_lte.h index ec20c0082..5710a07c5 100644 --- a/lib/include/srsran/rlc/rlc_am_lte.h +++ b/lib/include/srsran/rlc/rlc_am_lte.h @@ -86,6 +86,7 @@ private: void retransmit_pdu(uint32_t sn); // Helpers + bool window_full(); bool poll_required(); bool do_status(); void check_sn_reached_max_retx(uint32_t sn); diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index 8279a8858..f010a6860 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -242,7 +242,7 @@ void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n } // Bytes needed for tx SDUs - if (tx_window.size() < 1024) { + if (not window_full()) { n_sdus = tx_sdu_queue.get_n_sdus(); n_bytes_newtx += tx_sdu_queue.size_bytes(); if (tx_sdu != NULL) { @@ -290,7 +290,7 @@ uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes) } // Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU - if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty()) { + if (window_full() && retx_queue.empty()) { retransmit_pdu(vt_a); } @@ -314,7 +314,7 @@ void rlc_am_lte_tx::timer_expired(uint32_t timeout_id) // Section 5.2.2.3 in TS 36.322, schedule PDU for retransmission if // (a) both tx and retx buffer are empty (excluding tx'ed PDU waiting for ack), or // (b) no new data PDU can be transmitted (tx window is full) - if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) { + if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || window_full()) { retransmit_pdu(vt_a); // TODO: TS says to send vt_s - 1 here } } else if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) { @@ -359,6 +359,14 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) * Helper functions ***************************************************************************/ +bool rlc_am_lte_tx::window_full() +{ + if ((vt_s - vt_a) >= RLC_AM_WINDOW_SIZE) { + return true; + } + return false; +}; + /** * Called when building a RLC PDU for checking whether the poll bit needs * to be set. @@ -385,7 +393,7 @@ bool rlc_am_lte_tx::poll_required() return true; } - if (tx_window.size() >= RLC_AM_WINDOW_SIZE) { + if (window_full()) { RlcDebug("Poll required. Cause: TX window full."); return true; } @@ -690,7 +698,7 @@ int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes) } // do not build any more PDU if window is already full - if (tx_window.size() >= RLC_AM_WINDOW_SIZE) { + if (window_full()) { RlcInfo("Cannot build data PDU - Tx window full."); return 0; } @@ -1156,7 +1164,8 @@ rlc_am_lte_rx::rlc_am_lte_rx(rlc_am* parent_) : pool(byte_buffer_pool::get_instance()), reordering_timer(parent_->timers->get_unique_timer()), rlc_am_base_rx(parent_, parent_->logger) -{} +{ +} bool rlc_am_lte_rx::configure(const rlc_config_t& cfg_) { diff --git a/lib/test/rlc/rlc_am_lte_test.cc b/lib/test/rlc/rlc_am_lte_test.cc index 984d6afdd..e3d94459e 100644 --- a/lib/test/rlc/rlc_am_lte_test.cc +++ b/lib/test/rlc/rlc_am_lte_test.cc @@ -3757,6 +3757,176 @@ bool poll_retx_expiry_test() return SRSRAN_SUCCESS; } +bool full_window_check_test() +{ + rlc_config_t config = rlc_config_t::default_rlc_am_config(); + // [I] SRB1 configured: t_poll_retx=65, poll_pdu=-1, poll_byte=-1, max_retx_thresh=6, t_reordering=55, + // t_status_prohibit=0 + config.am.t_poll_retx = 65; + config.am.poll_pdu = -1; + config.am.poll_byte = -1; + config.am.max_retx_thresh = 6; + config.am.t_reordering = 55; + config.am.t_status_prohibit = 55; + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_poll_rext_expiry_test.pcap", config); + rlc_am_tester tester(true, &pcap); +#else + rlc_am_tester tester(true, NULL); +#endif + + srsran::timer_handler timers(8); + + rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); + + srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100); + + if (not rlc1.configure(config)) { + return -1; + } + + if (not rlc2.configure(config)) { + return -1; + } + + { + // Initial Tx + uint32_t num_tx_pdus = 512; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = 1; + pdu->msg[0] = i; + pdu->md.pdcp_sn = i; + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + } + { + // Tx one more to check the window is full + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = 0; + sdu->md.pdcp_sn = 512; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // If the TX window is full, we should RETX SN=0 + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 0); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + } + + // Ack one SN in the middle of the TX window. + // This is done to make sure the full window check is correct + // even if PDUs in the middle of the window are ACKed. + // ACK_SN=3, NACK_SN=0 + { + rlc_status_pdu_t status = {}; + status.ack_sn = 3; + status.N_nack = 1; + status.nacks[0].nack_sn = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + + // Read RETX for SN=0 from NACK + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // Check RETX SN=0 + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 0); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + TESTASSERT_EQ(0, rlc1.get_buffer_state()); + } + { + // Tx more PDUs to check the window is still full + uint32_t num_tx_pdus = 2; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = i; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = 1; + pdu->msg[0] = i; + pdu->md.pdcp_sn = i; + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // If the TX window is full, we should RETX SN=0 + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 0); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + } + } + // ACK more PDUs and advance VT(A). + // New PDUs should be available to read now. + { + rlc_status_pdu_t status = {}; + status.ack_sn = 5; + status.N_nack = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + + // Read new PDU + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // If the TX window is no longer full, we should TX a new SN (SN=512) + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 512); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + } + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSRAN_SUCCESS; +} + int main(int argc, char** argv) { // Setup the log message spy to intercept error and warning log entries from RLC @@ -3966,5 +4136,10 @@ int main(int argc, char** argv) printf("poll_retx_expiry_test failed\n"); exit(-1); }; + + if (full_window_check_test()) { + printf("full_window_check_test failed\n"); + exit(-1); + }; return SRSRAN_SUCCESS; } From e4207b177fe42593795f63990f3b72eee276ccbc Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 20 Jul 2022 18:32:38 +0100 Subject: [PATCH 16/16] lib,rlc_am_lte: added fix for full tx window with wraparround --- lib/src/rlc/rlc_am_lte.cc | 5 +- lib/test/rlc/rlc_am_lte_test.cc | 151 ++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 4 deletions(-) diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index f010a6860..d84e72723 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -361,10 +361,7 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) bool rlc_am_lte_tx::window_full() { - if ((vt_s - vt_a) >= RLC_AM_WINDOW_SIZE) { - return true; - } - return false; + return TX_MOD_BASE(vt_s) >= RLC_AM_WINDOW_SIZE; }; /** diff --git a/lib/test/rlc/rlc_am_lte_test.cc b/lib/test/rlc/rlc_am_lte_test.cc index e3d94459e..b9432d04d 100644 --- a/lib/test/rlc/rlc_am_lte_test.cc +++ b/lib/test/rlc/rlc_am_lte_test.cc @@ -3927,6 +3927,152 @@ bool full_window_check_test() return SRSRAN_SUCCESS; } +bool full_window_check_wraparound_test() +{ + rlc_config_t config = rlc_config_t::default_rlc_am_config(); + // [I] SRB1 configured: t_poll_retx=65, poll_pdu=-1, poll_byte=-1, max_retx_thresh=6, t_reordering=55, + // t_status_prohibit=0 + config.am.t_poll_retx = 65; + config.am.poll_pdu = -1; + config.am.poll_byte = -1; + config.am.max_retx_thresh = 6; + config.am.t_reordering = 55; + config.am.t_status_prohibit = 55; + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_poll_rext_expiry_test.pcap", config); + rlc_am_tester tester(true, &pcap); +#else + rlc_am_tester tester(true, NULL); +#endif + + uint32_t pdcp_count = 0; + + srsran::timer_handler timers(8); + + rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); + + srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100); + + if (not rlc1.configure(config)) { + return -1; + } + + if (not rlc2.configure(config)) { + return -1; + } + + // Advance vt_a to 512 and vt_s to 512 as well. + { + // Initial Tx + uint32_t num_tx_pdus = 512; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + + // ACK all SNs to advance the TX window. + rlc_status_pdu_t status = {}; + status.ack_sn = num_tx_pdus; + status.N_nack = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + } + + // Advance vt_a and vt_s to 1023 + { + // Initial Tx + uint32_t num_tx_pdus = 511; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + + // ACK all SNs to advance the TX window. + rlc_status_pdu_t status = {}; + status.ack_sn = 512 + num_tx_pdus; + status.N_nack = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + } + + // Now, fill up the window + { + // Initial Tx + uint32_t num_tx_pdus = 512; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + } + { + // Tx one more to check the window is full + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = 0; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // If the TX window is full, we should RETX SN=1023 + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 1023); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + } + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSRAN_SUCCESS; +} int main(int argc, char** argv) { // Setup the log message spy to intercept error and warning log entries from RLC @@ -4141,5 +4287,10 @@ int main(int argc, char** argv) printf("full_window_check_test failed\n"); exit(-1); }; + + if (full_window_check_wraparound_test()) { + printf("full_window_check_wraparound_test failed\n"); + exit(-1); + }; return SRSRAN_SUCCESS; }