diff --git a/lib/include/srslte/upper/pdcp_entity_lte.h b/lib/include/srslte/upper/pdcp_entity_lte.h index 4610d48e9..b1b2f4c9d 100644 --- a/lib/include/srslte/upper/pdcp_entity_lte.h +++ b/lib/include/srslte/upper/pdcp_entity_lte.h @@ -21,6 +21,8 @@ #include "srslte/interfaces/ue_rrc_interfaces.h" #include "srslte/upper/pdcp_entity_base.h" +#include + namespace srsue { class gw_interface_pdcp; @@ -165,9 +167,30 @@ private: // Discard callback (discardTimer) class discard_callback; - // TX Queue + // Tx info queue uint32_t maximum_allocated_sns_window = 2048; std::unique_ptr undelivered_sdus; + + // Rx info queue + uint32_t fmc = 0; + std::set rx_counts_info; // Keeps the RX_COUNT for generation of the stauts report + void update_rx_counts_queue(uint32_t rx_count); + + /* + * Helper function to see if an SN is larger + */ + bool is_sn_larger(uint32_t sn1, uint32_t sn2) + { + int32_t diff = sn2 - sn1; + uint32_t nof_sns = 1u << cfg.sn_len; + if (diff > (int32_t)(nof_sns / 2)) { + return false; + } + if (diff <= 0 && diff > -((int32_t)(nof_sns / 2))) { + return false; + } + return true; + } }; // Discard callback (discardTimer) diff --git a/lib/src/upper/pdcp_entity_lte.cc b/lib/src/upper/pdcp_entity_lte.cc index c87e23121..6d9eac2f1 100644 --- a/lib/src/upper/pdcp_entity_lte.cc +++ b/lib/src/upper/pdcp_entity_lte.cc @@ -404,10 +404,27 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu) // Update info on last PDU submitted to upper layers st.last_submitted_pdcp_rx_sn = sn; + // Store Rx SN/COUNT + update_rx_counts_queue(count); + // Pass to upper layers gw->write_pdu(lcid, std::move(pdu)); } +void pdcp_entity_lte::update_rx_counts_queue(uint32_t rx_count) +{ + // The received COUNT is the first missing COUNT + if (rx_count == fmc) { + fmc++; + // Update the queue for the Status report bitmap, if NEXT_PDCP_RX_SN changed + while (not rx_counts_info.empty() && *rx_counts_info.begin() == fmc) { + rx_counts_info.erase(fmc); + fmc++; + } + } else { + rx_counts_info.insert(rx_count); + } +} /**************************************************************************** * Control handler functions (Status Report) * Ref: 3GPP TS 36.323 v10.1.0 Section 5.1.3 @@ -434,15 +451,10 @@ void pdcp_entity_lte::send_status_report() } // Get First Missing Segment (FMS) - uint32_t fms = 0; - if (undelivered_sdus->empty()) { - fms = st.next_pdcp_tx_sn; - } else { - fms = undelivered_sdus->get_fms(); - } + uint32_t fms = SN(fmc); // Get Last Missing Segment - uint32_t lms = undelivered_sdus->get_lms(); + uint32_t nof_sns_in_bitmap = rx_counts_info.size(); // Allocate Status Report PDU unique_byte_buffer_t pdu = make_byte_buffer(); @@ -451,7 +463,7 @@ void pdcp_entity_lte::send_status_report() return; } - logger.debug("Status report: FMS=%d, LMS=%d", fms, lms); + logger.debug("Status report: FMS=%d, Nof SNs in bitmap=%d", fms, nof_sns_in_bitmap); // Set control bit and type of PDU pdu->msg[0] = ((uint8_t)PDCP_DC_FIELD_CONTROL_PDU << 7) | ((uint8_t)PDCP_PDU_TYPE_STATUS_REPORT << 4); @@ -474,8 +486,9 @@ void pdcp_entity_lte::send_status_report() } // Add bitmap of missing PDUs, if necessary - if (not undelivered_sdus->empty()) { + if (not rx_counts_info.empty()) { // First check size of bitmap + uint32_t lms = *rx_counts_info.rbegin(); int32_t diff = lms - (fms - 1); uint32_t nof_sns = 1u << cfg.sn_len; if (diff > (int32_t)(nof_sns / 2)) { @@ -494,13 +507,12 @@ void pdcp_entity_lte::send_status_report() lms, fms - 1, bitmap_sz); - for (uint32_t offset = 0; offset < sn_diff; ++offset) { - uint32_t sn = (fms + 1 + offset) % (1u << cfg.sn_len); - if (undelivered_sdus->has_sdu(sn)) { - uint32_t bit_offset = offset % 8; - uint32_t byte_offset = offset / 8; - pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset); - } + for (uint32_t rx_count : rx_counts_info) { + logger.debug("Setting bitmap for RX_COUNT=%d", rx_count); + uint32_t offset = rx_count - (fmc + 1); + uint32_t bit_offset = offset % 8; + uint32_t byte_offset = offset / 8; + pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset); } pdu->N_bytes += bitmap_sz; } @@ -575,6 +587,7 @@ void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu) undelivered_sdus->clear_sdu(sn); } } + /**************************************************************************** * TX PDUs Queue Helper ***************************************************************************/ diff --git a/lib/test/upper/pdcp_lte_test_status_report.cc b/lib/test/upper/pdcp_lte_test_status_report.cc index 925c28731..d2509ea4d 100644 --- a/lib/test/upper/pdcp_lte_test_status_report.cc +++ b/lib/test/upper/pdcp_lte_test_status_report.cc @@ -17,40 +17,61 @@ */ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::basic_logger& logger) { - srslte::pdcp_config_t cfg = {1, - srslte::PDCP_RB_IS_DRB, - srslte::SECURITY_DIRECTION_UPLINK, - srslte::SECURITY_DIRECTION_DOWNLINK, - srslte::PDCP_SN_LEN_12, - srslte::pdcp_t_reordering_t::ms500, - srslte::pdcp_discard_timer_t::ms500, - true}; - - pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); - srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; - rlc_dummy* rlc = &pdcp_hlp.rlc; - srsue::stack_test_dummy* stack = &pdcp_hlp.stack; - - pdcp_hlp.set_pdcp_initial_state(init_state); + srslte::pdcp_config_t cfg_tx = {1, + srslte::PDCP_RB_IS_DRB, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::PDCP_SN_LEN_12, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::ms500, + true}; + + srslte::pdcp_config_t cfg_rx = {1, + srslte::PDCP_RB_IS_DRB, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::PDCP_SN_LEN_12, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::ms500, + true}; + + // Setup TX + pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); + srslte::pdcp_entity_lte* pdcp_tx = &pdcp_hlp_tx.pdcp; + rlc_dummy* rlc_tx = &pdcp_hlp_tx.rlc; + srsue::stack_test_dummy* stack_tx = &pdcp_hlp_tx.stack; + pdcp_hlp_tx.set_pdcp_initial_state(init_state); + + // Setup RX + pdcp_lte_test_helper pdcp_hlp_rx(cfg_tx, sec_cfg, logger); + srslte::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_tx.pdcp; + rlc_dummy* rlc_rx = &pdcp_hlp_tx.rlc; + srsue::stack_test_dummy* stack_rx = &pdcp_hlp_tx.stack; + pdcp_hlp_rx.set_pdcp_initial_state(init_state); + + // Tmp variable to hold the PDCP PDU srslte::unique_byte_buffer_t out_pdu = srslte::make_byte_buffer(); // Write 256 SDUs and notify imediatly -> FMS 0001 0000 0001 for (uint32_t i = 0; i < 257; i++) { srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); sdu->append_bytes(sdu1, sizeof(sdu1)); - pdcp->write_sdu(std::move(sdu)); - pdcp->notify_delivery({i}); + pdcp_tx->write_sdu(std::move(sdu)); + pdcp_tx->notify_delivery({i}); + rlc_tx->get_last_sdu(pdu); + pdcp_rx->write_pdu(std::move(pdu)); } // Check undelivered SDUs queue size - TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running + TESTASSERT(pdcp_tx->nof_discard_timers() == 0); // 0 timers should be running on TX // Generate the status report - pdcp->send_status_report(); - rlc->get_last_sdu(out_pdu); + pdcp_rx->send_status_report(); + rlc_rx->get_last_sdu(out_pdu); logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); - // Check status PDU + // Check status PDU. We received up to /* * | D/C | TYPE | FMS | -> | 0 | 0 | 0001 | * | FMS | -> | 00000001 | @@ -62,33 +83,36 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba // Write another 16 SDUs but don't notify SN=257, SN=258, SN=271 and SN=272 for (uint32_t i = 257; i < 273; i++) { srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); sdu->append_bytes(sdu1, sizeof(sdu1)); - pdcp->write_sdu(std::move(sdu)); + pdcp_tx->write_sdu(std::move(sdu)); if (i != 257 && i != 258 && i != 271 && i != 272) { - pdcp->notify_delivery({i}); + pdcp_tx->notify_delivery({i}); + rlc_tx->get_last_sdu(pdu); + pdcp_rx->write_pdu(std::move(pdu)); } } // Check undelivered SDUs queue size - TESTASSERT(pdcp->nof_discard_timers() == 4); + TESTASSERT(pdcp_tx->nof_discard_timers() == 4); // Generate the status report - pdcp->send_status_report(); - rlc->get_last_sdu(out_pdu); + pdcp_tx->send_status_report(); + rlc_tx->get_last_sdu(out_pdu); logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); // Check status PDU /* * | D/C | TYPE | FMS | -> | 0 | 0 | 0001 | * | FMS | -> | 00000001 | - * | bitmap | -> | 11000000 | + * | bitmap | -> | 01111111 | * | bitmap (cont.) | -> | 00000011 | */ TESTASSERT(out_pdu->N_bytes == 4); - TESTASSERT(out_pdu->msg[0] == 0b00000001); + TESTASSERT(out_pdu->msg[0] == 0b00000001); // FMS = 257 TESTASSERT(out_pdu->msg[1] == 0b00000001); - TESTASSERT(out_pdu->msg[2] == 0b10000000); - TESTASSERT(out_pdu->msg[3] == 0b00000110); + TESTASSERT(out_pdu->msg[2] == 0b01111111); // FMS + 1 is missing + TESTASSERT(out_pdu->msg[3] == 0b11111000); // return 0; } @@ -97,37 +121,57 @@ int test_tx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba */ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::basic_logger& logger) { - srslte::pdcp_config_t cfg = {1, - srslte::PDCP_RB_IS_DRB, - srslte::SECURITY_DIRECTION_UPLINK, - srslte::SECURITY_DIRECTION_DOWNLINK, - srslte::PDCP_SN_LEN_12, - srslte::pdcp_t_reordering_t::ms500, - srslte::pdcp_discard_timer_t::ms500, - true}; - - pdcp_lte_test_helper pdcp_hlp(cfg, sec_cfg, logger); - srslte::pdcp_entity_lte* pdcp = &pdcp_hlp.pdcp; - rlc_dummy* rlc = &pdcp_hlp.rlc; - srsue::stack_test_dummy* stack = &pdcp_hlp.stack; + srslte::pdcp_config_t cfg_tx = {1, + srslte::PDCP_RB_IS_DRB, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::PDCP_SN_LEN_12, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::ms500, + true}; + + srslte::pdcp_config_t cfg_rx = {1, + srslte::PDCP_RB_IS_DRB, + srslte::SECURITY_DIRECTION_DOWNLINK, + srslte::SECURITY_DIRECTION_UPLINK, + srslte::PDCP_SN_LEN_12, + srslte::pdcp_t_reordering_t::ms500, + srslte::pdcp_discard_timer_t::ms500, + true}; + + // Setup TX + pdcp_lte_test_helper pdcp_hlp_tx(cfg_tx, sec_cfg, logger); + srslte::pdcp_entity_lte* pdcp_tx = &pdcp_hlp_tx.pdcp; + rlc_dummy* rlc_tx = &pdcp_hlp_tx.rlc; + srsue::stack_test_dummy* stack_tx = &pdcp_hlp_tx.stack; + pdcp_hlp_tx.set_pdcp_initial_state(init_state); + + // Setup RX + pdcp_lte_test_helper pdcp_hlp_rx(cfg_tx, sec_cfg, logger); + srslte::pdcp_entity_lte* pdcp_rx = &pdcp_hlp_tx.pdcp; + rlc_dummy* rlc_rx = &pdcp_hlp_tx.rlc; + srsue::stack_test_dummy* stack_rx = &pdcp_hlp_tx.stack; + pdcp_hlp_rx.set_pdcp_initial_state(init_state); - pdcp_hlp.set_pdcp_initial_state(init_state); srslte::unique_byte_buffer_t out_pdu = srslte::make_byte_buffer(); // Write 256 SDUs and notify imediatly -> FMS 1111 1111 0000 for (uint32_t i = 0; i < 4080; i++) { srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); sdu->append_bytes(sdu1, sizeof(sdu1)); - pdcp->write_sdu(std::move(sdu)); - pdcp->notify_delivery({i}); + pdcp_tx->write_sdu(std::move(sdu)); + pdcp_tx->notify_delivery({i}); + rlc_tx->get_last_sdu(pdu); + pdcp_rx->write_pdu(std::move(pdu)); } // Check undelivered SDUs queue size - TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running + TESTASSERT(pdcp_tx->nof_discard_timers() == 0); // 0 timers should be running // Generate the status report - pdcp->send_status_report(); - rlc->get_last_sdu(out_pdu); + pdcp_rx->send_status_report(); + rlc_rx->get_last_sdu(out_pdu); logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); // Check status PDU @@ -142,19 +186,22 @@ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state, // Write another 32 SDUs but don't notify SN=4080, SN=4081, SN=14 and SN=15 for (uint32_t i = 4080; i < 4112; i++) { srslte::unique_byte_buffer_t sdu = srslte::make_byte_buffer(); + srslte::unique_byte_buffer_t pdu = srslte::make_byte_buffer(); sdu->append_bytes(sdu1, sizeof(sdu1)); - pdcp->write_sdu(std::move(sdu)); + pdcp_tx->write_sdu(std::move(sdu)); if (i != 4080 && i != 4081 && i != 4110 && i != 4111) { - pdcp->notify_delivery({i % 4096}); + pdcp_tx->notify_delivery({i % 4096}); + rlc_tx->get_last_sdu(pdu); + pdcp_rx->write_pdu(std::move(pdu)); } } // Check undelivered SDUs queue size - TESTASSERT(pdcp->nof_discard_timers() == 4); + TESTASSERT(pdcp_tx->nof_discard_timers() == 4); // Generate the status report - pdcp->send_status_report(); - rlc->get_last_sdu(out_pdu); + pdcp_rx->send_status_report(); + rlc_rx->get_last_sdu(out_pdu); logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); // Check status PDU @@ -167,10 +214,10 @@ int test_tx_wraparound_status_report(const srslte::pdcp_lte_state_t& init_state, TESTASSERT(out_pdu->N_bytes == 6); TESTASSERT(out_pdu->msg[0] == 0b00001111); TESTASSERT(out_pdu->msg[1] == 0b11110000); - TESTASSERT(out_pdu->msg[2] == 0b10000000); - TESTASSERT(out_pdu->msg[3] == 0b00000000); - TESTASSERT(out_pdu->msg[4] == 0b00000000); - TESTASSERT(out_pdu->msg[5] == 0b00000110); + TESTASSERT(out_pdu->msg[2] == 0b01111111); + TESTASSERT(out_pdu->msg[3] == 0b11111111); + TESTASSERT(out_pdu->msg[4] == 0b11111111); + TESTASSERT(out_pdu->msg[5] == 0b11111000); return 0; } /* @@ -233,20 +280,6 @@ int test_rx_status_report(const srslte::pdcp_lte_state_t& init_state, srslog::ba pdcp->write_pdu(std::move(status_pdu)); TESTASSERT(pdcp->nof_discard_timers() == 1); - - // Check if the SDUs were correctly discarded with the status report - pdcp->send_status_report(); - rlc->get_last_sdu(out_pdu); - logger.debug(out_pdu->msg, out_pdu->N_bytes, "Status PDU:"); - - // Check status PDU, only 271 is missing => FMS = 271 - /* - * | D/C | TYPE | FMS | -> | 0 | 0 | 0001 | - * | FMS | -> | 00001111 | - */ - TESTASSERT(out_pdu->N_bytes == 3); - TESTASSERT(out_pdu->msg[0] == 0b00000001); - TESTASSERT(out_pdu->msg[1] == 0b00001111); return 0; } @@ -259,7 +292,8 @@ int run_all_tests() logger.set_hex_dump_max_size(128); // This is the normal initial state. All state variables are set to zero - srslte::pdcp_lte_state_t normal_init_state = {}; + srslte::pdcp_lte_state_t normal_init_state = { + .next_pdcp_tx_sn = 0, .tx_hfn = 0, .rx_hfn = 0, .next_pdcp_rx_sn = 0, .last_submitted_pdcp_rx_sn = 4095}; TESTASSERT(test_tx_status_report(normal_init_state, logger) == 0); TESTASSERT(test_tx_wraparound_status_report(normal_init_state, logger) == 0);