Merge branch 'next' into agpl_next

master
Codebot 2 years ago committed by SRS codebot
commit b5c994dd79

@ -140,6 +140,7 @@ public:
// Window helpers // Window helpers
bool inside_tx_window(uint32_t sn) const; bool inside_tx_window(uint32_t sn) const;
bool valid_ack_sn(uint32_t sn) const;
private: private:
rlc_am* parent = nullptr; rlc_am* parent = nullptr;
@ -248,7 +249,8 @@ public:
// Data handling methods // 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_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); 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 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; 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 // 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."); RlcInfo("Cannot build data PDU - Tx window full.");
return 0; 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. * 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 the ACK_SN is inside the valid ACK_SN window (the TX window "off-by-one")
* Checking if ACK_SN > Tx_Next makes sure we do not receive a ACK/NACK for something we did not TX * 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.", RlcInfo("Received ACK with SN outside of TX_WINDOW, ignoring status report. ACK_SN=%d, TX_NEXT_ACK=%d.",
status.ack_sn, status.ack_sn,
st.tx_next_ack); st.tx_next_ack);
info_state(); info_state();
return; 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", RlcWarning("Received ACK with SN larger than TX_NEXT, ignoring status report. SN=%d, TX_NEXT_ACK=%d, TX_NEXT=%d",
status.ack_sn, status.ack_sn,
st.tx_next_ack, 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: * - if t-PollRetransmit is running:
* - stop and reset t-PollRetransmit. * - 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()) { if (poll_retransmit_timer.is_running()) {
RlcDebug("Received ACK or NACK for POLL_SN=%d. Stopping t-PollRetransmit", st.poll_sn); RlcDebug("Received ACK or NACK for POLL_SN=%d. Stopping t-PollRetransmit", st.poll_sn);
poll_retransmit_timer.stop(); 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(); 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 * 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); 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); log_rlc_am_nr_pdu_header_to_string(logger.debug, header, rb_name);
// 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. // Trigger polling if poll bit is set.
// We do this before discarding duplicate SDUs/SDU segments // 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 // Because t-PollRetransmit may transmit a PDU that was already
// received. // received.
if (header.p) { if (header.p != 0U) {
RlcInfo("status packet requested through polling bit"); RlcInfo("status packet requested through polling bit");
do_status = true; 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;
}
// Section 5.2.3.2.2, discard duplicate PDUs // Section 5.2.3.2.2, discard duplicate PDUs
if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) { if (rx_window->has_sn(header.sn) && (*rx_window)[header.sn].fully_received) {
RlcInfo("discarding duplicate SN=%d", header.sn); 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; 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"); RlcError("Rx_Highest_Status not inside RX window");
debug_state(); 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; bool restart_reassembly_timer = false;
if (rx_mod_base_nr(st.rx_next_highest) > rx_mod_base_nr(st.rx_highest_status + 1)) { 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); 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 // RX_Next <= SN < RX_Next + AM_Window_Size
return rx_mod_base_nr(sn) < rx_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 * Debug Helpers
*/ */

@ -105,7 +105,7 @@ int basic_test_tx(rlc_am* rlc, byte_buffer_t pdu_bufs[NBUFS])
int basic_test() int basic_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; byte_buffer_t pdu_bufs[NBUFS];
@ -164,7 +164,7 @@ int basic_test()
int concat_test() int concat_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); 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 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) int segment_test(bool in_seq_rx)
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -333,7 +333,7 @@ int segment_test(bool in_seq_rx)
int retx_test() int retx_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
@ -469,7 +469,7 @@ int retx_test()
// Test correct upper layer signaling when maxRetx (default 4) have been reached // Test correct upper layer signaling when maxRetx (default 4) have been reached
int max_retx_test() int max_retx_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
@ -532,7 +532,7 @@ int max_retx_test()
// Purpose: test correct retx of lost segment and pollRetx timer expiration // Purpose: test correct retx of lost segment and pollRetx timer expiration
int segment_retx_test() int segment_retx_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
@ -657,7 +657,7 @@ int resegment_test_1()
// PDUs: | 10 | 10 | 10 | 10 | 10 | // PDUs: | 10 | 10 | 10 | 10 | 10 |
// Retx PDU segments: | 5 | 5| // Retx PDU segments: | 5 | 5|
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
int len = 0; int len = 0;
@ -815,7 +815,7 @@ int resegment_test_2()
// PDUs: | 5 | 10 | 20 | 10 | 5 | // PDUs: | 5 | 10 | 20 | 10 | 5 |
// Retx PDU segments: | 10 | 10 | // Retx PDU segments: | 10 | 10 |
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
timer_handler timers(8); timer_handler timers(8);
rlc_am rlc1(srsran_rat_t::lte, srslog::fetch_basic_logger("RLC_AM_1"), 1, &tester, &tester, &timers); 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 | // PDUs: | 5 | 5| 20 | 10 | 10 |
// Retx PDU segments: | 10 | 10 | // Retx PDU segments: | 10 | 10 |
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); 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 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| // PDUs: | 5 | 5| 30 | 5 | 5|
// Retx PDU segments: | 15 | 15 | // Retx PDU segments: | 15 | 15 |
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); 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 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| // PDUs: |2|3| 40 |3|2|
// Retx PDU segments: | 20 | 20 | // Retx PDU segments: | 20 | 20 |
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); 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 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 | // PDUs: |10|10|10| 270 | 54 |
// Retx PDU segments: | 120 | 150 | // Retx PDU segments: | 120 | 150 |
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -1502,9 +1502,9 @@ int resegment_test_7()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_test7.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, nullptr);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -1687,9 +1687,9 @@ int resegment_test_8()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_test8.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, nullptr);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -1839,9 +1839,9 @@ int resegment_test_9()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_resegment_test_9.pcap", config); pcap.open("rlc_resegment_test_9.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, nullptr);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -1981,9 +1981,9 @@ int resegment_test_10()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_resegment_test_10.pcap", config); pcap.open("rlc_resegment_test_10.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2130,9 +2130,9 @@ int resegment_test_11()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_resegment_test_11.pcap", config); pcap.open("rlc_resegment_test_11.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2288,9 +2288,9 @@ int resegment_test_12()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_resegment_test_12.pcap", config); pcap.open("rlc_resegment_test_12.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2432,9 +2432,9 @@ int header_reconstruction_test(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2495,9 +2495,9 @@ int header_reconstruction_test2(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test2.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2558,9 +2558,9 @@ int header_reconstruction_test3(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test3.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2644,9 +2644,9 @@ int header_reconstruction_test4(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test4.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2721,9 +2721,9 @@ int header_reconstruction_test5(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test5.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2800,9 +2800,9 @@ int header_reconstruction_test6(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test6.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -2899,9 +2899,9 @@ int header_reconstruction_test7(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test7.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -3001,9 +3001,9 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy)
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_header_reconstruction_test8.pcap", rlc_config_t::default_rlc_am_config()); 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 #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -3035,7 +3035,7 @@ int header_reconstruction_test8(srsran::log_sink_message_spy& spy)
bool reset_test() bool reset_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -3077,7 +3077,7 @@ bool reset_test()
bool resume_test() bool resume_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -3119,7 +3119,7 @@ bool resume_test()
bool stop_test() bool stop_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); 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 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 // be enough to fit all SNs that would need to be NACKed
bool status_pdu_test() bool status_pdu_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -3254,7 +3254,7 @@ bool status_pdu_test()
// The incidence is reported to the upper layers. // The incidence is reported to the upper layers.
bool incorrect_status_pdu_test() bool incorrect_status_pdu_test()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -3319,7 +3319,7 @@ bool incorrect_status_pdu_test()
/// In contrast to the without explicitly NACK-ing specific SNs /// In contrast to the without explicitly NACK-ing specific SNs
bool incorrect_status_pdu_test2() bool incorrect_status_pdu_test2()
{ {
rlc_am_tester tester; rlc_am_tester tester(true, nullptr);
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
int len = 0; int len = 0;
@ -3430,9 +3430,9 @@ bool reestablish_test()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_reestablish_test.pcap", config); pcap.open("rlc_am_reestablish_test.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, nullptr);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -3550,9 +3550,9 @@ bool discard_test()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_reestablish_test.pcap", config); pcap.open("rlc_am_reestablish_test.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); srsran::timer_handler timers(8);
@ -3640,9 +3640,9 @@ bool poll_retx_expiry_test()
#if HAVE_PCAP #if HAVE_PCAP
rlc_pcap pcap; rlc_pcap pcap;
pcap.open("rlc_am_poll_rext_expiry_test.pcap", config); pcap.open("rlc_am_poll_rext_expiry_test.pcap", config);
rlc_am_tester tester(&pcap); rlc_am_tester tester(true, &pcap);
#else #else
rlc_am_tester tester(NULL); rlc_am_tester tester(true, NULL);
#endif #endif
srsran::timer_handler timers(8); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); auto& test_logger = srslog::fetch_basic_logger("TESTER ");
test_delimit_logger delimiter("basic segmentation ({} bit SN)", to_number(sn_size)); 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 // - Check metrics and state
int segment_retx_test(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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 // - Check metrics and state
int segment_retx_and_loose_segments_test(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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; 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 // This test checks whether RLC informs upper layer when max retransmission has been reached
// due to lost SDUs as a whole // due to lost SDUs as a whole
int max_retx_lost_sdu_test(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
int len = 0; 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 // due to lost SDU segments
int max_retx_lost_segments_test(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
int len = 0; 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 // This test checks the correct functioning of RLC discard functionality
int discard_test(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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 // Test p bit set on new TX with PollPDU
int poll_pdu(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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 // Test p bit set on new TX with PollBYTE
int poll_byte(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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. // Test p bit set on RETXes that cause an empty retx queue.
int poll_retx(rlc_am_nr_sn_size_t sn_size) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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 // 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
auto& test_logger = srslog::fetch_basic_logger("TESTER "); 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) 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); timer_handler timers(8);
byte_buffer_t pdu_bufs[NBUFS]; 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; 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() int main()
{ {
// Setup the log message spy to intercept error and warning log entries from RLC // 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_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(segment_retx_and_loose_segments_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(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_sdu_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(max_retx_lost_segments_test(sn_size) == SRSRAN_SUCCESS); TESTASSERT(max_retx_lost_segments_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(discard_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_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(rx_nack_range_with_so_ending_with_full_sdu_test(sn_size) == SRSRAN_SUCCESS);
TESTASSERT(out_of_order_status(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; return SRSRAN_SUCCESS;
} }

@ -81,13 +81,15 @@ public:
class rlc_am_tester : public srsue::pdcp_interface_rlc, public srsue::rrc_interface_rlc class rlc_am_tester : public srsue::pdcp_interface_rlc, public srsue::rrc_interface_rlc
{ {
public: 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 // PDCP interface
void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu) void write_pdu(uint32_t lcid, unique_byte_buffer_t sdu)
{ {
assert(lcid == 1); 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_bch(unique_byte_buffer_t sdu) {}
void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {} void write_pdu_bcch_dlsch(unique_byte_buffer_t sdu) {}
@ -119,6 +121,7 @@ public:
rlc_pcap* pcap = nullptr; rlc_pcap* pcap = nullptr;
bool max_retx_triggered = false; bool max_retx_triggered = false;
bool protocol_failure_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 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; } bool is_crnti_set() const { return crnti_set; }
void set_scell_activation(const std::bitset<SRSRAN_MAX_CARRIERS>& scell_mask); 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 set_drb_activation(bool active);
void update_mac(); 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]; 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); 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; 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_current_bearers_cfg();
// Apply SCell+Bearer changes to MAC // 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_capabilities(next_sched_ue_cfg, *rrc_cfg, uecaps);
ue_cfg_apply_reconf_complete_updates(next_sched_ue_cfg, conn_recfg, ue_cell_list); 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); set_drb_activation(false);
// Apply changes to MAC scheduler // 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) void mac_controller::set_drb_activation(bool active)
{ {
for (const drb_to_add_mod_s& drb : bearer_list.get_established_drbs()) { 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); TESTASSERT(tester.rrc.get_nof_users() == 0);
return SRSRAN_SUCCESS; return SRSRAN_SUCCESS;
} }
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(); tester.tic();
TESTASSERT(tester.rrc.get_nof_users() == 1); TESTASSERT(tester.rrc.get_nof_users() == 1);
TESTASSERT(tester.mac.ue_db.count(0x46)); 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].active);
TESTASSERT(mac_ue.supported_cc_list[0].enb_cc_idx == 0); 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::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 // Check Security Configuration
TESTASSERT(tester.pdcp.bearers.count(0x46)); TESTASSERT(tester.pdcp.bearers.count(0x46));
TESTASSERT(tester.pdcp.bearers[0x46].count(srb_to_lcid(lte_srb::srb1)) and 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.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(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 // 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.rnti == 0x46);
TESTASSERT(tester.s1ap.last_ho_req_ack.ho_cmd_pdu != nullptr); 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); 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(); 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 // Receives MMEStatusTransfer
asn1::s1ap::bearers_subject_to_status_transfer_list_l bearers; asn1::s1ap::bearers_subject_to_status_transfer_list_l bearers;
bearers.resize(1); 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.next_pdcp_rx_sn == 120);
TESTASSERT(tester.pdcp.bearers[0x46][3].state.rx_hfn == 4); 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 // user PRACHs and sends C-RNTI CE
sched_interface::ue_cfg_t ue_cfg{}; sched_interface::ue_cfg_t ue_cfg{};
ue_cfg.supported_cc_list.resize(1); 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(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::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::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 */ /* Test Case: The UE receives a duplicate C-RNTI CE. Nothing should happen */
if (test_params == test_event::duplicate_crnti_ce) { 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 */ /* Test Case: Terminate first Handover. No extra messages should be sent DL. SR/CQI resources match recfg message */
uint8_t recfg_complete[] = {0x10, 0x00}; uint8_t recfg_complete[] = {0x10, 0x00};
copy_msg_to_buffer(pdu, recfg_complete); 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); TESTASSERT(tester.pdcp.last_sdu.sdu == nullptr);
ue_cfg = &tester.mac.ue_db[tester.rnti]; ue_cfg = &tester.mac.ue_db[tester.rnti];
TESTASSERT(ue_cfg->pucch_cfg.sr_configured); 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 == 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); 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->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 */ /* 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 uint8_t meas_report[] = {0x08, 0x10, 0x38, 0x74, 0x00, 0x05, 0xBC, 0x80}; // PCI == 1

Loading…
Cancel
Save