|
|
@ -26,6 +26,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "srslte/upper/rlc_um.h"
|
|
|
|
#include "srslte/upper/rlc_um.h"
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
|
|
#define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod
|
|
|
|
#define RX_MOD_BASE(x) (x-vr_uh-cfg.rx_window_size)%cfg.rx_mod
|
|
|
|
|
|
|
|
|
|
|
@ -55,6 +56,7 @@ rlc_um::rlc_um() : tx_sdu_queue(32)
|
|
|
|
vr_ur_in_rx_sdu = 0;
|
|
|
|
vr_ur_in_rx_sdu = 0;
|
|
|
|
|
|
|
|
|
|
|
|
mac_timers = NULL;
|
|
|
|
mac_timers = NULL;
|
|
|
|
|
|
|
|
mrb = false;
|
|
|
|
|
|
|
|
|
|
|
|
pdu_lost = false;
|
|
|
|
pdu_lost = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -63,24 +65,42 @@ rlc_um::~rlc_um()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
stop();
|
|
|
|
stop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rlc_um::init(srslte::log *log_,
|
|
|
|
void rlc_um::init(srslte::log *log_,
|
|
|
|
uint32_t lcid_,
|
|
|
|
uint32_t lcid_,
|
|
|
|
srsue::pdcp_interface_rlc *pdcp_,
|
|
|
|
srsue::pdcp_interface_rlc *pdcp_,
|
|
|
|
srsue::rrc_interface_rlc *rrc_,
|
|
|
|
srsue::rrc_interface_rlc *rrc_,
|
|
|
|
srslte::mac_interface_timers *mac_timers_,
|
|
|
|
srslte::mac_interface_timers *mac_timers_)
|
|
|
|
bool mrb_)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log = log_;
|
|
|
|
log = log_;
|
|
|
|
lcid = lcid_;
|
|
|
|
lcid = lcid_;
|
|
|
|
pdcp = pdcp_;
|
|
|
|
pdcp = pdcp_;
|
|
|
|
rrc = rrc_;
|
|
|
|
rrc = rrc_;
|
|
|
|
mac_timers = mac_timers_;
|
|
|
|
mac_timers = mac_timers_;
|
|
|
|
|
|
|
|
mrb = mrb_;
|
|
|
|
reordering_timer_id = mac_timers->timer_get_unique_id();
|
|
|
|
reordering_timer_id = mac_timers->timer_get_unique_id();
|
|
|
|
reordering_timer = mac_timers->timer_get(reordering_timer_id);
|
|
|
|
reordering_timer = mac_timers->timer_get(reordering_timer_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(mrb) {
|
|
|
|
|
|
|
|
cfg.t_reordering = 0;
|
|
|
|
|
|
|
|
cfg.rx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
|
|
|
|
|
|
|
|
cfg.rx_window_size = 0;
|
|
|
|
|
|
|
|
cfg.rx_mod = 32;
|
|
|
|
|
|
|
|
cfg.tx_sn_field_length = RLC_UMD_SN_SIZE_5_BITS;
|
|
|
|
|
|
|
|
cfg.tx_mod = 32;
|
|
|
|
|
|
|
|
log->info("MRB%d configured in %s mode: "
|
|
|
|
|
|
|
|
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
|
|
|
|
|
|
|
|
lcid, liblte_rrc_rlc_mode_text[LIBLTE_RRC_RLC_MODE_UM_UNI_DL],
|
|
|
|
|
|
|
|
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rlc_um::configure(srslte_rlc_config_t cnfg_)
|
|
|
|
void rlc_um::configure(srslte_rlc_config_t cnfg_)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(mrb) {
|
|
|
|
|
|
|
|
return; // Default configured in init()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
cfg = cnfg_.um;
|
|
|
|
cfg = cnfg_.um;
|
|
|
|
|
|
|
|
|
|
|
|
switch(cnfg_.rlc_mode)
|
|
|
|
switch(cnfg_.rlc_mode)
|
|
|
@ -88,18 +108,19 @@ void rlc_um::configure(srslte_rlc_config_t cnfg_)
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_BI:
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_BI:
|
|
|
|
log->warning("%s configured in %s mode: "
|
|
|
|
log->warning("%s configured in %s mode: "
|
|
|
|
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
|
|
|
|
"t_reordering=%d ms, rx_sn_field_length=%u bits, tx_sn_field_length=%u bits\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length], rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_UNI_UL:
|
|
|
|
log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n",
|
|
|
|
log->warning("%s configured in %s mode: tx_sn_field_length=%u bits\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
|
|
|
|
|
|
|
|
rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
|
|
|
|
case LIBLTE_RRC_RLC_MODE_UM_UNI_DL:
|
|
|
|
log->warning("%s configured in %s mode: "
|
|
|
|
log->warning("%s configured in %s mode: "
|
|
|
|
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
|
|
|
|
"t_reordering=%d ms, rx_sn_field_length=%u bits\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
rb_name().c_str(), liblte_rrc_rlc_mode_text[cnfg_.rlc_mode],
|
|
|
|
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
cfg.t_reordering, rlc_umd_sn_size_num[cfg.rx_sn_field_length]);
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
@ -116,6 +137,11 @@ void rlc_um::empty_queue() {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool rlc_um::is_mrb()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return mrb;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rlc_um::stop()
|
|
|
|
void rlc_um::stop()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
reset();
|
|
|
|
reset();
|
|
|
@ -197,7 +223,7 @@ uint32_t rlc_um::get_buffer_state()
|
|
|
|
|
|
|
|
|
|
|
|
// Room needed for fixed header?
|
|
|
|
// Room needed for fixed header?
|
|
|
|
if(n_bytes > 0)
|
|
|
|
if(n_bytes > 0)
|
|
|
|
n_bytes += 3;
|
|
|
|
n_bytes += (mrb)?2:3;
|
|
|
|
|
|
|
|
|
|
|
|
return n_bytes;
|
|
|
|
return n_bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -209,9 +235,14 @@ uint32_t rlc_um::get_total_buffer_state()
|
|
|
|
|
|
|
|
|
|
|
|
int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
int r;
|
|
|
|
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
|
|
|
|
log->debug("MAC opportunity - %d bytes\n", nof_bytes);
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
int r = build_data_pdu(payload, nof_bytes);
|
|
|
|
if(mrb){
|
|
|
|
|
|
|
|
r = build_mch_data_pdu(payload, nof_bytes);
|
|
|
|
|
|
|
|
} else{
|
|
|
|
|
|
|
|
r = build_data_pdu(payload, nof_bytes);
|
|
|
|
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
return r;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -219,7 +250,11 @@ int rlc_um::read_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
void rlc_um::write_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
handle_data_pdu(payload, nof_bytes);
|
|
|
|
if(mrb) {
|
|
|
|
|
|
|
|
handle_mch_data_pdu(payload, nof_bytes);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
handle_data_pdu(payload, nof_bytes);
|
|
|
|
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -235,7 +270,7 @@ void rlc_um::timer_expired(uint32_t timeout_id)
|
|
|
|
|
|
|
|
|
|
|
|
// 36.322 v10 Section 5.1.2.2.4
|
|
|
|
// 36.322 v10 Section 5.1.2.2.4
|
|
|
|
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
|
|
|
|
log->info("%s reordering timeout expiry - updating vr_ur and reassembling\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str());
|
|
|
|
rb_name().c_str());
|
|
|
|
|
|
|
|
|
|
|
|
log->warning("Lost PDU SN: %d\n", vr_ur);
|
|
|
|
log->warning("Lost PDU SN: %d\n", vr_ur);
|
|
|
|
pdu_lost = true;
|
|
|
|
pdu_lost = true;
|
|
|
@ -269,6 +304,130 @@ bool rlc_um::reordering_timeout_running()
|
|
|
|
* Helpers
|
|
|
|
* Helpers
|
|
|
|
***************************************************************************/
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int rlc_um::build_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(!tx_sdu && tx_sdu_queue.size() == 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
log->info("No data available to be sent\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
byte_buffer_t *pdu = pool_allocate;
|
|
|
|
|
|
|
|
if(!pdu || pdu->N_bytes != 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
log->error("Failed to allocate PDU buffer\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rlc_umd_pdu_header_t header;
|
|
|
|
|
|
|
|
header.fi = RLC_FI_FIELD_START_AND_END_ALIGNED;
|
|
|
|
|
|
|
|
header.sn = vt_us;
|
|
|
|
|
|
|
|
header.N_li = 0;
|
|
|
|
|
|
|
|
header.sn_size = RLC_UMD_SN_SIZE_5_BITS; //cfg.tx_sn_field_length;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t to_move = 0;
|
|
|
|
|
|
|
|
uint32_t last_li = 0;
|
|
|
|
|
|
|
|
uint8_t *pdu_ptr = pdu->msg;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int head_len = rlc_um_packed_length(&header);
|
|
|
|
|
|
|
|
int pdu_space = nof_bytes;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(pdu_space <= head_len + 1)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
|
|
|
|
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
|
|
|
|
|
|
|
|
rb_name().c_str(), nof_bytes, head_len);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check for SDU segment
|
|
|
|
|
|
|
|
if(tx_sdu)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
|
|
|
|
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
|
|
|
|
|
|
|
|
rb_name().c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
last_li = to_move;
|
|
|
|
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
|
|
|
|
pdu->N_bytes += to_move;
|
|
|
|
|
|
|
|
tx_sdu->N_bytes -= to_move;
|
|
|
|
|
|
|
|
tx_sdu->msg += to_move;
|
|
|
|
|
|
|
|
if(tx_sdu->N_bytes == 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
|
|
|
|
|
|
|
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pool->deallocate(tx_sdu);
|
|
|
|
|
|
|
|
tx_sdu = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pdu_space -= to_move;
|
|
|
|
|
|
|
|
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED; // First byte does not correspond to first byte of SDU
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Pull SDUs from queue
|
|
|
|
|
|
|
|
while(pdu_space > head_len + 1 && tx_sdu_queue.size() > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
log->debug("pdu_space=%d, head_len=%d\n", pdu_space, head_len);
|
|
|
|
|
|
|
|
if(last_li > 0)
|
|
|
|
|
|
|
|
header.li[header.N_li++] = last_li;
|
|
|
|
|
|
|
|
head_len = rlc_um_packed_length(&header);
|
|
|
|
|
|
|
|
tx_sdu_queue.read(&tx_sdu);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
|
|
|
|
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
|
|
|
|
|
|
|
|
rb_name().c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
|
|
|
|
last_li = to_move;
|
|
|
|
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
|
|
|
|
pdu->N_bytes += to_move;
|
|
|
|
|
|
|
|
tx_sdu->N_bytes -= to_move;
|
|
|
|
|
|
|
|
tx_sdu->msg += to_move;
|
|
|
|
|
|
|
|
if(tx_sdu->N_bytes == 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
log->debug("%s Complete SDU scheduled for tx. Stack latency: %ld us\n",
|
|
|
|
|
|
|
|
rrc->get_rb_name(lcid).c_str(), tx_sdu->get_latency_us());
|
|
|
|
|
|
|
|
pool->deallocate(tx_sdu);
|
|
|
|
|
|
|
|
tx_sdu = NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
pdu_space -= to_move;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(tx_sdu)
|
|
|
|
|
|
|
|
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set SN
|
|
|
|
|
|
|
|
header.sn = vt_us;
|
|
|
|
|
|
|
|
vt_us = (vt_us + 1)%cfg.tx_mod;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add header and TX
|
|
|
|
|
|
|
|
log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(pdu_space > 0 && tx_sdu == NULL){
|
|
|
|
|
|
|
|
//header.li[header.N_li++] = last_li;
|
|
|
|
|
|
|
|
header.fi |= RLC_FI_FIELD_NOT_START_ALIGNED;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
rlc_um_write_data_pdu_header(&header, pdu);
|
|
|
|
|
|
|
|
memcpy(payload, pdu->msg, pdu->N_bytes);
|
|
|
|
|
|
|
|
uint32_t ret = pdu->N_bytes;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
debug_state();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(!tx_sdu && tx_sdu_queue.size() == 0)
|
|
|
|
if(!tx_sdu && tx_sdu_queue.size() == 0)
|
|
|
@ -300,7 +459,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
|
|
|
|
log->warning("%s Cannot build a PDU - %d bytes available, %d bytes required for header\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), nof_bytes, head_len);
|
|
|
|
rb_name().c_str(), nof_bytes, head_len);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -310,7 +469,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
|
|
|
|
log->debug("%s adding remainder of SDU segment - %d bytes of %d remaining\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
rb_name().c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
last_li = to_move;
|
|
|
|
last_li = to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
@ -339,7 +498,7 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
uint32_t space = pdu_space-head_len;
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
to_move = space >= tx_sdu->N_bytes ? tx_sdu->N_bytes : space;
|
|
|
|
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
|
|
|
|
log->debug("%s adding new SDU segment - %d bytes of %d remaining\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
rb_name().c_str(), to_move, tx_sdu->N_bytes);
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
memcpy(pdu_ptr, tx_sdu->msg, to_move);
|
|
|
|
last_li = to_move;
|
|
|
|
last_li = to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
|
pdu_ptr += to_move;
|
|
|
@ -360,14 +519,16 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
|
|
|
|
header.fi |= RLC_FI_FIELD_NOT_END_ALIGNED; // Last byte does not correspond to last byte of SDU
|
|
|
|
|
|
|
|
|
|
|
|
// Set SN
|
|
|
|
// Set SN
|
|
|
|
|
|
|
|
|
|
|
|
header.sn = vt_us;
|
|
|
|
header.sn = vt_us;
|
|
|
|
vt_us = (vt_us + 1)%cfg.tx_mod;
|
|
|
|
vt_us = (vt_us + 1)%cfg.tx_mod;
|
|
|
|
|
|
|
|
|
|
|
|
// Add header and TX
|
|
|
|
// Add header and TX
|
|
|
|
log->debug("%s packing PDU with length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
|
|
|
|
log->debug("%s packing PDU with length %d\n", rb_name().c_str(), pdu->N_bytes);
|
|
|
|
rlc_um_write_data_pdu_header(&header, pdu);
|
|
|
|
rlc_um_write_data_pdu_header(&header, pdu);
|
|
|
|
memcpy(payload, pdu->msg, pdu->N_bytes);
|
|
|
|
memcpy(payload, pdu->msg, pdu->N_bytes);
|
|
|
|
uint32_t ret = pdu->N_bytes;
|
|
|
|
uint32_t ret = pdu->N_bytes;
|
|
|
|
|
|
|
|
|
|
|
|
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
|
|
|
|
log->debug("%s returning length %d\n", rrc->get_rb_name(lcid).c_str(), pdu->N_bytes);
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
pool->deallocate(pdu);
|
|
|
|
|
|
|
|
|
|
|
@ -375,6 +536,63 @@ int rlc_um::build_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
return ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void rlc_um::handle_mch_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(!rx_sdu) {
|
|
|
|
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rlc_umd_pdu_header_t header;
|
|
|
|
|
|
|
|
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
|
|
|
|
|
|
|
|
rb_name().c_str(), header.sn);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Strip header from PDU
|
|
|
|
|
|
|
|
int header_len = rlc_um_packed_length(&header);
|
|
|
|
|
|
|
|
payload += header_len;
|
|
|
|
|
|
|
|
nof_bytes -= header_len;
|
|
|
|
|
|
|
|
if(0 == header.sn) {
|
|
|
|
|
|
|
|
vr_uh = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Handle SDU segments
|
|
|
|
|
|
|
|
for(uint32_t i=0; i<header.N_li; i++) {
|
|
|
|
|
|
|
|
int len = header.li[i];
|
|
|
|
|
|
|
|
if(vr_uh != header.sn) {
|
|
|
|
|
|
|
|
rx_sdu->reset();
|
|
|
|
|
|
|
|
vr_uh = header.sn;
|
|
|
|
|
|
|
|
if(!rlc_um_start_aligned(header.fi)) {
|
|
|
|
|
|
|
|
payload += len;
|
|
|
|
|
|
|
|
nof_bytes -= len;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, len);
|
|
|
|
|
|
|
|
log->debug("Concatenating %d bytes in to current length %d.\n", len, rx_sdu->N_bytes);
|
|
|
|
|
|
|
|
rx_sdu->N_bytes += len;
|
|
|
|
|
|
|
|
payload += len;
|
|
|
|
|
|
|
|
nof_bytes -= len;
|
|
|
|
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU i=%d", rb_name().c_str(), i);
|
|
|
|
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
|
|
|
|
pdcp->write_pdu_mch(lcid, rx_sdu);
|
|
|
|
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Handle last segment
|
|
|
|
|
|
|
|
memcpy(&rx_sdu->msg[rx_sdu->N_bytes], payload, nof_bytes);
|
|
|
|
|
|
|
|
rx_sdu->N_bytes += nof_bytes;
|
|
|
|
|
|
|
|
log->debug("Writing last segment in SDU buffer. Buffer size=%d, segment size=%d\n",
|
|
|
|
|
|
|
|
rx_sdu->N_bytes, nof_bytes);
|
|
|
|
|
|
|
|
if(rlc_um_end_aligned(header.fi)) {
|
|
|
|
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU", rb_name().c_str());
|
|
|
|
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
|
|
|
|
pdcp->write_pdu_mch(lcid, rx_sdu);
|
|
|
|
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
vr_uh = (header.sn + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
|
|
|
|
std::map<uint32_t, rlc_umd_pdu_t>::iterator it;
|
|
|
@ -382,20 +600,20 @@ void rlc_um::handle_data_pdu(uint8_t *payload, uint32_t nof_bytes)
|
|
|
|
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
|
|
|
|
rlc_um_read_data_pdu_header(payload, nof_bytes, cfg.rx_sn_field_length, &header);
|
|
|
|
|
|
|
|
|
|
|
|
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
|
|
|
|
log->info_hex(payload, nof_bytes, "RX %s Rx data PDU SN: %d",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), header.sn);
|
|
|
|
rb_name().c_str(), header.sn);
|
|
|
|
|
|
|
|
|
|
|
|
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
|
|
|
|
if(RX_MOD_BASE(header.sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
|
|
|
|
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
|
|
|
|
RX_MOD_BASE(header.sn) < RX_MOD_BASE(vr_ur))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
|
|
|
|
log->info("%s SN: %d outside rx window [%d:%d] - discarding\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), header.sn, vr_ur, vr_uh);
|
|
|
|
rb_name().c_str(), header.sn, vr_ur, vr_uh);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
it = rx_window.find(header.sn);
|
|
|
|
it = rx_window.find(header.sn);
|
|
|
|
if(rx_window.end() != it)
|
|
|
|
if(rx_window.end() != it)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log->info("%s Discarding duplicate SN: %d\n",
|
|
|
|
log->info("%s Discarding duplicate SN: %d\n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), header.sn);
|
|
|
|
rb_name().c_str(), header.sn);
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -486,7 +704,7 @@ void rlc_um::reassemble_rx_sdus()
|
|
|
|
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
|
|
|
|
log->warning("Dropping remainder of lost PDU (lower edge middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
|
|
|
|
rx_sdu->reset();
|
|
|
|
rx_sdu->reset();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d (lower edge middle segments)", rb_name().c_str(), vr_ur, i);
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
@ -562,7 +780,7 @@ void rlc_um::reassemble_rx_sdus()
|
|
|
|
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
|
|
|
|
log->warning("Dropping remainder of lost PDU (update vr_ur middle segments, vr_ur=%d, vr_ur_in_rx_sdu=%d)\n", vr_ur, vr_ur_in_rx_sdu);
|
|
|
|
rx_sdu->reset();
|
|
|
|
rx_sdu->reset();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rrc->get_rb_name(lcid).c_str(), vr_ur, i);
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d, i=%d, (update vr_ur middle segments)", rb_name().c_str(), vr_ur, i);
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
@ -601,7 +819,7 @@ void rlc_um::reassemble_rx_sdus()
|
|
|
|
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
|
|
|
|
log->warning("Dropping remainder of lost PDU (update vr_ur last segments)\n");
|
|
|
|
rx_sdu->reset();
|
|
|
|
rx_sdu->reset();
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rrc->get_rb_name(lcid).c_str(), vr_ur);
|
|
|
|
log->info_hex(rx_sdu->msg, rx_sdu->N_bytes, "%s Rx SDU vr_ur=%d (update vr_ur last segments)", rb_name().c_str(), vr_ur);
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
rx_sdu->set_timestamp();
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
pdcp->write_pdu(lcid, rx_sdu);
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
|
rx_sdu = pool_allocate;
|
|
|
@ -625,6 +843,9 @@ clean_up_rx_window:
|
|
|
|
|
|
|
|
|
|
|
|
bool rlc_um::inside_reordering_window(uint16_t sn)
|
|
|
|
bool rlc_um::inside_reordering_window(uint16_t sn)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(cfg.rx_window_size == 0) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
|
|
|
|
if(RX_MOD_BASE(sn) >= RX_MOD_BASE(vr_uh-cfg.rx_window_size) &&
|
|
|
|
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
|
|
|
|
RX_MOD_BASE(sn) < RX_MOD_BASE(vr_uh))
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -637,10 +858,20 @@ bool rlc_um::inside_reordering_window(uint16_t sn)
|
|
|
|
void rlc_um::debug_state()
|
|
|
|
void rlc_um::debug_state()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
|
|
|
|
log->debug("%s vt_us = %d, vr_ur = %d, vr_ux = %d, vr_uh = %d \n",
|
|
|
|
rrc->get_rb_name(lcid).c_str(), vt_us, vr_ur, vr_ux, vr_uh);
|
|
|
|
rb_name().c_str(), vt_us, vr_ur, vr_ux, vr_uh);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string rlc_um::rb_name() {
|
|
|
|
|
|
|
|
if(mrb) {
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
ss << "MRB" << lcid;
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return rrc->get_rb_name(lcid);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
/****************************************************************************
|
|
|
|
* Header pack/unpack helper functions
|
|
|
|
* Header pack/unpack helper functions
|
|
|
|
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
|
|
|
|
* Ref: 3GPP TS 36.322 v10.0.0 Section 6.2.1
|
|
|
|