diff --git a/lib/src/rlc/rlc_am_lte.cc b/lib/src/rlc/rlc_am_lte.cc index f010a6860..d84e72723 100644 --- a/lib/src/rlc/rlc_am_lte.cc +++ b/lib/src/rlc/rlc_am_lte.cc @@ -361,10 +361,7 @@ void rlc_am_lte_tx::retransmit_pdu(uint32_t sn) bool rlc_am_lte_tx::window_full() { - if ((vt_s - vt_a) >= RLC_AM_WINDOW_SIZE) { - return true; - } - return false; + return TX_MOD_BASE(vt_s) >= RLC_AM_WINDOW_SIZE; }; /** diff --git a/lib/test/rlc/rlc_am_lte_test.cc b/lib/test/rlc/rlc_am_lte_test.cc index e3d94459e..b9432d04d 100644 --- a/lib/test/rlc/rlc_am_lte_test.cc +++ b/lib/test/rlc/rlc_am_lte_test.cc @@ -3927,6 +3927,152 @@ bool full_window_check_test() return SRSRAN_SUCCESS; } +bool full_window_check_wraparound_test() +{ + rlc_config_t config = rlc_config_t::default_rlc_am_config(); + // [I] SRB1 configured: t_poll_retx=65, poll_pdu=-1, poll_byte=-1, max_retx_thresh=6, t_reordering=55, + // t_status_prohibit=0 + config.am.t_poll_retx = 65; + config.am.poll_pdu = -1; + config.am.poll_byte = -1; + config.am.max_retx_thresh = 6; + config.am.t_reordering = 55; + config.am.t_status_prohibit = 55; + +#if HAVE_PCAP + rlc_pcap pcap; + pcap.open("rlc_am_poll_rext_expiry_test.pcap", config); + rlc_am_tester tester(true, &pcap); +#else + rlc_am_tester tester(true, NULL); +#endif + + uint32_t pdcp_count = 0; + + srsran::timer_handler timers(8); + + rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); + rlc_am rlc2(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers); + + srslog::fetch_basic_logger("RLC_AM_1").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC_AM_2").set_hex_dump_max_size(100); + srslog::fetch_basic_logger("RLC").set_hex_dump_max_size(100); + + if (not rlc1.configure(config)) { + return -1; + } + + if (not rlc2.configure(config)) { + return -1; + } + + // Advance vt_a to 512 and vt_s to 512 as well. + { + // Initial Tx + uint32_t num_tx_pdus = 512; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + + // ACK all SNs to advance the TX window. + rlc_status_pdu_t status = {}; + status.ack_sn = num_tx_pdus; + status.N_nack = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + } + + // Advance vt_a and vt_s to 1023 + { + // Initial Tx + uint32_t num_tx_pdus = 511; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + + // ACK all SNs to advance the TX window. + rlc_status_pdu_t status = {}; + status.ack_sn = 512 + num_tx_pdus; + status.N_nack = 0; + + unique_byte_buffer_t status_buf = srsran::make_byte_buffer(); + TESTASSERT(status_buf != nullptr); + rlc_am_write_status_pdu(&status, status_buf.get()); + rlc1.write_pdu(status_buf->msg, status_buf->N_bytes); + } + + // Now, fill up the window + { + // Initial Tx + uint32_t num_tx_pdus = 512; + for (uint32_t i = 0; i < num_tx_pdus; ++i) { + // Write SDU + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = i; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + } + } + { + // Tx one more to check the window is full + unique_byte_buffer_t sdu = srsran::make_byte_buffer(); + TESTASSERT(sdu != nullptr); + sdu->N_bytes = 1; + sdu->msg[0] = 0; + sdu->md.pdcp_sn = pdcp_count++; + rlc1.write_sdu(std::move(sdu)); + + unique_byte_buffer_t pdu = srsran::make_byte_buffer(); + TESTASSERT(pdu != nullptr); + pdu->N_bytes = rlc1.read_pdu(pdu->msg, 3); + TESTASSERT(pdu->N_bytes == 3); + + // If the TX window is full, we should RETX SN=1023 + rlc_amd_pdu_header_t header = {}; + rlc_am_read_data_pdu_header(&pdu->msg, &pdu->N_bytes, &header); + TESTASSERT_EQ(header.sn, 1023); + TESTASSERT_EQ(header.N_li, 0); + TESTASSERT_EQ(header.fi, 0); + } + +#if HAVE_PCAP + pcap.close(); +#endif + + return SRSRAN_SUCCESS; +} int main(int argc, char** argv) { // Setup the log message spy to intercept error and warning log entries from RLC @@ -4141,5 +4287,10 @@ int main(int argc, char** argv) printf("full_window_check_test failed\n"); exit(-1); }; + + if (full_window_check_wraparound_test()) { + printf("full_window_check_wraparound_test failed\n"); + exit(-1); + }; return SRSRAN_SUCCESS; }