From 876c45c534d531288114b968fe09f6175e62d578 Mon Sep 17 00:00:00 2001 From: Pedro Alvarez Date: Wed, 2 Feb 2022 12:50:29 +0000 Subject: [PATCH] lib,rlc_am_nr: added ability to pack/unpack SO_start and SO_end to rlc am nr NACKs. Added unit test for this feature. --- lib/src/rlc/rlc_am_nr_packing.cc | 49 +++++++++++++++++--- lib/test/rlc/rlc_am_nr_pdu_test.cc | 74 ++++++++++++++++++++---------- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/lib/src/rlc/rlc_am_nr_packing.cc b/lib/src/rlc/rlc_am_nr_packing.cc index 359ebcfff..709310245 100644 --- a/lib/src/rlc/rlc_am_nr_packing.cc +++ b/lib/src/rlc/rlc_am_nr_packing.cc @@ -185,15 +185,30 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload, // reset number of acks status->N_nack = 0; - if (e1) { + while (e1 != 0) { // E1 flag set, read a NACK_SN rlc_status_nack_t nack = {}; nack.nack_sn = (*ptr & 0xff) << 4; ptr++; + + e1 = *ptr & 0x08; + uint8_t e2 = *ptr & 0x04; + // uint8_t len2 = (*ptr & 0xF0) >> 4; nack.nack_sn |= (*ptr & 0xF0) >> 4; status->nacks[status->N_nack] = nack; + ptr++; + if (e2 != 0) { + status->nacks[status->N_nack].so_start = (*ptr) << 8; + ptr++; + status->nacks[status->N_nack].so_start |= (*ptr); + ptr++; + status->nacks[status->N_nack].so_end = (*ptr) << 8; + ptr++; + status->nacks[status->N_nack].so_end |= (*ptr); + ptr++; + } status->N_nack++; } } @@ -228,13 +243,33 @@ int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu, ptr++; if (status_pdu.N_nack > 0) { - // write first 8 bit of NACK_SN - *ptr = (status_pdu.nacks[0].nack_sn >> 4) & 0xff; - ptr++; + for (uint32_t i = 0; i < status_pdu.N_nack; i++) { + if (status_pdu.nacks[i].so_start != 0 || status_pdu.nacks[i].so_end != 0) { + // write first 8 bit of NACK_SN + *ptr = (status_pdu.nacks[i].nack_sn >> 4) & 0xff; + ptr++; - // write remaining 4 bits of NACK_SN - *ptr = (status_pdu.nacks[0].nack_sn & 0x0f) << 4; - ptr++; + // write remaining 4 bits of NACK_SN + *ptr = (status_pdu.nacks[i].nack_sn & 0x0f) << 4; + + // Set E1 if necessary + if (i < (uint32_t)(status_pdu.N_nack - 1)) { + *ptr |= 0x08; + } + // Set E2 + *ptr |= 0x04; + + ptr++; + (*ptr) = status_pdu.nacks[i].so_start >> 8; + ptr++; + (*ptr) = status_pdu.nacks[i].so_start; + ptr++; + (*ptr) = status_pdu.nacks[i].so_end >> 8; + ptr++; + (*ptr) = status_pdu.nacks[i].so_end; + ptr++; + } + } } } else { // 18bit SN diff --git a/lib/test/rlc/rlc_am_nr_pdu_test.cc b/lib/test/rlc/rlc_am_nr_pdu_test.cc index 445722134..dff22f9d4 100644 --- a/lib/test/rlc/rlc_am_nr_pdu_test.cc +++ b/lib/test/rlc/rlc_am_nr_pdu_test.cc @@ -10,39 +10,29 @@ * */ +#include "srsran/common/test_common.h" #include "srsran/config.h" #include "srsran/rlc/rlc.h" #include "srsran/rlc/rlc_am_nr_packing.h" #include +#include #include #include #include -#define TESTASSERT(cond) \ - { \ - if (!(cond)) { \ - std::cout << "[" << __FUNCTION__ << "][Line " << __LINE__ << "]: FAIL at " << (#cond) << std::endl; \ - return -1; \ - } \ - } - -#define PCAP 1 #define PCAP_CRNTI (0x1001) #define PCAP_TTI (666) using namespace srsran; -#if PCAP #include "srsran/common/mac_pcap.h" #include "srsran/mac/mac_rar_pdu_nr.h" #include "srsran/mac/mac_sch_pdu_nr.h" static std::unique_ptr pcap_handle = nullptr; -#endif int write_pdu_to_pcap(const uint32_t lcid, const uint8_t* payload, const uint32_t len) { -#if PCAP if (pcap_handle) { byte_buffer_t tx_buffer; srsran::mac_sch_pdu_nr tx_pdu; @@ -52,7 +42,6 @@ int write_pdu_to_pcap(const uint32_t lcid, const uint8_t* payload, const uint32_ pcap_handle->write_dl_crnti_nr(tx_buffer.msg, tx_buffer.N_bytes, PCAP_CRNTI, true, PCAP_TTI); return SRSRAN_SUCCESS; } -#endif return SRSRAN_ERROR; } @@ -79,6 +68,7 @@ void corrupt_pdu_header(srsran::byte_buffer_t& pdu, const uint32_t header_len, c // RLC AM PDU 12bit with complete SDU int rlc_am_nr_pdu_test1() { + test_delimit_logger delimiter("PDU test 1"); const int header_len = 2, payload_len = 4; std::array tv = {0x80, 0x00, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -102,6 +92,7 @@ int rlc_am_nr_pdu_test1() // RLC AM PDU 12bit first segment of SDU with P flag and SN 511 int rlc_am_nr_pdu_test2() { + test_delimit_logger delimiter("PDU test 2"); const int header_len = 2, payload_len = 4; std::array tv = {0xd1, 0xff, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -130,6 +121,7 @@ int rlc_am_nr_pdu_test2() // RLC AM PDU 12bit last segment of SDU without P flag and SN 0x0404 and SO 0x0404 (1028) int rlc_am_nr_pdu_test3() { + test_delimit_logger delimiter("PDU test 3"); const int header_len = 4, payload_len = 4; std::array tv = {0xa4, 0x04, 0x04, 0x04, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -158,6 +150,7 @@ int rlc_am_nr_pdu_test3() // RLC AM PDU 18bit full SDU with P flag and SN 0x100000001000000010 (131586) int rlc_am_nr_pdu_test4() { + test_delimit_logger delimiter("PDU test 4"); const int header_len = 3, payload_len = 4; std::array tv = {0xc2, 0x02, 0x02, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -186,6 +179,7 @@ int rlc_am_nr_pdu_test4() // RLC AM PDU 18bit middle part of SDU (SO 514) without P flag and SN 131327 int rlc_am_nr_pdu_test5() { + test_delimit_logger delimiter("PDU test 5"); const int header_len = 5, payload_len = 4; std::array tv = {0xb2, 0x00, 0xff, 0x02, 0x02, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -214,6 +208,7 @@ int rlc_am_nr_pdu_test5() // Malformed RLC AM PDU 18bit with reserved bits set int rlc_am_nr_pdu_test6() { + test_delimit_logger delimiter("PDU test 6"); const int header_len = 5, payload_len = 4; std::array tv = {0xb7, 0x00, 0xff, 0x02, 0x02, 0x11, 0x22, 0x33, 0x44}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -230,6 +225,7 @@ int rlc_am_nr_pdu_test6() // Status PDU for 12bit SN with ACK_SN=2065 and no further NACK_SN (E1 bit not set) int rlc_am_nr_control_pdu_test1() { + test_delimit_logger delimiter("Control PDU test 1"); const int len = 3; std::array tv = {0x08, 0x11, 0x00}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -259,6 +255,7 @@ int rlc_am_nr_control_pdu_test1() // Status PDU for 12bit SN with ACK_SN=2065 and NACK_SN=273 (E1 bit set) int rlc_am_nr_control_pdu_test2() { + test_delimit_logger delimiter("Control PDU test 2"); const int len = 5; std::array tv = {0x08, 0x11, 0x80, 0x11, 0x10}; srsran::byte_buffer_t pdu = make_pdu_and_log(tv); @@ -286,13 +283,14 @@ int rlc_am_nr_control_pdu_test2() return SRSRAN_SUCCESS; } -// Status PDU for 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275, SO_START=5, SO_END=0xFF -// E1 bit set) +// Status PDU for 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275, SO_START=5, SO_END=0xFFFF +// E1 and E2 bit set on first NACK, only E2 on second. int rlc_am_nr_control_pdu_test3() { - const int len = 5; - std::array tv = {0x08, 0x11, 0x80, 0x11, 0x10}; - srsran::byte_buffer_t pdu = make_pdu_and_log(tv); + const int len = 15; + std::array tv = { + 0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x34, 0x00, 0x05, 0xFF, 0xFF}; + srsran::byte_buffer_t pdu = make_pdu_and_log(tv); TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true); @@ -300,18 +298,22 @@ int rlc_am_nr_control_pdu_test3() rlc_am_nr_status_pdu_t status_pdu = {}; TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &status_pdu) == SRSRAN_SUCCESS); TESTASSERT(status_pdu.ack_sn == 2065); - TESTASSERT(status_pdu.N_nack == 1); + TESTASSERT(status_pdu.N_nack == 2); TESTASSERT(status_pdu.nacks[0].nack_sn == 273); + TESTASSERT(status_pdu.nacks[0].so_start == 2); + TESTASSERT(status_pdu.nacks[0].so_end == 5); + TESTASSERT(status_pdu.nacks[1].nack_sn == 275); + TESTASSERT(status_pdu.nacks[1].so_start == 5); + TESTASSERT(status_pdu.nacks[1].so_end == 0xFFFF); // reset status PDU pdu.clear(); // pack again TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size12bits, &pdu) == SRSRAN_SUCCESS); - // TESTASSERT(pdu.N_bytes == tv.size()); + TESTASSERT(pdu.N_bytes == tv.size()); write_pdu_to_pcap(4, pdu.msg, pdu.N_bytes); - TESTASSERT(memcmp(pdu.msg, tv.data(), pdu.N_bytes) == 0); return SRSRAN_SUCCESS; @@ -319,10 +321,27 @@ int rlc_am_nr_control_pdu_test3() int main(int argc, char** argv) { -#if PCAP - pcap_handle = std::unique_ptr(new srsran::mac_pcap()); - pcap_handle->open("rlc_am_nr_pdu_test.pcap"); -#endif + static const struct option long_options[] = {{"pcap", no_argument, nullptr, 'p'}, {nullptr, 0, nullptr, 0}}; + + // Parse arguments + while (true) { + int option_index = 0; + int c = getopt_long(argc, argv, "p", long_options, &option_index); + if (c == -1) { + break; + } + + switch (c) { + case 'p': + printf("Setting up PCAP\n"); + pcap_handle = std::unique_ptr(new srsran::mac_pcap()); + pcap_handle->open("rlc_am_nr_pdu_test.pcap"); + break; + default: + fprintf(stderr, "error parsing arguments\n"); + return SRSRAN_ERROR; + } + } srslog::init(); @@ -366,5 +385,10 @@ int main(int argc, char** argv) return SRSRAN_ERROR; } + if (rlc_am_nr_control_pdu_test3()) { + fprintf(stderr, "rlc_am_nr_control_pdu_test3() failed.\n"); + return SRSRAN_ERROR; + } + return SRSRAN_SUCCESS; }