mirror of https://github.com/PentHertz/srsLTE.git
- Added ability to the PDCP LTE entity to send PDCP Status report.
- Added handling of PDCP status report to the PDCP LTE entity. - Added test to the generation and handling of PDCP status report.
This commit is contained in:
parent
929b8650a3
commit
9bc08af880
|
@ -42,6 +42,18 @@ enum pdcp_dc_field_t {
|
|||
};
|
||||
static const char* pdcp_dc_field_text[PDCP_DC_FIELD_N_ITEMS] = {"Control PDU", "Data PDU"};
|
||||
|
||||
enum pdcp_pdu_type_t {
|
||||
PDCP_PDU_TYPE_STATUS_REPORT = 0,
|
||||
PDCP_PDU_TYPE_INTERSPERSED_ROHC_FEEDBACK_PACKET,
|
||||
PDCP_PDU_TYPE_LWA_STATUS_REPORT,
|
||||
PDCP_PDU_TYPE_LWA_END_MARKER_PACKET,
|
||||
PDCP_PDU_TYPE_N_ITEMS,
|
||||
};
|
||||
static const char* pdcp_pdu_type_text[PDCP_PDU_TYPE_N_ITEMS] = {"PDCP Report PDU",
|
||||
"Interspersed ROCH Feedback Packet",
|
||||
"LWA Status Report",
|
||||
"LWA End-marker Packet"};
|
||||
|
||||
// Taken from PDCP-Config (TS 38.331 version 15.2.1)
|
||||
enum class pdcp_t_reordering_t {
|
||||
ms0 = 0,
|
||||
|
|
|
@ -64,6 +64,10 @@ public:
|
|||
// Getter for unacknowledged PDUs. Used for handover
|
||||
std::map<uint32_t, srslte::unique_byte_buffer_t> get_buffered_pdus() override;
|
||||
|
||||
// Status report helper(s)
|
||||
bool send_status_report();
|
||||
void handle_status_report_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
|
||||
// Internal state getters/setters
|
||||
void get_bearer_state(pdcp_lte_state_t* state) override;
|
||||
void set_bearer_state(const pdcp_lte_state_t& state) override;
|
||||
|
@ -89,6 +93,7 @@ private:
|
|||
// TX Queue
|
||||
std::map<uint32_t, unique_byte_buffer_t> undelivered_sdus_queue;
|
||||
|
||||
void handle_control_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
void handle_srb_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
void handle_um_drb_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
void handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu);
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
*/
|
||||
|
||||
#include "srslte/upper/pdcp_entity_lte.h"
|
||||
#include "srslte/common/int_helpers.h"
|
||||
#include "srslte/common/security.h"
|
||||
#include <bitset>
|
||||
|
||||
namespace srslte {
|
||||
|
||||
|
@ -181,9 +183,10 @@ void pdcp_entity_lte::write_sdu(unique_byte_buffer_t sdu, int upper_sn)
|
|||
// RLC interface
|
||||
void pdcp_entity_lte::write_pdu(unique_byte_buffer_t pdu)
|
||||
{
|
||||
// drop control PDUs
|
||||
// Handle control PDUs
|
||||
if (is_drb() && is_control_pdu(pdu)) {
|
||||
logger.info("Dropping PDCP control PDU");
|
||||
logger.info("Handling PDCP control PDU");
|
||||
handle_control_pdu(std::move(pdu));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -223,8 +226,22 @@ void pdcp_entity_lte::write_pdu(unique_byte_buffer_t pdu)
|
|||
}
|
||||
}
|
||||
|
||||
// Handle control PDU
|
||||
void pdcp_entity_lte::handle_control_pdu(unique_byte_buffer_t pdu)
|
||||
{
|
||||
switch ((pdu->msg[0] >> 4) & 0x03) {
|
||||
case PDCP_PDU_TYPE_STATUS_REPORT:
|
||||
handle_status_report_pdu(std::move(pdu));
|
||||
break;
|
||||
default:
|
||||
logger.warning("Unhandled control PDU");
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Rx data/control handler functions
|
||||
* Rx data handler functions
|
||||
* Ref: 3GPP TS 36.323 v10.1.0 Section 5.1.2
|
||||
***************************************************************************/
|
||||
// SRBs (5.1.2.2)
|
||||
|
@ -333,7 +350,7 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu)
|
|||
sn_diff_last_submit,
|
||||
last_submit_diff_sn,
|
||||
reordering_window);
|
||||
return; // Discard
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int32_t)(st.next_pdcp_rx_sn - sn) > (int32_t)reordering_window) {
|
||||
|
@ -368,6 +385,127 @@ void pdcp_entity_lte::handle_am_drb_pdu(srslte::unique_byte_buffer_t pdu)
|
|||
gw->write_pdu(lcid, std::move(pdu));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Control handler functions (Status Report)
|
||||
* Ref: 3GPP TS 36.323 v10.1.0 Section 5.1.3
|
||||
***************************************************************************/
|
||||
|
||||
// Section 5.3.1 transmit operation
|
||||
bool pdcp_entity_lte::send_status_report()
|
||||
{
|
||||
// Check wether RCL AM is being used.
|
||||
if (rlc->rb_is_um(lcid)) {
|
||||
logger.error("Trying to send PDCP Status Report and RLC is not AM");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get First Missing Segment (FMS)
|
||||
uint32_t fms = 0;
|
||||
if (undelivered_sdus_queue.empty()) {
|
||||
fms = st.next_pdcp_tx_sn;
|
||||
} else {
|
||||
fms = undelivered_sdus_queue.begin()->first;
|
||||
}
|
||||
|
||||
logger.debug("PDCP Status report: FMS=%d", fms);
|
||||
|
||||
// Allocate Status Report PDU
|
||||
unique_byte_buffer_t pdu = make_byte_buffer();
|
||||
|
||||
// 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);
|
||||
|
||||
// Set FMS
|
||||
switch (cfg.sn_len) {
|
||||
case PDCP_SN_LEN_12:
|
||||
pdu->msg[0] = pdu->msg[0] | (0x0F & (fms >> 8));
|
||||
pdu->msg[1] = 0xFF & fms;
|
||||
pdu->N_bytes = 2;
|
||||
break;
|
||||
case PDCP_SN_LEN_18:
|
||||
pdu->msg[0] = pdu->msg[0] | (0x03 & (fms >> 16));
|
||||
pdu->msg[1] = 0xFF & (fms >> 8);
|
||||
pdu->msg[2] = 0xFF & fms;
|
||||
pdu->N_bytes = 3;
|
||||
break;
|
||||
default:
|
||||
logger.error("Unsupported SN length for Status Report.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add bitmap of missing PDUs, if necessary
|
||||
if (not undelivered_sdus_queue.empty()) {
|
||||
uint32_t byte_offset = 0;
|
||||
for (auto it = undelivered_sdus_queue.begin(); it != undelivered_sdus_queue.end(); it++) {
|
||||
uint32_t offset = it->first - fms;
|
||||
uint32_t bit_offset = offset % 8;
|
||||
byte_offset = offset / 8;
|
||||
pdu->msg[pdu->N_bytes + byte_offset] |= 1 << (7 - bit_offset);
|
||||
}
|
||||
pdu->N_bytes += (byte_offset + 1);
|
||||
}
|
||||
|
||||
// Write PDU to RLC
|
||||
rlc->write_sdu(lcid, std::move(pdu));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Section 5.3.2 receive operation
|
||||
void pdcp_entity_lte::handle_status_report_pdu(unique_byte_buffer_t pdu)
|
||||
{
|
||||
uint32_t fms;
|
||||
std::vector<uint32_t> acked_sns;
|
||||
uint32_t bitmap_offset;
|
||||
|
||||
// Get FMS
|
||||
switch (cfg.sn_len) {
|
||||
case PDCP_SN_LEN_12: {
|
||||
uint16_t tmp16;
|
||||
uint8_to_uint16(pdu->msg, &tmp16);
|
||||
fms = tmp16 & 0x0FFF;
|
||||
bitmap_offset = 2;
|
||||
break;
|
||||
}
|
||||
case PDCP_SN_LEN_18: {
|
||||
uint8_to_uint24(pdu->msg, &fms);
|
||||
fms = fms & 0x3FFF;
|
||||
bitmap_offset = 3;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
logger.error("Unsupported SN length for Status Report.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove all SDUs with SN smaller than FMS
|
||||
for (auto it = undelivered_sdus_queue.begin(); it != undelivered_sdus_queue.end();) {
|
||||
if (it->first < fms) {
|
||||
discard_timers_map.erase(it->first);
|
||||
it = undelivered_sdus_queue.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// Get acked SNs from bitmap
|
||||
for (uint32_t i = 0; (i + bitmap_offset) < pdu->N_bytes; i++) {
|
||||
std::bitset<8> bset{pdu->msg[bitmap_offset + i]};
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (bset[8 - j]) {
|
||||
uint32_t acked_sn = fms + i * 8 + j;
|
||||
acked_sns.push_back(acked_sn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discard ACK'ed SDUs
|
||||
for (uint32_t sn : acked_sns) {
|
||||
logger.debug("Status report ACKed SN=%d.", sn);
|
||||
undelivered_sdus_queue.erase(sn);
|
||||
discard_timers_map.erase(sn);
|
||||
}
|
||||
}
|
||||
/****************************************************************************
|
||||
* TX PDUs Queue Helper
|
||||
***************************************************************************/
|
||||
|
|
|
@ -77,6 +77,10 @@ add_executable(pdcp_lte_test_discard_sdu pdcp_lte_test_discard_sdu.cc)
|
|||
target_link_libraries(pdcp_lte_test_discard_sdu srslte_upper srslte_common)
|
||||
add_test(pdcp_lte_test_discard_sdu pdcp_lte_test_discard_sdu)
|
||||
|
||||
add_executable(pdcp_lte_test_status_report pdcp_lte_test_status_report.cc)
|
||||
target_link_libraries(pdcp_lte_test_status_report srslte_upper srslte_common)
|
||||
add_test(pdcp_lte_test_status_report pdcp_lte_test_status_report)
|
||||
|
||||
########################################################################
|
||||
# Option to run command after build (useful for remote builds)
|
||||
########################################################################
|
||||
|
|
|
@ -139,6 +139,8 @@ int run_all_tests()
|
|||
|
||||
int main()
|
||||
{
|
||||
srslog::init();
|
||||
|
||||
if (run_all_tests() != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "pdcp_lte_tests() failed\n");
|
||||
return SRSLTE_ERROR;
|
||||
|
|
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
*
|
||||
* \section COPYRIGHT
|
||||
*
|
||||
* Copyright 2013-2021 Software Radio Systems Limited
|
||||
*
|
||||
* By using this file, you agree to the terms and conditions set
|
||||
* forth in the LICENSE file which can be found at the top level of
|
||||
* the distribution.
|
||||
*
|
||||
*/
|
||||
#include "pdcp_lte_test.h"
|
||||
#include <numeric>
|
||||
|
||||
/*
|
||||
* Test correct transmission of FMS and Bitmap in status report
|
||||
*/
|
||||
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};
|
||||
|
||||
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::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();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp->notify_delivery({i});
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 0); // 0 timers should be running
|
||||
|
||||
// Generate 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
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00000001 |
|
||||
*/
|
||||
TESTASSERT(out_pdu->msg[0] == 1);
|
||||
TESTASSERT(out_pdu->msg[1] == 1);
|
||||
TESTASSERT(out_pdu->N_bytes == 2);
|
||||
|
||||
// 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();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
if (i != 257 && i != 258 && i != 271 && i != 272) {
|
||||
pdcp->notify_delivery({i});
|
||||
}
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 4);
|
||||
|
||||
// Generate 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
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00000001 |
|
||||
* | bitmap | -> | 11000000 |
|
||||
* | bitmap (cont.) | -> | 00000011 |
|
||||
*/
|
||||
TESTASSERT(out_pdu->N_bytes == 4);
|
||||
TESTASSERT(out_pdu->msg[0] == 0b00000001);
|
||||
TESTASSERT(out_pdu->msg[1] == 0b00000001);
|
||||
TESTASSERT(out_pdu->msg[2] == 0b11000000);
|
||||
TESTASSERT(out_pdu->msg[3] == 0b00000011);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test reception of status report
|
||||
*/
|
||||
int test_rx_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};
|
||||
|
||||
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::unique_byte_buffer_t status_pdu = srslte::make_byte_buffer();
|
||||
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();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
pdcp->notify_delivery({i});
|
||||
}
|
||||
|
||||
// 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();
|
||||
sdu->append_bytes(sdu1, sizeof(sdu1));
|
||||
pdcp->write_sdu(std::move(sdu));
|
||||
if (i != 257 && i != 258 && i != 271 && i != 272) {
|
||||
pdcp->notify_delivery({i});
|
||||
}
|
||||
}
|
||||
|
||||
// Check undelivered SDUs queue size
|
||||
TESTASSERT(pdcp->nof_discard_timers() == 4);
|
||||
|
||||
// Set status PDU
|
||||
// Notify up to 270 wit FMS
|
||||
// Notify 272 with bitmap
|
||||
/*
|
||||
* | D/C | TYPE | FMS | -> | 0 | 0 | 0001 |
|
||||
* | FMS | -> | 00001110 |
|
||||
* | bitmap | -> | 01000000 |
|
||||
*/
|
||||
status_pdu->N_bytes = 3;
|
||||
status_pdu->msg[0] = 0b00000001;
|
||||
status_pdu->msg[1] = 0b00001110;
|
||||
status_pdu->msg[2] = 0b01000000;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Setup all tests
|
||||
int run_all_tests()
|
||||
{
|
||||
// Setup log
|
||||
srslog::basic_logger& logger = srslog::fetch_basic_logger("PDCP LTE Test Status Report", false);
|
||||
logger.set_level(srslog::basic_levels::debug);
|
||||
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 = {};
|
||||
|
||||
TESTASSERT(test_tx_status_report(normal_init_state, logger) == 0);
|
||||
|
||||
TESTASSERT(test_rx_status_report(normal_init_state, logger) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
srslog::init();
|
||||
|
||||
if (run_all_tests() != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "pdcp_lte_tests() failed\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue