diff --git a/lib/include/srslte/upper/pdcp_entity_lte.h b/lib/include/srslte/upper/pdcp_entity_lte.h index a40fb8eb5..3dc27140c 100644 --- a/lib/include/srslte/upper/pdcp_entity_lte.h +++ b/lib/include/srslte/upper/pdcp_entity_lte.h @@ -66,6 +66,15 @@ public: // RLC interface void write_pdu(unique_byte_buffer_t pdu); + // State variable setters (should be used only for testing) + void set_tx_count(uint32_t tx_count_) { tx_count = tx_count_; } + void set_rx_hfn(uint32_t rx_hfn_) { rx_hfn = rx_hfn_; } + void set_next_pdcp_rx_sn(uint32_t next_pdcp_rx_sn_) { next_pdcp_rx_sn = next_pdcp_rx_sn_; } + void set_last_submitted_pdcp_rx_sn(uint32_t last_submitted_pdcp_rx_sn_) + { + last_submitted_pdcp_rx_sn = last_submitted_pdcp_rx_sn_; + } + private: srsue::rlc_interface_pdcp* rlc = nullptr; srsue::rrc_interface_pdcp* rrc = nullptr; diff --git a/lib/test/upper/CMakeLists.txt b/lib/test/upper/CMakeLists.txt index d1547dc06..f258b42d0 100644 --- a/lib/test/upper/CMakeLists.txt +++ b/lib/test/upper/CMakeLists.txt @@ -82,6 +82,10 @@ if (ENABLE_5GNR) add_test(pdcp_nr_test_discard_sdu pdcp_nr_test_discard_sdu) endif(ENABLE_5GNR) +add_executable(pdcp_lte_test_rx pdcp_lte_test_rx.cc) +target_link_libraries(pdcp_lte_test_rx srslte_upper srslte_common) +add_test(pdcp_lte_test_rx pdcp_lte_test_rx) + ######################################################################## # Option to run command after build (useful for remote builds) ######################################################################## diff --git a/lib/test/upper/pdcp_lte_test.h b/lib/test/upper/pdcp_lte_test.h new file mode 100644 index 000000000..d51bf198f --- /dev/null +++ b/lib/test/upper/pdcp_lte_test.h @@ -0,0 +1,158 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef SRSLTE_PDCP_LTE_TEST_H +#define SRSLTE_PDCP_LTE_TEST_H + +#include "pdcp_base_test.h" +#include "srslte/upper/pdcp_entity_lte.h" + +struct pdcp_lte_initial_state { + uint32_t tx_count; + uint32_t rx_hfn; + uint32_t next_pdcp_rx_sn; + uint32_t last_submitted_pdcp_rx_sn; +}; + +// Helper struct to hold a packet and the number of clock +// ticks to run after writing the packet to test timeouts. +struct pdcp_test_event_t { + srslte::unique_byte_buffer_t pkt; + uint32_t ticks = 0; +}; + +/* + * Constant definitions that are common to multiple tests + */ +// Encryption and Integrity Keys +uint8_t k_int[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31}; +uint8_t k_enc[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30, 0x31}; + +// Security Configuration, common to all tests. +pdcp_security_cfg sec_cfg = { + k_int, + k_enc, + k_int, + k_enc, + srslte::INTEGRITY_ALGORITHM_ID_128_EIA2, + srslte::CIPHERING_ALGORITHM_ID_128_EEA2, +}; + +// Test SDUs for tx +uint8_t sdu1[] = {0x18, 0xe2}; +uint8_t sdu2[] = {0xde, 0xad}; + +// This is the normal initial state. All state variables are set to zero +pdcp_lte_initial_state normal_init_state = {}; + +/* + * Helper classes to reduce copy / pasting in setting up tests + */ +// PDCP helper to setup PDCP + Dummy +class pdcp_lte_test_helper +{ +public: + pdcp_lte_test_helper(srslte::pdcp_config_t cfg, pdcp_security_cfg sec_cfg, srslte::log* log) : + rlc(log), + rrc(log), + gw(log), + timers(64), + pdcp(&rlc, &rrc, &gw, &timers, log) + { + pdcp.init(0, cfg); + pdcp.config_security( + sec_cfg.k_enc_rrc, sec_cfg.k_int_rrc, sec_cfg.k_enc_up, sec_cfg.k_int_up, sec_cfg.enc_algo, sec_cfg.int_algo); + pdcp.enable_integrity(); + pdcp.enable_encryption(); + } + + void set_pdcp_initial_state(pdcp_lte_initial_state init_state) + { + + pdcp.set_tx_count(init_state.tx_count); + pdcp.set_rx_hfn(init_state.rx_hfn); + pdcp.set_next_pdcp_rx_sn(init_state.next_pdcp_rx_sn); + pdcp.set_last_submitted_pdcp_rx_sn(init_state.last_submitted_pdcp_rx_sn); + } + + rlc_dummy rlc; + rrc_dummy rrc; + gw_dummy gw; + srslte::timer_handler timers; + srslte::pdcp_entity_lte pdcp; +}; + +// Helper function to generate PDUs +srslte::unique_byte_buffer_t gen_expected_pdu(const srslte::unique_byte_buffer_t& in_sdu, + uint32_t count, + uint8_t pdcp_sn_len, + srslte::pdcp_rb_type_t rb_type, + pdcp_security_cfg sec_cfg, + srslte::byte_buffer_pool* pool, + srslte::log* log) +{ + srslte::pdcp_config_t cfg = {1, + rb_type, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::SECURITY_DIRECTION_DOWNLINK, + pdcp_sn_len, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::infinity}; + + pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, log); + srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; + rlc_dummy* rlc = &pdcp_hlp.rlc; + + pdcp_lte_initial_state init_state = {}; + init_state.tx_count = count; + pdcp_hlp.set_pdcp_initial_state(init_state); + + srslte::unique_byte_buffer_t sdu = srslte::allocate_unique_buffer(*pool); + *sdu = *in_sdu; + pdcp->write_sdu(std::move(sdu), true); + srslte::unique_byte_buffer_t out_pdu = srslte::allocate_unique_buffer(*pool); + rlc->get_last_sdu(out_pdu); + + return out_pdu; +} + +// Helper function to generate vector of PDU from a vector of TX_NEXTs for generating expected pdus +std::vector gen_expected_pdus_vector(const srslte::unique_byte_buffer_t& in_sdu, + const std::vector& tx_nexts, + uint8_t pdcp_sn_len, + srslte::pdcp_rb_type_t rb_type, + pdcp_security_cfg sec_cfg, + srslte::byte_buffer_pool* pool, + srslte::log* log) +{ + std::vector pdu_vec; + for (uint32_t tx_next : tx_nexts) { + pdcp_test_event_t event; + event.pkt = gen_expected_pdu(in_sdu, tx_next, pdcp_sn_len, rb_type, sec_cfg, pool, log); + event.ticks = 0; + pdu_vec.push_back(std::move(event)); + } + return pdu_vec; +} + +#endif // SRSLTE_PDCP_NR_TEST_H diff --git a/lib/test/upper/pdcp_lte_test_rx.cc b/lib/test/upper/pdcp_lte_test_rx.cc new file mode 100644 index 000000000..5a322f527 --- /dev/null +++ b/lib/test/upper/pdcp_lte_test_rx.cc @@ -0,0 +1,128 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ +#include "pdcp_lte_test.h" +#include + +/* + * Genric function to test reception of in-sequence packets + */ +int test_rx(std::vector events, + const pdcp_lte_initial_state& init_state, + uint8_t pdcp_sn_len, + srslte::pdcp_rb_type_t rb_type, + uint32_t n_sdus_exp, + const srslte::unique_byte_buffer_t& sdu_exp, + srslte::byte_buffer_pool* pool, + srslte::log* log) + +{ + + srslte::pdcp_config_t cfg_rx = {1, + rb_type, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::SECURITY_DIRECTION_UPLINK, + pdcp_sn_len, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::infinity}; + + pdcp_lte_test_helper pdcp_hlp_rx(cfg_rx, sec_cfg, log); + srslte::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_rx.pdcp; + gw_dummy* gw_rx = &pdcp_hlp_rx.gw; + srslte::timer_handler* timers_rx = &pdcp_hlp_rx.timers; + pdcp_hlp_rx.set_pdcp_initial_state(init_state); + + // Generate test message and encript/decript SDU. + for (pdcp_test_event_t& event : events) { + + // Decript and integrity check the PDU + pdcp_rx->write_pdu(std::move(event.pkt)); + for (uint32_t i = 0; i < event.ticks; ++i) { + timers_rx->step_all(); + } + } + + // Test if the number of RX packets + TESTASSERT(gw_rx->rx_count == n_sdus_exp); + srslte::unique_byte_buffer_t sdu_act = allocate_unique_buffer(*pool); + gw_rx->get_last_pdu(sdu_act); + TESTASSERT(compare_two_packets(sdu_exp, sdu_act) == 0); + return 0; +} + +/* + * RX Test: PDCP Entity with SN LEN = 5 and 12. + * PDCP entity configured with EIA2 and EEA2 + */ +int test_rx_all(srslte::byte_buffer_pool* pool, srslte::log* log) +{ + // Test SDUs + srslte::unique_byte_buffer_t tst_sdu1 = allocate_unique_buffer(*pool); // SDU 1 + tst_sdu1->append_bytes(sdu1, sizeof(sdu1)); + srslte::unique_byte_buffer_t tst_sdu2 = allocate_unique_buffer(*pool); // SDU 2 + tst_sdu2->append_bytes(sdu2, sizeof(sdu2)); + + /* + * RX Test 1: PDCP LTE Entity with SN LEN = 5 + * Test in-sequence reception of 32 packets. + * This tests correct handling of HFN in the case of SN wraparound (SN LEN 5) + */ + { + std::vector test1_counts(2); // Test two packets + std::iota(test1_counts.begin(), test1_counts.end(), 31); // Starting at COUNT 31 + std::vector test1_pdus = gen_expected_pdus_vector( + tst_sdu1, test1_counts, srslte::PDCP_SN_LEN_5, srslte::PDCP_RB_IS_SRB, sec_cfg, pool, log); + pdcp_lte_initial_state test1_init_state = { + .tx_count = 0, .rx_hfn = 0, .next_pdcp_rx_sn = 31, .last_submitted_pdcp_rx_sn = 30}; + TESTASSERT(test_rx(std::move(test1_pdus), + test1_init_state, + srslte::PDCP_SN_LEN_5, + srslte::PDCP_RB_IS_SRB, + 2, + tst_sdu1, + pool, + log) == 0); + } + + return 0; +} + +// Setup all tests +int run_all_tests(srslte::byte_buffer_pool* pool) +{ + // Setup log + srslte::log_filter log("PDCP LTE Test RX"); + log.set_level(srslte::LOG_LEVEL_DEBUG); + log.set_hex_limit(128); + + TESTASSERT(test_rx_all(pool, &log) == 0); + return 0; +} + +int main() +{ + if (run_all_tests(srslte::byte_buffer_pool::get_instance()) != SRSLTE_SUCCESS) { + fprintf(stderr, "pdcp_nr_tests_rx() failed\n"); + return SRSLTE_ERROR; + } + srslte::byte_buffer_pool::cleanup(); + + return SRSLTE_SUCCESS; +}