2020-11-26 01:25:22 -08:00
|
|
|
/**
|
2017-05-18 03:52:29 -07:00
|
|
|
*
|
2020-11-26 01:25:22 -08:00
|
|
|
* \section COPYRIGHT
|
2017-05-18 03:52:29 -07:00
|
|
|
*
|
2021-03-19 03:45:56 -07:00
|
|
|
* Copyright 2013-2021 Software Radio Systems Limited
|
2017-05-18 03:52:29 -07:00
|
|
|
*
|
2020-11-26 01:25:22 -08:00
|
|
|
* 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.
|
2017-05-18 03:52:29 -07:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-06-25 06:24:56 -07:00
|
|
|
#include "srsran/rlc/rlc_am_lte.h"
|
2021-03-19 03:45:56 -07:00
|
|
|
#include "srsran/interfaces/ue_pdcp_interfaces.h"
|
|
|
|
#include "srsran/interfaces/ue_rrc_interfaces.h"
|
2021-10-01 03:38:33 -07:00
|
|
|
#include "srsran/rlc/rlc_am_lte_packing.h"
|
2021-03-19 03:45:56 -07:00
|
|
|
#include "srsran/srslog/event_trace.h"
|
2017-05-18 03:52:29 -07:00
|
|
|
#include <iostream>
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
#define RX_MOD_BASE(x) (((x)-vr_r) % 1024)
|
|
|
|
#define TX_MOD_BASE(x) (((x)-vt_a) % 1024)
|
2018-07-26 00:41:19 -07:00
|
|
|
#define LCID (parent->lcid)
|
|
|
|
#define RB_NAME (parent->rb_name.c_str())
|
2021-07-02 02:40:02 -07:00
|
|
|
#define MAX_SDUS_PER_PDU (128)
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
namespace srsran {
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-08-04 04:43:41 -07:00
|
|
|
using pdcp_pdu_info_lte = pdcp_pdu_info<rlc_amd_pdu_header_t>;
|
|
|
|
using rlc_amd_tx_pdu_lte = rlc_amd_tx_pdu<rlc_amd_pdu_header_t>;
|
|
|
|
using rlc_am_pdu_segment = rlc_am_pdu_segment_pool<rlc_amd_pdu_header_t>::segment_resource;
|
2021-04-10 07:20:31 -07:00
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
/****************************************************************************
|
|
|
|
* Tx subclass implementation
|
|
|
|
***************************************************************************/
|
2021-11-10 09:31:56 -08:00
|
|
|
rlc_am_lte_tx::rlc_am_lte_tx(rlc_am* parent_) :
|
2019-01-02 05:52:11 -08:00
|
|
|
parent(parent_),
|
2019-10-21 10:00:49 -07:00
|
|
|
pool(byte_buffer_pool::get_instance()),
|
|
|
|
poll_retx_timer(parent_->timers->get_unique_timer()),
|
2021-07-28 04:26:11 -07:00
|
|
|
status_prohibit_timer(parent_->timers->get_unique_timer()),
|
|
|
|
rlc_am_base_tx(&parent_->logger)
|
2021-11-10 09:31:56 -08:00
|
|
|
{
|
|
|
|
rx = dynamic_cast<rlc_am_lte_rx*>(parent->rx_base.get());
|
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_tx::configure(const rlc_config_t& cfg_)
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
2021-09-24 02:29:20 -07:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2021-03-09 05:41:46 -08:00
|
|
|
if (cfg_.tx_queue_length > MAX_SDUS_PER_RLC_PDU) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Configuring Tx queue length of %d PDUs too big. Maximum value is %d.",
|
|
|
|
cfg_.tx_queue_length,
|
|
|
|
MAX_SDUS_PER_RLC_PDU);
|
2021-03-09 05:41:46 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: add more config checks
|
2019-01-02 05:52:11 -08:00
|
|
|
cfg = cfg_.am;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
// check timers
|
2019-10-21 10:00:49 -07:00
|
|
|
if (not poll_retx_timer.is_valid() or not status_prohibit_timer.is_valid()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Configuring RLC AM TX: timers not configured");
|
2018-07-26 00:41:19 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
// configure timers
|
|
|
|
if (cfg.t_status_prohibit > 0) {
|
2019-10-21 10:00:49 -07:00
|
|
|
status_prohibit_timer.set(static_cast<uint32_t>(cfg.t_status_prohibit),
|
|
|
|
[this](uint32_t timerid) { timer_expired(timerid); });
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cfg.t_poll_retx > 0) {
|
2019-10-21 10:00:49 -07:00
|
|
|
poll_retx_timer.set(static_cast<uint32_t>(cfg.t_poll_retx), [this](uint32_t timerid) { timer_expired(timerid); });
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
|
2021-09-24 02:29:20 -07:00
|
|
|
// make sure Tx queue is empty before attempting to resize
|
2021-09-24 05:20:58 -07:00
|
|
|
empty_queue_nolock();
|
2019-01-02 05:52:11 -08:00
|
|
|
tx_sdu_queue.resize(cfg_.tx_queue_length);
|
|
|
|
|
2018-07-08 15:26:58 -07:00
|
|
|
tx_enabled = true;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
return true;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::stop()
|
2017-09-19 06:15:25 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2021-10-19 08:06:43 -07:00
|
|
|
stop_nolock();
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::stop_nolock()
|
2021-10-19 08:06:43 -07:00
|
|
|
{
|
2021-09-24 05:20:58 -07:00
|
|
|
empty_queue_nolock();
|
2021-09-24 02:29:20 -07:00
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
tx_enabled = false;
|
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
if (parent->timers != nullptr && poll_retx_timer.is_valid()) {
|
|
|
|
poll_retx_timer.stop();
|
2018-09-07 04:10:22 -07:00
|
|
|
}
|
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
if (parent->timers != nullptr && status_prohibit_timer.is_valid()) {
|
|
|
|
status_prohibit_timer.stop();
|
2018-09-07 04:10:22 -07:00
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
vt_a = 0;
|
|
|
|
vt_ms = RLC_AM_WINDOW_SIZE;
|
|
|
|
vt_s = 0;
|
|
|
|
poll_sn = 0;
|
|
|
|
|
|
|
|
pdu_without_poll = 0;
|
|
|
|
byte_without_poll = 0;
|
|
|
|
|
|
|
|
// Drop all messages in TX window
|
|
|
|
tx_window.clear();
|
|
|
|
|
|
|
|
// Drop all messages in RETX queue
|
|
|
|
retx_queue.clear();
|
2021-02-17 10:48:01 -08:00
|
|
|
|
|
|
|
// Drop all SDU info in queue
|
|
|
|
undelivered_sdu_info_queue.clear();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::empty_queue()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2021-09-24 05:20:58 -07:00
|
|
|
empty_queue_nolock();
|
2021-09-24 02:29:20 -07:00
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::empty_queue_nolock()
|
2021-09-24 02:29:20 -07:00
|
|
|
{
|
2018-07-26 00:41:19 -07:00
|
|
|
// deallocate all SDUs in transmit queue
|
2019-12-16 07:04:22 -08:00
|
|
|
while (tx_sdu_queue.size() > 0) {
|
2019-05-13 07:34:15 -07:00
|
|
|
unique_byte_buffer_t buf = tx_sdu_queue.read();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// deallocate SDU that is currently processed
|
2021-04-29 03:59:55 -07:00
|
|
|
if (tx_sdu != nullptr) {
|
|
|
|
undelivered_sdu_info_queue.clear_pdcp_sdu(tx_sdu->md.pdcp_sn);
|
|
|
|
}
|
2019-05-01 09:41:04 -07:00
|
|
|
tx_sdu.reset();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::reestablish()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-10-19 08:06:43 -07:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
stop_nolock();
|
2018-07-26 00:41:19 -07:00
|
|
|
tx_enabled = true;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_tx::do_status()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-11-10 07:25:10 -08:00
|
|
|
return rx->get_do_status();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2018-11-30 03:26:37 -08:00
|
|
|
// Function is supposed to return as fast as possible
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_tx::has_data()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2019-10-21 10:00:49 -07:00
|
|
|
return (((do_status() && not status_prohibit_timer.is_running())) || // if we have a status PDU to transmit
|
|
|
|
(not retx_queue.empty()) || // if we have a retransmission
|
2021-04-10 07:20:31 -07:00
|
|
|
(tx_sdu != nullptr) || // if we are currently transmitting a SDU
|
2021-03-22 09:51:32 -07:00
|
|
|
(tx_sdu_queue.get_n_sdus() != 0)); // or if there is a SDU queued up for transmission
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-03-04 04:27:26 -08:00
|
|
|
/**
|
|
|
|
* Helper to check if a SN has reached the max reTx threshold
|
|
|
|
*
|
|
|
|
* Caller _must_ hold the mutex when calling the function.
|
2021-03-06 07:14:18 -08:00
|
|
|
* If the retx has been reached for a SN the upper layers (i.e. RRC/PDCP) will be informed.
|
|
|
|
* The SN is _not_ removed from the Tx window, so retransmissions of that SN can still occur.
|
2021-03-04 04:27:26 -08:00
|
|
|
*
|
|
|
|
* @param sn The SN of the PDU to check
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::check_sn_reached_max_retx(uint32_t sn)
|
2021-03-04 04:27:26 -08:00
|
|
|
{
|
2021-03-06 07:14:18 -08:00
|
|
|
if (tx_window[sn].retx_count == cfg.max_retx_thresh) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("%s Signaling max number of reTx=%d for SN=%d", RB_NAME, tx_window[sn].retx_count, sn);
|
2021-03-04 04:27:26 -08:00
|
|
|
parent->rrc->max_retx_attempted();
|
2021-04-10 07:20:31 -07:00
|
|
|
srsran::pdcp_sn_vector_t pdcp_sns;
|
2021-04-12 01:42:26 -07:00
|
|
|
for (const rlc_am_pdu_segment& segment : tx_window[sn]) {
|
2021-04-10 07:20:31 -07:00
|
|
|
pdcp_sns.push_back(segment.pdcp_sn());
|
|
|
|
}
|
|
|
|
parent->pdcp->notify_failure(parent->lcid, pdcp_sns);
|
2021-09-15 02:31:24 -07:00
|
|
|
|
|
|
|
std::lock_guard<std::mutex> lock(parent->metrics_mutex);
|
2021-03-04 04:27:26 -08:00
|
|
|
parent->metrics.num_lost_pdus++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
uint32_t rlc_am_lte_tx::get_buffer_state()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-10-20 06:46:46 -07:00
|
|
|
uint32_t new_tx_queue = 0, prio_tx_queue = 0;
|
|
|
|
get_buffer_state(new_tx_queue, prio_tx_queue);
|
|
|
|
return new_tx_queue + prio_tx_queue;
|
2021-10-19 09:47:59 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::get_buffer_state(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio)
|
2021-10-21 08:36:10 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
get_buffer_state_nolock(n_bytes_newtx, n_bytes_prio);
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::get_buffer_state_nolock(uint32_t& n_bytes_newtx, uint32_t& n_bytes_prio)
|
2021-10-19 09:47:59 -07:00
|
|
|
{
|
|
|
|
n_bytes_newtx = 0;
|
|
|
|
n_bytes_prio = 0;
|
|
|
|
uint32_t n_sdus = 0;
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
if (not tx_enabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Buffer state - do_status=%s, status_prohibit_running=%s (%d/%d)",
|
|
|
|
parent->rb_name,
|
|
|
|
do_status() ? "yes" : "no",
|
|
|
|
status_prohibit_timer.is_running() ? "yes" : "no",
|
|
|
|
status_prohibit_timer.time_elapsed(),
|
|
|
|
status_prohibit_timer.duration());
|
2019-06-05 07:12:35 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Bytes needed for status report
|
2019-10-21 10:00:49 -07:00
|
|
|
if (do_status() && not status_prohibit_timer.is_running()) {
|
2021-11-10 07:25:10 -08:00
|
|
|
n_bytes_prio += rx->get_status_pdu_length();
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Buffer state - total status report: %d bytes", RB_NAME, n_bytes_prio);
|
2018-03-06 03:26:49 -08:00
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Bytes needed for retx
|
2019-12-16 07:04:22 -08:00
|
|
|
if (not retx_queue.empty()) {
|
2021-02-24 01:38:33 -08:00
|
|
|
rlc_amd_retx_t& retx = retx_queue.front();
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Buffer state - retx - SN=%d, Segment: %s, %d:%d",
|
|
|
|
RB_NAME,
|
|
|
|
retx.sn,
|
|
|
|
retx.is_segment ? "true" : "false",
|
|
|
|
retx.so_start,
|
|
|
|
retx.so_end);
|
2021-02-20 11:30:05 -08:00
|
|
|
if (tx_window.has_sn(retx.sn)) {
|
2017-11-10 03:39:28 -08:00
|
|
|
int req_bytes = required_buffer_size(retx);
|
|
|
|
if (req_bytes < 0) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("In get_buffer_state(): Removing retx.sn=%d from queue", retx.sn);
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2018-07-26 00:41:19 -07:00
|
|
|
} else {
|
2021-10-19 09:47:59 -07:00
|
|
|
n_bytes_prio += req_bytes;
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Buffer state - retx: %d bytes", n_bytes_prio);
|
2017-11-10 03:39:28 -08:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bytes needed for tx SDUs
|
2019-12-16 07:04:22 -08:00
|
|
|
if (tx_window.size() < 1024) {
|
2021-03-22 09:51:32 -07:00
|
|
|
n_sdus = tx_sdu_queue.get_n_sdus();
|
2021-10-19 09:47:59 -07:00
|
|
|
n_bytes_newtx += tx_sdu_queue.size_bytes();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_sdu != NULL) {
|
2017-06-02 03:27:01 -07:00
|
|
|
n_sdus++;
|
2021-10-19 09:47:59 -07:00
|
|
|
n_bytes_newtx += tx_sdu->N_bytes;
|
2017-06-02 03:27:01 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Room needed for header extensions? (integer rounding)
|
2018-09-12 01:57:49 -07:00
|
|
|
if (n_sdus > 1) {
|
2021-10-19 09:47:59 -07:00
|
|
|
n_bytes_newtx += ((n_sdus - 1) * 1.5) + 0.5;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2018-11-30 03:26:37 -08:00
|
|
|
// Room needed for fixed header of data PDUs
|
2021-10-19 09:47:59 -07:00
|
|
|
if (n_bytes_newtx > 0 && n_sdus > 0) {
|
|
|
|
n_bytes_newtx += 2; // Two bytes for fixed header with SN length = 10
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Total buffer state - %d SDUs (%d B)", RB_NAME, n_sdus, n_bytes_newtx);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2021-10-21 08:36:10 -07:00
|
|
|
|
|
|
|
if (bsr_callback) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Calling BSR callback - %d new_tx, %d prio bytes", RB_NAME, n_bytes_newtx, n_bytes_prio);
|
2021-10-21 08:36:10 -07:00
|
|
|
bsr_callback(parent->lcid, n_bytes_newtx, n_bytes_prio);
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::discard_sdu(uint32_t discard_sn)
|
2019-11-25 07:16:37 -08:00
|
|
|
{
|
|
|
|
if (!tx_enabled) {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-22 09:51:32 -07:00
|
|
|
|
2021-03-23 06:01:48 -07:00
|
|
|
bool discarded = tx_sdu_queue.apply_first([&discard_sn, this](unique_byte_buffer_t& sdu) {
|
|
|
|
if (sdu != nullptr && sdu->md.pdcp_sn == discard_sn) {
|
|
|
|
tx_sdu_queue.queue.pop_func(sdu);
|
|
|
|
sdu = nullptr;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
2021-03-22 09:51:32 -07:00
|
|
|
|
2021-04-28 06:04:48 -07:00
|
|
|
// Discard fails when the PDCP PDU is already in Tx window.
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s PDU with PDCP_SN=%d", discarded ? "Discarding" : "Couldn't discard", discard_sn);
|
2019-11-25 07:16:37 -08:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_tx::sdu_queue_is_full()
|
2020-07-10 13:23:35 -07:00
|
|
|
{
|
|
|
|
return tx_sdu_queue.is_full();
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
uint32_t rlc_am_lte_tx::read_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-02-02 05:20:47 -08:00
|
|
|
if (not tx_enabled) {
|
2021-03-09 08:44:27 -08:00
|
|
|
return 0;
|
2021-02-02 05:20:47 -08:00
|
|
|
}
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("MAC opportunity - %d bytes", nof_bytes);
|
|
|
|
logger->debug("tx_window size - %zu PDUs", tx_window.size());
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (not tx_enabled) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("RLC entity not active. Not generating PDU.");
|
2021-03-09 08:44:27 -08:00
|
|
|
return 0;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Tx STATUS if requested
|
2019-10-21 10:00:49 -07:00
|
|
|
if (do_status() && not status_prohibit_timer.is_running()) {
|
2021-03-09 08:44:27 -08:00
|
|
|
return build_status_pdu(payload, nof_bytes);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2018-02-06 07:59:20 -08:00
|
|
|
|
2021-01-21 09:13:09 -08:00
|
|
|
// Section 5.2.2.3 in TS 36.311, if tx_window is full and retx_queue empty, retransmit PDU
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_window.size() >= RLC_AM_WINDOW_SIZE && retx_queue.empty()) {
|
2021-05-19 09:08:58 -07:00
|
|
|
retransmit_pdu(vt_a);
|
2018-02-06 07:59:20 -08:00
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// RETX if required
|
2018-09-12 01:57:49 -07:00
|
|
|
if (not retx_queue.empty()) {
|
2021-03-09 08:44:27 -08:00
|
|
|
int32_t pdu_size = build_retx_pdu(payload, nof_bytes);
|
2018-07-23 06:44:50 -07:00
|
|
|
if (pdu_size > 0) {
|
2021-03-09 08:44:27 -08:00
|
|
|
return pdu_size;
|
2018-02-01 08:17:18 -08:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build a PDU from SDUs
|
2021-03-09 08:44:27 -08:00
|
|
|
return build_data_pdu(payload, nof_bytes);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::timer_expired(uint32_t timeout_id)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::unique_lock<std::mutex> lock(mutex);
|
2019-10-21 10:00:49 -07:00
|
|
|
if (poll_retx_timer.is_valid() && poll_retx_timer.id() == timeout_id) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Poll reTx timer expired after %dms", RB_NAME, poll_retx_timer.duration());
|
2021-05-19 09:08:58 -07:00
|
|
|
// Section 5.2.2.3 in TS 36.322, schedule PDU for retransmission if
|
|
|
|
// (a) both tx and retx buffer are empty (excluding tx'ed PDU waiting for ack), or
|
2018-09-26 07:57:07 -07:00
|
|
|
// (b) no new data PDU can be transmitted (tx window is full)
|
|
|
|
if ((retx_queue.empty() && tx_sdu_queue.size() == 0) || tx_window.size() >= RLC_AM_WINDOW_SIZE) {
|
2021-05-19 09:08:58 -07:00
|
|
|
retransmit_pdu(vt_a); // TODO: TS says to send vt_s - 1 here
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2021-05-31 03:40:17 -07:00
|
|
|
} else if (status_prohibit_timer.is_valid() && status_prohibit_timer.id() == timeout_id) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Status prohibit timer expired after %dms", RB_NAME, status_prohibit_timer.duration());
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2021-03-09 08:44:27 -08:00
|
|
|
|
2020-05-22 02:20:33 -07:00
|
|
|
if (bsr_callback) {
|
2021-10-20 06:46:46 -07:00
|
|
|
uint32_t new_tx_queue = 0, prio_tx_queue = 0;
|
2021-10-21 08:36:10 -07:00
|
|
|
get_buffer_state_nolock(new_tx_queue, prio_tx_queue);
|
2020-05-22 02:20:33 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::retransmit_pdu(uint32_t sn)
|
2018-09-24 06:15:35 -07:00
|
|
|
{
|
2021-03-22 13:34:51 -07:00
|
|
|
if (tx_window.empty()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("%s No PDU to retransmit", RB_NAME);
|
2021-03-22 13:34:51 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-19 09:08:58 -07:00
|
|
|
if (not tx_window.has_sn(sn)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("%s Can't retransmit unexisting SN=%d", RB_NAME, sn);
|
2021-03-22 13:34:51 -07:00
|
|
|
return;
|
2018-09-26 07:57:07 -07:00
|
|
|
}
|
2021-03-22 13:34:51 -07:00
|
|
|
|
|
|
|
// select first PDU in tx window for retransmission
|
2021-08-04 04:43:41 -07:00
|
|
|
rlc_amd_tx_pdu_lte& pdu = tx_window[sn];
|
2021-08-03 08:11:32 -07:00
|
|
|
|
|
|
|
// increment retx counter and inform upper layers
|
|
|
|
pdu.retx_count++;
|
|
|
|
check_sn_reached_max_retx(sn);
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Schedule SN=%d for reTx", RB_NAME, pdu.rlc_sn);
|
|
|
|
|
2021-03-22 13:34:51 -07:00
|
|
|
rlc_amd_retx_t& retx = retx_queue.push();
|
|
|
|
retx.is_segment = false;
|
|
|
|
retx.so_start = 0;
|
|
|
|
retx.so_end = pdu.buf->N_bytes;
|
|
|
|
retx.sn = pdu.rlc_sn;
|
2018-09-24 06:15:35 -07:00
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
/****************************************************************************
|
2018-07-26 00:41:19 -07:00
|
|
|
* Helper functions
|
2017-05-18 03:52:29 -07:00
|
|
|
***************************************************************************/
|
|
|
|
|
2020-02-04 08:02:38 -08:00
|
|
|
/**
|
|
|
|
* Called when building a RLC PDU for checking whether the poll bit needs
|
|
|
|
* to be set.
|
|
|
|
*
|
|
|
|
* Note that this is called from a PHY worker thread.
|
|
|
|
*
|
|
|
|
* @return True if a status PDU needs to be requested, false otherwise.
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_tx::poll_required()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2018-09-12 01:57:49 -07:00
|
|
|
if (cfg.poll_pdu > 0 && pdu_without_poll > static_cast<uint32_t>(cfg.poll_pdu)) {
|
2018-07-26 00:41:19 -07:00
|
|
|
return true;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (cfg.poll_byte > 0 && byte_without_poll > static_cast<uint32_t>(cfg.poll_byte)) {
|
2017-05-18 03:52:29 -07:00
|
|
|
return true;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
2020-02-04 08:02:38 -08:00
|
|
|
if (poll_retx_timer.is_valid() && poll_retx_timer.is_expired()) {
|
|
|
|
// re-arming of timer is handled by caller
|
|
|
|
return true;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2017-10-26 00:02:30 -07:00
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_window.size() >= RLC_AM_WINDOW_SIZE) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tx_sdu_queue.size() == 0 && retx_queue.empty()) {
|
2017-10-26 00:02:30 -07:00
|
|
|
return true;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2017-10-26 00:02:30 -07:00
|
|
|
|
|
|
|
/* According to 5.2.2.1 in 36.322 v13.3.0 a poll should be requested if
|
|
|
|
* the entire AM window is unacknowledged, i.e. no new PDU can be transmitted.
|
|
|
|
* However, it seems more appropiate to request more often if polling
|
|
|
|
* is disabled otherwise, e.g. every N PDUs.
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
if (cfg.poll_pdu == 0 && cfg.poll_byte == 0 && vt_s % rlc_am::poll_periodicity == 0) {
|
2017-10-26 00:02:30 -07:00
|
|
|
return true;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
return false;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_tx::build_status_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-07-23 05:13:10 -07:00
|
|
|
logger->debug("%s Generating status PDU. Nof bytes %d", RB_NAME, nof_bytes);
|
2021-11-10 07:25:10 -08:00
|
|
|
int pdu_len = rx->get_status_pdu(&tx_status, nof_bytes);
|
2021-07-02 02:41:11 -07:00
|
|
|
if (pdu_len == SRSRAN_ERROR) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Deferred Status PDU. Cause: Failed to acquire Rx lock", RB_NAME);
|
2021-07-02 02:41:11 -07:00
|
|
|
pdu_len = 0;
|
|
|
|
} else if (pdu_len > 0 && nof_bytes >= static_cast<uint32_t>(pdu_len)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
log_rlc_am_status_pdu_to_string(logger->info, "%s Tx status PDU - %s", &tx_status, RB_NAME);
|
2019-10-21 10:00:49 -07:00
|
|
|
if (cfg.t_status_prohibit > 0 && status_prohibit_timer.is_valid()) {
|
2018-09-12 01:57:49 -07:00
|
|
|
// re-arm timer
|
2019-10-21 10:00:49 -07:00
|
|
|
status_prohibit_timer.run();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
debug_state();
|
2018-09-12 01:57:49 -07:00
|
|
|
pdu_len = rlc_am_write_status_pdu(&tx_status, payload);
|
2019-10-21 10:00:49 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Cannot tx status PDU - %d bytes available, %d bytes required", RB_NAME, nof_bytes, pdu_len);
|
2018-09-12 01:57:49 -07:00
|
|
|
pdu_len = 0;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2018-09-12 01:57:49 -07:00
|
|
|
|
|
|
|
return pdu_len;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_tx::build_retx_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2017-11-10 03:39:28 -08:00
|
|
|
// Check there is at least 1 element before calling front()
|
|
|
|
if (retx_queue.empty()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("In build_retx_pdu(): retx_queue is empty");
|
2017-11-10 03:39:28 -08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
rlc_amd_retx_t retx = retx_queue.front();
|
|
|
|
|
|
|
|
// Sanity check - drop any retx SNs not present in tx_window
|
2021-02-20 11:30:05 -08:00
|
|
|
while (not tx_window.has_sn(retx.sn)) {
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2017-11-10 03:39:28 -08:00
|
|
|
if (!retx_queue.empty()) {
|
|
|
|
retx = retx_queue.front();
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s SN=%d not in Tx window. Ignoring retx.", RB_NAME, retx.sn);
|
2021-05-26 12:34:40 -07:00
|
|
|
if (tx_window.has_sn(vt_a)) {
|
|
|
|
// schedule next SN for retx
|
|
|
|
retransmit_pdu(vt_a);
|
|
|
|
retx = retx_queue.front();
|
|
|
|
} else {
|
|
|
|
// empty tx window, can't provide retx PDU
|
|
|
|
return 0;
|
|
|
|
}
|
2017-11-10 03:39:28 -08:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Is resegmentation needed?
|
2017-11-10 03:39:28 -08:00
|
|
|
int req_size = required_buffer_size(retx);
|
|
|
|
if (req_size < 0) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("In build_retx_pdu(): Removing retx.sn=%d from queue", retx.sn);
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2017-11-10 03:39:28 -08:00
|
|
|
return -1;
|
|
|
|
}
|
2018-09-12 01:57:49 -07:00
|
|
|
|
|
|
|
if (retx.is_segment || req_size > static_cast<int>(nof_bytes)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s build_retx_pdu - resegmentation required", RB_NAME);
|
2017-05-18 03:52:29 -07:00
|
|
|
return build_segment(payload, nof_bytes, retx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update & write header
|
|
|
|
rlc_amd_pdu_header_t new_header = tx_window[retx.sn].header;
|
2019-12-16 07:04:22 -08:00
|
|
|
new_header.p = 0;
|
2018-02-07 07:32:15 -08:00
|
|
|
|
|
|
|
// Set poll bit
|
|
|
|
pdu_without_poll++;
|
|
|
|
byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header));
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll);
|
|
|
|
logger->info("%s byte_without_poll: %d", RB_NAME, byte_without_poll);
|
2018-07-26 00:41:19 -07:00
|
|
|
if (poll_required()) {
|
2020-11-09 01:53:14 -08:00
|
|
|
new_header.p = 1;
|
|
|
|
// vt_s won't change for reTx, so don't update poll_sn
|
2017-05-18 03:52:29 -07:00
|
|
|
pdu_without_poll = 0;
|
|
|
|
byte_without_poll = 0;
|
2019-10-21 10:00:49 -07:00
|
|
|
if (poll_retx_timer.is_valid()) {
|
2020-02-04 08:02:38 -08:00
|
|
|
// re-arm timer (will be stopped when status PDU is received)
|
2019-10-21 10:00:49 -07:00
|
|
|
poll_retx_timer.run();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
uint8_t* ptr = payload;
|
2017-05-18 03:52:29 -07:00
|
|
|
rlc_am_write_data_pdu_header(&new_header, &ptr);
|
|
|
|
memcpy(ptr, tx_window[retx.sn].buf->msg, tx_window[retx.sn].buf->N_bytes);
|
|
|
|
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(payload,
|
|
|
|
tx_window[retx.sn].buf->N_bytes,
|
|
|
|
"%s Tx PDU SN=%d (%d B) (attempt %d/%d)",
|
|
|
|
RB_NAME,
|
|
|
|
retx.sn,
|
|
|
|
tx_window[retx.sn].buf->N_bytes,
|
|
|
|
tx_window[retx.sn].retx_count + 1,
|
|
|
|
cfg.max_retx_thresh);
|
|
|
|
log_rlc_amd_pdu_header_to_string(logger->debug, new_header);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
debug_state();
|
2019-12-16 07:04:22 -08:00
|
|
|
return (ptr - payload) + tx_window[retx.sn].buf->N_bytes;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_tx::build_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_retx_t retx)
|
2019-11-12 08:04:09 -08:00
|
|
|
{
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_window[retx.sn].buf == NULL) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("In build_segment: retx.sn=%d has null buffer", retx.sn);
|
2017-11-10 03:39:28 -08:00
|
|
|
return 0;
|
|
|
|
}
|
2018-09-12 01:57:49 -07:00
|
|
|
if (!retx.is_segment) {
|
2017-05-18 03:52:29 -07:00
|
|
|
retx.so_start = 0;
|
2019-12-16 07:04:22 -08:00
|
|
|
retx.so_end = tx_window[retx.sn].buf->N_bytes;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Construct new header
|
|
|
|
rlc_amd_pdu_header_t new_header;
|
|
|
|
rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header;
|
|
|
|
|
2018-02-07 07:32:15 -08:00
|
|
|
pdu_without_poll++;
|
|
|
|
byte_without_poll += (tx_window[retx.sn].buf->N_bytes + rlc_am_packed_length(&new_header));
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll);
|
|
|
|
logger->info("%s byte_without_poll: %d", RB_NAME, byte_without_poll);
|
2018-02-07 07:32:15 -08:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
new_header.dc = RLC_DC_FIELD_DATA_PDU;
|
|
|
|
new_header.rf = 1;
|
|
|
|
new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED;
|
2019-10-21 10:00:49 -07:00
|
|
|
new_header.sn = old_header.sn;
|
|
|
|
new_header.lsf = 0;
|
|
|
|
new_header.so = retx.so_start;
|
2017-05-18 03:52:29 -07:00
|
|
|
new_header.N_li = 0;
|
2019-10-21 10:00:49 -07:00
|
|
|
new_header.p = 0;
|
2018-09-12 01:57:49 -07:00
|
|
|
if (poll_required()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s setting poll bit to request status", RB_NAME);
|
2020-11-09 01:53:14 -08:00
|
|
|
new_header.p = 1;
|
|
|
|
// vt_s won't change for reTx, so don't update poll_sn
|
2019-10-21 10:00:49 -07:00
|
|
|
pdu_without_poll = 0;
|
2018-02-06 06:23:36 -08:00
|
|
|
byte_without_poll = 0;
|
2019-10-21 10:00:49 -07:00
|
|
|
if (poll_retx_timer.is_valid()) {
|
|
|
|
poll_retx_timer.run();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2018-02-06 06:23:36 -08:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
uint32_t head_len = 0;
|
2017-05-18 03:52:29 -07:00
|
|
|
uint32_t pdu_space = 0;
|
|
|
|
|
|
|
|
head_len = rlc_am_packed_length(&new_header);
|
2018-07-30 05:54:49 -07:00
|
|
|
if (old_header.N_li > 0) {
|
|
|
|
// Make sure we can fit at least one N_li element if old header contained at least one
|
|
|
|
head_len += 2;
|
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (nof_bytes <= head_len) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Cannot build a PDU segment - %d bytes available, %d bytes required for header",
|
|
|
|
RB_NAME,
|
|
|
|
nof_bytes,
|
|
|
|
head_len);
|
2017-05-18 03:52:29 -07:00
|
|
|
return 0;
|
|
|
|
}
|
2018-02-12 04:44:55 -08:00
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
pdu_space = nof_bytes - head_len;
|
|
|
|
if (pdu_space < (retx.so_end - retx.so_start)) {
|
|
|
|
retx.so_end = retx.so_start + pdu_space;
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Need to rebuild the li table & update fi based on so_start and so_end
|
2018-09-12 01:57:49 -07:00
|
|
|
if (retx.so_start == 0 && rlc_am_start_aligned(old_header.fi)) {
|
2019-12-16 07:04:22 -08:00
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
uint32_t lower = 0;
|
|
|
|
uint32_t upper = 0;
|
|
|
|
uint32_t li = 0;
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t i = 0; i < old_header.N_li; i++) {
|
2018-09-12 01:57:49 -07:00
|
|
|
if (lower >= retx.so_end) {
|
2017-05-18 03:52:29 -07:00
|
|
|
break;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
upper += old_header.li[i];
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
head_len = rlc_am_packed_length(&new_header);
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
pdu_space = nof_bytes - head_len;
|
2021-03-04 04:27:26 -08:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (pdu_space < (retx.so_end - retx.so_start)) {
|
2018-09-12 01:57:49 -07:00
|
|
|
retx.so_end = retx.so_start + pdu_space;
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed
|
2017-05-18 03:52:29 -07:00
|
|
|
li = upper - lower;
|
2018-09-12 01:57:49 -07:00
|
|
|
if (upper > retx.so_end) {
|
2017-05-18 03:52:29 -07:00
|
|
|
li -= upper - retx.so_end;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (lower < retx.so_start) {
|
2017-05-18 03:52:29 -07:00
|
|
|
li -= retx.so_start - lower;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (lower > 0 && lower == retx.so_start) {
|
2019-12-16 07:04:22 -08:00
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (upper == retx.so_end) {
|
2017-05-18 03:52:29 -07:00
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU
|
|
|
|
}
|
2018-10-02 08:00:34 -07:00
|
|
|
new_header.li[new_header.N_li] = li;
|
|
|
|
|
2021-03-04 04:27:26 -08:00
|
|
|
// only increment N_li if more SDU (segments) are/can being added
|
2018-10-02 08:00:34 -07:00
|
|
|
if (retx.so_end > upper) {
|
2021-03-04 04:27:26 -08:00
|
|
|
// Calculate header space for possible segment addition
|
|
|
|
rlc_amd_pdu_header_t tmp_header = new_header;
|
|
|
|
tmp_header.N_li++;
|
|
|
|
uint32_t tmp_header_len = rlc_am_packed_length(&tmp_header);
|
|
|
|
uint32_t tmp_data_len = retx.so_end - retx.so_start;
|
|
|
|
if (tmp_header_len + tmp_data_len <= nof_bytes) {
|
|
|
|
// Space is sufficiant to fit at least 1 B of yet another segment
|
|
|
|
new_header.N_li++;
|
|
|
|
} else {
|
|
|
|
// can't add new SDU, calculate total data length
|
|
|
|
uint32_t data_len = 0;
|
|
|
|
for (uint32_t k = 0; k <= new_header.N_li; ++k) {
|
|
|
|
data_len += new_header.li[k];
|
|
|
|
}
|
|
|
|
retx.so_end = retx.so_start + data_len;
|
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU
|
|
|
|
}
|
2018-10-02 08:00:34 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
lower += old_header.li[i];
|
|
|
|
}
|
|
|
|
|
2021-03-04 04:27:26 -08:00
|
|
|
// Santity check we don't pack beyond the provided buffer
|
2021-03-22 13:34:18 -07:00
|
|
|
srsran_expect(head_len + (retx.so_end - retx.so_start) <= nof_bytes, "The provided buffer was overflown.");
|
2021-03-04 04:27:26 -08:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Update retx_queue
|
2019-12-16 07:04:22 -08:00
|
|
|
if (tx_window[retx.sn].buf->N_bytes == retx.so_end) {
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2017-05-18 03:52:29 -07:00
|
|
|
new_header.lsf = 1;
|
2019-12-16 07:04:22 -08:00
|
|
|
if (rlc_am_end_aligned(old_header.fi)) {
|
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment is end aligned
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2019-12-16 07:04:22 -08:00
|
|
|
} else if (retx_queue.front().so_end == retx.so_end) {
|
2021-02-24 01:38:33 -08:00
|
|
|
retx_queue.pop();
|
2017-05-18 03:52:29 -07:00
|
|
|
} else {
|
|
|
|
retx_queue.front().is_segment = true;
|
2019-12-16 07:04:22 -08:00
|
|
|
retx_queue.front().so_start = retx.so_end;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Write header and pdu
|
2019-12-16 07:04:22 -08:00
|
|
|
uint8_t* ptr = payload;
|
2017-05-18 03:52:29 -07:00
|
|
|
rlc_am_write_data_pdu_header(&new_header, &ptr);
|
|
|
|
uint8_t* data = &tx_window[retx.sn].buf->msg[retx.so_start];
|
|
|
|
uint32_t len = retx.so_end - retx.so_start;
|
|
|
|
memcpy(ptr, data, len);
|
|
|
|
|
|
|
|
debug_state();
|
2019-12-16 07:04:22 -08:00
|
|
|
int pdu_len = (ptr - payload) + len;
|
2018-09-12 01:57:49 -07:00
|
|
|
if (pdu_len > static_cast<int>(nof_bytes)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("%s Retx PDU segment length error. Available: %d, Used: %d", RB_NAME, nof_bytes, pdu_len);
|
2019-11-11 02:27:42 -08:00
|
|
|
int header_len = (ptr - payload);
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Retx PDU segment length error. Actual header len: %d, Payload len: %d, N_li: %d",
|
|
|
|
RB_NAME,
|
|
|
|
header_len,
|
|
|
|
len,
|
|
|
|
new_header.N_li);
|
|
|
|
}
|
|
|
|
|
|
|
|
logger->info(payload,
|
|
|
|
pdu_len,
|
|
|
|
"%s Retx PDU segment SN=%d [so=%d] (%d B) (attempt %d/%d)",
|
|
|
|
RB_NAME,
|
|
|
|
retx.sn,
|
|
|
|
retx.so_start,
|
|
|
|
pdu_len,
|
|
|
|
tx_window[retx.sn].retx_count + 1,
|
|
|
|
cfg.max_retx_thresh);
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
return pdu_len;
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_tx::build_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2020-06-25 12:37:02 -07:00
|
|
|
if (tx_sdu == NULL && tx_sdu_queue.is_empty()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("No data available to be sent");
|
2017-05-18 03:52:29 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-02-07 11:49:04 -08:00
|
|
|
// do not build any more PDU if window is already full
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_sdu == NULL && tx_window.size() >= RLC_AM_WINDOW_SIZE) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("Tx window full.");
|
2018-02-07 11:49:04 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-09 05:41:46 -08:00
|
|
|
if (nof_bytes < RLC_AM_MIN_DATA_PDU_SIZE) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Cannot build data PDU - %d bytes available but at least %d bytes are required ",
|
|
|
|
RB_NAME,
|
|
|
|
nof_bytes,
|
|
|
|
RLC_AM_MIN_DATA_PDU_SIZE);
|
2021-03-09 05:41:46 -08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
unique_byte_buffer_t pdu = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (pdu == NULL) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Could not allocate PDU in build_data_pdu()\n");
|
|
|
|
srsran::console("tx_window size: %zd PDUs\n", tx_window.size());
|
|
|
|
srsran::console("vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d\n", vt_a, vt_ms, vt_s, poll_sn);
|
|
|
|
srsran::console("retx_queue size: %zd PDUs\n", retx_queue.size());
|
2021-04-12 01:42:26 -07:00
|
|
|
std::map<uint32_t, rlc_amd_tx_pdu>::iterator txit;
|
2019-12-16 07:04:22 -08:00
|
|
|
for (txit = tx_window.begin(); txit != tx_window.end(); txit++) {
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("tx_window - SN=%d\n", txit->first);
|
2017-06-24 11:39:33 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
exit(-1);
|
2018-02-08 08:50:19 -08:00
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Couldn't allocate PDU in build_data_pdu().");
|
2018-02-08 08:50:19 -08:00
|
|
|
return 0;
|
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2020-05-20 05:32:50 -07:00
|
|
|
rlc_amd_pdu_header_t header = {};
|
2020-09-25 06:26:14 -07:00
|
|
|
header.dc = RLC_DC_FIELD_DATA_PDU;
|
|
|
|
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
|
|
|
|
header.sn = vt_s;
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-04-12 01:42:26 -07:00
|
|
|
if (not segment_pool.has_segments()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("Can't build a PDU - No segments available");
|
2021-04-12 01:42:26 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-03-09 05:41:46 -08:00
|
|
|
// insert newly assigned SN into window and use reference for in-place operations
|
|
|
|
// NOTE: from now on, we can't return from this function anymore before increasing vt_s
|
2021-08-04 04:43:41 -07:00
|
|
|
rlc_amd_tx_pdu_lte& tx_pdu = tx_window.add_pdu(header.sn);
|
2021-03-09 05:41:46 -08:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
uint32_t head_len = rlc_am_packed_length(&header);
|
|
|
|
uint32_t to_move = 0;
|
|
|
|
uint32_t last_li = 0;
|
2021-03-19 03:45:56 -07:00
|
|
|
uint32_t pdu_space = SRSRAN_MIN(nof_bytes, pdu->get_tailroom());
|
2019-12-16 07:04:22 -08:00
|
|
|
uint8_t* pdu_ptr = pdu->msg;
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Building PDU - pdu_space: %d, head_len: %d ", RB_NAME, pdu_space, head_len);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Check for SDU segment
|
2021-03-04 04:27:26 -08:00
|
|
|
if (tx_sdu != nullptr) {
|
2019-12-16 07:04:22 -08:00
|
|
|
to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len;
|
2017-05-18 03:52:29 -07:00
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
2019-12-16 07:04:22 -08:00
|
|
|
last_li = to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
pdu->N_bytes += to_move;
|
2017-05-18 03:52:29 -07:00
|
|
|
tx_sdu->N_bytes -= to_move;
|
2019-12-16 07:04:22 -08:00
|
|
|
tx_sdu->msg += to_move;
|
2021-03-04 04:27:26 -08:00
|
|
|
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) {
|
2021-08-04 04:43:41 -07:00
|
|
|
pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
|
2021-04-12 01:42:26 -07:00
|
|
|
segment_pool.make_segment(tx_pdu, pdcp_pdu);
|
2021-03-04 04:27:26 -08:00
|
|
|
if (tx_sdu->N_bytes == 0) {
|
2021-04-12 01:42:26 -07:00
|
|
|
pdcp_pdu.fully_txed = true;
|
2021-03-04 04:27:26 -08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// PDCP SNs for the RLC SDU has been removed from the queue
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("Couldn't find PDCP_SN=%d in SDU info queue (segment)", tx_sdu->md.pdcp_sn);
|
2021-02-02 05:20:47 -08:00
|
|
|
}
|
2021-03-04 04:27:26 -08:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (tx_sdu->N_bytes == 0) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Complete SDU scheduled for tx.", RB_NAME);
|
2019-05-01 09:41:04 -07:00
|
|
|
tx_sdu.reset();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2018-09-12 01:57:49 -07:00
|
|
|
if (pdu_space > to_move) {
|
2021-03-19 03:45:56 -07:00
|
|
|
pdu_space -= SRSRAN_MIN(to_move, pdu->get_tailroom());
|
2018-09-12 01:57:49 -07:00
|
|
|
} else {
|
2017-05-18 03:52:29 -07:00
|
|
|
pdu_space = 0;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(
|
2021-03-04 04:27:26 -08:00
|
|
|
"%s Building PDU - added SDU segment from previous PDU (len:%d) - pdu_space: %d, head_len: %d header_sn=%d",
|
|
|
|
RB_NAME,
|
|
|
|
to_move,
|
|
|
|
pdu_space,
|
|
|
|
head_len,
|
|
|
|
header.sn);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Pull SDUs from queue
|
2021-07-02 02:40:02 -07:00
|
|
|
while (pdu_space > head_len && tx_sdu_queue.get_n_sdus() > 0 && header.N_li < MAX_SDUS_PER_PDU) {
|
2021-04-10 07:20:31 -07:00
|
|
|
if (not segment_pool.has_segments()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("Can't build a PDU segment - No segment resources available");
|
2021-04-12 01:42:26 -07:00
|
|
|
if (pdu_ptr != pdu->msg) {
|
2021-04-10 07:20:31 -07:00
|
|
|
break; // continue with the segments created up to this point
|
|
|
|
}
|
|
|
|
tx_window.remove_pdu(tx_pdu.rlc_sn);
|
|
|
|
return 0;
|
|
|
|
}
|
2018-09-12 01:57:49 -07:00
|
|
|
if (last_li > 0) {
|
2018-10-02 08:00:34 -07:00
|
|
|
header.li[header.N_li] = last_li;
|
|
|
|
header.N_li++;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
head_len = rlc_am_packed_length(&header);
|
2018-09-12 01:57:49 -07:00
|
|
|
if (head_len >= pdu_space) {
|
2020-10-16 05:20:35 -07:00
|
|
|
if (header.N_li > 0) {
|
|
|
|
header.N_li--;
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
break;
|
|
|
|
}
|
2021-03-22 09:51:32 -07:00
|
|
|
|
|
|
|
do {
|
|
|
|
tx_sdu = tx_sdu_queue.read();
|
|
|
|
} while (tx_sdu == nullptr && tx_sdu_queue.size() != 0);
|
|
|
|
if (tx_sdu == nullptr) {
|
|
|
|
if (header.N_li > 0) {
|
|
|
|
header.N_li--;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-04-29 03:59:55 -07:00
|
|
|
// store sdu info
|
|
|
|
if (undelivered_sdu_info_queue.has_pdcp_sn(tx_sdu->md.pdcp_sn)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("PDCP_SN=%d already marked as undelivered", tx_sdu->md.pdcp_sn);
|
2021-04-29 03:59:55 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("marking pdcp_sn=%d as undelivered (queue_len=%ld)",
|
|
|
|
tx_sdu->md.pdcp_sn,
|
|
|
|
undelivered_sdu_info_queue.nof_sdus());
|
2021-04-29 03:59:55 -07:00
|
|
|
undelivered_sdu_info_queue.add_pdcp_sdu(tx_sdu->md.pdcp_sn);
|
|
|
|
}
|
2021-08-04 04:43:41 -07:00
|
|
|
pdcp_pdu_info_lte& pdcp_pdu = undelivered_sdu_info_queue[tx_sdu->md.pdcp_sn];
|
2021-04-29 03:59:55 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
to_move = ((pdu_space - head_len) >= tx_sdu->N_bytes) ? tx_sdu->N_bytes : pdu_space - head_len;
|
2017-05-18 03:52:29 -07:00
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
2019-12-16 07:04:22 -08:00
|
|
|
last_li = to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
pdu->N_bytes += to_move;
|
2017-05-18 03:52:29 -07:00
|
|
|
tx_sdu->N_bytes -= to_move;
|
2019-12-16 07:04:22 -08:00
|
|
|
tx_sdu->msg += to_move;
|
2021-04-29 03:59:55 -07:00
|
|
|
segment_pool.make_segment(tx_pdu, pdcp_pdu);
|
|
|
|
if (tx_sdu->N_bytes == 0) {
|
|
|
|
pdcp_pdu.fully_txed = true;
|
2021-02-02 05:20:47 -08:00
|
|
|
}
|
2021-03-04 04:27:26 -08:00
|
|
|
|
2018-09-26 07:57:07 -07:00
|
|
|
if (tx_sdu->N_bytes == 0) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Complete SDU scheduled for tx. PDCP SN=%d", RB_NAME, tx_sdu->md.pdcp_sn);
|
2019-05-01 09:41:04 -07:00
|
|
|
tx_sdu.reset();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2019-12-16 07:04:22 -08:00
|
|
|
if (pdu_space > to_move) {
|
2017-05-18 03:52:29 -07:00
|
|
|
pdu_space -= to_move;
|
2018-09-12 01:57:49 -07:00
|
|
|
} else {
|
2017-05-18 03:52:29 -07:00
|
|
|
pdu_space = 0;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Building PDU - added SDU segment (len:%d) - pdu_space: %d, head_len: %d ",
|
|
|
|
RB_NAME,
|
|
|
|
to_move,
|
|
|
|
pdu_space,
|
|
|
|
head_len);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2018-03-27 12:33:26 -07:00
|
|
|
// Make sure, at least one SDU (segment) has been added until this point
|
|
|
|
if (pdu->N_bytes == 0) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Generated empty RLC PDU.");
|
2018-03-27 12:33:26 -07:00
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (tx_sdu != NULL) {
|
2017-05-18 03:52:29 -07:00
|
|
|
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Set Poll bit
|
|
|
|
pdu_without_poll++;
|
|
|
|
byte_without_poll += (pdu->N_bytes + head_len);
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s pdu_without_poll: %d", RB_NAME, pdu_without_poll);
|
|
|
|
logger->debug("%s byte_without_poll: %d", RB_NAME, byte_without_poll);
|
2019-12-16 07:04:22 -08:00
|
|
|
if (poll_required()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s setting poll bit to request status", RB_NAME);
|
2017-05-18 03:52:29 -07:00
|
|
|
header.p = 1;
|
|
|
|
poll_sn = vt_s;
|
|
|
|
pdu_without_poll = 0;
|
|
|
|
byte_without_poll = 0;
|
2019-10-21 10:00:49 -07:00
|
|
|
if (poll_retx_timer.is_valid()) {
|
|
|
|
poll_retx_timer.run();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-03-09 05:41:46 -08:00
|
|
|
// Update Tx window
|
2021-03-22 09:51:32 -07:00
|
|
|
vt_s = (vt_s + 1) % MOD;
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-03-09 05:41:46 -08:00
|
|
|
// Write final header and TX
|
|
|
|
tx_pdu.buf = std::move(pdu);
|
|
|
|
tx_pdu.header = header;
|
|
|
|
const byte_buffer_t* buffer_ptr = tx_pdu.buf.get();
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
uint8_t* ptr = payload;
|
2017-05-18 03:52:29 -07:00
|
|
|
rlc_am_write_data_pdu_header(&header, &ptr);
|
2019-05-01 09:41:04 -07:00
|
|
|
memcpy(ptr, buffer_ptr->msg, buffer_ptr->N_bytes);
|
|
|
|
int total_len = (ptr - payload) + buffer_ptr->N_bytes;
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(payload, total_len, "%s Tx PDU SN=%d (%d B)", RB_NAME, header.sn, total_len);
|
|
|
|
log_rlc_amd_pdu_header_to_string(logger->debug, header);
|
2017-05-18 03:52:29 -07:00
|
|
|
debug_state();
|
2020-12-11 07:39:37 -08:00
|
|
|
|
2018-10-02 08:00:34 -07:00
|
|
|
return total_len;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::handle_control_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
2021-02-02 05:20:47 -08:00
|
|
|
if (not tx_enabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
// Local variables for handling Status PDU will be updated with lock
|
|
|
|
rlc_status_pdu_t status = {};
|
|
|
|
uint32_t i = 0;
|
|
|
|
uint32_t vt_s_local = 0;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(payload, nof_bytes, "%s Rx control PDU", RB_NAME);
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
rlc_am_read_status_pdu(payload, nof_bytes, &status);
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
log_rlc_am_status_pdu_to_string(logger->info, "%s Rx Status PDU: %s", &status, RB_NAME);
|
2021-06-14 03:33:57 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
// make sure ACK_SN is within our Tx window
|
|
|
|
if (((MOD + status.ack_sn - vt_a) % MOD > RLC_AM_WINDOW_SIZE) ||
|
|
|
|
((MOD + vt_s - status.ack_sn) % MOD > RLC_AM_WINDOW_SIZE)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("%s Received invalid status PDU (ack_sn=%d, vt_a=%d, vt_s=%d). Dropping PDU.",
|
|
|
|
RB_NAME,
|
|
|
|
status.ack_sn,
|
|
|
|
vt_a,
|
|
|
|
vt_s);
|
2021-06-15 02:59:39 -07:00
|
|
|
return;
|
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
// Sec 5.2.2.2, stop poll reTx timer if status PDU comprises a positive _or_ negative acknowledgement
|
|
|
|
// for the RLC data PDU with sequence number poll_sn
|
|
|
|
if (poll_retx_timer.is_valid() && (TX_MOD_BASE(poll_sn) < TX_MOD_BASE(status.ack_sn))) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s Stopping pollRetx timer", RB_NAME);
|
2021-06-15 02:59:39 -07:00
|
|
|
poll_retx_timer.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
// flush retx queue to avoid unordered SNs, we expect the Rx to request lost PDUs again
|
|
|
|
if (status.N_nack > 0) {
|
|
|
|
retx_queue.clear();
|
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
i = vt_a;
|
|
|
|
vt_s_local = vt_s;
|
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
bool update_vt_a = true;
|
|
|
|
while (TX_MOD_BASE(i) < TX_MOD_BASE(status.ack_sn) && TX_MOD_BASE(i) < TX_MOD_BASE(vt_s_local)) {
|
2018-07-26 00:41:19 -07:00
|
|
|
bool nack = false;
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t j = 0; j < status.N_nack; j++) {
|
|
|
|
if (status.nacks[j].nack_sn == i) {
|
|
|
|
nack = true;
|
2018-07-26 00:41:19 -07:00
|
|
|
update_vt_a = false;
|
2021-06-15 02:59:39 -07:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2021-02-20 11:30:05 -08:00
|
|
|
if (tx_window.has_sn(i)) {
|
|
|
|
auto& pdu = tx_window[i];
|
2021-08-03 08:11:32 -07:00
|
|
|
|
|
|
|
// add to retx queue if it's not already there
|
2021-04-07 11:37:42 -07:00
|
|
|
if (not retx_queue.has_sn(i)) {
|
2021-08-03 08:11:32 -07:00
|
|
|
// increment Retx counter and inform upper layers if needed
|
|
|
|
pdu.retx_count++;
|
|
|
|
check_sn_reached_max_retx(i);
|
|
|
|
|
2021-02-24 01:38:33 -08:00
|
|
|
rlc_amd_retx_t& retx = retx_queue.push();
|
2021-03-22 13:34:18 -07:00
|
|
|
srsran_expect(tx_window[i].rlc_sn == i, "Incorrect RLC SN=%d!=%d being accessed", tx_window[i].rlc_sn, i);
|
2021-03-08 14:54:32 -08:00
|
|
|
retx.sn = i;
|
|
|
|
retx.is_segment = false;
|
|
|
|
retx.so_start = 0;
|
|
|
|
retx.so_end = pdu.buf->N_bytes;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (status.nacks[j].has_so) {
|
2018-07-26 00:41:19 -07:00
|
|
|
// sanity check
|
2021-02-20 11:30:05 -08:00
|
|
|
if (status.nacks[j].so_start >= pdu.buf->N_bytes) {
|
2018-07-26 00:41:19 -07:00
|
|
|
// print error but try to send original PDU again
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(
|
2021-02-20 11:30:05 -08:00
|
|
|
"SO_start is larger than original PDU (%d >= %d)", status.nacks[j].so_start, pdu.buf->N_bytes);
|
2018-07-26 00:41:19 -07:00
|
|
|
status.nacks[j].so_start = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// check for special SO_end value
|
2019-12-16 07:04:22 -08:00
|
|
|
if (status.nacks[j].so_end == 0x7FFF) {
|
2021-02-20 11:30:05 -08:00
|
|
|
status.nacks[j].so_end = pdu.buf->N_bytes;
|
2019-12-16 07:04:22 -08:00
|
|
|
} else {
|
2018-07-26 00:41:19 -07:00
|
|
|
retx.so_end = status.nacks[j].so_end + 1;
|
|
|
|
}
|
|
|
|
|
2021-02-20 11:30:05 -08:00
|
|
|
if (status.nacks[j].so_start < pdu.buf->N_bytes && status.nacks[j].so_end <= pdu.buf->N_bytes) {
|
2019-12-16 07:04:22 -08:00
|
|
|
retx.is_segment = true;
|
|
|
|
retx.so_start = status.nacks[j].so_start;
|
2018-07-26 00:41:19 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("%s invalid segment NACK received for SN %d. so_start: %d, so_end: %d, N_bytes: %d",
|
|
|
|
RB_NAME,
|
|
|
|
i,
|
|
|
|
status.nacks[j].so_start,
|
|
|
|
status.nacks[j].so_end,
|
|
|
|
pdu.buf->N_bytes);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
}
|
2021-04-07 11:37:42 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s NACKed SN=%d already considered for retransmission", RB_NAME, i);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2021-03-04 04:27:26 -08:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("%s NACKed SN=%d already removed from Tx window", RB_NAME, i);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (!nack) {
|
2021-03-04 04:27:26 -08:00
|
|
|
// ACKed SNs get marked and removed from tx_window so PDCP get's only notified once
|
2021-06-15 02:59:39 -07:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2021-02-20 11:30:05 -08:00
|
|
|
if (tx_window.has_sn(i)) {
|
2021-04-12 01:42:26 -07:00
|
|
|
update_notification_ack_info(i);
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Tx PDU SN=%zd being removed from tx window", i);
|
2021-03-04 04:27:26 -08:00
|
|
|
tx_window.remove_pdu(i);
|
|
|
|
}
|
|
|
|
// Advance window if possible
|
|
|
|
if (update_vt_a) {
|
|
|
|
vt_a = (vt_a + 1) % MOD;
|
|
|
|
vt_ms = (vt_ms + 1) % MOD;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
}
|
2019-12-16 07:04:22 -08:00
|
|
|
i = (i + 1) % MOD;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
2021-06-15 02:59:39 -07:00
|
|
|
{
|
|
|
|
// Make sure vt_a points to valid SN
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
if (not tx_window.empty() && not tx_window.has_sn(vt_a)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("%s vt_a=%d points to invalid position in Tx window.", RB_NAME, vt_a);
|
2021-06-15 02:59:39 -07:00
|
|
|
parent->rrc->protocol_failure();
|
|
|
|
}
|
2021-03-22 13:34:51 -07:00
|
|
|
}
|
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
debug_state();
|
|
|
|
|
2021-02-20 13:22:16 -08:00
|
|
|
// Notify PDCP without holding Tx mutex
|
|
|
|
if (not notify_info_vec.empty()) {
|
|
|
|
parent->pdcp->notify_delivery(parent->lcid, notify_info_vec);
|
|
|
|
}
|
2021-02-23 14:03:35 -08:00
|
|
|
notify_info_vec.clear();
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
2021-01-15 05:07:30 -08:00
|
|
|
/*
|
|
|
|
* Helper function to detect whether a PDU has been fully ack'ed and the PDCP needs to be notified about it
|
|
|
|
* @tx_pdu: RLC PDU that was ack'ed.
|
|
|
|
* @notify_info_vec: Vector which will keep track of the PDCP PDU SNs that have been fully ack'ed.
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::update_notification_ack_info(uint32_t rlc_sn)
|
2021-01-15 05:07:30 -08:00
|
|
|
{
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Updating ACK info: RLC SN=%d, number of notified SDU=%ld, number of undelivered SDUs=%ld",
|
|
|
|
rlc_sn,
|
|
|
|
notify_info_vec.size(),
|
|
|
|
undelivered_sdu_info_queue.nof_sdus());
|
2021-01-29 03:28:34 -08:00
|
|
|
// Iterate over all undelivered SDUs
|
2021-04-12 01:42:26 -07:00
|
|
|
if (not tx_window.has_sn(rlc_sn)) {
|
2021-02-20 06:08:00 -08:00
|
|
|
return;
|
|
|
|
}
|
2021-04-12 01:42:26 -07:00
|
|
|
auto& acked_pdu = tx_window[rlc_sn];
|
2021-04-11 13:35:47 -07:00
|
|
|
// Iterate over all PDCP SNs of the same RLC PDU that were TX'ed
|
2021-04-12 01:42:26 -07:00
|
|
|
for (rlc_am_pdu_segment& acked_segment : acked_pdu) {
|
2021-04-28 06:04:48 -07:00
|
|
|
uint32_t pdcp_sn = acked_segment.pdcp_sn();
|
|
|
|
if (pdcp_sn == rlc_am_pdu_segment::invalid_pdcp_sn) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("ACKed segment in RLC_SN=%d already discarded in PDCP. No need to notify the PDCP.", rlc_sn);
|
2021-04-28 06:04:48 -07:00
|
|
|
continue;
|
|
|
|
}
|
2021-08-04 04:43:41 -07:00
|
|
|
pdcp_pdu_info_lte& info = undelivered_sdu_info_queue[pdcp_sn];
|
2021-04-10 07:20:31 -07:00
|
|
|
|
2021-04-11 13:35:47 -07:00
|
|
|
// Remove RLC SN from PDCP PDU undelivered list
|
2021-04-12 01:42:26 -07:00
|
|
|
info.ack_segment(acked_segment);
|
2021-04-11 13:35:47 -07:00
|
|
|
|
|
|
|
// Check whether the SDU was fully acked
|
2021-04-16 04:49:18 -07:00
|
|
|
if (info.fully_acked()) {
|
2021-02-02 05:20:47 -08:00
|
|
|
// Check if all SNs were ACK'ed
|
2021-04-11 13:35:47 -07:00
|
|
|
if (not notify_info_vec.full()) {
|
|
|
|
notify_info_vec.push_back(pdcp_sn);
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("Can't notify delivery of PDCP_SN=%d.", pdcp_sn);
|
2021-01-29 03:28:34 -08:00
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Erasing SDU info: PDCP_SN=%d", pdcp_sn);
|
2021-04-11 13:35:47 -07:00
|
|
|
undelivered_sdu_info_queue.clear_pdcp_sdu(pdcp_sn);
|
2021-01-15 05:07:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_tx::debug_state()
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s vt_a = %d, vt_ms = %d, vt_s = %d, poll_sn = %d", RB_NAME, vt_a, vt_ms, vt_s, poll_sn);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_tx::required_buffer_size(const rlc_amd_retx_t& retx)
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
|
|
|
if (!retx.is_segment) {
|
2021-02-20 11:30:05 -08:00
|
|
|
if (tx_window.has_sn(retx.sn)) {
|
2018-07-26 00:41:19 -07:00
|
|
|
if (tx_window[retx.sn].buf) {
|
|
|
|
return rlc_am_packed_length(&tx_window[retx.sn].header) + tx_window[retx.sn].buf->N_bytes;
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("retx.sn=%d has null ptr in required_buffer_size()", retx.sn);
|
2018-07-26 00:41:19 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("retx.sn=%d does not exist in required_buffer_size()", retx.sn);
|
2018-07-26 00:41:19 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Construct new header
|
|
|
|
rlc_amd_pdu_header_t new_header;
|
|
|
|
rlc_amd_pdu_header_t old_header = tx_window[retx.sn].header;
|
|
|
|
|
|
|
|
new_header.dc = RLC_DC_FIELD_DATA_PDU;
|
|
|
|
new_header.rf = 1;
|
|
|
|
new_header.p = 0;
|
|
|
|
new_header.fi = RLC_FI_FIELD_NOT_START_OR_END_ALIGNED;
|
|
|
|
new_header.sn = old_header.sn;
|
|
|
|
new_header.lsf = 0;
|
|
|
|
new_header.so = retx.so_start;
|
|
|
|
new_header.N_li = 0;
|
|
|
|
|
|
|
|
// Need to rebuild the li table & update fi based on so_start and so_end
|
2019-12-16 07:04:22 -08:00
|
|
|
if (retx.so_start != 0 && rlc_am_start_aligned(old_header.fi)) {
|
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment is start aligned
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
uint32_t lower = 0;
|
|
|
|
uint32_t upper = 0;
|
|
|
|
uint32_t li = 0;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t i = 0; i < old_header.N_li; i++) {
|
|
|
|
if (lower >= retx.so_end) {
|
2018-07-26 00:41:19 -07:00
|
|
|
break;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
upper += old_header.li[i];
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (upper > retx.so_start && lower < retx.so_end) { // Current SDU is needed
|
2018-07-26 00:41:19 -07:00
|
|
|
li = upper - lower;
|
2018-09-12 01:57:49 -07:00
|
|
|
if (upper > retx.so_end) {
|
2018-07-26 00:41:19 -07:00
|
|
|
li -= upper - retx.so_end;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (lower < retx.so_start) {
|
2018-07-26 00:41:19 -07:00
|
|
|
li -= retx.so_start - lower;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (lower > 0 && lower == retx.so_start) {
|
2019-12-16 07:04:22 -08:00
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_END_ALIGNED; // segment start is aligned with this SDU
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
if (upper == retx.so_end) {
|
2018-07-26 00:41:19 -07:00
|
|
|
new_header.fi &= RLC_FI_FIELD_NOT_START_ALIGNED; // segment end is aligned with this SDU
|
|
|
|
}
|
|
|
|
new_header.li[new_header.N_li++] = li;
|
|
|
|
}
|
|
|
|
|
|
|
|
lower += old_header.li[i];
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
// if(tx_window[retx.sn].buf->N_bytes != retx.so_end) {
|
|
|
|
// if(new_header.N_li > 0)
|
|
|
|
// new_header.N_li--; // No li for last segment
|
|
|
|
// }
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
return rlc_am_packed_length(&new_header) + (retx.so_end - retx.so_start);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Rx subclass implementation
|
|
|
|
***************************************************************************/
|
2021-11-10 09:31:56 -08:00
|
|
|
rlc_am_lte_rx::rlc_am_lte_rx(rlc_am* parent_) :
|
2019-06-06 03:00:48 -07:00
|
|
|
parent(parent_),
|
|
|
|
pool(byte_buffer_pool::get_instance()),
|
2021-07-28 04:26:11 -07:00
|
|
|
reordering_timer(parent_->timers->get_unique_timer()),
|
2021-07-29 09:00:10 -07:00
|
|
|
rlc_am_base_rx(parent_, &parent_->logger)
|
2021-11-10 09:31:56 -08:00
|
|
|
{
|
|
|
|
tx = dynamic_cast<rlc_am_lte_tx*>(parent->tx_base.get());
|
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
rlc_am_lte_rx::~rlc_am_lte_rx() {}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_rx::configure(const rlc_config_t& cfg_)
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
|
|
|
// TODO: add config checks
|
2021-07-06 09:45:03 -07:00
|
|
|
cfg = cfg_.am;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
// check timers
|
2019-10-21 10:00:49 -07:00
|
|
|
if (not reordering_timer.is_valid()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Configuring RLC AM TX: timers not configured");
|
2018-07-26 00:41:19 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
// configure timer
|
|
|
|
if (cfg.t_reordering > 0) {
|
2019-10-21 10:00:49 -07:00
|
|
|
reordering_timer.set(static_cast<uint32_t>(cfg.t_reordering), [this](uint32_t tid) { timer_expired(tid); });
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::reestablish()
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::stop()
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2018-09-07 04:10:22 -07:00
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
if (parent->timers != nullptr && reordering_timer.is_valid()) {
|
|
|
|
reordering_timer.stop();
|
2018-09-07 04:10:22 -07:00
|
|
|
}
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-05-01 09:41:04 -07:00
|
|
|
rx_sdu.reset();
|
2018-07-26 00:41:19 -07:00
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
vr_r = 0;
|
|
|
|
vr_mr = RLC_AM_WINDOW_SIZE;
|
|
|
|
vr_x = 0;
|
|
|
|
vr_ms = 0;
|
|
|
|
vr_h = 0;
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
poll_received = false;
|
|
|
|
do_status = false;
|
|
|
|
|
|
|
|
// Drop all messages in RX segments
|
|
|
|
rx_segments.clear();
|
|
|
|
|
|
|
|
// Drop all messages in RX window
|
|
|
|
rx_window.clear();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-07-29 09:00:10 -07:00
|
|
|
/** Called from stack thread when MAC has received a new RLC PDU
|
|
|
|
*
|
|
|
|
* @param payload Pointer to payload
|
|
|
|
* @param nof_bytes Payload length
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::handle_data_pdu(uint8_t* payload, uint32_t nof_bytes)
|
2021-07-29 09:00:10 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
|
|
|
|
rlc_amd_pdu_header_t header = {};
|
|
|
|
uint32_t payload_len = nof_bytes;
|
|
|
|
rlc_am_read_data_pdu_header(&payload, &payload_len, &header);
|
|
|
|
if (payload_len > nof_bytes) {
|
|
|
|
logger->info("Dropping corrupted PDU (%d B). Remaining length after header %d B.", nof_bytes, payload_len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (header.rf != 0) {
|
|
|
|
handle_data_pdu_segment(payload, payload_len, header);
|
|
|
|
} else {
|
|
|
|
handle_data_pdu_full(payload, payload_len, header);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-04 08:02:38 -08:00
|
|
|
/** Called from stack thread when MAC has received a new RLC PDU
|
|
|
|
*
|
|
|
|
* @param payload Pointer to payload
|
|
|
|
* @param nof_bytes Payload length
|
|
|
|
* @param header Reference to PDU header (unpacked by caller)
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::handle_data_pdu_full(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header)
|
2018-09-07 04:08:45 -07:00
|
|
|
{
|
2021-04-12 01:42:26 -07:00
|
|
|
std::map<uint32_t, rlc_amd_rx_pdu>::iterator it;
|
2018-09-07 04:08:45 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(payload, nof_bytes, "%s Rx data PDU SN=%d (%d B)", RB_NAME, header.sn, nof_bytes);
|
|
|
|
log_rlc_amd_pdu_header_to_string(logger->debug, header);
|
2018-09-07 04:08:45 -07:00
|
|
|
|
2019-06-28 08:02:49 -07:00
|
|
|
// sanity check for segments not exceeding PDU length
|
|
|
|
if (header.N_li > 0) {
|
|
|
|
uint32_t segments_len = 0;
|
|
|
|
for (uint32_t i = 0; i < header.N_li; i++) {
|
|
|
|
segments_len += header.li[i];
|
|
|
|
if (segments_len > nof_bytes) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("Dropping corrupted PDU (segments_len=%d > pdu_len=%d)", segments_len, nof_bytes);
|
2019-06-28 08:02:49 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
if (!inside_rx_window(header.sn)) {
|
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2018-09-07 04:08:45 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr);
|
2018-09-07 04:08:45 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-04 04:27:26 -08:00
|
|
|
if (rx_window.has_sn(header.sn)) {
|
2019-12-16 07:04:22 -08:00
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2018-09-07 04:08:45 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Discarding duplicate SN=%d", RB_NAME, header.sn);
|
2018-09-07 04:08:45 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write to rx window
|
2021-04-12 01:42:26 -07:00
|
|
|
rlc_amd_rx_pdu& pdu = rx_window.add_pdu(header.sn);
|
|
|
|
pdu.buf = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (pdu.buf == NULL) {
|
2018-09-07 04:08:45 -07:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu().\n");
|
2018-09-07 04:08:45 -07:00
|
|
|
exit(-1);
|
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu().");
|
2021-03-04 04:27:26 -08:00
|
|
|
rx_window.remove_pdu(header.sn);
|
2018-09-07 04:08:45 -07:00
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
}
|
2020-12-16 13:07:04 -08:00
|
|
|
pdu.buf->set_timestamp();
|
2018-09-07 04:08:45 -07:00
|
|
|
|
|
|
|
// check available space for payload
|
|
|
|
if (nof_bytes > pdu.buf->get_tailroom()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("%s Discarding SN=%d of size %d B (available space %d B)",
|
|
|
|
RB_NAME,
|
|
|
|
header.sn,
|
|
|
|
nof_bytes,
|
|
|
|
pdu.buf->get_tailroom());
|
2018-09-07 04:08:45 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
memcpy(pdu.buf->msg, payload, nof_bytes);
|
2019-12-16 07:04:22 -08:00
|
|
|
pdu.buf->N_bytes = nof_bytes;
|
|
|
|
pdu.header = header;
|
2018-09-07 04:08:45 -07:00
|
|
|
|
|
|
|
// Update vr_h
|
2019-12-16 07:04:22 -08:00
|
|
|
if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) {
|
2018-09-07 04:08:45 -07:00
|
|
|
vr_h = (header.sn + 1) % MOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update vr_ms
|
2021-03-04 04:27:26 -08:00
|
|
|
while (rx_window.has_sn(vr_ms)) {
|
2019-12-16 07:04:22 -08:00
|
|
|
vr_ms = (vr_ms + 1) % MOD;
|
2018-09-07 04:08:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check poll bit
|
2018-09-12 01:57:49 -07:00
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2018-09-07 04:08:45 -07:00
|
|
|
poll_received = true;
|
|
|
|
|
|
|
|
// 36.322 v10 Section 5.2.3
|
2018-10-02 08:00:34 -07:00
|
|
|
if (RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) {
|
2018-09-07 04:08:45 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
|
|
|
// else delay for reordering timer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reassemble and deliver SDUs
|
|
|
|
reassemble_rx_sdus();
|
|
|
|
|
|
|
|
// Update reordering variables and timers (36.322 v10.0.0 Section 5.1.3.2.3)
|
2019-10-21 10:00:49 -07:00
|
|
|
if (reordering_timer.is_valid()) {
|
|
|
|
if (reordering_timer.is_running()) {
|
|
|
|
if (vr_x == vr_r || (!inside_rx_window(vr_x) && vr_x != vr_mr)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Stopping reordering timer.");
|
2019-10-21 10:00:49 -07:00
|
|
|
reordering_timer.stop();
|
2019-07-10 03:10:03 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Leave reordering timer running.");
|
2018-09-07 04:08:45 -07:00
|
|
|
}
|
2019-07-10 03:10:03 -07:00
|
|
|
debug_state();
|
2018-09-07 04:08:45 -07:00
|
|
|
}
|
|
|
|
|
2019-10-21 10:00:49 -07:00
|
|
|
if (not reordering_timer.is_running()) {
|
|
|
|
if (RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_r)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Starting reordering timer.");
|
2019-10-21 10:00:49 -07:00
|
|
|
reordering_timer.run();
|
2018-09-07 04:08:45 -07:00
|
|
|
vr_x = vr_h;
|
2019-07-10 03:10:03 -07:00
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Leave reordering timer stopped.");
|
2018-09-07 04:08:45 -07:00
|
|
|
}
|
2019-07-10 03:10:03 -07:00
|
|
|
debug_state();
|
2018-09-07 04:08:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_state();
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::handle_data_pdu_segment(uint8_t* payload, uint32_t nof_bytes, rlc_amd_pdu_header_t& header)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
|
|
|
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(payload,
|
|
|
|
nof_bytes,
|
|
|
|
"%s Rx data PDU segment of SN=%d (%d B), SO=%d, N_li=%d",
|
|
|
|
RB_NAME,
|
|
|
|
header.sn,
|
|
|
|
nof_bytes,
|
|
|
|
header.so,
|
|
|
|
header.N_li);
|
|
|
|
log_rlc_amd_pdu_header_to_string(logger->debug, header);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Check inside rx window
|
2019-12-16 07:04:22 -08:00
|
|
|
if (!inside_rx_window(header.sn)) {
|
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2017-05-18 03:52:29 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s SN=%d outside rx window [%d:%d] - discarding", RB_NAME, header.sn, vr_r, vr_mr);
|
2017-05-18 03:52:29 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-04-12 01:42:26 -07:00
|
|
|
rlc_amd_rx_pdu segment;
|
2021-03-19 03:45:56 -07:00
|
|
|
segment.buf = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (segment.buf == NULL) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().\n");
|
2017-05-18 03:52:29 -07:00
|
|
|
exit(-1);
|
2018-02-08 08:50:19 -08:00
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Couldn't allocate PDU in handle_data_pdu_segment().");
|
2018-02-08 08:50:19 -08:00
|
|
|
return;
|
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2018-02-07 15:13:59 -08:00
|
|
|
|
2019-06-28 08:02:49 -07:00
|
|
|
if (segment.buf->get_tailroom() < nof_bytes) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("Dropping corrupted segment SN=%d, not enough space to fit %d B", header.sn, nof_bytes);
|
2019-06-28 08:02:49 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
memcpy(segment.buf->msg, payload, nof_bytes);
|
|
|
|
segment.buf->N_bytes = nof_bytes;
|
2019-04-26 06:57:50 -07:00
|
|
|
segment.header = header;
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Check if we already have a segment from the same PDU
|
|
|
|
it = rx_segments.find(header.sn);
|
2018-10-02 08:00:34 -07:00
|
|
|
if (rx_segments.end() != it) {
|
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2017-05-18 03:52:29 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add segment to PDU list and check for complete
|
2019-05-01 09:41:04 -07:00
|
|
|
// NOTE: MAY MOVE. Preference would be to capture by value, and then move; but header is stack allocated
|
2019-12-16 07:04:22 -08:00
|
|
|
if (add_segment_and_check(&it->second, &segment)) {
|
2017-05-18 03:52:29 -07:00
|
|
|
rx_segments.erase(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Create new PDU segment list and write to rx_segments
|
|
|
|
rlc_amd_rx_pdu_segments_t pdu;
|
2019-05-01 09:41:04 -07:00
|
|
|
pdu.segments.push_back(std::move(segment));
|
|
|
|
rx_segments[header.sn] = std::move(pdu);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Update vr_h
|
2018-09-12 01:57:49 -07:00
|
|
|
if (RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_h)) {
|
|
|
|
vr_h = (header.sn + 1) % MOD;
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Check poll bit
|
2018-09-12 01:57:49 -07:00
|
|
|
if (header.p) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info("%s Status packet requested through polling bit", RB_NAME);
|
2017-05-18 03:52:29 -07:00
|
|
|
poll_received = true;
|
|
|
|
|
|
|
|
// 36.322 v10 Section 5.2.3
|
2019-12-16 07:04:22 -08:00
|
|
|
if (RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ms) || RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_mr)) {
|
2017-05-18 03:52:29 -07:00
|
|
|
do_status = true;
|
|
|
|
}
|
|
|
|
// else delay for reordering timer
|
|
|
|
}
|
|
|
|
}
|
2018-02-09 02:36:55 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2018-02-07 15:13:59 -08:00
|
|
|
print_rx_segments();
|
2018-02-09 02:36:55 -08:00
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
debug_state();
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::reassemble_rx_sdus()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2018-07-04 04:26:57 -07:00
|
|
|
uint32_t len = 0;
|
2018-09-12 01:57:49 -07:00
|
|
|
if (rx_sdu == NULL) {
|
2021-03-19 03:45:56 -07:00
|
|
|
rx_sdu = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (rx_sdu == NULL) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)\n");
|
2017-05-18 03:52:29 -07:00
|
|
|
exit(-1);
|
2018-02-08 08:50:19 -08:00
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (1)");
|
2018-02-08 08:50:19 -08:00
|
|
|
return;
|
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
2018-03-27 12:33:26 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Iterate through rx_window, assembling and delivering SDUs
|
2021-03-04 04:27:26 -08:00
|
|
|
while (rx_window.has_sn(vr_r)) {
|
2017-05-18 03:52:29 -07:00
|
|
|
// Handle any SDU segments
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t i = 0; i < rx_window[vr_r].header.N_li; i++) {
|
2018-07-04 04:26:57 -07:00
|
|
|
len = rx_window[vr_r].header.li[i];
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(rx_window[vr_r].buf->msg,
|
|
|
|
len,
|
|
|
|
"Handling segment %d/%d of length %d B of SN=%d",
|
|
|
|
i + 1,
|
|
|
|
rx_window[vr_r].header.N_li,
|
|
|
|
len,
|
|
|
|
vr_r);
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2018-04-04 08:27:06 -07:00
|
|
|
// sanity check to avoid zero-size SDUs
|
|
|
|
if (len == 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-27 12:33:26 -07:00
|
|
|
if (rx_sdu->get_tailroom() >= len) {
|
2021-03-19 03:45:56 -07:00
|
|
|
if ((rx_window[vr_r].buf->msg - rx_window[vr_r].buf->buffer) + len < SRSRAN_MAX_BUFFER_SIZE_BYTES) {
|
2019-06-28 08:02:49 -07:00
|
|
|
if (rx_window[vr_r].buf->N_bytes < len) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Dropping corrupted SN=%d", vr_r);
|
2019-06-28 08:02:49 -07:00
|
|
|
rx_sdu.reset();
|
|
|
|
goto exit;
|
|
|
|
}
|
2020-12-16 13:07:04 -08:00
|
|
|
// store timestamp of the first segment when starting to assemble SDUs
|
|
|
|
if (rx_sdu->N_bytes == 0) {
|
|
|
|
rx_sdu->set_timestamp(rx_window[vr_r].buf->get_timestamp());
|
|
|
|
}
|
2018-07-04 04:26:57 -07:00
|
|
|
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len);
|
|
|
|
rx_sdu->N_bytes += len;
|
2019-06-28 08:02:49 -07:00
|
|
|
|
2018-07-04 04:26:57 -07:00
|
|
|
rx_window[vr_r].buf->msg += len;
|
|
|
|
rx_window[vr_r].buf->N_bytes -= len;
|
2019-06-28 08:02:49 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes);
|
2020-12-16 13:07:04 -08:00
|
|
|
sdu_rx_latency_ms.push(std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
std::chrono::high_resolution_clock::now() - rx_sdu->get_timestamp())
|
|
|
|
.count());
|
2019-05-01 09:41:04 -07:00
|
|
|
parent->pdcp->write_pdu(parent->lcid, std::move(rx_sdu));
|
2021-09-15 02:31:24 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(parent->metrics_mutex);
|
|
|
|
parent->metrics.num_rx_sdus++;
|
|
|
|
}
|
2018-07-04 04:26:57 -07:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
rx_sdu = srsran::make_byte_buffer();
|
2019-06-28 08:02:49 -07:00
|
|
|
if (rx_sdu == nullptr) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)\n");
|
2019-12-16 07:04:22 -08:00
|
|
|
exit(-1);
|
2018-02-08 08:50:19 -08:00
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (2)");
|
2018-07-04 04:26:57 -07:00
|
|
|
return;
|
2018-02-08 08:50:19 -08:00
|
|
|
#endif
|
2018-07-04 04:26:57 -07:00
|
|
|
}
|
|
|
|
} else {
|
2019-11-11 02:27:42 -08:00
|
|
|
int buf_len = rx_window[vr_r].buf->msg - rx_window[vr_r].buf->buffer;
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Cannot read %d bytes from rx_window. vr_r=%d, msg-buffer=%d B", len, vr_r, buf_len);
|
2019-05-01 09:41:04 -07:00
|
|
|
rx_sdu.reset();
|
2018-07-04 04:26:57 -07:00
|
|
|
goto exit;
|
2018-03-27 12:33:26 -07:00
|
|
|
}
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Cannot fit RLC PDU in SDU buffer, dropping both.");
|
2019-05-01 09:41:04 -07:00
|
|
|
rx_sdu.reset();
|
2018-07-04 04:26:57 -07:00
|
|
|
goto exit;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle last segment
|
2018-07-04 04:26:57 -07:00
|
|
|
len = rx_window[vr_r].buf->N_bytes;
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(rx_window[vr_r].buf->msg, len, "Handling last segment of length %d B of SN=%d", len, vr_r);
|
2018-03-27 12:33:26 -07:00
|
|
|
if (rx_sdu->get_tailroom() >= len) {
|
2020-12-16 13:07:04 -08:00
|
|
|
// store timestamp of the first segment when starting to assemble SDUs
|
|
|
|
if (rx_sdu->N_bytes == 0) {
|
|
|
|
rx_sdu->set_timestamp(rx_window[vr_r].buf->get_timestamp());
|
|
|
|
}
|
2018-03-27 12:33:26 -07:00
|
|
|
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], rx_window[vr_r].buf->msg, len);
|
|
|
|
rx_sdu->N_bytes += rx_window[vr_r].buf->N_bytes;
|
|
|
|
} else {
|
2019-06-28 08:02:49 -07:00
|
|
|
printf("Cannot fit RLC PDU in SDU buffer (tailroom=%d, len=%d), dropping both. Erasing SN=%d.\n",
|
|
|
|
rx_sdu->get_tailroom(),
|
|
|
|
len,
|
|
|
|
vr_r);
|
2019-05-01 09:41:04 -07:00
|
|
|
rx_sdu.reset();
|
2019-06-28 08:02:49 -07:00
|
|
|
goto exit;
|
2018-03-27 12:33:26 -07:00
|
|
|
}
|
|
|
|
|
2018-09-12 01:57:49 -07:00
|
|
|
if (rlc_am_end_aligned(rx_window[vr_r].header.fi)) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->info(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU (%d B)", RB_NAME, rx_sdu->N_bytes);
|
2020-12-16 13:07:04 -08:00
|
|
|
sdu_rx_latency_ms.push(std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
|
|
std::chrono::high_resolution_clock::now() - rx_sdu->get_timestamp())
|
|
|
|
.count());
|
2019-05-01 09:41:04 -07:00
|
|
|
parent->pdcp->write_pdu(parent->lcid, std::move(rx_sdu));
|
2021-09-15 02:31:24 -07:00
|
|
|
{
|
|
|
|
std::lock_guard<std::mutex> lock(parent->metrics_mutex);
|
|
|
|
parent->metrics.num_rx_sdus++;
|
|
|
|
}
|
2020-06-25 12:52:31 -07:00
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
rx_sdu = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (rx_sdu == NULL) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)\n");
|
2018-02-08 08:50:19 -08:00
|
|
|
exit(-1);
|
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Could not allocate PDU in reassemble_rx_sdus() (3)");
|
2018-02-08 08:50:19 -08:00
|
|
|
return;
|
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-16 07:04:22 -08:00
|
|
|
exit:
|
2017-05-18 03:52:29 -07:00
|
|
|
// Move the rx_window
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Erasing SN=%d.", vr_r);
|
2018-10-02 08:00:34 -07:00
|
|
|
// also erase any segments of this SN
|
|
|
|
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
|
|
|
|
it = rx_segments.find(vr_r);
|
2019-12-16 07:04:22 -08:00
|
|
|
if (rx_segments.end() != it) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Erasing segments of SN=%d", vr_r);
|
2021-04-12 01:42:26 -07:00
|
|
|
std::list<rlc_amd_rx_pdu>::iterator segit;
|
2019-12-16 07:04:22 -08:00
|
|
|
for (segit = it->second.segments.begin(); segit != it->second.segments.end(); ++segit) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(" Erasing segment of SN=%d SO=%d Len=%d N_li=%d",
|
|
|
|
segit->header.sn,
|
|
|
|
segit->header.so,
|
|
|
|
segit->buf->N_bytes,
|
|
|
|
segit->header.N_li);
|
2018-10-02 08:00:34 -07:00
|
|
|
}
|
|
|
|
it->second.segments.clear();
|
|
|
|
}
|
2021-03-04 04:27:26 -08:00
|
|
|
rx_window.remove_pdu(vr_r);
|
2019-12-16 07:04:22 -08:00
|
|
|
vr_r = (vr_r + 1) % MOD;
|
|
|
|
vr_mr = (vr_mr + 1) % MOD;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::reset_status()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2019-12-16 07:04:22 -08:00
|
|
|
do_status = false;
|
2018-07-26 00:41:19 -07:00
|
|
|
poll_received = false;
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_rx::get_do_status()
|
2018-07-26 00:41:19 -07:00
|
|
|
{
|
2021-07-05 07:10:39 -07:00
|
|
|
return do_status.load(std::memory_order_relaxed);
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
uint32_t rlc_am_lte_rx::get_rx_buffered_bytes()
|
2020-12-16 13:07:04 -08:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
return rx_window.get_buffered_bytes();
|
2020-12-16 13:07:04 -08:00
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
uint32_t rlc_am_lte_rx::get_sdu_rx_latency_ms()
|
2020-12-16 13:07:04 -08:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
|
|
|
return sdu_rx_latency_ms.value();
|
2020-12-16 13:07:04 -08:00
|
|
|
}
|
|
|
|
|
2020-02-04 08:02:38 -08:00
|
|
|
/**
|
|
|
|
* Function called from stack thread when timer has expired
|
|
|
|
*
|
|
|
|
* @param timeout_id
|
|
|
|
*/
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::timer_expired(uint32_t timeout_id)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-03-09 08:44:27 -08:00
|
|
|
std::lock_guard<std::mutex> lock(mutex);
|
2019-10-21 10:00:49 -07:00
|
|
|
if (reordering_timer.is_valid() and reordering_timer.id() == timeout_id) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s reordering timeout expiry - updating vr_ms (was %d)", RB_NAME, vr_ms);
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
// 36.322 v10 Section 5.1.3.2.4
|
2021-03-04 04:27:26 -08:00
|
|
|
vr_ms = vr_x;
|
|
|
|
while (rx_window.has_sn(vr_ms)) {
|
2018-07-26 00:41:19 -07:00
|
|
|
vr_ms = (vr_ms + 1) % MOD;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poll_received) {
|
|
|
|
do_status = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RX_MOD_BASE(vr_h) > RX_MOD_BASE(vr_ms)) {
|
2019-10-21 10:00:49 -07:00
|
|
|
reordering_timer.run();
|
2018-07-26 00:41:19 -07:00
|
|
|
vr_x = vr_h;
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_state();
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-02 08:00:34 -07:00
|
|
|
// Called from Tx object to pack status PDU that doesn't exceed a given size
|
2021-07-02 02:41:11 -07:00
|
|
|
// If lock-acquisition fails, return -1. Otherwise it returns the length of the generated PDU.
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_rx::get_status_pdu(rlc_status_pdu_t* status, const uint32_t max_pdu_size)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-07-02 02:41:11 -07:00
|
|
|
std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
|
|
|
|
if (not lock.owns_lock()) {
|
|
|
|
return SRSRAN_ERROR;
|
|
|
|
}
|
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
status->N_nack = 0;
|
2019-07-13 08:31:37 -07:00
|
|
|
status->ack_sn = vr_r; // start with lower edge of the rx window
|
2018-07-26 00:41:19 -07:00
|
|
|
|
|
|
|
// We don't use segment NACKs - just NACK the full PDU
|
|
|
|
uint32_t i = vr_r;
|
2021-01-20 03:23:03 -08:00
|
|
|
while (RX_MOD_BASE(i) <= RX_MOD_BASE(vr_ms) && status->N_nack < RLC_AM_WINDOW_SIZE) {
|
2021-03-04 04:27:26 -08:00
|
|
|
if (rx_window.has_sn(i) || i == vr_ms) {
|
2021-01-20 03:23:03 -08:00
|
|
|
// only update ACK_SN if this SN has been received, or if we reached the maximum possible SN
|
|
|
|
status->ack_sn = i;
|
|
|
|
} else {
|
2018-09-21 07:36:55 -07:00
|
|
|
status->nacks[status->N_nack].nack_sn = i;
|
|
|
|
status->N_nack++;
|
2019-07-13 08:31:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// make sure we don't exceed grant size
|
|
|
|
if (rlc_am_packed_length(status) > max_pdu_size) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Status PDU too big (%d > %d)", rlc_am_packed_length(status), max_pdu_size);
|
2019-12-12 06:11:28 -08:00
|
|
|
if (status->N_nack >= 1 && status->N_nack < RLC_AM_WINDOW_SIZE) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Removing last NACK SN=%d", status->nacks[status->N_nack].nack_sn);
|
2019-07-13 08:31:37 -07:00
|
|
|
status->N_nack--;
|
2019-09-30 12:03:32 -07:00
|
|
|
// make sure we don't have the current ACK_SN in the NACK list
|
2021-06-08 06:40:07 -07:00
|
|
|
if (rlc_am_is_valid_status_pdu(*status, vr_r) == false) {
|
2021-05-26 12:42:34 -07:00
|
|
|
// No space to send any NACKs, play safe and just ack lower edge
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning("Resetting ACK_SN and N_nack to initial state");
|
2021-05-26 12:42:34 -07:00
|
|
|
status->ack_sn = vr_r;
|
2019-09-30 12:03:32 -07:00
|
|
|
status->N_nack = 0;
|
|
|
|
}
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->warning(
|
|
|
|
"Failed to generate small enough status PDU (packed_len=%d, max_pdu_size=%d, status->N_nack=%d)",
|
|
|
|
rlc_am_packed_length(status),
|
|
|
|
max_pdu_size,
|
|
|
|
status->N_nack);
|
2021-03-05 09:09:00 -08:00
|
|
|
return 0;
|
2019-07-13 08:31:37 -07:00
|
|
|
}
|
|
|
|
break;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2019-07-09 11:31:13 -07:00
|
|
|
i = (i + 1) % MOD;
|
2018-07-26 00:41:19 -07:00
|
|
|
}
|
2019-07-09 11:31:13 -07:00
|
|
|
|
2021-07-05 07:32:52 -07:00
|
|
|
// valid PDU could be generated
|
|
|
|
reset_status();
|
|
|
|
|
2018-07-26 00:41:19 -07:00
|
|
|
return rlc_am_packed_length(status);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2018-10-02 08:00:34 -07:00
|
|
|
// Called from Tx object to obtain length of the full status PDU
|
2021-11-10 09:31:56 -08:00
|
|
|
int rlc_am_lte_rx::get_status_pdu_length()
|
2018-10-02 08:00:34 -07:00
|
|
|
{
|
2021-07-02 02:41:11 -07:00
|
|
|
std::unique_lock<std::mutex> lock(mutex, std::try_to_lock);
|
|
|
|
if (not lock.owns_lock()) {
|
|
|
|
return 0;
|
|
|
|
}
|
2021-09-15 02:31:24 -07:00
|
|
|
rlc_status_pdu_t status = {};
|
|
|
|
status.ack_sn = vr_ms;
|
|
|
|
uint32_t i = vr_r;
|
2018-10-02 08:00:34 -07:00
|
|
|
while (RX_MOD_BASE(i) < RX_MOD_BASE(vr_ms) && status.N_nack < RLC_AM_WINDOW_SIZE) {
|
2021-03-04 04:27:26 -08:00
|
|
|
if (not rx_window.has_sn(i)) {
|
2018-10-02 08:00:34 -07:00
|
|
|
status.N_nack++;
|
|
|
|
}
|
2019-12-16 07:04:22 -08:00
|
|
|
i = (i + 1) % MOD;
|
2018-10-02 08:00:34 -07:00
|
|
|
}
|
|
|
|
return rlc_am_packed_length(&status);
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::print_rx_segments()
|
2018-02-07 15:13:59 -08:00
|
|
|
{
|
|
|
|
std::map<uint32_t, rlc_amd_rx_pdu_segments_t>::iterator it;
|
2019-12-16 07:04:22 -08:00
|
|
|
std::stringstream ss;
|
2018-02-07 15:13:59 -08:00
|
|
|
ss << "rx_segments:" << std::endl;
|
2019-12-16 07:04:22 -08:00
|
|
|
for (it = rx_segments.begin(); it != rx_segments.end(); it++) {
|
2021-04-12 01:42:26 -07:00
|
|
|
std::list<rlc_amd_rx_pdu>::iterator segit;
|
2019-12-16 07:04:22 -08:00
|
|
|
for (segit = it->second.segments.begin(); segit != it->second.segments.end(); segit++) {
|
2020-07-14 00:47:53 -07:00
|
|
|
ss << " SN=" << segit->header.sn << " SO:" << segit->header.so << " N:" << segit->buf->N_bytes
|
2019-12-16 07:04:22 -08:00
|
|
|
<< " N_li: " << segit->header.N_li << std::endl;
|
2018-02-07 15:13:59 -08:00
|
|
|
}
|
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s", ss.str().c_str());
|
2018-02-07 15:13:59 -08:00
|
|
|
}
|
|
|
|
|
2019-05-01 09:41:04 -07:00
|
|
|
// NOTE: Preference would be to capture by value, and then move; but header is stack allocated
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_rx::add_segment_and_check(rlc_amd_rx_pdu_segments_t* pdu, rlc_amd_rx_pdu* segment)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2020-01-23 01:18:33 -08:00
|
|
|
// Find segment insertion point in the list of segments
|
|
|
|
auto it1 = pdu->segments.begin();
|
|
|
|
while (it1 != pdu->segments.end() && (*it1).header.so < segment->header.so) {
|
|
|
|
// Increment iterator
|
|
|
|
it1++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the insertion point was found
|
|
|
|
if (it1 != pdu->segments.end()) {
|
|
|
|
// Found insertion point
|
2021-04-12 01:42:26 -07:00
|
|
|
rlc_amd_rx_pdu& s = *it1;
|
2020-01-23 01:18:33 -08:00
|
|
|
if (s.header.so == segment->header.so) {
|
|
|
|
// Same Segment offset
|
|
|
|
if (segment->buf->N_bytes > s.buf->N_bytes) {
|
|
|
|
// replace if the new one is bigger
|
|
|
|
s = std::move(*segment);
|
|
|
|
} else {
|
|
|
|
// Ignore otherwise
|
|
|
|
}
|
|
|
|
} else if (s.header.so > segment->header.so) {
|
|
|
|
pdu->segments.insert(it1, std::move(*segment));
|
|
|
|
}
|
2018-02-12 05:09:31 -08:00
|
|
|
} else {
|
2020-01-23 01:18:33 -08:00
|
|
|
// Either the new segment is the latest or the only one, push back
|
2019-05-01 09:41:04 -07:00
|
|
|
pdu->segments.push_back(std::move(*segment));
|
2018-02-12 05:09:31 -08:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// Check for complete
|
2021-04-12 01:42:26 -07:00
|
|
|
uint32_t so = 0;
|
|
|
|
std::list<rlc_amd_rx_pdu>::iterator it, tmpit;
|
2020-01-23 02:14:32 -08:00
|
|
|
for (it = pdu->segments.begin(); it != pdu->segments.end(); /* Do not increment */) {
|
2020-01-23 01:18:33 -08:00
|
|
|
// Check that there is no gap between last segment and current; overlap allowed
|
|
|
|
if (so < it->header.so) {
|
2020-01-23 02:14:32 -08:00
|
|
|
// return
|
2017-05-18 03:52:29 -07:00
|
|
|
return false;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2020-01-23 01:18:33 -08:00
|
|
|
|
2020-01-23 02:14:32 -08:00
|
|
|
// Check if segment is overlapped
|
|
|
|
if (it->header.so + it->buf->N_bytes <= so) {
|
|
|
|
// completely overlapped with previous segments, erase
|
|
|
|
it = pdu->segments.erase(it); // Returns next iterator
|
|
|
|
} else {
|
|
|
|
// Update segment offset it shall not go backwards
|
2021-03-19 03:45:56 -07:00
|
|
|
so = SRSRAN_MAX(so, it->header.so + it->buf->N_bytes);
|
2020-01-23 02:14:32 -08:00
|
|
|
it++; // Increments iterator
|
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2020-01-23 01:18:33 -08:00
|
|
|
|
|
|
|
// Check for last segment flag available
|
2018-09-12 01:57:49 -07:00
|
|
|
if (!pdu->segments.back().header.lsf) {
|
2017-05-18 03:52:29 -07:00
|
|
|
return false;
|
2018-09-12 01:57:49 -07:00
|
|
|
}
|
2017-05-18 03:52:29 -07:00
|
|
|
|
|
|
|
// We have all segments of the PDU - reconstruct and handle
|
|
|
|
rlc_amd_pdu_header_t header;
|
|
|
|
header.dc = RLC_DC_FIELD_DATA_PDU;
|
|
|
|
header.rf = 0;
|
|
|
|
header.p = 0;
|
|
|
|
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
|
|
|
|
header.sn = pdu->segments.front().header.sn;
|
|
|
|
header.lsf = 0;
|
|
|
|
header.so = 0;
|
|
|
|
header.N_li = 0;
|
|
|
|
|
|
|
|
// Reconstruct fi field
|
|
|
|
header.fi |= (pdu->segments.front().header.fi & RLC_FI_FIELD_NOT_START_ALIGNED);
|
2019-12-16 07:04:22 -08:00
|
|
|
header.fi |= (pdu->segments.back().header.fi & RLC_FI_FIELD_NOT_END_ALIGNED);
|
2017-05-18 03:52:29 -07:00
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Starting header reconstruction of %zd segments", pdu->segments.size());
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Reconstruct li fields
|
2021-03-08 14:54:32 -08:00
|
|
|
uint16_t count = 0;
|
|
|
|
uint16_t carryover = 0;
|
2021-03-04 04:27:26 -08:00
|
|
|
uint16_t consumed_bytes = 0; // rolling sum of all allocated LIs during segment reconstruction
|
|
|
|
|
|
|
|
for (it = pdu->segments.begin(); it != pdu->segments.end(); ++it) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(" Handling %d PDU segments", it->header.N_li);
|
2019-12-16 07:04:22 -08:00
|
|
|
for (uint32_t i = 0; i < it->header.N_li; i++) {
|
2021-03-04 04:27:26 -08:00
|
|
|
// variable marks total offset of each _processed_ LI of this segment
|
|
|
|
uint32_t total_pdu_offset = it->header.so;
|
|
|
|
for (uint32_t k = 0; k <= i; k++) {
|
|
|
|
total_pdu_offset += it->header.li[k];
|
|
|
|
}
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(" - (total_pdu_offset=%d, consumed_bytes=%d, header.li[i]=%d)",
|
|
|
|
total_pdu_offset,
|
|
|
|
consumed_bytes,
|
|
|
|
header.li[i]);
|
2021-03-04 04:27:26 -08:00
|
|
|
if (total_pdu_offset > header.li[i] && total_pdu_offset > consumed_bytes) {
|
|
|
|
header.li[header.N_li] = total_pdu_offset - consumed_bytes;
|
|
|
|
consumed_bytes = total_pdu_offset;
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(" - adding segment %d/%d (%d B, SO=%d, carryover=%d, count=%d)",
|
|
|
|
i + 1,
|
|
|
|
it->header.N_li,
|
|
|
|
header.li[header.N_li],
|
|
|
|
header.so,
|
|
|
|
carryover,
|
|
|
|
count);
|
2021-03-04 04:27:26 -08:00
|
|
|
header.N_li++;
|
|
|
|
count += it->header.li[i];
|
|
|
|
carryover = 0;
|
|
|
|
} else {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug(" - Skipping segment in reTx PDU segment which is already included (%d B, SO=%d)",
|
|
|
|
it->header.li[i],
|
|
|
|
header.so);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
2018-04-04 08:18:13 -07:00
|
|
|
|
2018-10-02 08:00:34 -07:00
|
|
|
if (count <= it->buf->N_bytes) {
|
2021-03-04 04:27:26 -08:00
|
|
|
carryover = it->header.so + it->buf->N_bytes;
|
|
|
|
// substract all previous LIs
|
|
|
|
for (uint32_t k = 0; k < header.N_li; ++k) {
|
|
|
|
carryover -= header.li[k];
|
|
|
|
}
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Incremented carryover (it->buf->N_bytes=%d, count=%d). New carryover=%d",
|
|
|
|
it->buf->N_bytes,
|
|
|
|
count,
|
|
|
|
carryover);
|
2018-04-04 08:18:13 -07:00
|
|
|
} else {
|
2018-10-02 08:00:34 -07:00
|
|
|
// Next segment would be too long, recalculate carryover
|
|
|
|
header.N_li--;
|
|
|
|
carryover = it->buf->N_bytes - (count - header.li[header.N_li]);
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Recalculated carryover=%d (it->buf->N_bytes=%d, count=%d, header.li[header.N_li]=%d)",
|
|
|
|
carryover,
|
|
|
|
it->buf->N_bytes,
|
|
|
|
count,
|
|
|
|
header.li[header.N_li]);
|
2018-04-04 08:18:13 -07:00
|
|
|
}
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
tmpit = it;
|
2019-12-16 07:04:22 -08:00
|
|
|
if (rlc_am_end_aligned(it->header.fi) && ++tmpit != pdu->segments.end()) {
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Header is end-aligned, overwrite header.li[%d]=%d", header.N_li, carryover);
|
2018-10-02 08:00:34 -07:00
|
|
|
header.li[header.N_li] = carryover;
|
|
|
|
header.N_li++;
|
2021-03-04 04:27:26 -08:00
|
|
|
consumed_bytes += carryover;
|
2017-05-18 03:52:29 -07:00
|
|
|
carryover = 0;
|
|
|
|
}
|
|
|
|
count = 0;
|
2020-10-29 14:15:42 -07:00
|
|
|
|
|
|
|
// set Poll bit if any of the segments had it set
|
|
|
|
header.p |= it->header.p;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("Finished header reconstruction of %zd segments", pdu->segments.size());
|
2018-10-02 08:00:34 -07:00
|
|
|
|
2017-05-18 03:52:29 -07:00
|
|
|
// Copy data
|
2021-03-19 03:45:56 -07:00
|
|
|
unique_byte_buffer_t full_pdu = srsran::make_byte_buffer();
|
2018-09-12 01:57:49 -07:00
|
|
|
if (full_pdu == NULL) {
|
2018-02-08 08:50:19 -08:00
|
|
|
#ifdef RLC_AM_BUFFER_DEBUG
|
2021-03-19 03:45:56 -07:00
|
|
|
srsran::console("Fatal Error: Could not allocate PDU in add_segment_and_check()\n");
|
2017-05-18 03:52:29 -07:00
|
|
|
exit(-1);
|
2018-02-08 08:50:19 -08:00
|
|
|
#else
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->error("Fatal Error: Could not allocate PDU in add_segment_and_check()");
|
2018-02-08 08:50:19 -08:00
|
|
|
return false;
|
|
|
|
#endif
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
2019-12-16 07:04:22 -08:00
|
|
|
for (it = pdu->segments.begin(); it != pdu->segments.end(); it++) {
|
2020-01-23 01:18:33 -08:00
|
|
|
// By default, the segment is not copied. It could be it is fully overlapped with previous segments
|
|
|
|
uint32_t overlap = 0;
|
|
|
|
uint32_t n = 0;
|
|
|
|
|
|
|
|
// Check if the segment has non-overlapped bytes
|
|
|
|
if (it->header.so + it->buf->N_bytes > full_pdu->N_bytes) {
|
|
|
|
// Calculate overlap and number of bytes
|
|
|
|
overlap = full_pdu->N_bytes - it->header.so;
|
|
|
|
n = it->buf->N_bytes - overlap;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy data itself
|
|
|
|
memcpy(&full_pdu->msg[full_pdu->N_bytes], &it->buf->msg[overlap], n);
|
|
|
|
full_pdu->N_bytes += n;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-07-29 09:00:10 -07:00
|
|
|
handle_data_pdu_full(full_pdu->msg, full_pdu->N_bytes, header);
|
2017-05-18 03:52:29 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
bool rlc_am_lte_rx::inside_rx_window(const int16_t sn)
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2019-09-10 00:52:08 -07:00
|
|
|
if (RX_MOD_BASE(sn) >= RX_MOD_BASE(static_cast<int16_t>(vr_r)) && RX_MOD_BASE(sn) < RX_MOD_BASE(vr_mr)) {
|
2018-07-26 00:41:19 -07:00
|
|
|
return true;
|
2019-09-10 00:52:08 -07:00
|
|
|
} else {
|
2018-07-26 00:41:19 -07:00
|
|
|
return false;
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-10 09:31:56 -08:00
|
|
|
void rlc_am_lte_rx::debug_state()
|
2017-05-18 03:52:29 -07:00
|
|
|
{
|
2021-07-28 04:26:11 -07:00
|
|
|
logger->debug("%s vr_r = %d, vr_mr = %d, vr_x = %d, vr_ms = %d, vr_h = %d", RB_NAME, vr_r, vr_mr, vr_x, vr_ms, vr_h);
|
2017-05-18 03:52:29 -07:00
|
|
|
}
|
|
|
|
|
2021-03-19 03:45:56 -07:00
|
|
|
} // namespace srsran
|