lib,rlc_am_nr: fix assert triggered by receiving duplicate segments

master
Pedro Alvarez 3 years ago
parent de8b7d6c48
commit 68cc16ad68

@ -1224,6 +1224,11 @@ void rlc_am_nr_tx::timer_expired(uint32_t timeout_id)
retx.current_so = 0; retx.current_so = 0;
retx.segment_length = (*tx_window)[st.tx_next_ack].segment_list.begin()->payload_len; retx.segment_length = (*tx_window)[st.tx_next_ack].segment_list.begin()->payload_len;
} }
RlcDebug("Retransmission because of t-PollRetransmit. RETX SN=%d, is_segment=%s, so_start=%d, segment_length=%d",
retx.sn,
retx.is_segment ? "true" : "false",
retx.so_start,
retx.segment_length);
} }
return; return;
} }
@ -1352,6 +1357,29 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
return; return;
} }
// Section 5.2.3.2.2, discard segments with overlapping bytes
if (rx_window->has_sn(header.sn) && header.si != rlc_nr_si_field_t::full_sdu) {
for (const auto& segm : (*rx_window)[header.sn].segments) {
uint32_t segm_last_byte = segm.header.so + segm.buf->N_bytes - 1;
uint32_t pdu_last_byte = header.so + nof_bytes - hdr_len - 1;
if ((header.so >= segm.header.so && header.so <= segm_last_byte) ||
(pdu_last_byte >= segm.header.so && pdu_last_byte <= segm_last_byte)) {
RlcInfo("Got SDU segment with duplicate bytes. Discarding.");
RlcInfo("Discarded SDU segment. SN=%d, SO=%d, last_byte=%d, payload=%d",
header.sn,
header.so,
header.so + (nof_bytes - hdr_len),
(nof_bytes - hdr_len));
RlcInfo("Overlaping with SDU segment with SN=%d, SO=%d, last_byte=%d, payload=%d",
header.sn,
segm.header.so,
segm_last_byte,
segm.buf->N_bytes);
return;
}
}
}
// Write to rx window either full SDU or SDU segment // Write to rx window either full SDU or SDU segment
if (header.si == rlc_nr_si_field_t::full_sdu) { if (header.si == rlc_nr_si_field_t::full_sdu) {
int err = handle_full_data_sdu(header, payload, nof_bytes); int err = handle_full_data_sdu(header, payload, nof_bytes);
@ -1622,11 +1650,30 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m
nack.so_start = last_so; nack.so_start = last_so;
nack.so_end = segm->header.so - 1; // set to last missing byte nack.so_end = segm->header.so - 1; // set to last missing byte
status->push_nack(nack); status->push_nack(nack);
if (nack.so_start > nack.so_end) {
// Print segment list
for (auto segm_it = (*rx_window)[i].segments.begin(); segm_it != (*rx_window)[i].segments.end();
segm_it++) {
RlcError("Segment: segm.header.so=%d, segm.buf.N_bytes=%d", segm_it->header.so, segm_it->buf->N_bytes);
}
RlcError("Error: SO_start=%d > SO_end=%d. NACK_SN=%d. SO_start=%d, SO_end=%d, seg.so=%d",
nack.so_start,
nack.so_end,
nack.nack_sn,
nack.so_start,
nack.so_end,
segm->header.so);
srsran_assert(nack.so_start <= nack.so_end,
"Error: SO_start=%d > SO_end=%d. NACK_SN=%d",
nack.so_start,
nack.so_end,
nack.nack_sn);
} else {
RlcDebug("First/middle segment missing. NACK_SN=%d. SO_start=%d, SO_end=%d", RlcDebug("First/middle segment missing. NACK_SN=%d. SO_start=%d, SO_end=%d",
nack.nack_sn, nack.nack_sn,
nack.so_start, nack.so_start,
nack.so_end); nack.so_end);
srsran_assert(nack.so_start <= nack.so_end, "Error: SO_start > SO_end. NACK_SN=%d", nack.nack_sn); }
} }
if (segm->header.si == rlc_nr_si_field_t::last_segment) { if (segm->header.si == rlc_nr_si_field_t::last_segment) {
last_segment_rx = true; last_segment_rx = true;

@ -302,6 +302,10 @@ void stress_test(stress_test_args_t args)
seed = rd(); seed = rd();
} }
if (args.seed != 0) {
seed = args.seed;
}
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
srsran::rlc rlc1(log1.id().c_str()); srsran::rlc rlc1(log1.id().c_str());

Loading…
Cancel
Save