lib,rlc_am_nr: fix pack/unpack of NACKs in status PDUs

master
Robert Falkenberg 3 years ago
parent aabd22f493
commit dd7bd351b3

@ -82,17 +82,16 @@ struct rlc_amd_tx_sdu_nr_t {
struct rlc_am_nr_status_pdu_t {
rlc_am_nr_control_pdu_type_t cpt;
uint32_t ack_sn; ///< SN of the next not received RLC Data PDU
uint16_t N_nack; ///< number of NACKs
std::vector<rlc_status_nack_t> nacks;
rlc_am_nr_status_pdu_t() :
cpt(rlc_am_nr_control_pdu_type_t::status_pdu), ack_sn(INVALID_RLC_SN), N_nack(0), nacks(RLC_AM_NR_TYP_NACKS)
{}
rlc_am_nr_status_pdu_t() : cpt(rlc_am_nr_control_pdu_type_t::status_pdu), ack_sn(INVALID_RLC_SN), nacks(0)
{
nacks.reserve(RLC_AM_NR_TYP_NACKS);
}
void reset()
{
cpt = rlc_am_nr_control_pdu_type_t::status_pdu;
ack_sn = INVALID_RLC_SN;
N_nack = 0;
nacks.clear();
}
};
@ -147,10 +146,10 @@ void log_rlc_am_nr_status_pdu_to_string(srslog::log_channel& log_ch,
return;
}
fmt::memory_buffer buffer;
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->N_nack);
if (status->N_nack > 0) {
fmt::format_to(buffer, "ACK_SN = {}, N_nack = {}", status->ack_sn, status->nacks.size());
if (status->nacks.size() > 0) {
fmt::format_to(buffer, ", NACK_SN = ");
for (uint32_t i = 0; i < status->N_nack; ++i) {
for (uint32_t i = 0; i < status->nacks.size(); ++i) {
if (status->nacks[i].has_so) {
fmt::format_to(
buffer, "[{} {}:{}]", status->nacks[i].nack_sn, status->nacks[i].so_start, status->nacks[i].so_end);

@ -719,7 +719,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
* retransmission.
*/
// Process ACKs
uint32_t stop_sn = status.N_nack == 0
uint32_t stop_sn = status.nacks.size() == 0
? status.ack_sn
: status.nacks[0].nack_sn; // Stop processing ACKs at the first NACK, if it exists.
if (stop_sn > st.tx_next) {
@ -745,7 +745,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
// Process N_nacks
std::set<uint32_t> retx_sn_set; // Set of PDU SNs added for retransmission (no duplicates)
for (uint32_t nack_idx = 0; nack_idx < status.N_nack; nack_idx++) {
for (uint32_t nack_idx = 0; nack_idx < status.nacks.size(); nack_idx++) {
if (status.nacks[nack_idx].has_nack_range) {
RlcError("Handling NACK ranges is not yet implemented. Ignoring NACK across %d SDU(s) starting from SN=%d",
status.nacks[nack_idx].nack_range,
@ -1322,7 +1322,7 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
return 0;
}
status->N_nack = 0;
status->nacks.clear();
status->ack_sn = st.rx_next; // Start with the lower end of the window
byte_buffer_t tmp_buf;
@ -1337,12 +1337,12 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
// only update ACK_SN if this SN has been fully received
status->ack_sn = i;
} else {
status->nacks[status->N_nack] = {};
if (not rx_window->has_sn(i)) {
// No segment received, NACK the whole SDU
status->nacks[status->N_nack].nack_sn = i;
status->nacks[status->N_nack].has_so = false;
status->N_nack++;
rlc_status_nack_t nack;
nack.nack_sn = i;
nack.has_so = false;
status->nacks.push_back(nack);
} else if (not(*rx_window)[i].fully_received) {
// Some segments were received, but not all.
// NACK non consecutive missing bytes
@ -1351,11 +1351,12 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
for (auto segm = (*rx_window)[i].segments.begin(); segm != (*rx_window)[i].segments.end(); segm++) {
if (segm->header.so != last_so) {
// Some bytes were not received
status->nacks[status->N_nack].nack_sn = i;
status->nacks[status->N_nack].has_so = true;
status->nacks[status->N_nack].so_start = last_so;
status->nacks[status->N_nack].so_end = segm->header.so - 1; // set to last missing byte
status->N_nack++;
rlc_status_nack_t nack;
nack.nack_sn = i;
nack.has_so = true;
nack.so_start = last_so;
nack.so_end = segm->header.so - 1; // set to last missing byte
status->nacks.push_back(nack);
}
if (segm->header.si == rlc_nr_si_field_t::last_segment) {
last_segment_rx = true;
@ -1363,11 +1364,12 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
last_so = segm->header.so + segm->buf->N_bytes;
}
if (not last_segment_rx) {
status->nacks[status->N_nack].nack_sn = i;
status->nacks[status->N_nack].has_so = true;
status->nacks[status->N_nack].so_start = last_so;
status->nacks[status->N_nack].so_end = so_end_of_sdu;
status->N_nack++;
rlc_status_nack_t nack;
nack.nack_sn = i;
nack.has_so = true;
nack.so_start = last_so;
nack.so_end = so_end_of_sdu;
status->nacks.push_back(nack);
}
}
}

@ -168,6 +168,7 @@ 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);
status->reset();
// fixed part
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
@ -196,9 +197,6 @@ rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_by
// 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 = {};
@ -215,26 +213,25 @@ rlc_am_nr_read_status_pdu_12bit_sn(const uint8_t* payload, const uint32_t nof_by
return 0;
}
nack.nack_sn |= (*ptr & 0xF0) >> 4;
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;
nack.has_so = true;
nack.so_start = (*ptr) << 8;
ptr++;
status->nacks[status->N_nack].so_start |= (*ptr);
nack.so_start |= (*ptr);
ptr++;
status->nacks[status->N_nack].so_end = (*ptr) << 8;
nack.so_end = (*ptr) << 8;
ptr++;
status->nacks[status->N_nack].so_end |= (*ptr);
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);
nack.has_nack_range = true;
nack.nack_range = (*ptr);
ptr++;
}
status->N_nack++;
status->nacks.push_back(nack);
if (uint32_t(ptr - payload) > nof_bytes) {
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
return 0;
@ -248,6 +245,7 @@ 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);
status->reset();
// fixed part
status->cpt = (rlc_am_nr_control_pdu_type_t)((*ptr >> 4) & 0x07); // 3 bits CPT
@ -278,9 +276,6 @@ rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_by
// 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 = {};
@ -300,26 +295,25 @@ rlc_am_nr_read_status_pdu_18bit_sn(const uint8_t* payload, const uint32_t nof_by
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;
nack.has_so = true;
nack.so_start = (*ptr) << 8;
ptr++;
status->nacks[status->N_nack].so_start |= (*ptr);
nack.so_start |= (*ptr);
ptr++;
status->nacks[status->N_nack].so_end = (*ptr) << 8;
nack.so_end = (*ptr) << 8;
ptr++;
status->nacks[status->N_nack].so_end |= (*ptr);
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);
nack.has_nack_range = true;
nack.nack_range = (*ptr);
ptr++;
}
status->N_nack++;
status->nacks.push_back(nack);
if (uint32_t(ptr - payload) > nof_bytes) {
fprintf(stderr, "Malformed PDU, trying to read more bytes than it is available\n");
return 0;
@ -360,15 +354,15 @@ int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status
ptr++;
// write E1 flag in octet 3
if (status_pdu.N_nack > 0) {
if (status_pdu.nacks.size() > 0) {
*ptr = 0x80;
} else {
*ptr = 0x00;
}
ptr++;
if (status_pdu.N_nack > 0) {
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
if (status_pdu.nacks.size() > 0) {
for (uint32_t i = 0; i < status_pdu.nacks.size(); i++) {
// write first 8 bit of NACK_SN
*ptr = (status_pdu.nacks[i].nack_sn >> 4) & 0xff;
ptr++;
@ -376,7 +370,7 @@ int32_t rlc_am_nr_write_status_pdu_12bit_sn(const rlc_am_nr_status_pdu_t& status
// 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)) {
if (i < (uint32_t)(status_pdu.nacks.size() - 1)) {
*ptr |= 0x08;
}
@ -427,20 +421,20 @@ int32_t rlc_am_nr_write_status_pdu_18bit_sn(const rlc_am_nr_status_pdu_t& status
*ptr = (status_pdu.ack_sn << 2) & 0xFC; // lower 6 bits of SN
// set E1 flag if necessary
if (status_pdu.N_nack > 0) {
if (status_pdu.nacks.size() > 0) {
*ptr |= 0x02;
}
ptr++;
if (status_pdu.N_nack > 0) {
for (uint32_t i = 0; i < status_pdu.N_nack; i++) {
if (status_pdu.nacks.size() > 0) {
for (uint32_t i = 0; i < status_pdu.nacks.size(); 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 (i < (uint32_t)(status_pdu.N_nack - 1)) {
if (i < (uint32_t)(status_pdu.nacks.size() - 1)) {
*ptr |= 0x20; // Set E1
}
if (status_pdu.nacks[i].has_so) {

@ -236,7 +236,7 @@ int rlc_am_nr_control_pdu_12bit_sn_test1()
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 == 0);
TESTASSERT(status_pdu.nacks.size() == 0);
// reset status PDU
pdu.clear();
@ -266,7 +266,7 @@ int rlc_am_nr_control_pdu_12bit_sn_test2()
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.nacks.size() == 1);
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
// reset status PDU
@ -299,7 +299,7 @@ int rlc_am_nr_control_pdu_12bit_sn_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 == 2);
TESTASSERT(status_pdu.nacks.size() == 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);
@ -335,7 +335,7 @@ int rlc_am_nr_control_pdu_12bit_sn_test4()
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 == 2);
TESTASSERT(status_pdu.nacks.size() == 2);
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
TESTASSERT(status_pdu.nacks[0].has_so == true);
TESTASSERT(status_pdu.nacks[0].so_start == 2);
@ -407,7 +407,7 @@ int rlc_am_nr_control_pdu_12bit_sn_test_nack_range()
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 == 2);
TESTASSERT(status_pdu.nacks.size() == 2);
TESTASSERT(status_pdu.nacks[0].nack_sn == 273);
TESTASSERT(status_pdu.nacks[0].has_so == false);
TESTASSERT(status_pdu.nacks[0].has_nack_range == true);
@ -448,7 +448,7 @@ int rlc_am_nr_control_pdu_18bit_sn_test1()
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);
TESTASSERT(status_pdu.nacks.size() == 0);
// reset status PDU
pdu.clear();
@ -479,7 +479,7 @@ int rlc_am_nr_control_pdu_18bit_sn_test2()
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.size() == 1);
TESTASSERT(status_pdu.nacks[0].nack_sn == 222822);
// reset status PDU
@ -530,7 +530,7 @@ int rlc_am_nr_control_pdu_18bit_sn_test3()
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.size() == 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);
@ -582,7 +582,7 @@ int rlc_am_nr_control_pdu_18bit_sn_test4()
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.size() == 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);
@ -674,7 +674,7 @@ int rlc_am_nr_control_pdu_18bit_sn_test_nack_range()
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.size() == 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);

@ -393,7 +393,7 @@ int lost_pdu_test(rlc_am_nr_sn_size_t sn_size)
rlc_am_nr_status_pdu_t status_check = {};
rlc_am_nr_read_status_pdu(&status_buf, sn_size, &status_check);
TESTASSERT_EQ(5, status_check.ack_sn); // 5 is the next expected SN.
TESTASSERT_EQ(1, status_check.N_nack); // We lost one PDU.
TESTASSERT_EQ(1, status_check.nacks.size()); // We lost one PDU.
TESTASSERT_EQ(3, status_check.nacks[0].nack_sn); // Lost PDU SN=3.
// Write status PDU to RLC1
@ -426,7 +426,7 @@ int lost_pdu_test(rlc_am_nr_sn_size_t sn_size)
rlc_am_nr_status_pdu_t status_check = {};
rlc_am_nr_read_status_pdu(&status_buf, sn_size, &status_check);
TESTASSERT_EQ(5, status_check.ack_sn); // 5 is the next expected SN.
TESTASSERT_EQ(0, status_check.N_nack); // All PDUs are acked now
TESTASSERT_EQ(0, status_check.nacks.size()); // All PDUs are acked now
}
{
@ -664,7 +664,7 @@ int segment_retx_test(rlc_am_nr_sn_size_t sn_size)
rlc_am_nr_status_pdu_t status_check = {};
rlc_am_nr_read_status_pdu(&status_buf, sn_size, &status_check);
TESTASSERT_EQ(5, status_check.ack_sn); // 5 is the next expected SN.
TESTASSERT_EQ(1, status_check.N_nack); // We lost one PDU.
TESTASSERT_EQ(1, status_check.nacks.size()); // We lost one PDU.
TESTASSERT_EQ(3, status_check.nacks[0].nack_sn); // Lost PDU SN=3.
// Write status PDU to RLC1
@ -900,7 +900,7 @@ int retx_segment_test(rlc_am_nr_sn_size_t sn_size)
rlc_am_nr_status_pdu_t status_check = {};
rlc_am_nr_read_status_pdu(&status_buf, sn_size, &status_check);
TESTASSERT_EQ(2, status_check.ack_sn); // 5 is the next expected SN.
TESTASSERT_EQ(1, status_check.N_nack); // We lost one PDU.
TESTASSERT_EQ(1, status_check.nacks.size()); // We lost one PDU.
TESTASSERT_EQ(1, status_check.nacks[0].nack_sn); // Lost SDU on SN=1.
TESTASSERT_EQ(true, status_check.nacks[0].has_so); // It's a segment.
TESTASSERT_EQ(0, status_check.nacks[0].so_start); // First byte missing is 0.
@ -941,7 +941,7 @@ int retx_segment_test(rlc_am_nr_sn_size_t sn_size)
rlc_am_nr_status_pdu_t status_check = {};
rlc_am_nr_read_status_pdu(&status_buf, sn_size, &status_check);
TESTASSERT_EQ(5, status_check.ack_sn); // 5 is the next expected SN.
TESTASSERT_EQ(3, status_check.N_nack); // We lost one PDU.
TESTASSERT_EQ(3, status_check.nacks.size()); // We lost one PDU.
TESTASSERT_EQ(1, status_check.nacks[0].nack_sn); // Lost SDU on SN=1.
TESTASSERT_EQ(true, status_check.nacks[0].has_so); // Lost SDU on SN=1.
TESTASSERT_EQ(0, status_check.nacks[0].so_start); // Lost SDU on SN=1.
@ -1094,8 +1094,9 @@ int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size)
// Fake status PDU that ack SN=1 and nack SN=0
rlc_am_nr_status_pdu_t fake_status = {};
fake_status.ack_sn = 2; // delivered up to SN=1
fake_status.N_nack = 1; // one SN was lost
fake_status.nacks[0].nack_sn = 0; // it was SN=0 that was lost
rlc_status_nack_t nack; // one SN was lost
nack.nack_sn = 0; // it was SN=0 that was lost
fake_status.nacks.push_back(nack);
// pack into PDU
byte_buffer_t status_pdu;
@ -1174,15 +1175,25 @@ int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size)
// Fake status PDU that ack SN=1 and nack {SN=0 segment 0, SN=0 segment 1}
rlc_am_nr_status_pdu_t status_lost_both_segments = {};
status_lost_both_segments.ack_sn = 2; // delivered up to SN=1
status_lost_both_segments.N_nack = 2; // two segments lost
status_lost_both_segments.nacks[0].nack_sn = 0; // it was SN=0 that was lost
status_lost_both_segments.nacks[0].has_so = true; // this NACKs a segment
status_lost_both_segments.nacks[0].so_start = 0; // segment starts at (and includes) byte 0
status_lost_both_segments.nacks[0].so_end = 12; // segment ends at (and includes) byte 12
status_lost_both_segments.nacks[1].nack_sn = 0; // it was SN=0 that was lost
status_lost_both_segments.nacks[1].has_so = true; // this NACKs a segment
status_lost_both_segments.nacks[1].so_start = 13; // segment starts at (and includes) byte 13
status_lost_both_segments.nacks[1].so_end = 19; // segment ends at (and includes) byte 19
// two segments lost
{
rlc_status_nack_t nack;
nack.nack_sn = 0; // it was SN=0 that was lost
nack.has_so = true; // this NACKs a segment
nack.so_start = 0; // segment starts at (and includes) byte 0
nack.so_end = 12; // segment ends at (and includes) byte 12
status_lost_both_segments.nacks.push_back(nack);
}
{
rlc_status_nack_t nack;
nack.nack_sn = 0; // it was SN=0 that was lost
nack.has_so = true; // this NACKs a segment
nack.so_start = 13; // segment starts at (and includes) byte 13
nack.so_end = 19; // segment ends at (and includes) byte 19
status_lost_both_segments.nacks.push_back(nack);
}
// pack into PDU
byte_buffer_t status_pdu_lost_both_segments;
@ -1191,12 +1202,17 @@ int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size)
// Fake status PDU that ack SN=1 and nack {SN=0 segment 1}
rlc_am_nr_status_pdu_t status_lost_second_segment = {};
status_lost_second_segment.ack_sn = 2; // delivered up to SN=1
status_lost_second_segment.N_nack = 1; // one SN was lost
status_lost_second_segment.nacks[0].nack_sn = 0; // it was SN=0 that was lost
status_lost_second_segment.nacks[0].has_so = true; // this NACKs a segment
status_lost_second_segment.nacks[0].so_start = 13; // segment starts at (and includes) byte 13
status_lost_second_segment.nacks[0].so_end = 19; // segment ends at (and includes) byte 19
status_lost_second_segment.ack_sn = 2; // delivered up to SN=1
// one SN was lost
{
rlc_status_nack_t nack;
nack.nack_sn = 0; // it was SN=0 that was lost
nack.has_so = true; // this NACKs a segment
nack.so_start = 13; // segment starts at (and includes) byte 13
nack.so_end = 19; // segment ends at (and includes) byte 19
status_lost_second_segment.nacks.push_back(nack);
}
// pack into PDU
byte_buffer_t status_pdu_lost_second_segment;
@ -1501,8 +1517,11 @@ int poll_retx()
TESTASSERT(status_pdu != nullptr);
rlc_am_nr_status_pdu_t status = {};
status.ack_sn = 2;
status.N_nack = 1;
status.nacks[0].nack_sn = 1; // SN=1 needs RETX
{
rlc_status_nack_t nack;
nack.nack_sn = 1; // SN=1 needs RETX
status.nacks.push_back(nack);
}
rlc_am_nr_write_status_pdu(status, rlc_cnfg.am_nr.tx_sn_field_length, status_pdu.get());
rlc1.write_pdu(status_pdu->msg, status_pdu->N_bytes);
}
@ -1529,8 +1548,11 @@ int poll_retx()
TESTASSERT(status_pdu != nullptr);
rlc_am_nr_status_pdu_t status = {};
status.ack_sn = 4;
status.N_nack = 1;
status.nacks[0].nack_sn = 1; // SN=1 needs RETX
{
rlc_status_nack_t nack;
nack.nack_sn = 1; // SN=1 needs RETX
status.nacks.push_back(nack);
}
rlc_am_nr_write_status_pdu(status, rlc_cnfg.am_nr.tx_sn_field_length, status_pdu.get());
rlc1.write_pdu(status_pdu->msg, status_pdu->N_bytes);
}

Loading…
Cancel
Save