lib,rlc: Fixed issue where `p` bit was not checked if PDU was outside of

the RX window. This could lead to a data stall, where TX keeps retx'ing
the same PDU to request a status report.
This commit is contained in:
Pedro Alvarez 2022-07-07 15:55:59 +01:00
parent 40f19b0e2c
commit 7ac7c8673a
4 changed files with 172 additions and 88 deletions

View File

@ -1425,21 +1425,25 @@ void rlc_am_nr_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
RlcHexInfo(payload, nof_bytes, "Rx data PDU SN=%d (%d B)", header.sn, nof_bytes);
log_rlc_am_nr_pdu_header_to_string(logger.debug, header, rb_name);
// Trigger polling if poll bit is set.
// We do this before checking if the PDU is inside the RX window,
// as the RX window may have advanced without the TX having received the ACKs
// This can cause a data stall, whereby the TX keeps retransmiting
// a PDU outside of the Rx window.
// Also, we do this before discarding duplicate SDUs/SDU segments
// Because t-PollRetransmit may transmit a PDU that was already
// received.
if (header.p != 0U) {
RlcInfo("status packet requested through polling bit");
do_status = true;
}
// Check whether SDU is within Rx Window
if (!inside_rx_window(header.sn)) {
RlcInfo("SN=%d outside rx window [%d:%d] - discarding", header.sn, st.rx_next, st.rx_next + rx_window_size());
return;
}
// Trigger polling if poll bit is set.
// We do this before discarding duplicate SDUs/SDU segments
// Because t-PollRetransmit may transmit a PDU that was already
// received.
if (header.p) {
RlcInfo("status packet requested through polling bit");
do_status = true;
}
// Section 5.2.3.2.2, discard duplicate PDUs
if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) {
RlcInfo("discarding duplicate SN=%d", header.sn);

View File

@ -96,7 +96,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
int basic_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -155,7 +155,7 @@ int basic_test()
int concat_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -229,7 +229,7 @@ int concat_test()
int segment_test(bool in_seq_rx)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -324,7 +324,7 @@ int segment_test(bool in_seq_rx)
int retx_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -460,7 +460,7 @@ int retx_test()
// Test correct upper layer signaling when maxRetx (default 4) have been reached
int max_retx_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -523,7 +523,7 @@ int max_retx_test()
// Purpose: test correct retx of lost segment and pollRetx timer expiration
int segment_retx_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -648,7 +648,7 @@ int resegment_test_1()
// PDUs: | 10 | 10 | 10 | 10 | 10 |
// Retx PDU segments: | 5 | 5|
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -806,7 +806,7 @@ int resegment_test_2()
// PDUs: | 5 | 10 | 20 | 10 | 5 |
// Retx PDU segments: | 10 | 10 |
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -938,7 +938,7 @@ int resegment_test_3()
// PDUs: | 5 | 5| 20 | 10 | 10 |
// Retx PDU segments: | 10 | 10 |
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -1068,7 +1068,7 @@ int resegment_test_4()
// PDUs: | 5 | 5| 30 | 5 | 5|
// Retx PDU segments: | 15 | 15 |
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -1200,7 +1200,7 @@ int resegment_test_5()
// PDUs: |2|3| 40 |3|2|
// Retx PDU segments: | 20 | 20 |
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -1326,7 +1326,7 @@ int resegment_test_6()
// PDUs: |10|10|10| 270 | 54 |
// Retx PDU segments: | 120 | 150 |
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -1493,9 +1493,9 @@ int resegment_test_7()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_test7.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, nullptr);
#endif
srsran::timer_handler timers(8);
@ -1678,9 +1678,9 @@ int resegment_test_8()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_test8.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, nullptr);
#endif
srsran::timer_handler timers(8);
@ -1830,9 +1830,9 @@ int resegment_test_9()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_resegment_test_9.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, nullptr);
#endif
srsran::timer_handler timers(8);
@ -1972,9 +1972,9 @@ int resegment_test_10()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_resegment_test_10.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2121,9 +2121,9 @@ int resegment_test_11()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_resegment_test_11.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2279,9 +2279,9 @@ int resegment_test_12()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_resegment_test_12.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2423,9 +2423,9 @@ int header_reconstruction_test(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2486,9 +2486,9 @@ int header_reconstruction_test2(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test2.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2549,9 +2549,9 @@ int header_reconstruction_test3(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test3.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2635,9 +2635,9 @@ int header_reconstruction_test4(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test4.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2712,9 +2712,9 @@ int header_reconstruction_test5(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test5.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2791,9 +2791,9 @@ int header_reconstruction_test6(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test6.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2890,9 +2890,9 @@ int header_reconstruction_test7(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test7.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -2992,9 +2992,9 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test8.pcap", rlc_config_t::default_rlc_am_config());
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -3026,7 +3026,7 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy)
bool reset_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -3068,7 +3068,7 @@ bool reset_test()
bool resume_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -3110,7 +3110,7 @@ bool resume_test()
bool stop_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
@ -3136,7 +3136,7 @@ bool stop_test()
// be enough to fit all SNs that would need to be NACKed
bool status_pdu_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -3245,7 +3245,7 @@ bool status_pdu_test()
// The incidence is reported to the upper layers.
bool incorrect_status_pdu_test()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -3310,7 +3310,7 @@ bool incorrect_status_pdu_test()
/// In contrast to the without explicitly NACK-ing specific SNs
bool incorrect_status_pdu_test2()
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8);
int len = 0;
@ -3421,9 +3421,9 @@ bool reestablish_test()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_reestablish_test.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, nullptr);
#endif
srsran::timer_handler timers(8);
@ -3541,9 +3541,9 @@ bool discard_test()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_reestablish_test.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);
@ -3631,9 +3631,9 @@ bool poll_retx_expiry_test()
#if HAVE_PCAP
rlc_pcap pcap;
pcap.open("rlc_am_poll_rext_expiry_test.pcap", config);
rlc_am_tester tester(&pcap);
rlc_am_tester tester(true, &pcap);
#else
rlc_am_tester tester(NULL);
rlc_am_tester tester(true, NULL);
#endif
srsran::timer_handler timers(8);

View File

@ -60,7 +60,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS], rlc_am_nr_sn_size_
*/
int window_checker_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -124,7 +124,7 @@ int window_checker_test(rlc_am_nr_sn_size_t sn_size)
*/
int retx_segmentation_required_checker_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -210,7 +210,7 @@ int retx_segmentation_required_checker_test(rlc_am_nr_sn_size_t sn_size)
*/
int basic_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -318,7 +318,7 @@ int basic_test(rlc_am_nr_sn_size_t sn_size)
*/
int lost_pdu_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -493,7 +493,7 @@ int lost_pdu_test(rlc_am_nr_sn_size_t sn_size)
*/
int lost_pdu_duplicated_nack_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -678,7 +678,7 @@ int lost_pdu_duplicated_nack_test(rlc_am_nr_sn_size_t sn_size)
*/
int lost_pdus_trimmed_nack_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -897,7 +897,7 @@ int lost_pdus_trimmed_nack_test(rlc_am_nr_sn_size_t sn_size)
*/
int clean_retx_queue_of_acked_sdus_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -1085,7 +1085,7 @@ int clean_retx_queue_of_acked_sdus_test(rlc_am_nr_sn_size_t sn_size)
*/
int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_delimit_logger delimiter("basic segmentation ({} bit SN)", to_number(sn_size));
@ -1177,7 +1177,7 @@ int basic_segmentation_test(rlc_am_nr_sn_size_t sn_size)
// - Check metrics and state
int segment_retx_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -1376,7 +1376,7 @@ int segment_retx_test(rlc_am_nr_sn_size_t sn_size)
// - Check metrics and state
int segment_retx_and_loose_segments_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -1640,7 +1640,7 @@ int segment_retx_and_loose_segments_test(rlc_am_nr_sn_size_t sn_size)
int retx_segment_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -1958,7 +1958,7 @@ int retx_segment_test(rlc_am_nr_sn_size_t sn_size)
// SN==TX_NEXT.
int handle_status_of_non_tx_last_segment(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_delimit_logger delimiter("basic segmentation ({} bit SN)", to_number(sn_size));
@ -2045,7 +2045,7 @@ int handle_status_of_non_tx_last_segment(rlc_am_nr_sn_size_t sn_size)
// due to lost SDUs as a whole
int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -2120,7 +2120,7 @@ int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size)
// due to lost SDU segments
int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
int len = 0;
@ -2249,7 +2249,7 @@ int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size)
// This test checks the correct functioning of RLC discard functionality
int discard_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2355,7 +2355,7 @@ int discard_test(rlc_am_nr_sn_size_t sn_size)
// Test p bit set on new TX with PollPDU
int poll_pdu(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2411,7 +2411,7 @@ int poll_pdu(rlc_am_nr_sn_size_t sn_size)
// Test p bit set on new TX with PollBYTE
int poll_byte(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2467,7 +2467,7 @@ int poll_byte(rlc_am_nr_sn_size_t sn_size)
// Test p bit set on RETXes that cause an empty retx queue.
int poll_retx(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2585,7 +2585,7 @@ int poll_retx(rlc_am_nr_sn_size_t sn_size)
// It checks if the poll retx timer is re-armed upon receiving an ACK for POLL_SN
bool poll_retx_expiry(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2740,7 +2740,7 @@ bool poll_retx_expiry(rlc_am_nr_sn_size_t sn_size)
int rx_nack_range_no_so_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2832,7 +2832,7 @@ int rx_nack_range_no_so_test(rlc_am_nr_sn_size_t sn_size)
int rx_nack_range_with_so_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -2928,7 +2928,7 @@ int rx_nack_range_with_so_test(rlc_am_nr_sn_size_t sn_size)
int rx_nack_range_with_so_starting_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -3035,7 +3035,7 @@ int rx_nack_range_with_so_starting_with_full_sdu_test(rlc_am_nr_sn_size_t sn_siz
int rx_nack_range_with_so_ending_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
@ -3142,7 +3142,7 @@ int rx_nack_range_with_so_ending_with_full_sdu_test(rlc_am_nr_sn_size_t sn_size)
int out_of_order_status(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -3210,9 +3210,85 @@ int out_of_order_status(rlc_am_nr_sn_size_t sn_size)
return SRSRAN_SUCCESS;
}
// If we lose the status report
int lost_status_and_advanced_rx_window(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester(true, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_delimit_logger delimiter("Lost status report and advance RX window ({} bit SN)", to_number(sn_size));
rlc_am rlc1(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers);
rlc_am rlc2(srsran_rat_t::nr, srslog::fetch_basic_logger("RLC_AM_2"), 1, &tester, &tester, &timers);
rlc_am_nr_tx* tx1 = dynamic_cast<rlc_am_nr_tx*>(rlc1.get_tx());
rlc_am_nr_rx* rx1 = dynamic_cast<rlc_am_nr_rx*>(rlc1.get_rx());
rlc_am_nr_tx* tx2 = dynamic_cast<rlc_am_nr_tx*>(rlc2.get_tx());
rlc_am_nr_rx* rx2 = dynamic_cast<rlc_am_nr_rx*>(rlc2.get_rx());
auto cfg = rlc_config_t::default_rlc_am_nr_config(to_number(sn_size));
if (not rlc1.configure(cfg)) {
return -1;
}
if (not rlc2.configure(cfg)) {
return -1;
}
uint32_t mod_nr = cardinality(cfg.am_nr.tx_sn_field_length);
// Fill up the RX window
constexpr uint32_t payload_size = 3; // Give the SDU the size of 3 bytes
uint32_t header_size = sn_size == rlc_am_nr_sn_size_t::size12bits ? 2 : 3;
for (uint32_t sn = 0; sn < 10; ++sn) {
// Write SDU
unique_byte_buffer_t sdu_buf = srsran::make_byte_buffer();
sdu_buf->msg[0] = sn; // Write the index into the buffer
sdu_buf->N_bytes = payload_size; // Give each buffer a size of 3 bytes
sdu_buf->md.pdcp_sn = sn; // PDCP SN for notifications
rlc1.write_sdu(std::move(sdu_buf));
// Read PDU
unique_byte_buffer_t pdu_buf = srsran::make_byte_buffer();
pdu_buf->N_bytes = rlc1.read_pdu(pdu_buf->msg, 100);
// Write PDU into RLC 2
// We receive all PDUs
rlc2.write_pdu(pdu_buf->msg, pdu_buf->N_bytes);
}
// We got the polling bit, so we generate the status report.
TESTASSERT_EQ(3, rlc2.get_buffer_state());
// Read status PDU
{
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
status_buf->N_bytes = rlc2.read_pdu(status_buf->msg, 3);
}
TESTASSERT_EQ(0, rlc2.get_buffer_state());
// We do not write the status report into RLC 1
// We step trought the timers to let t-PollRetransmission expire
TESTASSERT_EQ(0, rlc1.get_buffer_state());
for (int t = 0; t < 45; t++) {
timers.step_all();
}
TESTASSERT_EQ(header_size + payload_size, rlc1.get_buffer_state());
// Read RETX of POLL_SN and check if it triggered the
// Status report
{
unique_byte_buffer_t pdu_buf = srsran::make_byte_buffer();
pdu_buf->N_bytes = rlc1.read_pdu(pdu_buf->msg, 100);
TESTASSERT_EQ(0, rlc2.get_buffer_state());
rlc2.write_pdu(pdu_buf->msg, pdu_buf->N_bytes);
TESTASSERT_EQ(3, rlc2.get_buffer_state());
}
return SRSRAN_SUCCESS;
}
int full_rx_window_t_reassembly_expiry(rlc_am_nr_sn_size_t sn_size)
{
rlc_am_tester tester;
rlc_am_tester tester(false, nullptr);
timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS];
@ -3330,6 +3406,7 @@ int main()
TESTASSERT(rx_nack_range_with_so_starting_with_full_sdu_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(rx_nack_range_with_so_ending_with_full_sdu_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(out_of_order_status(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(lost_status_and_advanced_rx_window(sn_size) == SRSRAN_SUCCESS);
}
TESTASSERT(full_rx_window_t_reassembly_expiry(rlc_am_nr_sn_size_t::size12bits) == SRSRAN_SUCCESS);
return SRSRAN_SUCCESS;

View File

@ -72,13 +72,15 @@ public:
class rlc_am_tester : public srsue::pdcp_interface_rlc, public srsue::rrc_interface_rlc
{
public:
rlc_am_tester(rlc_pcap* pcap_ = NULL) : pcap(pcap_) {}
explicit rlc_am_tester(bool save_sdus_, rlc_pcap* pcap_) : save_sdus(save_sdus_), pcap(pcap_) {}
// PDCP interface
void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu)
{
assert(lcid == 1);
// sdus.push_back(std::move(sdu));
if (save_sdus) {
sdus.push_back(std::move(sdu));
}
}
void write_pdu_bcch_bch(unique_byte_buffer_t sdu) {}
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
@ -110,6 +112,7 @@ public:
rlc_pcap* pcap = nullptr;
bool max_retx_triggered = false;
bool protocol_failure_triggered = false;
bool save_sdus = true;
std::map<uint32_t, uint32_t> notified_counts; // Map of PDCP SNs to number of notifications
};