rlc, nr: complete packing of status PDUs with 18bit SNs

master
Robert Falkenberg 3 years ago
parent f7515e98cf
commit 60c3d79f47

@ -113,10 +113,16 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status);
uint32_t
rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status);
uint32_t
rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status);
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu);
int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu);
int32_t rlc_am_nr_write_status_pdu_18bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu);
/**
* Logs Status PDU into provided log channel, using fmt_str as format string

@ -141,6 +141,11 @@ uint32_t rlc_am_nr_write_data_pdu_header(const rlc_am_nr_pdu_header_t& header, b
return len;
}
/****************************************************************************
* Status PDU pack/unpack helper functions
* Ref: 3GPP TS 38.322 v16.2.0 Section 6.2.2.5
***************************************************************************/
uint32_t
rlc_am_nr_read_status_pdu(const byte_buffer_t* pdu, const rlc_am_nr_sn_size_t sn_size, rlc_am_nr_status_pdu_t* status)
{
@ -151,6 +156,16 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
const uint32_t nof_bytes,
const rlc_am_nr_sn_size_t sn_size,
rlc_am_nr_status_pdu_t* status)
{
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
return rlc_am_nr_read_status_pdu_12bit_sn(payload, nof_bytes, status);
} else { // 18bit SN
return rlc_am_nr_read_status_pdu_18bit_sn(payload, nof_bytes, status);
}
}
uint32_t
rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
@ -163,68 +178,151 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
return 0;
}
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
status->ack_sn = (*ptr & 0x0F) << 8; // first 4 bits SN
ptr++;
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
ptr++;
// read E1 flag
uint8_t e1 = *ptr & 0x80;
// sanity check for reserved bits
if ((*ptr & 0x7f) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
status->ack_sn |= (*ptr & 0xFF); // last 8 bits SN
// all good, continue with next byte depending on E1
ptr++;
// reset number of acks
status->N_nack = 0;
while (e1 != 0) {
// E1 flag set, read a NACK_SN
rlc_status_nack_t nack = {};
nack.nack_sn = (*ptr & 0xff) << 4;
ptr++;
// read E1 flag
uint8_t e1 = *ptr & 0x80;
e1 = *ptr & 0x08; // 1 = further NACKs follow
uint8_t e2 = *ptr & 0x04; // 1 = set of {so_start, so_end} follows
uint8_t e3 = *ptr & 0x02; // 1 = NACK range follows (i.e. NACK across multiple SNs)
// sanity check for reserved bits
if ((*ptr & 0x7f) != 0) {
if ((*ptr & 0x01) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
nack.nack_sn |= (*ptr & 0xF0) >> 4;
status->nacks[status->N_nack] = nack;
// all good, continue with next byte depending on E1
ptr++;
if (e2 != 0) {
status->nacks[status->N_nack].has_so = true;
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++;
}
if (e3 != 0) {
status->nacks[status->N_nack].has_nack_range = true;
status->nacks[status->N_nack].nack_range = (*ptr);
ptr++;
}
status->N_nack++;
if (uint32_t(ptr - payload) > nof_bytes) {
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
return 0;
}
}
// reset number of acks
status->N_nack = 0;
return SRSRAN_SUCCESS;
}
while (e1 != 0) {
// E1 flag set, read a NACK_SN
rlc_status_nack_t nack = {};
nack.nack_sn = (*ptr & 0xff) << 4;
ptr++;
uint32_t
rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_bytes, rlc_am_nr_status_pdu_t* status)
{
uint8_t* ptr = const_cast<uint8_t*>(payload);
e1 = *ptr & 0x08; // 1 = further NACKs follow
uint8_t e2 = *ptr & 0x04; // 1 = set of {so_start, so_end} follows
uint8_t e3 = *ptr & 0x02; // 1 = NACK range follows (i.e. NACK across multiple SNs)
// fixed part
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
// sanity check for reserved bits
if ((*ptr & 0x01) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
nack.nack_sn |= (*ptr & 0xF0) >> 4;
status->nacks[status->N_nack] = nack;
// sanity check
if (status->cpt != rlc_am_nr_control_pdu_type_t::status_pdu) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
status->ack_sn = (*ptr & 0x0F) << 14; // upper 4 bits of SN
ptr++;
status->ack_sn |= (*ptr & 0xFF) << 6; // center 8 bits of SN
ptr++;
status->ack_sn |= (*ptr & 0xFC) >> 2; // lower 6 bits of SN
// read E1 flag
uint8_t e1 = *ptr & 0x02;
// sanity check for reserved bits
if ((*ptr & 0x01) != 0) {
fprintf(stderr, "Malformed PDU, reserved bit is set.\n");
return 0;
}
// all good, continue with next byte depending on E1
ptr++;
// reset number of acks
status->N_nack = 0;
while (e1 != 0) {
// E1 flag set, read a NACK_SN
rlc_status_nack_t nack = {};
nack.nack_sn = (*ptr & 0xFF) << 10; // upper 8 bits of SN
ptr++;
nack.nack_sn |= (*ptr & 0xFF) << 2; // center 8 bits of SN
ptr++;
nack.nack_sn |= (*ptr & 0xC0) >> 6; // lower 2 bits of SN
e1 = *ptr & 0x20; // 1 = further NACKs follow
uint8_t e2 = *ptr & 0x10; // 1 = set of {so_start, so_end} follows
uint8_t e3 = *ptr & 0x08; // 1 = NACK range follows (i.e. NACK across multiple SNs)
// sanity check for reserved bits
if ((*ptr & 0x07) != 0) {
fprintf(stderr, "Malformed PDU, reserved bits are set.\n");
return 0;
}
status->nacks[status->N_nack] = nack;
ptr++;
if (e2 != 0) {
status->nacks[status->N_nack].has_so = true;
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++;
}
if (e3 != 0) {
status->nacks[status->N_nack].has_nack_range = true;
status->nacks[status->N_nack].nack_range = (*ptr);
ptr++;
if (e2 != 0) {
status->nacks[status->N_nack].has_so = true;
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++;
}
if (e3 != 0) {
status->nacks[status->N_nack].has_nack_range = true;
status->nacks[status->N_nack].nack_range = (*ptr);
ptr++;
}
status->N_nack++;
if (uint32_t(ptr - payload) > nof_bytes) {
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
return 0;
}
}
status->N_nack++;
if (uint32_t(ptr - payload) > nof_bytes) {
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
return 0;
}
}
@ -240,75 +338,134 @@ uint32_t rlc_am_nr_read_status_pdu(const uint8_t* payload,
int32_t rlc_am_nr_write_status_pdu(const rlc_am_nr_status_pdu_t& status_pdu,
const rlc_am_nr_sn_size_t sn_size,
byte_buffer_t* pdu)
{
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
return rlc_am_nr_write_status_pdu_12bit_sn(status_pdu, pdu);
} else { // 18bit SN
return rlc_am_nr_write_status_pdu_18bit_sn(status_pdu, pdu);
}
}
int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
if (sn_size == rlc_am_nr_sn_size_t::size12bits) {
// write first 4 bit of ACK_SN
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
ptr++;
// write first 4 bit of ACK_SN
*ptr |= (status_pdu.ack_sn >> 8) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn & 0xff; // remaining 8 bit of SN
ptr++;
// write E1 flag in octet 3
if (status_pdu.N_nack > 0) {
*ptr = 0x80;
} else {
*ptr = 0x00;
}
ptr++;
// write E1 flag in octet 3
if (status_pdu.N_nack > 0) {
*ptr = 0x80;
} else {
*ptr = 0x00;
}
ptr++;
if (status_pdu.N_nack > 0) {
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
// 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[i].nack_sn & 0x0f) << 4;
// Set E1 if necessary
if (i < (uint32_t)(status_pdu.N_nack - 1)) {
*ptr |= 0x08;
}
if (status_pdu.N_nack > 0) {
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
// write first 8 bit of NACK_SN
*ptr = (status_pdu.nacks[i].nack_sn >> 4) & 0xff;
if (status_pdu.nacks[i].has_so) {
// Set E2
*ptr |= 0x04;
}
if (status_pdu.nacks[i].has_nack_range) {
// Set E3
*ptr |= 0x02;
}
ptr++;
if (status_pdu.nacks[i].has_so) {
(*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++;
}
if (status_pdu.nacks[i].has_nack_range) {
(*ptr) = status_pdu.nacks[i].nack_range;
ptr++;
}
}
}
pdu->N_bytes = ptr - pdu->msg;
return SRSRAN_SUCCESS;
}
int32_t rlc_am_nr_write_status_pdu_18bit_sn(const rlc_am_nr_status_pdu_t& status_pdu, byte_buffer_t* pdu)
{
uint8_t* ptr = pdu->msg;
// fixed header part
*ptr = 0; ///< 1 bit D/C field and 3bit CPT are all zero
*ptr |= (status_pdu.ack_sn >> 14) & 0x0F; // upper 4 bits of SN
ptr++;
*ptr = (status_pdu.ack_sn >> 6) & 0xFF; // center 8 bits of SN
ptr++;
*ptr = (status_pdu.ack_sn << 2) & 0xFC; // lower 6 bits of SN
// 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 E1 flag if necessary
if (status_pdu.N_nack > 0) {
*ptr |= 0x02;
}
ptr++;
if (status_pdu.nacks[i].has_so) {
// Set E2
*ptr |= 0x04;
}
if (status_pdu.N_nack > 0) {
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
*ptr = (status_pdu.nacks[i].nack_sn >> 10) & 0xFF; // upper 8 bits of SN
ptr++;
*ptr = (status_pdu.nacks[i].nack_sn >> 2) & 0xFF; // center 8 bits of SN
ptr++;
*ptr = (status_pdu.nacks[i].nack_sn << 6) & 0xC0; // lower 2 bits of SN
if (status_pdu.nacks[i].has_nack_range) {
// Set E3
*ptr |= 0x02;
}
if (i < (uint32_t)(status_pdu.N_nack - 1)) {
*ptr |= 0x20; // Set E1
}
if (status_pdu.nacks[i].has_so) {
*ptr |= 0x10; // Set E2
}
if (status_pdu.nacks[i].has_nack_range) {
*ptr |= 0x08; // Set E3
}
ptr++;
if (status_pdu.nacks[i].has_so) {
(*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++;
}
if (status_pdu.nacks[i].has_nack_range) {
(*ptr) = status_pdu.nacks[i].nack_range;
ptr++;
if (status_pdu.nacks[i].has_so) {
(*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++;
}
if (status_pdu.nacks[i].has_nack_range) {
(*ptr) = status_pdu.nacks[i].nack_range;
ptr++;
}
}
}
} else {
// 18bit SN
*ptr |= (status_pdu.ack_sn >> 14) & 0x0f; // 4 bit ACK_SN
ptr++;
*ptr = status_pdu.ack_sn >> 8; // bit 3 - 10 of SN
ptr++;
*ptr = (status_pdu.ack_sn & 0xff); // remaining 6 bit of SN
ptr++;
}
pdu->N_bytes = ptr - pdu->msg;

@ -221,11 +221,11 @@ int rlc_am_nr_pdu_test6()
return SRSRAN_SUCCESS;
}
///< Control PDU tests
///< Control PDU tests (12bit SN)
// 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()
int rlc_am_nr_control_pdu_12bit_sn_test1()
{
test_delimit_logger delimiter("Control PDU test 1");
test_delimit_logger delimiter("Control PDU (12bit SN) test 1");
const int len = 3;
std::array<uint8_t, len> tv = {0x08, 0x11, 0x00};
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
@ -253,9 +253,9 @@ 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()
int rlc_am_nr_control_pdu_12bit_sn_test2()
{
test_delimit_logger delimiter("Control PDU test 2");
test_delimit_logger delimiter("Control PDU (12bit SN) test 2");
const int len = 5;
std::array<uint8_t, len> tv = {0x08, 0x11, 0x80, 0x11, 0x10};
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
@ -274,7 +274,7 @@ int rlc_am_nr_control_pdu_test2()
// 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);
@ -285,9 +285,9 @@ int rlc_am_nr_control_pdu_test2()
// 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()
int rlc_am_nr_control_pdu_12bit_sn_test3()
{
test_delimit_logger delimiter("Control PDU test 3");
test_delimit_logger delimiter("Control PDU (12bit SN) test 3");
const int len = 15;
std::array<uint8_t, len> tv = {
0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x34, 0x00, 0x05, 0xFF, 0xFF};
@ -322,9 +322,9 @@ int rlc_am_nr_control_pdu_test3()
// Status PDU for 12bit SN with ACK_SN=2065, NACK_SN=273, SO_START=2, SO_END=5, NACK_SN=275
// E1 and E2 bit set on first NACK, neither E1 or E2 on the second.
int rlc_am_nr_control_pdu_test4()
int rlc_am_nr_control_pdu_12bit_sn_test4()
{
test_delimit_logger delimiter("Control PDU test 4");
test_delimit_logger delimiter("Control PDU (12bit SN) test 4");
const int len = 11;
std::array<uint8_t, len> tv = {0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x30};
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
@ -359,9 +359,9 @@ int rlc_am_nr_control_pdu_test4()
// Malformed Status PDU, with E1 still set at the end of the PDU
// 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_test5()
int rlc_am_nr_control_pdu_12bit_sn_test5()
{
test_delimit_logger delimiter("Control PDU test 5");
test_delimit_logger delimiter("Control PDU (12bit SN) test 5");
const int len = 15;
std::array<uint8_t, len> tv = {
0x08, 0x11, 0x80, 0x11, 0x1c, 0x00, 0x02, 0x00, 0x05, 0x11, 0x3c, 0x00, 0x05, 0xFF, 0xFF};
@ -382,23 +382,23 @@ int rlc_am_nr_control_pdu_test5()
// starting at NACK_SN=276, SO_START=2,
// ending at NACK_SN=279, SO_END=5
// E1 and E3 bit set on first NACK, E2 and E3 bit set on the second.
int rlc_am_nr_control_pdu_test_nack_range()
int rlc_am_nr_control_pdu_12bit_sn_test_nack_range()
{
test_delimit_logger delimiter("Control PDU test NACK range");
test_delimit_logger delimiter("Control PDU (12bit SN) test NACK range");
const int len = 13;
std::array<uint8_t, len> tv = {0x08, // D/C | CPT | ACK_SN_upper
0x11, // ACK_SN_lower
0x80, // E1 | R
0x11, // NACK_SN_upper
0x1a, // NACK_SN_lower | E1 | E2 | E3 | R
0x03, // NACK_range
0x11, // NACK_SN_upper
0x46, // NACK_SN_lower | E1 | E2 | E3 | R
0x00, // SO_START_upper
0x02, // SO_START_lower
0x00, // SO_END_upper
0x05, // SO_END_lower
0x04}; // NACK_range
std::array<uint8_t, len> tv = {0x08, // D/C | 3CPT | 4ACK_SN_upper
0x11, // 8ACK_SN_lower
0x80, // E1 | 7R
0x11, // 8NACK_SN_upper
0x1a, // 4NACK_SN_lower | E1 | E2 | E3 | R
0x03, // 8NACK_range
0x11, // 8NACK_SN_upper
0x46, // 4NACK_SN_lower | E1 | E2 | E3 | R
0x00, // 8SO_START_upper
0x02, // 8SO_START_lower
0x00, // 8SO_END_upper
0x05, // 8SO_END_lower
0x04}; // 8NACK_range
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
@ -433,6 +433,273 @@ int rlc_am_nr_control_pdu_test_nack_range()
return SRSRAN_SUCCESS;
}
///< Control PDU tests (18bit SN)
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 and no further NACK_SN (E1 bit not set)
int rlc_am_nr_control_pdu_18bit_sn_test1()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test 1");
const int len = 3;
std::array<uint8_t, len> tv = {0x0E, 0x66, 0x64};
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
TESTASSERT(status_pdu.ack_sn == 235929);
TESTASSERT(status_pdu.N_nack == 0);
// reset status PDU
pdu.clear();
// pack again
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
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;
}
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set)
// and NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110
int rlc_am_nr_control_pdu_18bit_sn_test2()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test 2");
const int len = 6;
std::array<uint8_t, len> tv = {0x0E, 0x66, 0x66, 0xD9, 0x99, 0x80};
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
TESTASSERT(status_pdu.ack_sn == 235929);
TESTASSERT(status_pdu.N_nack == 1);
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
// reset status PDU
pdu.clear();
// pack again
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
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;
}
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
// SO_START=2, SO_END=5,
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 (E2 bit set),
// SO_START=5, SO_END=0xFFFF
int rlc_am_nr_control_pdu_18bit_sn_test3()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test 3");
const int len = 17;
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
0b01100110, // 8ACK_SN_center
0b01100110, // 6ACK_SN_lower | E1 | R
0b11011001, // 8NACK_SN_upper
0b10011001, // 8NACK_SN_center
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x02, // 8SO_START_lower
0x00, // 8SO_END_upper
0x05, // 8SO_END_lower
0b11011001, // 8NACK_SN_upper
0b10111111, // 8NACK_SN_center
0b11010000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x05, // 8SO_START_lower
0xFF, // 8SO_END_upper
0xFF}; // 8SO_END_lower
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
TESTASSERT(status_pdu.ack_sn == 235929);
TESTASSERT(status_pdu.N_nack == 2);
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
TESTASSERT(status_pdu.nacks[0].has_so == true);
TESTASSERT(status_pdu.nacks[0].so_start == 2);
TESTASSERT(status_pdu.nacks[0].so_end == 5);
TESTASSERT(status_pdu.nacks[1].nack_sn == 222975);
TESTASSERT(status_pdu.nacks[1].has_so == true);
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::size18bits, &pdu) == SRSRAN_SUCCESS);
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;
}
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
// SO_START=2, SO_END=5,
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 (E1 and E2 bit not set),
int rlc_am_nr_control_pdu_18bit_sn_test4()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test 4");
const int len = 13;
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
0b01100110, // 8ACK_SN_center
0b01100110, // 6ACK_SN_lower | E1 | R
0b11011001, // 8NACK_SN_upper
0b10011001, // 8NACK_SN_center
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x02, // 8SO_START_lower
0x00, // 8SO_END_upper
0x05, // 8SO_END_lower
0b11011001, // 8NACK_SN_upper
0b10111111, // 8NACK_SN_center
0b11000000}; // 2NACK_SN_lower | E1 | E2 | E3 | 3R
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
TESTASSERT(status_pdu.ack_sn == 235929);
TESTASSERT(status_pdu.N_nack == 2);
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
TESTASSERT(status_pdu.nacks[0].has_so == true);
TESTASSERT(status_pdu.nacks[0].so_start == 2);
TESTASSERT(status_pdu.nacks[0].so_end == 5);
TESTASSERT(status_pdu.nacks[1].nack_sn == 222975);
TESTASSERT(status_pdu.nacks[1].has_so == false);
// reset status PDU
pdu.clear();
// pack again
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
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;
}
// Malformed Status PDU, similar to test3 but with E1 still set at the end of the PDU
// Status PDU for 18bit SN with ACK_SN=235929=0x39999=0b11 1001 1001 1001 1001 (E1 bit set),
// NACK_SN=222822=0x36666=0b11 0110 0110 0110 0110 (E1 and E2 bit set),
// SO_START=2, SO_END=5,
// NACK_SN=222975=0x366ff=0b11 0110 0110 1111 1111 ([!E1!] and E2 bit set),
// SO_START=5, SO_END=0xFFFF
int rlc_am_nr_control_pdu_18bit_sn_test5()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test 5");
const int len = 17;
std::array<uint8_t, len> tv = {0b00001110, // D/C | 3CPT | 4ACK_SN_upper
0b01100110, // 8ACK_SN_center
0b01100110, // 6ACK_SN_lower | E1 | R
0b11011001, // 8NACK_SN_upper
0b10011001, // 8NACK_SN_center
0b10110000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x02, // 8SO_START_lower
0x00, // 8SO_END_upper
0x05, // 8SO_END_lower
0b11011001, // 8NACK_SN_upper
0b10111111, // 8NACK_SN_center
0b11110000, // 2NACK_SN_lower | [!E1!] | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x05, // 8SO_START_lower
0xFF, // 8SO_END_upper
0xFF}; // 8SO_END_lower
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == 0);
return SRSRAN_SUCCESS;
}
// Status PDU for 18bit SN with ACK_SN=200977=0x31111=0b11 0001 0001 0001 0001,
// NACK range0: 3 full SDUs, NACK_SN=69905=0x11111=0b01 0001 0001 0001 0001
// NACK range1: missing segment sequence across 4 SDUs
// starting at NACK_SN=69913=0x11119=0b01 0001 0001 0001 1001, SO_START=2,
// ending at NACK_SN=69916, SO_END=5
// E1 and E3 bit set on first NACK, E2 and E3 bit set on the second.
int rlc_am_nr_control_pdu_18bit_sn_test_nack_range()
{
test_delimit_logger delimiter("Control PDU (18bit SN) test NACK range");
const int len = 15;
std::array<uint8_t, len> tv = {0b00001100, // D/C | 3CPT | 4ACK_SN_upper
0b01000100, // 8ACK_SN_center
0b01000110, // 6ACK_SN_lower | E1 | R
0b01000100, // 8NACK_SN_upper
0b01000100, // 8NACK_SN_center
0b01101000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x03, // 8NACK_range
0b01000100, // 8NACK_SN_upper
0b01000110, // 8NACK_SN_center
0b01011000, // 2NACK_SN_lower | E1 | E2 | E3 | 3R
0x00, // 8SO_START_upper
0x02, // 8SO_START_lower
0x00, // 8SO_END_upper
0x05, // 8SO_END_lower
0x04}; // 8NACK_range
srsran::byte_buffer_t pdu = make_pdu_and_log(tv);
TESTASSERT(rlc_am_is_control_pdu(pdu.msg) == true);
// unpack PDU
rlc_am_nr_status_pdu_t status_pdu = {};
TESTASSERT(rlc_am_nr_read_status_pdu(&pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &status_pdu) == SRSRAN_SUCCESS);
TESTASSERT(status_pdu.ack_sn == 200977);
TESTASSERT(status_pdu.N_nack == 2);
TESTASSERT(status_pdu.nacks[0].nack_sn == 69905);
TESTASSERT(status_pdu.nacks[0].has_so == false);
TESTASSERT(status_pdu.nacks[0].has_nack_range == true);
TESTASSERT(status_pdu.nacks[0].nack_range == 3);
TESTASSERT(status_pdu.nacks[1].nack_sn == 69913);
TESTASSERT(status_pdu.nacks[1].has_so == true);
TESTASSERT(status_pdu.nacks[1].so_start == 2);
TESTASSERT(status_pdu.nacks[1].so_end == 5);
TESTASSERT(status_pdu.nacks[1].has_nack_range == true);
TESTASSERT(status_pdu.nacks[1].nack_range == 4);
// reset status PDU
pdu.clear();
// pack again
TESTASSERT(rlc_am_nr_write_status_pdu(status_pdu, srsran::rlc_am_nr_sn_size_t::size18bits, &pdu) == SRSRAN_SUCCESS);
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;
}
int main(int argc, char** argv)
{
static const struct option long_options[] = {{"pcap", no_argument, nullptr, 'p'}, {nullptr, 0, nullptr, 0}};
@ -489,33 +756,63 @@ int main(int argc, char** argv)
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test1()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test1() failed.\n");
if (rlc_am_nr_control_pdu_12bit_sn_test1()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test1() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_12bit_sn_test2()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test2() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_12bit_sn_test3()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test3() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_12bit_sn_test4()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test4() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_12bit_sn_test5()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test5() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_12bit_sn_test_nack_range()) {
fprintf(stderr, "rlc_am_nr_control_pdu_12bit_sn_test_nack_range() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_18bit_sn_test1()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test1() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test2()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test2() failed.\n");
if (rlc_am_nr_control_pdu_18bit_sn_test2()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test2() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test3()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test3() failed.\n");
if (rlc_am_nr_control_pdu_18bit_sn_test3()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test3() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test4()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test4() failed.\n");
if (rlc_am_nr_control_pdu_18bit_sn_test4()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test4() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test5()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test5() failed.\n");
if (rlc_am_nr_control_pdu_18bit_sn_test5()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test5() failed.\n");
return SRSRAN_ERROR;
}
if (rlc_am_nr_control_pdu_test_nack_range()) {
fprintf(stderr, "rlc_am_nr_control_pdu_test_nack_range() failed.\n");
if (rlc_am_nr_control_pdu_18bit_sn_test_nack_range()) {
fprintf(stderr, "rlc_am_nr_control_pdu_18bit_sn_test_nack_range() failed.\n");
return SRSRAN_ERROR;
}

Loading…
Cancel
Save