From d8cb4ec700bcb375cbd9a3e929c1d04b042f9792 Mon Sep 17 00:00:00 2001 From: Robert Falkenberg Date: Tue, 29 Mar 2022 09:11:01 +0200 Subject: [PATCH] lib,rlc_am_nr: detect gaps in sequence of received SDU segments This is required for checks such as "there is at least one missing byte segment [...] before the last byte of all received segments of this SDU" --- lib/include/srsran/rlc/rlc_am_nr.h | 7 +++- lib/include/srsran/rlc/rlc_am_nr_packing.h | 1 + lib/src/rlc/rlc_am_nr.cc | 37 ++++++++++++++-------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/include/srsran/rlc/rlc_am_nr.h b/lib/include/srsran/rlc/rlc_am_nr.h index db954dcad..94d57fabf 100644 --- a/lib/include/srsran/rlc/rlc_am_nr.h +++ b/lib/include/srsran/rlc/rlc_am_nr.h @@ -230,7 +230,12 @@ public: bool inside_rx_window(uint32_t sn); void write_to_upper_layers(uint32_t lcid, unique_byte_buffer_t sdu); void insert_received_segment(rlc_amd_rx_pdu_nr segment, rlc_amd_rx_sdu_nr_t::segment_list_t& segment_list) const; - bool have_all_segments_been_received(const rlc_amd_rx_sdu_nr_t::segment_list_t& segment_list) const; + /** + * @brief update_segment_inventory This function updates the flags has_gap and fully_received of an SDU + * according to the current inventory of received SDU segments + * @param rx_sdu The SDU to operate on + */ + void update_segment_inventory(rlc_amd_rx_sdu_nr_t& rx_sdu) const; // Metrics uint32_t get_sdu_rx_latency_ms() final; diff --git a/lib/include/srsran/rlc/rlc_am_nr_packing.h b/lib/include/srsran/rlc/rlc_am_nr_packing.h index 7f1b47afa..5df015542 100644 --- a/lib/include/srsran/rlc/rlc_am_nr_packing.h +++ b/lib/include/srsran/rlc/rlc_am_nr_packing.h @@ -61,6 +61,7 @@ struct rlc_amd_rx_pdu_nr_cmp { struct rlc_amd_rx_sdu_nr_t { uint32_t rlc_sn = 0; bool fully_received = false; + bool has_gap = false; unique_byte_buffer_t buf; using segment_list_t = std::set; segment_list_t segments; diff --git a/lib/src/rlc/rlc_am_nr.cc b/lib/src/rlc/rlc_am_nr.cc index e26100869..baa4e86d5 100644 --- a/lib/src/rlc/rlc_am_nr.cc +++ b/lib/src/rlc/rlc_am_nr.cc @@ -1255,6 +1255,7 @@ int rlc_am_nr_rx::handle_full_data_sdu(const rlc_am_nr_pdu_header_t& header, con memcpy(rx_sdu.buf->msg, payload + hdr_len, nof_bytes - hdr_len); // Don't copy header rx_sdu.buf->N_bytes = nof_bytes - hdr_len; rx_sdu.fully_received = true; + rx_sdu.has_gap = false; return SRSRAN_SUCCESS; } @@ -1296,7 +1297,7 @@ int rlc_am_nr_rx::handle_segment_data_sdu(const rlc_am_nr_pdu_header_t& header, insert_received_segment(std::move(pdu_segment), rx_sdu.segments); // Check weather all segments have been received - rx_sdu.fully_received = have_all_segments_been_received(rx_sdu.segments); + update_segment_inventory(rx_sdu); if (rx_sdu.fully_received) { RlcInfo("Fully received segmented SDU. SN=%d.", header.sn); rx_sdu.buf = srsran::make_byte_buffer(); @@ -1305,6 +1306,7 @@ int rlc_am_nr_rx::handle_segment_data_sdu(const rlc_am_nr_pdu_header_t& header, rx_window->remove_pdu(header.sn); return SRSRAN_ERROR; } + // Assemble SDU from segments for (const auto& it : rx_sdu.segments) { memcpy(&rx_sdu.buf->msg[rx_sdu.buf->N_bytes], it.buf->msg, it.buf->N_bytes); rx_sdu.buf->N_bytes += it.buf->N_bytes; @@ -1515,27 +1517,34 @@ void rlc_am_nr_rx::insert_received_segment(rlc_amd_rx_pdu_nr segment_list.insert(std::move(segment)); } -bool rlc_am_nr_rx::have_all_segments_been_received( - const std::set& segment_list) const +void rlc_am_nr_rx::update_segment_inventory(rlc_amd_rx_sdu_nr_t& rx_sdu) const { - if (segment_list.empty()) { - return false; - } - - // Check if we have received the last segment - if (segment_list.rbegin()->header.si != rlc_nr_si_field_t::last_segment) { - return false; + if (rx_sdu.segments.empty()) { + rx_sdu.fully_received = false; + rx_sdu.has_gap = false; + return; } - // Check if all segments have been received + // Check for gaps and if all segments have been received uint32_t next_byte = 0; - for (const auto& it : segment_list) { + for (const auto& it : rx_sdu.segments) { if (it.header.so != next_byte) { - return false; + // Found gap: set flags and return + rx_sdu.has_gap = true; + rx_sdu.fully_received = false; + return; + } + if (it.header.si == rlc_nr_si_field_t::last_segment) { + // Reached last segment without any gaps: set flags and return + rx_sdu.has_gap = false; + rx_sdu.fully_received = true; + return; } next_byte += it.buf->N_bytes; } - return true; + // No gaps, but last segment not yet received + rx_sdu.has_gap = false; + rx_sdu.fully_received = false; } /*