diff --git a/lib/include/srsran/rlc/rlc_common.h b/lib/include/srsran/rlc/rlc_common.h index 796704823..0703afe03 100644 --- a/lib/include/srsran/rlc/rlc_common.h +++ b/lib/include/srsran/rlc/rlc_common.h @@ -165,6 +165,8 @@ public: // NACK helper (for LTE and NR) struct rlc_status_nack_t { + const static uint16_t so_end_of_sdu = 0xFFFF; + uint32_t nack_sn; // Sequence Number (SN) of first missing SDU bool has_so; // NACKs continuous sequence of bytes [so_start..so_end] uint16_t so_start; // First missing byte in SDU with SN=nack_sn diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index 2a979cf53..44f682968 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -23,7 +23,6 @@ namespace srsran { const static uint32_t max_tx_queue_size = 256; -const static uint32_t so_end_of_sdu = 0xFFFF; /**************************************************************************** * RLC AM NR entity @@ -838,7 +837,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes) // First SN nack.has_so = true; nack.so_start = status.nacks[nack_idx].so_start; - nack.so_end = so_end_of_sdu; + nack.so_end = rlc_status_nack_t::so_end_of_sdu; } else if (range_sn == (status.nacks[nack_idx].nack_sn + status.nacks[nack_idx].nack_range - 1)) { // Last SN nack.has_so = true; @@ -1743,7 +1742,7 @@ uint32_t rlc_am_nr_rx::get_status_pdu(rlc_am_nr_status_pdu_t* status, uint32_t m nack.nack_sn = i; nack.has_so = true; nack.so_start = last_so; - nack.so_end = so_end_of_sdu; + nack.so_end = rlc_status_nack_t::so_end_of_sdu; status->push_nack(nack); RlcDebug( "Final segment missing. NACK_SN=%d. SO_start=%d, SO_end=%d", nack.nack_sn, nack.so_start, nack.so_end); diff --git a/lib/src/rlc/rlc_am_nr_packing.cc b/lib/src/rlc/rlc_am_nr_packing.cc index 72054c26c..e1469d21d 100644 --- a/lib/src/rlc/rlc_am_nr_packing.cc +++ b/lib/src/rlc/rlc_am_nr_packing.cc @@ -32,10 +32,85 @@ void rlc_am_nr_status_pdu_t::reset() packed_size_ = rlc_am_nr_status_pdu_sizeof_header_ack_sn; } +static bool is_continuous_sequence(const rlc_status_nack_t& left, const rlc_status_nack_t& right) +{ + // SN must be continuous + if (right.nack_sn != left.has_nack_range ? left.nack_sn + left.nack_range : left.nack_sn + 1) { + return false; + } + + // Segments on left side (if present) must reach the end of sdu + if (left.has_so && left.so_end != rlc_status_nack_t::so_end_of_sdu) { + return false; + } + + // Segments on right side (if present) must start from the beginning + if (right.has_so && right.so_start != 0) { + return false; + } + + return true; +} + void rlc_am_nr_status_pdu_t::push_nack(const rlc_status_nack_t& nack) { - nacks_.push_back(nack); - packed_size_ += nack_size(nack); + if (nacks_.size() == 0) { + nacks_.push_back(nack); + packed_size_ += nack_size(nack); + return; + } + + rlc_status_nack_t& prev = nacks_.back(); + if (is_continuous_sequence(prev, nack) == false) { + nacks_.push_back(nack); + packed_size_ += nack_size(nack); + return; + } + + // expand previous NACK + // subtract size of previous NACK (add updated size later) + packed_size_ -= nack_size(prev); + + // enable and update NACK range + if (nack.has_nack_range == true) { + if (prev.has_nack_range == true) { + // [NACK range][NACK range] + prev.nack_range += nack.nack_range; + } else { + // [NACK SDU][NACK range] + prev.nack_range = nack.nack_range + 1; + prev.has_nack_range = true; + } + } else { + if (prev.has_nack_range == true) { + // [NACK range][NACK SDU] + prev.nack_range++; + } else { + // [NACK SDU][NACK SDU] + prev.nack_range = 2; + prev.has_nack_range = true; + } + } + + // enable and update segment offsets (if required) + if (nack.has_so == true) { + if (prev.has_so == false) { + // [NACK SDU][NACK segm] + prev.has_so = true; + prev.so_start = 0; + } + // [NACK SDU][NACK segm] or [NACK segm][NACK segm] + prev.so_end = nack.so_end; + } else { + if (prev.has_so == true) { + // [NACK segm][NACK SDU] + prev.so_end = rlc_status_nack_t::so_end_of_sdu; + } + // [NACK segm][NACK SDU] or [NACK SDU][NACK SDU] + } + + // add updated size + packed_size_ += nack_size(prev); } bool rlc_am_nr_status_pdu_t::trim(uint32_t max_packed_size)