diff --git a/lib/include/srsran/rlc/rlc_um_nr.h b/lib/include/srsran/rlc/rlc_um_nr.h index b3f3bece3..7e5b860ba 100644 --- a/lib/include/srsran/rlc/rlc_um_nr.h +++ b/lib/include/srsran/rlc/rlc_um_nr.h @@ -102,8 +102,8 @@ private: uint32_t RX_Next_Highest = 0; // the SN following the SN of the UMD PDU with the highest SN among // received UMD PDUs. It serves as the higher edge of the reassembly window. - uint32_t UM_Window_Size; - uint32_t mod; // Rx counter modulus + uint32_t UM_Window_Size = 0; + uint32_t mod = 0; // Rx counter modulus // Rx window typedef struct { diff --git a/lib/src/rlc/rlc_um_nr.cc b/lib/src/rlc/rlc_um_nr.cc index c87ac2eb4..45a395f23 100644 --- a/lib/src/rlc/rlc_um_nr.cc +++ b/lib/src/rlc/rlc_um_nr.cc @@ -304,9 +304,10 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id) { std::lock_guard lock(mutex); if (reassembly_timer.id() == timeout_id) { - logger.info("%s reassembly timeout expiry - updating RX_Next_Reassembly and reassembling", rb_name.c_str()); + logger.info("%s reassembly timeout expiry for SN=%d - updating RX_Next_Reassembly and reassembling", + rb_name.c_str(), + RX_Next_Reassembly); - logger.info("Lost PDU SN=%d", RX_Next_Reassembly); metrics.num_lost_pdus++; if (rx_sdu != nullptr) { @@ -333,6 +334,7 @@ void rlc_um_nr::rlc_um_nr_rx::timer_expired(uint32_t timeout_id) if (RX_MOD_NR_BASE(RX_Next_Highest) > RX_MOD_NR_BASE(RX_Next_Reassembly + 1) || ((RX_MOD_NR_BASE(RX_Next_Highest) == RX_MOD_NR_BASE(RX_Next_Reassembly + 1) && has_missing_byte_segment(RX_Next_Reassembly)))) { + logger.info("%s Starting reassembly timer for SN=%d", rb_name.c_str(), RX_Next_Reassembly); reassembly_timer.run(); RX_Timer_Trigger = RX_Next_Highest; } @@ -385,6 +387,8 @@ bool rlc_um_nr::rlc_um_nr_rx::has_missing_byte_segment(const uint32_t sn) void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn) { if (rx_window.find(sn) != rx_window.end()) { + bool sdu_complete = false; + // iterate over received segments and try to assemble full SDU auto& pdu = rx_window.at(sn); for (auto it = pdu.segments.begin(); it != pdu.segments.end();) { @@ -427,25 +431,9 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn) it = pdu.segments.erase(it); if (pdu.next_expected_so == pdu.total_sdu_length) { - // deliver full SDU to upper layers - logger.info("Delivering %s SDU SN=%d (%d B)", rb_name.c_str(), sn, pdu.sdu->N_bytes); - pdcp->write_pdu(lcid, std::move(pdu.sdu)); - - // find next SN in rx buffer - if (sn == RX_Next_Reassembly) { - for (auto it = rx_window.begin(); it != rx_window.end(); ++it) { - logger.debug("SN=%d has %zd segments", it->first, it->second.segments.size()); - if (RX_MOD_NR_BASE(it->first) > RX_MOD_NR_BASE(RX_Next_Reassembly)) { - RX_Next_Reassembly = it->first; - break; - } - } - logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly); - } - - // delete PDU from rx_window - rx_window.erase(sn); - return; + // entire SDU has been received, it will be passed up the stack outside the loop + sdu_complete = true; + break; } } } else { @@ -454,10 +442,34 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn) } } - // check for SN outside of rx window - if (not sn_in_reassembly_window(sn)) { - // update RX_Next_highest - RX_Next_Highest = sn + 1; + if (sdu_complete) { + // deliver full SDU to upper layers + logger.info("%s Delivering SDU SN=%d (%d B)", rb_name.c_str(), sn, pdu.sdu->N_bytes); + pdcp->write_pdu(lcid, std::move(pdu.sdu)); + + // delete PDU from rx_window + rx_window.erase(sn); + + // find next SN in rx buffer + if (sn == RX_Next_Reassembly) { + if (rx_window.empty()) { + // no further segments received + RX_Next_Reassembly = RX_Next_Highest; + } else { + for (auto it = rx_window.begin(); it != rx_window.end(); ++it) { + logger.debug("SN=%d has %zd segments", it->first, it->second.segments.size()); + if (RX_MOD_NR_BASE(it->first) > RX_MOD_NR_BASE(RX_Next_Reassembly)) { + RX_Next_Reassembly = it->first; + break; + } + } + } + logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly); + } + } else if (not sn_in_reassembly_window(sn)) { + // SN outside of rx window + + RX_Next_Highest = sn + 1; // update RX_Next_highest logger.debug("Updating RX_Next_Highest=%d", RX_Next_Highest); // drop all SNs outside of new rx window @@ -480,29 +492,32 @@ void rlc_um_nr::rlc_um_nr_rx::handle_rx_buffer_update(const uint32_t sn) for (const auto& rx_pdu : rx_window) { if (rx_pdu.first >= RX_MOD_NR_BASE(RX_Next_Highest - UM_Window_Size)) { RX_Next_Reassembly = rx_pdu.first; - logger.debug("Updating RX_Next_Reassembly=%d", RX_Next_Reassembly); + logger.debug("%s Updating RX_Next_Reassembly=%d", rb_name.c_str(), RX_Next_Reassembly); break; } } } + } - if (reassembly_timer.is_running()) { - if (RX_Timer_Trigger <= RX_Next_Reassembly || - (not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) || - ((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(sn))) { - reassembly_timer.stop(); - } + if (reassembly_timer.is_running()) { + if (RX_Timer_Trigger <= RX_Next_Reassembly || + (not sn_in_reassembly_window(RX_Timer_Trigger) and RX_Timer_Trigger != RX_Next_Highest) || + ((RX_Next_Highest == RX_Next_Reassembly + 1) && not has_missing_byte_segment(RX_Next_Reassembly))) { + logger.debug("%s stopping reassembly timer", rb_name.c_str()); + reassembly_timer.stop(); } + } - if (not reassembly_timer.is_running() && has_missing_byte_segment(sn)) { - if (RX_Next_Highest > RX_Next_Reassembly + 1) { - reassembly_timer.run(); - RX_Timer_Trigger = RX_Next_Highest; - } + if (not reassembly_timer.is_running()) { + if ((RX_Next_Highest > RX_Next_Reassembly + 1) || + ((RX_Next_Highest == RX_Next_Reassembly + 1) && has_missing_byte_segment(RX_Next_Reassembly))) { + logger.info("%s Starting reassembly timer for SN=%d", rb_name.c_str(), sn); + reassembly_timer.run(); + RX_Timer_Trigger = RX_Next_Highest; } } } else { - logger.error("SN=%d does not exist in Rx buffer", sn); + logger.error("%s SN=%d does not exist in Rx buffer", rb_name.c_str(), sn); } }