From 99b10a6eb0bb24f7a5392b6ab1491a5dded1101c Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Wed, 26 Sep 2018 16:57:07 +0200 Subject: [PATCH] fix various RLC AM issues, where - (a) no PDU is scheduled for retx after poll_retx timer expired - (b) we write outside of the PDU buffer when concatenating many SDUs --- lib/src/upper/rlc_am.cc | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/lib/src/upper/rlc_am.cc b/lib/src/upper/rlc_am.cc index a30e0c264..933a1d9af 100644 --- a/lib/src/upper/rlc_am.cc +++ b/lib/src/upper/rlc_am.cc @@ -496,8 +496,10 @@ void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) pthread_mutex_lock(&mutex); if (poll_retx_timer != NULL && poll_retx_timer_id == timeout_id) { log->debug("Poll reTx timer expired for LCID=%d after %d ms\n", parent->lcid, poll_retx_timer->get_timeout()); - // Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit random PDU - if ((tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty() && tx_sdu_queue.size() == 0)) { + // Section 5.2.2.3 in TS 36.311, schedule random PDU for retransmission if + // (a) both tx and retx buffer are empty, or + // (b) no new data PDU can be transmitted (tx window is full) + if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) { retransmit_random_pdu(); } } else @@ -509,17 +511,18 @@ void rlc_am::rlc_am_tx::timer_expired(uint32_t timeout_id) void rlc_am::rlc_am_tx::retransmit_random_pdu() { - // randomly select PDU in tx window for retransmission - std::map::iterator it = tx_window.begin(); - std::advance(it, rand() % tx_window.size()); - - log->info("Schedule SN=%d for reTx.\n", it->first); - rlc_amd_retx_t retx = {}; - retx.is_segment = false; - retx.so_start = 0; - retx.so_end = it->second.buf->N_bytes; - retx.sn = it->first; - retx_queue.push_back(retx); + if (not tx_window.empty()) { + // randomly select PDU in tx window for retransmission + std::map::iterator it = tx_window.begin(); + std::advance(it, rand() % tx_window.size()); + log->info("Schedule SN=%d for reTx.\n", it->first); + rlc_amd_retx_t retx = {}; + retx.is_segment = false; + retx.so_start = 0; + retx.so_end = it->second.buf->N_bytes; + retx.sn = it->first; + retx_queue.push_back(retx); + } } uint32_t rlc_am::rlc_am_tx::get_num_tx_bytes() @@ -830,8 +833,7 @@ int rlc_am::rlc_am_tx::build_segment(uint8_t *payload, uint32_t nof_bytes, rlc_a int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) { - if(tx_sdu == NULL && tx_sdu_queue.size() == 0) - { + if (tx_sdu == NULL && tx_sdu_queue.size() == 0) { log->info("No data available to be sent\n"); return 0; } @@ -875,7 +877,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) uint32_t head_len = rlc_am_packed_length(&header); uint32_t to_move = 0; uint32_t last_li = 0; - uint32_t pdu_space = nof_bytes; + uint32_t pdu_space = SRSLTE_MIN(nof_bytes, pdu->get_tailroom()); uint8_t *pdu_ptr = pdu->msg; if(pdu_space <= head_len + 1) @@ -906,7 +908,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) tx_sdu = NULL; } if (pdu_space > to_move) { - pdu_space -= to_move; + pdu_space -= SRSLTE_MIN(to_move, pdu->get_tailroom());; } else { pdu_space = 0; } @@ -934,8 +936,7 @@ int rlc_am::rlc_am_tx::build_data_pdu(uint8_t *payload, uint32_t nof_bytes) pdu->N_bytes += to_move; tx_sdu->N_bytes -= to_move; tx_sdu->msg += to_move; - if(tx_sdu->N_bytes == 0) - { + if (tx_sdu->N_bytes == 0) { log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n", RB_NAME, tx_sdu->get_latency_us()); pool->deallocate(tx_sdu);