mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'next' into agpl_next
This commit is contained in:
commit
b5c994dd79
|
@ -140,6 +140,7 @@ public:
|
|||
|
||||
// Window helpers
|
||||
bool inside_tx_window(uint32_t sn) const;
|
||||
bool valid_ack_sn(uint32_t sn) const;
|
||||
|
||||
private:
|
||||
rlc_am* parent = nullptr;
|
||||
|
@ -248,7 +249,8 @@ public:
|
|||
// Data handling methods
|
||||
int handle_full_data_sdu(const rlc_am_nr_pdu_header_t& header, const uint8_t* payload, uint32_t nof_bytes);
|
||||
int handle_segment_data_sdu(const rlc_am_nr_pdu_header_t& header, const uint8_t* payload, uint32_t nof_bytes);
|
||||
bool inside_rx_window(uint32_t sn);
|
||||
bool inside_rx_window(uint32_t sn) const;
|
||||
bool valid_ack_sn(uint32_t sn) const;
|
||||
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;
|
||||
/**
|
||||
|
|
|
@ -186,7 +186,7 @@ uint32_t rlc_am_nr_tx::build_new_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
}
|
||||
|
||||
// do not build any more PDU if window is already full
|
||||
if (tx_window->size() >= RLC_AM_WINDOW_SIZE) {
|
||||
if (tx_window->full()) {
|
||||
RlcInfo("Cannot build data PDU - Tx window full.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -793,17 +793,20 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
|
||||
/*
|
||||
* Sanity check the received status report.
|
||||
* Checking if the ACK_SN is inside the the TX_WINDOW makes sure we discard out of order status reports
|
||||
* Checking if ACK_SN > Tx_Next makes sure we do not receive a ACK/NACK for something we did not TX
|
||||
* Checking if the ACK_SN is inside the valid ACK_SN window (the TX window "off-by-one")
|
||||
* makes sure we discard out of order status reports.
|
||||
* Checking if ACK_SN > Tx_Next + 1 makes sure we do not receive a ACK/NACK for something we did not TX
|
||||
* ACK_SN may be equal to TX_NEXT + 1, if not all SDU segments with SN=TX_NEXT have been transmitted.
|
||||
*/
|
||||
if (not inside_tx_window(status.ack_sn)) {
|
||||
if (not valid_ack_sn(status.ack_sn)) {
|
||||
RlcInfo("Received ACK with SN outside of TX_WINDOW, ignoring status report. ACK_SN=%d, TX_NEXT_ACK=%d.",
|
||||
status.ack_sn,
|
||||
st.tx_next_ack);
|
||||
info_state();
|
||||
return;
|
||||
}
|
||||
if (tx_mod_base_nr(status.ack_sn) > tx_mod_base_nr(st.tx_next)) {
|
||||
|
||||
if (tx_mod_base_nr(status.ack_sn) > tx_mod_base_nr(st.tx_next + 1)) {
|
||||
RlcWarning("Received ACK with SN larger than TX_NEXT, ignoring status report. SN=%d, TX_NEXT_ACK=%d, TX_NEXT=%d",
|
||||
status.ack_sn,
|
||||
st.tx_next_ack,
|
||||
|
@ -819,7 +822,7 @@ void rlc_am_nr_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
|||
* - if t-PollRetransmit is running:
|
||||
* - stop and reset t-PollRetransmit.
|
||||
*/
|
||||
if (tx_mod_base_nr(st.poll_sn) <= tx_mod_base_nr(status.ack_sn)) {
|
||||
if (tx_mod_base_nr(st.poll_sn) < tx_mod_base_nr(status.ack_sn)) {
|
||||
if (poll_retransmit_timer.is_running()) {
|
||||
RlcDebug("Received ACK or NACK for POLL_SN=%d. Stopping t-PollRetransmit", st.poll_sn);
|
||||
poll_retransmit_timer.stop();
|
||||
|
@ -1318,6 +1321,21 @@ bool rlc_am_nr_tx::inside_tx_window(uint32_t sn) const
|
|||
return tx_mod_base_nr(sn) < tx_window_size();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to check if a received status report
|
||||
* as a valid ACK_SN.
|
||||
*
|
||||
* ACK_SN may be equal to TX_NEXT + AM_Window_Size if the PDU
|
||||
* with SN=TX_NEXT+AM_Window_Size has been received by the RX
|
||||
* An ACK_SN == Tx_Next_Ack doesn't ACK or NACKs any PDUs, as
|
||||
* such, such a status report can be discarded.
|
||||
*/
|
||||
bool rlc_am_nr_tx::valid_ack_sn(uint32_t sn) const
|
||||
{
|
||||
// Tx_Next_Ack < SN <= TX_Next + AM_Window_Size
|
||||
return (0 < tx_mod_base_nr(sn)) && (tx_mod_base_nr(sn) <= tx_window_size());
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug Helpers
|
||||
*/
|
||||
|
@ -1428,21 +1446,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);
|
||||
|
@ -1853,11 +1875,11 @@ void rlc_am_nr_rx::timer_expired(uint32_t timeout_id)
|
|||
}
|
||||
}
|
||||
st.rx_highest_status = sn_upd;
|
||||
if (not inside_rx_window(st.rx_highest_status)) {
|
||||
if (not valid_ack_sn(st.rx_highest_status)) {
|
||||
RlcError("Rx_Highest_Status not inside RX window");
|
||||
debug_state();
|
||||
}
|
||||
srsran_assert(inside_rx_window(st.rx_highest_status), "Error: rx_highest_status assigned outside rx window");
|
||||
srsran_assert(valid_ack_sn(st.rx_highest_status), "Error: rx_highest_status assigned outside rx window");
|
||||
|
||||
bool restart_reassembly_timer = false;
|
||||
if (rx_mod_base_nr(st.rx_next_highest) > rx_mod_base_nr(st.rx_highest_status + 1)) {
|
||||
|
@ -1946,12 +1968,27 @@ uint32_t rlc_am_nr_rx::rx_window_size() const
|
|||
return am_window_size(cfg.rx_sn_field_length);
|
||||
}
|
||||
|
||||
bool rlc_am_nr_rx::inside_rx_window(uint32_t sn)
|
||||
bool rlc_am_nr_rx::inside_rx_window(uint32_t sn) const
|
||||
{
|
||||
// RX_Next <= SN < RX_Next + AM_Window_Size
|
||||
return rx_mod_base_nr(sn) < rx_window_size();
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used to check if the Rx_Highest_Status is
|
||||
* valid when t-Reasseambly expires.
|
||||
*
|
||||
* ACK_SN may be equal to RX_NEXT + AM_Window_Size if the PDU
|
||||
* with SN=RX_NEXT+AM_Window_Size has been received by the RX.
|
||||
* An ACK_SN == Rx_Next should not update Rx_Highest_Status,
|
||||
* it should be updated when Rx_Next is updated.
|
||||
*/
|
||||
bool rlc_am_nr_rx::valid_ack_sn(uint32_t sn) const
|
||||
{
|
||||
// RX_Next < SN <= RX_Next + AM_Window_Size
|
||||
return (0 < rx_mod_base_nr(sn)) && (rx_mod_base_nr(sn) <= rx_window_size());
|
||||
}
|
||||
|
||||
/*
|
||||
* Debug Helpers
|
||||
*/
|
||||
|
|
|
@ -105,7 +105,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];
|
||||
|
||||
|
@ -164,7 +164,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);
|
||||
|
@ -238,7 +238,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;
|
||||
|
||||
|
@ -333,7 +333,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;
|
||||
|
||||
|
@ -469,7 +469,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;
|
||||
|
||||
|
@ -532,7 +532,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;
|
||||
|
||||
|
@ -657,7 +657,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;
|
||||
|
||||
|
@ -815,7 +815,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);
|
||||
|
@ -947,7 +947,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);
|
||||
|
@ -1077,7 +1077,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);
|
||||
|
@ -1209,7 +1209,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);
|
||||
|
@ -1335,7 +1335,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;
|
||||
|
||||
|
@ -1502,9 +1502,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);
|
||||
|
||||
|
@ -1687,9 +1687,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);
|
||||
|
||||
|
@ -1839,9 +1839,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);
|
||||
|
||||
|
@ -1981,9 +1981,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);
|
||||
|
||||
|
@ -2130,9 +2130,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);
|
||||
|
||||
|
@ -2288,9 +2288,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);
|
||||
|
||||
|
@ -2432,9 +2432,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);
|
||||
|
||||
|
@ -2495,9 +2495,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);
|
||||
|
||||
|
@ -2558,9 +2558,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);
|
||||
|
||||
|
@ -2644,9 +2644,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);
|
||||
|
||||
|
@ -2721,9 +2721,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);
|
||||
|
||||
|
@ -2800,9 +2800,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);
|
||||
|
||||
|
@ -2899,9 +2899,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);
|
||||
|
||||
|
@ -3001,9 +3001,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);
|
||||
|
||||
|
@ -3035,7 +3035,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;
|
||||
|
||||
|
@ -3077,7 +3077,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;
|
||||
|
||||
|
@ -3119,7 +3119,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);
|
||||
|
@ -3145,7 +3145,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;
|
||||
|
||||
|
@ -3254,7 +3254,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;
|
||||
|
||||
|
@ -3319,7 +3319,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;
|
||||
|
||||
|
@ -3430,9 +3430,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);
|
||||
|
@ -3550,9 +3550,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);
|
||||
|
@ -3640,9 +3640,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);
|
||||
|
|
|
@ -69,7 +69,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 ");
|
||||
|
@ -133,7 +133,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 ");
|
||||
|
@ -219,7 +219,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];
|
||||
|
||||
|
@ -327,7 +327,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];
|
||||
|
||||
|
@ -502,7 +502,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];
|
||||
|
||||
|
@ -687,7 +687,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];
|
||||
|
||||
|
@ -906,7 +906,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];
|
||||
|
||||
|
@ -1094,7 +1094,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));
|
||||
|
@ -1186,7 +1186,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];
|
||||
|
||||
|
@ -1385,7 +1385,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];
|
||||
|
||||
|
@ -1649,7 +1649,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 ");
|
||||
|
@ -1961,11 +1961,100 @@ int retx_segment_test(rlc_am_nr_sn_size_t sn_size)
|
|||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// We only increment TX_NEXT after transmitting the last segment of a SDU
|
||||
// This means that we need to handle status reports where ACK_SN may be larger
|
||||
// than TX_NEXT, as it may contain a NACK for the partially transmitted PDU with
|
||||
// SN==TX_NEXT.
|
||||
int handle_status_of_non_tx_last_segment(rlc_am_nr_sn_size_t sn_size)
|
||||
{
|
||||
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));
|
||||
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());
|
||||
|
||||
if (not rlc1.configure(rlc_config_t::default_rlc_am_nr_config(to_number(sn_size)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (not rlc2.configure(rlc_config_t::default_rlc_am_nr_config(to_number(sn_size)))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// after configuring entity
|
||||
TESTASSERT_EQ(0, rlc1.get_buffer_state());
|
||||
|
||||
// Push 1 SDU into RLC1
|
||||
unique_byte_buffer_t sdu;
|
||||
constexpr uint32_t payload_size = 3; // Give the SDU the size of 3 bytes
|
||||
sdu = srsran::make_byte_buffer();
|
||||
TESTASSERT(nullptr != sdu);
|
||||
sdu->msg[0] = 0; // Write the index into the buffer
|
||||
sdu->N_bytes = payload_size; // Give the SDU the size of 3 bytes
|
||||
sdu->md.pdcp_sn = 0; // PDCP SN for notifications
|
||||
rlc1.write_sdu(std::move(sdu));
|
||||
|
||||
// Read 2 PDUs. Leave last one in the tx_window.
|
||||
constexpr uint16_t n_pdus = 2;
|
||||
unique_byte_buffer_t pdu_bufs[n_pdus];
|
||||
uint32_t header_size = sn_size == rlc_am_nr_sn_size_t::size12bits ? 2 : 3;
|
||||
constexpr uint32_t so_size = 2;
|
||||
constexpr uint32_t segment_size = 1;
|
||||
uint32_t pdu_size_first = header_size + segment_size;
|
||||
uint32_t pdu_size_continued = header_size + so_size + segment_size;
|
||||
for (int i = 0; i < n_pdus; i++) {
|
||||
pdu_bufs[i] = srsran::make_byte_buffer();
|
||||
TESTASSERT(nullptr != pdu_bufs[i]);
|
||||
if (i == 0) {
|
||||
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, pdu_size_first);
|
||||
TESTASSERT_EQ(pdu_size_first, pdu_bufs[i]->N_bytes);
|
||||
} else {
|
||||
pdu_bufs[i]->N_bytes = rlc1.read_pdu(pdu_bufs[i]->msg, pdu_size_continued);
|
||||
TESTASSERT_EQ(pdu_size_continued, pdu_bufs[i]->N_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Only middle PDU into RLC2
|
||||
// First PDU is lost to trigger status report
|
||||
for (int i = 0; i < n_pdus; i++) {
|
||||
if (i == 1) {
|
||||
rlc2.write_pdu(pdu_bufs[i]->msg, pdu_bufs[i]->N_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Advance timer to trigger status report
|
||||
for (uint8_t t = 0; t < 35; t++) {
|
||||
timers.step_all();
|
||||
}
|
||||
TESTASSERT_NEQ(0, rlc2.get_buffer_state());
|
||||
|
||||
// Make sure RLC 1 has only the last segment to TX before getting the status report
|
||||
TESTASSERT_EQ(pdu_size_continued, rlc1.get_buffer_state());
|
||||
|
||||
// Get status report from RLC 2
|
||||
// and write it to RLC 1
|
||||
{
|
||||
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
|
||||
status_buf->N_bytes = rlc2.read_pdu(status_buf->msg, 100);
|
||||
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
|
||||
}
|
||||
|
||||
// Make sure RLC 1 now has the last segment to TX and the RETX of the first segment
|
||||
TESTASSERT_EQ(pdu_size_continued + pdu_size_first, rlc1.get_buffer_state());
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
// This test checks whether RLC informs upper layer when max retransmission has been reached
|
||||
// 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;
|
||||
|
||||
|
@ -2040,7 +2129,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;
|
||||
|
||||
|
@ -2169,7 +2258,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 ");
|
||||
|
@ -2275,7 +2364,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 ");
|
||||
|
@ -2331,7 +2420,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 ");
|
||||
|
@ -2387,7 +2476,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 ");
|
||||
|
@ -2505,7 +2594,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 ");
|
||||
|
@ -2660,7 +2749,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 ");
|
||||
|
@ -2752,7 +2841,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 ");
|
||||
|
@ -2848,7 +2937,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 ");
|
||||
|
@ -2955,7 +3044,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 ");
|
||||
|
@ -3062,7 +3151,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];
|
||||
|
||||
|
@ -3130,6 +3219,152 @@ 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(false, nullptr);
|
||||
timer_handler timers(8);
|
||||
byte_buffer_t pdu_bufs[NBUFS];
|
||||
|
||||
auto& test_logger = srslog::fetch_basic_logger("TESTER ");
|
||||
test_delimit_logger delimiter("Full RX window and t-Reassmbly expiry test ({} 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 < am_window_size(sn_size); ++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 PDUs into RLC 2
|
||||
// Do not write SN=0 to fill up the RX window
|
||||
if (sn != 0) {
|
||||
rlc2.write_pdu(pdu_buf->msg, pdu_buf->N_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// Step timers until reassambly timeout expires
|
||||
for (int cnt = 0; cnt < 35; cnt++) {
|
||||
timers.step_all();
|
||||
}
|
||||
|
||||
// Read status PDU
|
||||
{
|
||||
TESTASSERT_EQ(0, rlc1.get_buffer_state());
|
||||
unique_byte_buffer_t status_buf = srsran::make_byte_buffer();
|
||||
status_buf->N_bytes = rlc2.read_pdu(status_buf->msg, 1000);
|
||||
rlc1.write_pdu(status_buf->msg, status_buf->N_bytes);
|
||||
TESTASSERT_EQ(header_size + payload_size, rlc1.get_buffer_state());
|
||||
}
|
||||
// Check Rx_Status_Highest
|
||||
{
|
||||
rlc_am_nr_rx_state_t st = rx2->get_rx_state();
|
||||
TESTASSERT_EQ(2048, st.rx_highest_status);
|
||||
}
|
||||
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Setup the log message spy to intercept error and warning log entries from RLC
|
||||
|
@ -3168,6 +3403,7 @@ int main()
|
|||
TESTASSERT(segment_retx_test(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(segment_retx_and_loose_segments_test(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(retx_segment_test(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(handle_status_of_non_tx_last_segment(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(max_retx_lost_sdu_test(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(max_retx_lost_segments_test(sn_size) == SRSRAN_SUCCESS);
|
||||
TESTASSERT(discard_test(sn_size) == SRSRAN_SUCCESS);
|
||||
|
@ -3180,6 +3416,8 @@ 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;
|
||||
}
|
||||
|
|
|
@ -81,13 +81,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) {}
|
||||
|
@ -119,6 +121,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
|
||||
};
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
bool is_crnti_set() const { return crnti_set; }
|
||||
|
||||
void set_scell_activation(const std::bitset<SRSRAN_MAX_CARRIERS>& scell_mask);
|
||||
void set_srb2_activation(bool active);
|
||||
void set_drb_activation(bool active);
|
||||
|
||||
void update_mac();
|
||||
|
|
|
@ -146,6 +146,9 @@ int mac_controller::handle_crnti_ce(uint32_t temp_crnti)
|
|||
current_sched_ue_cfg.ue_bearers[i] = next_sched_ue_cfg.ue_bearers[i];
|
||||
}
|
||||
|
||||
// keep SRB2 disabled until RRCReconfComplete is received
|
||||
set_srb2_activation(false);
|
||||
|
||||
return mac->ue_set_crnti(temp_crnti, rnti, current_sched_ue_cfg);
|
||||
}
|
||||
|
||||
|
@ -229,7 +232,10 @@ void mac_controller::handle_con_reconf_complete()
|
|||
{
|
||||
current_sched_ue_cfg = next_sched_ue_cfg;
|
||||
|
||||
// Setup all bearers
|
||||
// Setup SRB2
|
||||
set_srb2_activation(true);
|
||||
|
||||
// Setup all data bearers
|
||||
apply_current_bearers_cfg();
|
||||
|
||||
// Apply SCell+Bearer changes to MAC
|
||||
|
@ -265,7 +271,9 @@ void mac_controller::handle_target_enb_ho_cmd(const asn1::rrc::rrc_conn_recfg_r8
|
|||
ue_cfg_apply_capabilities(next_sched_ue_cfg, *rrc_cfg, uecaps);
|
||||
ue_cfg_apply_reconf_complete_updates(next_sched_ue_cfg, conn_recfg, ue_cell_list);
|
||||
|
||||
// Temporarily freeze new allocations for DRBs (SRBs are needed to send RRC Reconf Message)
|
||||
// Temporarily freeze SRB2 and DRBs. SRB1 is needed to send
|
||||
// RRC Reconfiguration and receive RRC Reconfiguration Complete
|
||||
set_srb2_activation(false);
|
||||
set_drb_activation(false);
|
||||
|
||||
// Apply changes to MAC scheduler
|
||||
|
@ -329,6 +337,12 @@ void mac_controller::set_scell_activation(const std::bitset<SRSRAN_MAX_CARRIERS>
|
|||
}
|
||||
}
|
||||
|
||||
void mac_controller::set_srb2_activation(bool active)
|
||||
{
|
||||
current_sched_ue_cfg.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction =
|
||||
active ? mac_lc_ch_cfg_t::BOTH : mac_lc_ch_cfg_t::IDLE;
|
||||
}
|
||||
|
||||
void mac_controller::set_drb_activation(bool active)
|
||||
{
|
||||
for (const drb_to_add_mod_s& drb : bearer_list.get_established_drbs()) {
|
||||
|
|
|
@ -327,13 +327,24 @@ int test_s1ap_tenb_mobility(test_event test_params)
|
|||
TESTASSERT(tester.rrc.get_nof_users() == 0);
|
||||
return SRSRAN_SUCCESS;
|
||||
}
|
||||
tester.tic();
|
||||
TESTASSERT(tester.rrc.get_nof_users() == 1);
|
||||
TESTASSERT(tester.mac.ue_db.count(0x46));
|
||||
auto& mac_ue = tester.mac.ue_db[0x46];
|
||||
TESTASSERT(mac_ue.supported_cc_list[0].active);
|
||||
TESTASSERT(mac_ue.supported_cc_list[0].enb_cc_idx == 0);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb0)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(mac_ue.ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
|
||||
tester.tic();
|
||||
TESTASSERT(tester.rrc.get_nof_users() == 1);
|
||||
TESTASSERT(tester.mac.ue_db.count(0x46));
|
||||
TESTASSERT(mac_ue.supported_cc_list[0].active);
|
||||
TESTASSERT(mac_ue.supported_cc_list[0].enb_cc_idx == 0);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb0)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(mac_ue.ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
// Check Security Configuration
|
||||
TESTASSERT(tester.pdcp.bearers.count(0x46));
|
||||
TESTASSERT(tester.pdcp.bearers[0x46].count(srb_to_lcid(lte_srb::srb1)) and
|
||||
|
@ -350,6 +361,10 @@ int test_s1ap_tenb_mobility(test_event test_params)
|
|||
TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].sec_cfg.cipher_algo == as_sec_cfg.cipher_algo);
|
||||
TESTASSERT(tester.pdcp.bearers[0x46][srb_to_lcid(lte_srb::srb1)].sec_cfg.integ_algo == as_sec_cfg.integ_algo);
|
||||
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(mac_ue.ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
|
||||
// Check if S1AP Handover Request ACK send is called
|
||||
TESTASSERT(tester.s1ap.last_ho_req_ack.rnti == 0x46);
|
||||
TESTASSERT(tester.s1ap.last_ho_req_ack.ho_cmd_pdu != nullptr);
|
||||
|
@ -365,6 +380,10 @@ int test_s1ap_tenb_mobility(test_event test_params)
|
|||
TESTASSERT(dl_dcch_msg.msg.c1().type().value == dl_dcch_msg_type_c::c1_c_::types_opts::rrc_conn_recfg);
|
||||
auto& recfg_r8 = dl_dcch_msg.msg.c1().rrc_conn_recfg().crit_exts.c1().rrc_conn_recfg_r8();
|
||||
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(mac_ue.ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
|
||||
// Receives MMEStatusTransfer
|
||||
asn1::s1ap::bearers_subject_to_status_transfer_list_l bearers;
|
||||
bearers.resize(1);
|
||||
|
@ -381,6 +400,10 @@ int test_s1ap_tenb_mobility(test_event test_params)
|
|||
TESTASSERT(tester.pdcp.bearers[0x46][3].state.next_pdcp_rx_sn == 120);
|
||||
TESTASSERT(tester.pdcp.bearers[0x46][3].state.rx_hfn == 4);
|
||||
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(mac_ue.ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(mac_ue.ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == mac_lc_ch_cfg_t::IDLE);
|
||||
|
||||
// user PRACHs and sends C-RNTI CE
|
||||
sched_interface::ue_cfg_t ue_cfg{};
|
||||
ue_cfg.supported_cc_list.resize(1);
|
||||
|
@ -496,7 +519,8 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
|
|||
TESTASSERT(tester.phy.last_cfg[0].enb_cc_idx == ue_cfg->supported_cc_list[0].enb_cc_idx);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb0)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == srsenb::mac_lc_ch_cfg_t::IDLE);
|
||||
TESTASSERT(ue_cfg->ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == srsenb::mac_lc_ch_cfg_t::IDLE);
|
||||
|
||||
/* Test Case: The UE receives a duplicate C-RNTI CE. Nothing should happen */
|
||||
if (test_params == test_event::duplicate_crnti_ce) {
|
||||
|
@ -510,7 +534,8 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
|
|||
/* Test Case: Terminate first Handover. No extra messages should be sent DL. SR/CQI resources match recfg message */
|
||||
uint8_t recfg_complete[] = {0x10, 0x00};
|
||||
copy_msg_to_buffer(pdu, recfg_complete);
|
||||
tester.rrc.write_pdu(tester.rnti, srb_to_lcid(lte_srb::srb2), std::move(pdu));
|
||||
tester.rrc.write_pdu(tester.rnti, srb_to_lcid(lte_srb::srb1), std::move(pdu));
|
||||
tester.tic();
|
||||
TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
|
||||
ue_cfg = &tester.mac.ue_db[tester.rnti];
|
||||
TESTASSERT(ue_cfg->pucch_cfg.sr_configured);
|
||||
|
@ -519,6 +544,10 @@ int test_intraenb_mobility(srsran::log_sink_spy& spy, test_event test_params)
|
|||
TESTASSERT(ue_cfg->supported_cc_list[0].dl_cfg.cqi_report.pmi_idx ==
|
||||
phy_cfg_ded.cqi_report_cfg.cqi_report_periodic.setup().cqi_pmi_cfg_idx);
|
||||
TESTASSERT(ue_cfg->pucch_cfg.n_pucch == phy_cfg_ded.cqi_report_cfg.cqi_report_periodic.setup().cqi_pucch_res_idx);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb0)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb1)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[srb_to_lcid(lte_srb::srb2)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
TESTASSERT(ue_cfg->ue_bearers[drb_to_lcid(lte_drb::drb1)].direction == srsenb::mac_lc_ch_cfg_t::BOTH);
|
||||
|
||||
/* Test Case: The RRC should be able to start a new handover */
|
||||
uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x05, 0xBC, 0x80}; // PCI == 1
|
||||
|
|
Loading…
Reference in New Issue