|
|
|
@ -185,6 +185,10 @@ uint32_t rlc_am_nr_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
*/
|
|
|
|
|
uint32_t rlc_am_nr_tx::build_new_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
{
|
|
|
|
|
if (nof_bytes <= min_hdr_size) {
|
|
|
|
|
RlcInfo("Not enough bytes for payload plus header. nof_bytes=%d", nof_bytes);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
// Read new SDU from TX queue
|
|
|
|
|
unique_byte_buffer_t tx_sdu;
|
|
|
|
|
RlcDebug("Reading from RLC SDU queue. Queue size %d", tx_sdu_queue.size());
|
|
|
|
@ -449,12 +453,12 @@ uint32_t rlc_am_nr_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
|
|
|
|
|
// Sanity check - drop any retx SNs not present in tx_window
|
|
|
|
|
while (not tx_window->has_sn(retx.sn)) {
|
|
|
|
|
RlcWarning("SN=%d not in tx window. Ignoring retx.", retx.sn);
|
|
|
|
|
RlcInfo("SN=%d not in tx window, probably already ACKed. Skip and remove from retx queue", retx.sn);
|
|
|
|
|
retx_queue->pop();
|
|
|
|
|
if (!retx_queue->empty()) {
|
|
|
|
|
retx = retx_queue->front();
|
|
|
|
|
} else {
|
|
|
|
|
RlcWarning("empty retx queue, cannot provide retx PDU");
|
|
|
|
|
RlcInfo("empty retx queue, cannot provide any retx PDU");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -833,9 +837,9 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
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.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,
|
|
|
|
|
status.nacks[nack_idx].nack_sn);
|
|
|
|
|
RlcWarning("Handling NACK ranges is not yet implemented. Ignoring NACK across %d SDU(s) starting from SN=%d",
|
|
|
|
|
status.nacks[nack_idx].nack_range,
|
|
|
|
|
status.nacks[nack_idx].nack_sn);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (tx_mod_base_nr(st.tx_next_ack) <= tx_mod_base_nr(status.nacks[nack_idx].nack_sn) &&
|
|
|
|
@ -1159,11 +1163,6 @@ void rlc_am_nr_tx::reestablish()
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rlc_am_nr_tx::sdu_queue_is_full()
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rlc_am_nr_tx::empty_queue()
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
@ -1234,6 +1233,11 @@ void rlc_am_nr_tx::timer_expired(uint32_t timeout_id)
|
|
|
|
|
retx.current_so = 0;
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
@ -1356,12 +1360,44 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trigger polling if poll bit is set.
|
|
|
|
|
// We do this before discarding duplicate SDUs/SDU segments
|
|
|
|
|
// Because t-PollRetransmit may transmit a PDU that was already
|
|
|
|
|
// received.
|
|
|
|
|
if (header.p) {
|
|
|
|
|
RlcInfo("status packet requested through polling bit");
|
|
|
|
|
do_status = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Section 5.2.3.2.2, discard duplicate PDUs
|
|
|
|
|
if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) {
|
|
|
|
|
RlcInfo("discarding duplicate SN=%d", header.sn);
|
|
|
|
|
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
|
|
|
|
|
if (header.si == rlc_nr_si_field_t::full_sdu) {
|
|
|
|
|
int err = handle_full_data_sdu(header, payload, nof_bytes);
|
|
|
|
@ -1375,12 +1411,6 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check poll bit
|
|
|
|
|
if (header.p) {
|
|
|
|
|
RlcInfo("status packet requested through polling bit");
|
|
|
|
|
do_status = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
debug_state();
|
|
|
|
|
|
|
|
|
|
// 5.2.3.2.3 Actions when an AMD PDU is placed in the reception buffer
|
|
|
|
@ -1632,11 +1662,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_end = segm->header.so - 1; // set to last missing byte
|
|
|
|
|
status->push_nack(nack);
|
|
|
|
|
RlcDebug("First/middle segment missing. NACK_SN=%d. SO_start=%d, SO_end=%d",
|
|
|
|
|
nack.nack_sn,
|
|
|
|
|
nack.so_start,
|
|
|
|
|
nack.so_end);
|
|
|
|
|
srsran_assert(nack.so_start <= nack.so_end, "Error: SO_start > SO_end. NACK_SN=%d", nack.nack_sn);
|
|
|
|
|
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",
|
|
|
|
|
nack.nack_sn,
|
|
|
|
|
nack.so_start,
|
|
|
|
|
nack.so_end);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (segm->header.si == rlc_nr_si_field_t::last_segment) {
|
|
|
|
|
last_segment_rx = true;
|
|
|
|
|