Commit b0d468c0 authored by fnabet's avatar fnabet

RLC AM: add retransmission and Rx status pdu

parent e7e48144
......@@ -389,7 +389,7 @@ rlc_am_get_pdus (
rlc_am_entity_t * const rlc_pP
)
{
int display_flag = 0;
//int display_flag = 0;
// 5.1.3.1 Transmit operations
// 5.1.3.1.1
// General
......@@ -436,123 +436,21 @@ rlc_am_get_pdus (
rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED));
}
/*while ((rlc_pP->nb_bytes_requested_by_mac > 0) && (stay_on_this_list)) {
mem_block_t* pdu = list_get_head(&rlc_pP->control_pdu_list);
if (pdu != NULL {
if ( ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size <= rlc_pP->nb_bytes_requested_by_mac) {
pdu = list_remove_head(&rlc_pP->control_pdu_list);
#if TRACE_RLC_AM_TX
msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] SEND CONTROL PDU\n", ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, ctxt_pP->frame);
#endif
list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer);
rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size;
} else {
stay_on_this_list = 0;
}
} else {
stay_on_this_list = 0;
}
}*/
// THEN TRY TO SEND RETRANS PDU
// BUG FIX : they can be PDU to ReTx due to received NACK or 1 PDU (SN = vtS - 1) to ReTx due TPoll Expiry if Buffer Occupancy is null
if (rlc_pP->first_retrans_pdu_sn >= 0) {
rlc_am_tx_data_pdu_management_t* tx_data_pdu_management;
// tx min 3 bytes because of the size of the RLC header
while ((rlc_pP->nb_bytes_requested_by_mac > 2) &&
(rlc_pP->first_retrans_pdu_sn >= 0) &&
(rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s)) {
tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn];
if ((tx_data_pdu_management->header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) && (tx_data_pdu_management->retx_count >= 0)
&& (tx_data_pdu_management->nack_so_start == 0) && (tx_data_pdu_management->nack_so_stop == 0x7FFF)) {
mem_block_t* copy = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn);
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RE-SEND DATA PDU SN %04d %d BYTES\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn,
tx_data_pdu_management->header_and_payload_size);
rlc_pP->stat_tx_data_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu_by_status += 1;
rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->header_and_payload_size;
rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->header_and_payload_size;
rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->header_and_payload_size;
list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer);
rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - tx_data_pdu_management->header_and_payload_size;
tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next;
return;
} else if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac >= RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d MAC BYTES %d SIZE %d RTX COUNT %d nack_so_start %d nack_so_stop %04X(hex)\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn,
rlc_pP->nb_bytes_requested_by_mac,
tx_data_pdu_management->header_and_payload_size,
tx_data_pdu_management->retx_count,
tx_data_pdu_management->nack_so_start,
tx_data_pdu_management->nack_so_stop);
mem_block_t* copy = rlc_am_retransmit_get_subsegment(
ctxt_pP,
rlc_pP,
rlc_pP->first_retrans_pdu_sn,
&rlc_pP->nb_bytes_requested_by_mac);
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d (NEW SO %05d)\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn,
tx_data_pdu_management->nack_so_start);
rlc_pP->stat_tx_data_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu_by_status += 1;
rlc_pP->stat_tx_data_bytes += (((struct mac_tb_req*)(copy->data))->tb_size);
rlc_pP->stat_tx_retransmit_bytes += (((struct mac_tb_req*)(copy->data))->tb_size);
rlc_pP->stat_tx_retransmit_bytes_by_status += (((struct mac_tb_req*)(copy->data))->tb_size);
list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer);
} else {
break;
}
if ((rlc_pP->retrans_num_bytes_to_retransmit) && (rlc_pP->nb_bytes_requested_by_mac > 2)) {
// update first_retrans_pdu_sn
while ((rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s) &&
(!(rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].flags.retransmit))) {
rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn+1) & RLC_AM_SN_MASK;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn SN %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn);
};
display_flag = 1;
if (rlc_pP->first_retrans_pdu_sn == rlc_pP->vt_s) {
// no more pdu to be retransmited
rlc_pP->first_retrans_pdu_sn = -1;
display_flag = 0;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CLEAR first_retrans_pdu_sn\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
}
/* Get 1 AM data PDU or PDU segment to retransmit */
mem_block_t* pdu_retx = rlc_am_get_pdu_to_retransmit(ctxt_pP, rlc_pP);
if (display_flag > 0) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn);
}
return;
if (pdu_retx != NULL) {
list_add_tail_eurecom (pdu_retx, &rlc_pP->pdus_to_mac_layer);
/* ONLY ONE TB PER TTI
if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac < RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) {
#if TRACE_RLC_AM_TX
msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] BREAK LOOP ON RETRANSMISSION BECAUSE ONLY %d BYTES ALLOWED TO TRANSMIT BY MAC\n",ctxt_pP->frame, ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, rlc_pP->nb_bytes_requested_by_mac);
#endif
break;
}*/
return;
}
}
if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->vt_s != rlc_pP->vt_ms)) {
// THEN TRY TO SEND NEW DATA PDU
if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->sdu_buffer_occupancy) && (rlc_pP->vt_s != rlc_pP->vt_ms)) {
rlc_am_segment_10(ctxt_pP, rlc_pP);
list_add_list (&rlc_pP->segmentation_pdu_list, &rlc_pP->pdus_to_mac_layer);
......@@ -563,29 +461,6 @@ rlc_am_get_pdus (
}
}
if ((rlc_pP->pdus_to_mac_layer.head == NULL) &&
(rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP)) &&
(rlc_pP->nb_bytes_requested_by_mac > 2)) {
rlc_am_retransmit_any_pdu(ctxt_pP, rlc_pP);
return;
} else {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" COULD NOT RETRANSMIT ANY PDU BECAUSE ",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
if (rlc_pP->pdus_to_mac_layer.head != NULL) {
LOG_D(RLC, "THERE ARE SOME PDUS READY TO TRANSMIT ");
}
if (!(rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP))) {
LOG_D(RLC, "TIMER POLL DID NOT TIMED OUT (RUNNING = %d NUM PDUS TO RETRANS = %d NUM BYTES TO RETRANS = %d) ", rlc_pP->t_poll_retransmit.running,
rlc_pP->retrans_num_pdus, rlc_pP->retrans_num_bytes_to_retransmit);
}
if (rlc_pP->nb_bytes_requested_by_mac <= 2) {
LOG_D(RLC, "NUM BYTES REQUESTED BY MAC = %d", rlc_pP->nb_bytes_requested_by_mac);
}
LOG_D(RLC, "\n");
}
break;
......
......@@ -56,6 +56,9 @@
/** PDU minimal header size in bytes. */
# define RLC_AM_HEADER_MIN_SIZE 2
/** PDU Segment minimal header size in bytes = PDU header + SOStart + SOEnd. */
# define RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE 4
/** If we want to send a segment of a PDU, then the min transport block size requested by MAC should be this amount. */
# define RLC_AM_MIN_SEGMENT_SIZE_REQUEST 8
......@@ -77,8 +80,8 @@
/* MACRO DEFINITIONS */
#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1))
#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1))
#define RLC_AM_NEXT_SN(sn) (((sn)+1) & (RLC_AM_SN_MASK))
#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & (RLC_AM_SN_MASK))
#define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1))
#define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1))
......@@ -103,7 +106,8 @@
#define RLC_AM_PDU_RF_BITS 1
#define EURL_AM_PDU_LSF_BITS 1
#define RLC_AM_LI_BITS 11
#define RLC_AM_LI_MASK 0x7FF
/* AM Data PDU */
......@@ -113,12 +117,28 @@
#define RLC_AM_PDU_RF_OFFSET (RLC_AM_PDU_POLL_OFFSET + RLC_AM_PDU_POLL_BITS)
#define RLC_AM_PDU_D_C_OFFSET (RLC_AM_PDU_RF_OFFSET + RLC_AM_PDU_RF_BITS)
#define RLC_AM_PDU_GET_FI_START(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET + 1))
#define RLC_AM_PDU_GET_FI_END(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET))
#define RLC_AM_PDU_GET_LI(x,offset) (((x) >> (offset)) & RLC_AM_LI_MASK)
#define RLC_AM_PDU_SET_LI(x,li,offset) ((x) |= (((li) & RLC_AM_LI_MASK) << (offset)))
#define RLC_AM_PDU_SET_E(px) (RLC_SET_BIT((px),RLC_AM_PDU_E_OFFSET))
#define RLC_AM_PDU_SET_D_C(px) (RLC_SET_BIT((px),RLC_AM_PDU_D_C_OFFSET))
#define RLC_AM_PDU_SET_RF(px) (RLC_SET_BIT((px),RLC_AM_PDU_RF_OFFSET))
#define RLC_AM_PDU_SET_POLL(px) (RLC_SET_BIT((px),RLC_AM_PDU_POLL_OFFSET))
#define RLC_AM_PDU_CLEAR_POLL(px) (RLC_CLEAR_BIT((px),RLC_AM_PDU_POLL_OFFSET))
#define RLC_AM_PDU_SEGMENT_SO_LENGTH 15
#define RLC_AM_PDU_SEGMENT_SO_BYTES 2
#define RLC_AM_PDU_SEGMENT_SO_OFFSET 0
#define RLC_AM_PDU_LSF_OFFSET (RLC_AM_PDU_SEGMENT_SO_OFFSET + RLC_AM_PDU_SEGMENT_SO_LENGTH)
#define RLC_AM_PDU_SET_LSF(px) (RLC_SET_BIT((px),RLC_AM_PDU_LSF_OFFSET))
#define RLC_AM_HEADER_LI_LENGTH(li) ((li) + ((li)>>1) + ((li)&1))
#define RLC_AM_PDU_SEGMENT_HEADER_SIZE(numLis) (RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + RLC_AM_HEADER_LI_LENGTH(numLis))
/* STATUS PDU */
#define RLC_AM_STATUS_PDU_CPT_STATUS 0
......
......@@ -175,7 +175,6 @@ typedef struct rlc_am_entity_s {
sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of remaining bytes available for transmission of any RLC PDU indicated by lower layer */
list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */
list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */
rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */
list_t segmentation_pdu_list; /*!< \brief List of "freshly" segmented PDUs. */
uint8_t status_requested; /*!< \brief Status bitmap requested by peer. */
......
......@@ -108,3 +108,41 @@ rlc_am_in_sdu_is_empty(
return 0;
}
// called when PDU is ACKED
//-----------------------------------------------------------------------------
void
rlc_am_pdu_sdu_data_cnf(
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t* const rlc_pP,
const rlc_sn_t snP)
{
int pdu_sdu_index;
int sdu_index;
for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) {
sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index];
assert(sdu_index >= 0);
assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE);
rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1;
if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) &&
(rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) {
#if TEST_RLC_AM
rlc_am_v9_3_0_test_data_conf (
rlc_pP->module_id,
rlc_pP->rb_id,
rlc_pP->input_sdus[sdu_index].mui,
RLC_SDU_CONFIRM_YES);
#else
rlc_data_conf(
ctxt_pP,
rlc_pP->rb_id,
rlc_pP->input_sdus[sdu_index].mui,
RLC_SDU_CONFIRM_YES,
rlc_pP->is_data_plane);
#endif
rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index);
}
}
}
......@@ -77,5 +77,13 @@ protected_rlc_am_in_sdu(void rlc_am_free_in_sdu_data (const protocol_ctxt_t* con
* \return 1 if the buffer is empty, else 0.
*/
protected_rlc_am_in_sdu(signed int rlc_am_in_sdu_is_empty(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP);)
/*! \fn void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP)
* \brief Process SDU cnf of a ACKED PDU for all SDUs concatenated in this PDU.
* \param[in] ctxtP Running context.
* \param[in] rlcP RLC AM protocol instance pointer.
* \param[in] snP Sequence number of the PDU.
*/
protected_rlc_am_in_sdu(void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP);)
/** @} */
# endif
......@@ -80,7 +80,6 @@ rlc_am_init(
rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED;
rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1
rlc_pP->first_retrans_pdu_sn = -1;
rlc_pP->initialized = TRUE;
}
......@@ -136,7 +135,6 @@ rlc_am_reestablish(
rlc_pP->status_requested = RLC_AM_STATUS_NOT_TRIGGERED;
rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1
rlc_pP->first_retrans_pdu_sn = -1;
rlc_pP->initialized = TRUE;
......
......@@ -30,12 +30,13 @@
#include "UTIL/LOG/log.h"
#include "msc.h"
//-----------------------------------------------------------------------------
void rlc_am_nack_pdu (
boolean_t rlc_am_nack_pdu (
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t *const rlc_pP,
const rlc_sn_t snP,
const sdu_size_t so_startP,
const sdu_size_t so_endP)
const rlc_sn_t prev_nack_snP,
sdu_size_t so_startP,
sdu_size_t so_endP)
{
// 5.2.1 Retransmission
// ...
......@@ -51,43 +52,116 @@ void rlc_am_nack_pdu (
mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block;
rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP];
//int pdu_sdu_index;
//int sdu_index;
boolean_t status = TRUE;
boolean_t retx_count_increment = FALSE;
sdu_size_t pdu_data_to_retx = 0;
if (mb_p != NULL) {
assert(so_startP <= so_endP);
//-----------------------------------------
// allow holes in reports
// it is assumed that hole reports are done in byte offset
// increasing order among calls refering to only one status PDU
// and among time
//-----------------------------------------
if (rlc_pP->tx_data_pdu_buffer[snP].last_nack_time != ctxt_pP->frame) {
rlc_pP->tx_data_pdu_buffer[snP].last_nack_time = ctxt_pP->frame;
rlc_am_clear_holes(ctxt_pP, rlc_pP, snP);
}
rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP);
// Handle full PDU NACK first
if ((so_startP == 0) && (so_endP == 0x7FFF)) {
if ((prev_nack_snP != snP) && (tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) {
pdu_data_to_retx = tx_data_pdu_buffer_p->payload_size;
/* Increment VtReTxNext if this is the first NACK or if some segments have already been transmitted */
if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (tx_data_pdu_buffer_p->nack_so_start))
{
retx_count_increment = TRUE;
}
if (rlc_pP->first_retrans_pdu_sn < 0) {
rlc_pP->first_retrans_pdu_sn = snP;
} else if (rlc_am_tx_sn1_gt_sn2(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn, snP)) {
rlc_pP->first_retrans_pdu_sn = snP;
tx_data_pdu_buffer_p->nack_so_start = 0;
tx_data_pdu_buffer_p->num_holes = 0;
tx_data_pdu_buffer_p->retx_hole_index = 0;
tx_data_pdu_buffer_p->nack_so_stop = tx_data_pdu_buffer_p->payload_size - 1;
#if TRACE_RLC_AM_HOLE
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] SN %04d GLOBAL NACK 0->%05d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
snP,
so_stopP);
#endif
assert(tx_data_pdu_buffer_p->nack_so_start < tx_data_pdu_buffer_p->payload_size);
}
else {
status = FALSE;
}
}
else if (tx_data_pdu_buffer_p->flags.max_retransmit == 0) {
// Handle Segment offset
if (so_endP == 0x7FFF) {
so_endP = tx_data_pdu_buffer_p->payload_size - 1;
}
// Check consistency
if ((so_startP < so_endP) && (so_endP < tx_data_pdu_buffer_p->payload_size)) {
if (prev_nack_snP != snP) {
/* New NACK_SN with SO */
/* check whether a new segment is to be placed in Retransmission Buffer, then increment vrReTx */
if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (so_startP < tx_data_pdu_buffer_p->nack_so_start)) {
retx_count_increment = TRUE;
}
tx_data_pdu_buffer_p->num_holes = 1;
tx_data_pdu_buffer_p->retx_hole_index = 0;
tx_data_pdu_buffer_p->hole_so_start[0] = so_startP;
tx_data_pdu_buffer_p->hole_so_stop[0] = so_endP;
tx_data_pdu_buffer_p->nack_so_start = so_startP;
tx_data_pdu_buffer_p->nack_so_stop = so_endP;
pdu_data_to_retx = so_endP - so_startP + 1;
}
else if ((tx_data_pdu_buffer_p->num_holes) && (tx_data_pdu_buffer_p->num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU)) {
/* New SOStart/SOEnd for the same NACK_SN than before */
/* check discontinuity */
if (so_startP > tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes - 1]) {
tx_data_pdu_buffer_p->hole_so_start[tx_data_pdu_buffer_p->num_holes] = so_startP;
tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes] = so_endP;
tx_data_pdu_buffer_p->nack_so_stop = so_endP;
tx_data_pdu_buffer_p->num_holes ++;
pdu_data_to_retx = so_endP - so_startP + 1;
}
else {
status = FALSE;
}
}
else {
status = FALSE;
}
}
else {
status = FALSE;
}
}
else {
status = FALSE;
}
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] NACK PDU SN %04d previous retx_count %d 1ST_RETRANS_PDU %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
snP,
rlc_pP->tx_data_pdu_buffer[snP].retx_count,
rlc_pP->first_retrans_pdu_sn);
rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 1;
/* TODO : before incrementing retx_count_next, one have to check this must be a new occurrence of retransmission */
if (rlc_pP->tx_data_pdu_buffer[snP].retx_count == rlc_pP->tx_data_pdu_buffer[snP].retx_count_next){
rlc_pP->tx_data_pdu_buffer[snP].retx_count_next ++;
rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[snP].payload_size;
if (status) {
tx_data_pdu_buffer_p->flags.nack = 1;
if ((retx_count_increment) && (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next)) {
tx_data_pdu_buffer_p->retx_count_next ++;
}
if (tx_data_pdu_buffer_p->flags.retransmit == 1) {
if (prev_nack_snP != snP) {
/* if first process of this NACK_SN and data already pending for retx */
rlc_pP->retrans_num_bytes_to_retransmit += (pdu_data_to_retx - tx_data_pdu_buffer_p->retx_payload_size);
tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx;
}
else if (tx_data_pdu_buffer_p->num_holes > 1) {
/* Segment case : SOStart and SOEnd already received for same NACK_SN */
/* filter case where a NACK_SN is received twice with SO first time and no SO second time */
rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx;
tx_data_pdu_buffer_p->retx_payload_size += pdu_data_to_retx;
}
}
else {
tx_data_pdu_buffer_p->flags.retransmit = 1;
rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx;
tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx;
rlc_pP->retrans_num_pdus ++;
}
}
/* TODO: Move this part in UL SCH processing */
......@@ -123,8 +197,10 @@ void rlc_am_nack_pdu (
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU SN %05d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
snP);
//assert(2==3);
status = FALSE;
}
return status;
}
//-----------------------------------------------------------------------------
void rlc_am_ack_pdu (
......@@ -133,8 +209,6 @@ void rlc_am_ack_pdu (
const rlc_sn_t snP)
{
mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block;
int pdu_sdu_index;
int sdu_index;
rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0;
......@@ -147,83 +221,13 @@ void rlc_am_ack_pdu (
snP,
rlc_pP->tx_data_pdu_buffer[snP].retx_count);
if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= 0) {
rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].payload_size;
if (rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size) {
rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size;
rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size = 0;
rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0;
rlc_pP->retrans_num_pdus --;
}
for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) {
sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index];
assert(sdu_index >= 0);
assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE);
rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1;
if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) &&
(rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) {
#if TEST_RLC_AM
rlc_am_v9_3_0_test_data_conf (
rlc_pP->module_id,
rlc_pP->rb_id,
rlc_pP->input_sdus[sdu_index].mui,
RLC_SDU_CONFIRM_YES);
#else
rlc_data_conf(
ctxt_pP,
rlc_pP->rb_id,
rlc_pP->input_sdus[sdu_index].mui,
RLC_SDU_CONFIRM_YES,
rlc_pP->is_data_plane);
#endif
rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index);
}
}
// 7.1...
// VT(A) – Acknowledgement state variable
// This state variable holds the value of the SN of the next AMD PDU for which a positive acknowledgment is to be
// received in-sequence, and it serves as the lower edge of the transmitting window. It is initially set to 0, and is updated
// whenever the AM RLC entity receives a positive acknowledgment for an AMD PDU with SN = VT(A).
rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1;
if (snP == rlc_pP->vt_a) {
//rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1;
do {
memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t));
if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) {
rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK;
}
rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK;
} while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s));
rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->vt_a,
rlc_pP->vt_ms,
rlc_pP->vt_s);
}
if (snP == rlc_pP->first_retrans_pdu_sn) {
do {
rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn + 1) & RLC_AM_SN_MASK;
if (rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].retx_count >= 0) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn);
break;
}
} while (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s);
if (rlc_pP->vt_s == rlc_pP->first_retrans_pdu_sn) {
rlc_pP->first_retrans_pdu_sn = -1;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->first_retrans_pdu_sn);
}
}
} else {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] WARNING ACK PDU SN %05d -> NO PDU TO ACK\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
......@@ -233,29 +237,11 @@ void rlc_am_ack_pdu (
free_mem_block(mb_p, __func__);
rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL;
}
if (rlc_pP->tx_data_pdu_buffer[snP].flags.ack > 0) {
if (snP == rlc_pP->vt_a) {
//rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1;
do {
memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t));
if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) {
rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK;
}
rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK;
} while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s));
rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
rlc_pP->vt_a,
rlc_pP->vt_ms,
rlc_pP->vt_s);
}
}
}
rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1;
rlc_pP->tx_data_pdu_buffer[snP].flags.transmitted = 0;
rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0;
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_copy (
......@@ -265,25 +251,343 @@ mem_block_t* rlc_am_retransmit_get_copy (
{
mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block;
if (mb_original_p != NULL) {
AssertFatal (mb_original_p != NULL, "RLC AM PDU Copy Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n",
snP,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE];
rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE];
int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req);
mem_block_t* mb_copy = get_free_mem_block(size, __func__);
memcpy(mb_copy->data, mb_original_p->data, size);
/* We need to allocate a new buffer and copy to it because header content may change for Polling bit */
int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req);
mem_block_t* mb_copy = get_free_mem_block(size, __func__);
memcpy(mb_copy->data, mb_original_p->data, size);
rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]);
((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p;
rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]);
((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p;
pdu_mngt->flags.retransmit = 0;
return mb_copy;
}
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size,false);
return mb_copy;
} else {
return NULL;
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_am_segment(
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t *const rlc_pP,
rlc_am_tx_data_pdu_management_t *const pdu_mngt,
sdu_size_t * const payload_sizeP /* in-out*/)
{
int16_t sdus_segment_size[RLC_AM_MAX_SDU_IN_PDU];
mem_block_t* mb_original_p = pdu_mngt->mem_block;
mem_block_t* mem_pdu_segment_p = NULL;
uint8_t *pdu_original_header_p = NULL;
uint8_t *pdu_segment_header_p = NULL;
sdu_size_t retx_so_start,retx_so_stop; //starting and ending SO for retransmission in this PDU
rlc_sn_t sn = pdu_mngt->sn;
uint16_t header_so_part;
boolean_t fi_start, fi_end;
uint8_t sdu_index = 0;
uint8_t sdu_segment_index = 0;
uint8_t num_LIs_pdu_segment = pdu_mngt->nb_sdus - 1;
uint8_t li_bit_offset = 4; /* toggle between 0 and 4 */
uint8_t li_jump_offset = 1; /* toggle between 1 and 2 */
AssertFatal (mb_original_p != NULL, "RLC AM PDU Segment Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n",
sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
AssertFatal (pdu_mngt->payload == mb_original_p->data + sizeof(struct mac_tb_req) + pdu_mngt->header_and_payload_size - pdu_mngt->payload_size,
"RLC AM PDU Segment Error: Inconsistent data pointers p1=%p p2=%p sn = %d total size = %d data size = %d LcId=%d !\n",
pdu_mngt->payload,mb_original_p->data + sizeof(struct mac_tb_req),pdu_mngt->header_and_payload_size,pdu_mngt->payload_size,sn,rlc_pP->channel_id);
/* Init ReTx Hole list if not configured, ie the whole PDU has to be retransmitted */
if (pdu_mngt->num_holes == 0)
{
AssertFatal (pdu_mngt->retx_payload_size == pdu_mngt->payload_size,"RLC AM PDU ReTx Segment: Expecting full PDU size ReTxSize=%d DataSize=%d sn=%d vtA=%d vtS=%d LcId=%d !\n",
pdu_mngt->retx_payload_size,pdu_mngt->payload_size,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
pdu_mngt->retx_hole_index = 0;
pdu_mngt->hole_so_start[0] = 0;
pdu_mngt->hole_so_stop[0] = pdu_mngt->payload_size - 1;
pdu_mngt->num_holes = 1;
}
/* Init SO Start and SO Stop */
retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index];
retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index];
/* Init FI to the same value as original PDU */
fi_start = (!(RLC_AM_PDU_GET_FI_START(*(pdu_mngt->first_byte))));
fi_end = (!(RLC_AM_PDU_GET_FI_END(*(pdu_mngt->first_byte))));
/* Handle no LI case first */
if (num_LIs_pdu_segment == 0)
{
/* Bound retx_so_stop to available TBS */
if (retx_so_stop - retx_so_start + 1 + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac)
{
retx_so_stop = retx_so_start + rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE - 1;
}
*payload_sizeP = retx_so_stop - retx_so_start + 1;
mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + sizeof(struct mac_tb_req)), __func__);
pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)];
/* clear all PDU segment */
memset(pdu_segment_header_p, 0, *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE);
/* copy data part */
memcpy(pdu_segment_header_p + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE, pdu_mngt->payload + retx_so_start, *payload_sizeP);
/* Set FI part to false if SO Start and SO End are different from PDU boundaries */
if (retx_so_start)
{
fi_start = FALSE;
}
if (retx_so_stop < pdu_mngt->payload_size - 1)
{
fi_end = FALSE;
}
/* Header content is filled at the end */
}
else
{
/* Step 1 */
/* Find the SDU index in the original PDU containing retx_so_start */
sdu_size_t sdu_size = 0;
sdu_size_t data_size = 0;
sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE;
pdu_original_header_p = pdu_mngt->first_byte + 2;
li_bit_offset = 4; /* toggle between 0 and 4 */
li_jump_offset = 1; /* toggle between 1 and 2 */
/* Read first LI */
sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset);
pdu_original_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
data_size += sdu_size;
while ((data_size - 1 < retx_so_start) && (sdu_index < pdu_mngt->nb_sdus))
{
sdu_index ++;
if (sdu_index < pdu_mngt->nb_sdus)
{
sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset);
pdu_original_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
data_size += sdu_size;
}
}
/* Set FI Start if retx_so_start = cumulated data size */
if (retx_so_start == data_size)
{
fi_start = TRUE;
/* jump to next SDU */
sdu_index ++;
/* there must be at least one SDU more */
AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n",
sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id);
sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset);
pdu_original_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
data_size += sdu_size;
}
/* Set first SDU portion of the segment */
sdus_segment_size[0] = data_size - retx_so_start;
/* Now look for the end */
while ((data_size - 1 < retx_so_stop) && (sdu_index < pdu_mngt->nb_sdus))
{
sdu_index ++;
sdu_segment_index ++;
if (sdu_index < pdu_mngt->nb_sdus)
{
sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset);
pdu_original_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
data_size += sdu_size;
sdus_segment_size[sdu_segment_index] = sdu_size;
}
}
/* Set FI End if retx_so_stop = cumulated data size */
if (retx_so_stop == data_size - 1)
{
fi_end = TRUE;
}
/* Set last SDU portion of the segment even if it will be out of LI */
if (sdu_segment_index)
{
sdus_segment_size[sdu_segment_index] = retx_so_stop - (data_size - sdu_size) + 1;
}
else
{
sdus_segment_size[0] = retx_so_stop - retx_so_start + 1;
}
/* Set number of LIs in the segment */
num_LIs_pdu_segment = sdu_segment_index;
/* Memory allocation taking into account available TBS */
/* Compute Header Length and Data Length */
/* Init Segment Payload data size */
*payload_sizeP = sdus_segment_size[0];
/* Bound to available TBS taking into account min PDU segment header*/
if (*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac)
{
*payload_sizeP = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE;
}
sdu_segment_index = 1;
while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index)))
{
/* Add next sdu_segment_index to data part */
if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + sdus_segment_size[sdu_segment_index] < rlc_pP->nb_bytes_requested_by_mac)
{
(*payload_sizeP) += sdus_segment_size[sdu_segment_index];
}
else
{
/* bound to available TBS size */
(*payload_sizeP) += (rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index));
sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index);
}
header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index);
sdu_segment_index ++;
}
num_LIs_pdu_segment = sdu_segment_index - 1;
/* Check consistency between sdus_segment_size and payload_sizeP */
data_size = 0;
for (int i = 0; i < num_LIs_pdu_segment + 1; i++)
{
data_size += sdus_segment_size[i];
}
AssertFatal (data_size == *payload_sizeP, "RLC AM PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n",
data_size,*payload_sizeP,sn,rlc_pP->channel_id);
/* Allocation */
AssertFatal (header_segment_length + *payload_sizeP <= pdu_mngt->header_and_payload_size + 2, "RLC AM PDU Segment Error: Hdr=%d Data=%d Original Hdr+Data =%d sn=%d LcId=%d !\n",
header_segment_length,*payload_sizeP,pdu_mngt->header_and_payload_size,sn,rlc_pP->channel_id);
mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + header_segment_length + sizeof(struct mac_tb_req)), __func__);
pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)];
/* clear all PDU segment */
memset(pdu_segment_header_p, 0, *payload_sizeP + header_segment_length);
/* copy data part */
memcpy(pdu_segment_header_p + header_segment_length, pdu_mngt->payload + retx_so_start, *payload_sizeP);
}
/* Last step : update contexts and fill PDU Segment Header */
if (mem_pdu_segment_p != NULL)
{
/* Update PDU Segment contexts */
if (*payload_sizeP == pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index] - pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] + 1)
{
/* All data in the segment are transmitted : switch to next one */
pdu_mngt->retx_hole_index ++;
if (pdu_mngt->retx_hole_index < pdu_mngt->num_holes)
{
/* Set min SOStart to the value of next hole : assumption is holes are ordered by increasing SOStart */
pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index];
}
else
{
/* no more scheduled Retx: reset values */
/* Retx size is reset in the calling function */
pdu_mngt->num_holes = 0;
pdu_mngt->retx_hole_index = 0;
}
}
else
{
/* not all segment data could be transmitted, just update SoStart */
pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] += (*payload_sizeP);
pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index];
}
/* Set Fixed part of AM PDU Segment Header */
pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)];
/* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */
/* copy first two bytes from original: D/C + RF + FI + E+ SN*/
*pdu_segment_header_p = *(pdu_mngt->first_byte);
*(pdu_segment_header_p + 1) = *(pdu_mngt->first_byte + 1);
/* Set Segmentation Flag */
RLC_AM_PDU_SET_RF(*pdu_segment_header_p);
/* clear polling */
RLC_AM_PDU_CLEAR_POLL(*pdu_segment_header_p);
/* Change FI */
if (!fi_start)
{
// Set to not starting
(*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1));
}
if (!fi_end)
{
// Set to not starting
(*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET));
}
/* Segment Offset */
header_so_part = retx_so_start;
/* Last Segment Flag (LSF) */
if (retx_so_stop == pdu_mngt->payload_size - 1)
{
RLC_AM_PDU_SET_LSF(header_so_part);
}
/* Store SO bytes */
* (pdu_segment_header_p + 2) = (header_so_part >> 8) & 0xFF;
* (pdu_segment_header_p + 3) = header_so_part & 0xFF;
/* Fill LI part */
if (num_LIs_pdu_segment)
{
uint16_t index = 0;
uint16_t temp = 0;
/* Set Extension bit in first byte */
RLC_AM_PDU_SET_E(*pdu_segment_header_p);
/* loop on nb of LIs */
pdu_segment_header_p += RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE;
li_bit_offset = 4; /* toggle between 0 and 4 */
li_jump_offset = 1; /* toggle between 1 and 2 */
while (index < num_LIs_pdu_segment)
{
/* Set E bit for next LI if present */
if (index < num_LIs_pdu_segment - 1)
RLC_SET_BIT(temp,li_bit_offset + RLC_AM_LI_BITS);
/* Set LI */
RLC_AM_PDU_SET_LI(temp,sdus_segment_size[index],li_bit_offset);
*pdu_segment_header_p = temp >> 8;
*(pdu_segment_header_p + 1) = temp & 0xFF;
pdu_segment_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
temp = ((*pdu_segment_header_p) << 8) + *(pdu_segment_header_p + 1);
index ++;
}
}
}
return mem_pdu_segment_p;
}
#if 0
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_subsegment(
const protocol_ctxt_t* const ctxt_pP,
......@@ -739,8 +1043,6 @@ mem_block_t* rlc_am_retransmit_get_subsegment(
snP);
return NULL;
}
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size,false);
return mb_sub_segment_p;
} else {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n",
......@@ -750,6 +1052,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment(
return NULL;
}
}
#endif
//-----------------------------------------------------------------------------
void rlc_am_tx_buffer_display (
const protocol_ctxt_t* const ctxt_pP,
......@@ -803,6 +1106,124 @@ void rlc_am_tx_buffer_display (
LOG_D(RLC, "\n");
}
//-----------------------------------------------------------------------------
mem_block_t * rlc_am_get_pdu_to_retransmit(
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t* const rlc_pP)
{
rlc_sn_t sn = rlc_pP->vt_a;
rlc_sn_t sn_end = rlc_pP->vt_s;
mem_block_t* pdu_p = NULL;
rlc_am_tx_data_pdu_management_t* tx_data_pdu_management;
AssertFatal ((rlc_pP->retrans_num_pdus > 0) && (rlc_pP->vt_a != rlc_pP->vt_s), "RLC AM ReTx start process Error: NbPDUtoRetx=%d vtA=%d vtS=%d LcId=%d !\n",
rlc_pP->retrans_num_pdus,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
do
{
tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE];
if ((tx_data_pdu_management->flags.retransmit) && (tx_data_pdu_management->flags.max_retransmit == 0))
{
AssertFatal (tx_data_pdu_management->sn == sn, "RLC AM ReTx PDU Error: SN Error pdu_sn=%d sn=%d vtA=%d vtS=%d LcId=%d !\n",
tx_data_pdu_management->sn,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
AssertFatal (tx_data_pdu_management->flags.transmitted == 1, "RLC AM ReTx PDU Error: State Error sn=%d vtA=%d vtS=%d LcId=%d !\n",
sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
AssertFatal (tx_data_pdu_management->retx_payload_size > 0, "RLC AM ReTx PDU Error: No Data to Retx sn=%d vtA=%d vtS=%d LcId=%d !\n",
sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
/* Either the whole RLC PDU is to be transmitted and there is enough MAC TBS or there is minimum TBS size for transmitting 1 AM PDU segment */
if ((tx_data_pdu_management->retx_payload_size == tx_data_pdu_management->payload_size) && (rlc_pP->nb_bytes_requested_by_mac >= tx_data_pdu_management->header_and_payload_size))
{
/* check maxretx is not hit */
if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold)
{
pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn);
if (pdu_p != NULL)
{
rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_management->retx_payload_size;
rlc_pP->retrans_num_pdus --;
tx_data_pdu_management->retx_payload_size = 0;
tx_data_pdu_management->flags.retransmit = 0;
// update stats
rlc_pP->stat_tx_data_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu_by_status += 1;
rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->payload_size;
rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->payload_size;
rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->payload_size;
}
}
else
{
// TO DO : RLC Notification to RRC + ReEstablishment procedure
tx_data_pdu_management->flags.max_retransmit = 1;
}
}
else if (rlc_pP->nb_bytes_requested_by_mac >= 5)
{
/* Resegmentation case */
/* check maxretx is not hit */
if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold)
{
sdu_size_t pdu_data_size = 0;
pdu_p = rlc_am_retransmit_get_am_segment(ctxt_pP, rlc_pP, tx_data_pdu_management,&pdu_data_size);
if (pdu_p != NULL)
{
AssertFatal ((tx_data_pdu_management->retx_payload_size >= pdu_data_size) && (rlc_pP->retrans_num_bytes_to_retransmit >= pdu_data_size), "RLC AM ReTx PDU Segment Error: DataSize=%d PDUReTxsize=%d TotalReTxsize=%d sn=%d LcId=%d !\n",
pdu_data_size,tx_data_pdu_management->retx_payload_size,rlc_pP->retrans_num_bytes_to_retransmit,sn,rlc_pP->channel_id);
tx_data_pdu_management->retx_payload_size -= pdu_data_size;
rlc_pP->retrans_num_bytes_to_retransmit -= pdu_data_size;
if (tx_data_pdu_management->retx_payload_size == 0)
{
rlc_pP->retrans_num_pdus --;
tx_data_pdu_management->retx_payload_size = 0;
tx_data_pdu_management->flags.retransmit = 0;
}
// update stats
rlc_pP->stat_tx_data_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu += 1;
rlc_pP->stat_tx_retransmit_pdu_by_status += 1;
rlc_pP->stat_tx_data_bytes += pdu_data_size;
rlc_pP->stat_tx_retransmit_bytes += pdu_data_size;
rlc_pP->stat_tx_retransmit_bytes_by_status += pdu_data_size;
}
}
else
{
// TO DO : RLC Notification to RRC + ReEstablishment procedure
tx_data_pdu_management->flags.max_retransmit = 1;
}
}
if (pdu_p != NULL)
{
/* check polling */
rlc_am_pdu_sn_10_t* pdu_header_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]);
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_header_p, tx_data_pdu_management->payload_size,false);
tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next;
break;
}
}
sn = RLC_AM_NEXT_SN(sn);
} while((sn != sn_end) && (rlc_pP->retrans_num_pdus > 0));
return pdu_p;
}
#if 0
//-----------------------------------------------------------------------------
void rlc_am_retransmit_any_pdu(
const protocol_ctxt_t* const ctxt_pP,
......@@ -891,3 +1312,4 @@ void rlc_am_retransmit_any_pdu(
}
}
}
#endif
......@@ -50,21 +50,24 @@
# define public_rlc_am_retransmit(x) extern x
# endif
# endif
/*! \fn void rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, uint16_t snP, sdu_size_t so_startP, sdu_size_t so_endP)
/*! \fn boolean_t rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, int16_t snP, int16_t prev_nack_snP,sdu_size_t so_startP, sdu_size_t so_endP)
* \brief The RLC AM PDU which have the sequence number snP is marked NACKed with segment offset fields.
* \param[in] ctxtP Running context.
* \param[in] rlcP RLC AM protocol instance pointer.
* \param[in] snP Sequence number of the PDU that is negative acknowledged.
* \param[in] prev_nack_snP Sequence number of previous PDU that is negative acknowledged.
* \param[in] so_startP Start of the segment offset of the PDU that .
* \param[in] so_endP Transport blocks received from MAC layer.
* \return OK/KO
* \note It may appear a new hole in the retransmission buffer depending on the segment offset informations. Depending on the state of the retransmission buffer, negative confirmation can be sent to higher layers about the drop by the RLC AM instance of a particular SDU.
*/
protected_rlc_am_retransmit(void rlc_am_nack_pdu (
protected_rlc_am_retransmit(boolean_t rlc_am_nack_pdu (
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t *const rlcP,
const rlc_sn_t snP,
const sdu_size_t so_startP,
const sdu_size_t so_endP);)
const rlc_sn_t prev_nack_snP,
sdu_size_t so_startP,
sdu_size_t so_endP);)
/*! \fn void rlc_am_ack_pdu (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP, rlc_sn_t snP)
* \brief The RLC AM PDU which have the sequence number snP is marked ACKed.
......@@ -90,6 +93,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_copy (
rlc_am_entity_t *const rlcP,
const rlc_sn_t snP));
#if 0
/*! \fn mem_block_t* rlc_am_retransmit_get_subsegment (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP,rlc_sn_t snP, sdu_size_t *sizeP)
* \brief The RLC AM PDU which have the sequence number snP is marked ACKed.
* \param[in] ctxtP Running context.
......@@ -103,7 +107,18 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment (
rlc_am_entity_t *const rlcP,
const rlc_sn_t snP,
sdu_size_t *const sizeP));
#endif
/*! \fn mem_block_t* rlc_am_get_pdu_to_retransmit(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP)
* \brief Find a PDU or PDU segment to retransmit.
* \param[in] ctxtP Running context.
* \param[in] rlcP RLC AM protocol instance pointer.
* \return A copy of the retransmitted PDU or PDU segment or NULL if TBS was not big enough
*/
protected_rlc_am_retransmit(mem_block_t* rlc_am_get_pdu_to_retransmit(
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t* const rlcP);)
#if 0
/*! \fn void rlc_am_retransmit_any_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP)
* \brief Retransmit any PDU in order to unblock peer entity, if no suitable PDU is found (depending on requested MAC size) to be retransmitted, then try to retransmit a subsegment of any PDU.
* \param[in] ctxtP Running context.
......@@ -112,6 +127,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment (
protected_rlc_am_retransmit(void rlc_am_retransmit_any_pdu(
const protocol_ctxt_t* const ctxt_pP,
rlc_am_entity_t* const rlcP);)
#endif
/*! \fn void rlc_am_tx_buffer_display (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* rlcP, char* message_pP)
* \brief Display the dump of the retransmission buffer.
......
......@@ -113,14 +113,14 @@ void rlc_am_pdu_polling (
rlc_pP->c_byte_without_poll = 0;
// vt_s shall have been updated before in case of new transmission
rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
rlc_pP->poll_sn = RLC_AM_PREV_SN(rlc_pP->vt_s);
//optimisation if (!rlc_pP->t_poll_retransmit.running) {
rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
//optimisation } else {
//optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out;
//optimisation }
} else {
// Not sure this is necessary
// Need to clear poll bit as it may be a copy(retransmission case) of the original RLC PDU which was containing a poll
RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1);
}
}
......@@ -533,16 +533,19 @@ void rlc_am_segment_10 (
pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size;
pdu_mngt_p->retx_count = 0;
pdu_mngt_p->retx_count_next = 0;
pdu_mngt_p->flags.retransmit = 0;
pdu_mngt_p->flags.transmitted = 1;
//TBC: What for resetting local pointers at the end ??
pdu_p = NULL;
pdu_mem_p = NULL;
//nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size;
nb_bytes_to_transmit = 0; // 1 PDU only
mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, (rlc_pP->vt_s-1) & RLC_AM_SN_MASK);
/* We need to copy the PDU to pass to MAC in order to keep it in the buffer for potential retransmissions */
mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, RLC_AM_PREV_SN(rlc_pP->vt_s));
list_add_tail_eurecom (copy, &rlc_pP->segmentation_pdu_list);
}
......
......@@ -268,6 +268,14 @@ rlc_am_receive_process_control_pdu(
{
rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)*first_byte_ppP;
sdu_size_t initial_pdu_size = *tb_size_in_bytes_pP;
rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn;
rlc_sn_t sn_cursor = rlc_pP->vt_a;
rlc_sn_t vt_a_new = rlc_pP->vt_a;
rlc_sn_t sn_data_cnf;
rlc_sn_t nack_sn,prev_nack_sn;
sdu_size_t data_cnf_so_stop = 0x7FFF;
unsigned int nack_index;
boolean_t status = TRUE;
if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, tb_size_in_bytes_pP, &rlc_pP->control_pdu_info) >= 0) {
......@@ -280,10 +288,6 @@ rlc_am_receive_process_control_pdu(
rlc_pP->control_pdu_info.ack_sn);
rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info);
rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn;
rlc_sn_t sn_cursor = rlc_pP->vt_a;
rlc_sn_t nack_sn;
unsigned int nack_index;
// 5.2.1 Retransmission
//
......@@ -308,66 +312,113 @@ rlc_am_receive_process_control_pdu(
assert(ack_sn < RLC_AM_SN_MODULO);
assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU);
/* Nv1495998 : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */
/* Note : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */
/* and meaning the report is not complete due to not enough ressources to fill all SOStart/SOEnd of this NACK_SN */
if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a))
{
if (rlc_pP->control_pdu_info.num_nack == 0) {
while (sn_cursor != ack_sn) {
rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor);
sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK;
sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
}
vt_a_new = ack_sn;
sn_data_cnf = RLC_AM_PREV_SN(vt_a_new);
} else {
nack_index = 0;
nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
prev_nack_sn = 0x3FFF;
while (sn_cursor != ack_sn) {
while (sn_cursor != nack_sn) {
rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor);
sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
}
vt_a_new = nack_sn;
// catch DataCfn
rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn];
if (tx_data_pdu_buffer_p->retx_payload_size == tx_data_pdu_buffer_p->payload_size) {
sn_data_cnf = RLC_AM_PREV_SN(nack_sn);
}
else if (tx_data_pdu_buffer_p->nack_so_start != 0) {
sn_data_cnf = nack_sn;
data_cnf_so_stop = tx_data_pdu_buffer_p->nack_so_start - 1;
}
else {
sn_data_cnf = RLC_AM_PREV_SN(nack_sn);
}
while ((sn_cursor != ack_sn) && (status)) {
if (sn_cursor != nack_sn) {
rlc_am_ack_pdu(ctxt_pP,
rlc_pP,
sn_cursor);
} else {
rlc_am_nack_pdu (ctxt_pP,
status = rlc_am_nack_pdu (ctxt_pP,
rlc_pP,
sn_cursor,
nack_sn,
prev_nack_sn,
rlc_pP->control_pdu_info.nack_list[nack_index].so_start,
rlc_pP->control_pdu_info.nack_list[nack_index].so_end);
nack_index = nack_index + 1;
prev_nack_sn = nack_sn;
if (nack_index == rlc_pP->control_pdu_info.num_nack) {
nack_sn = 0xFFFF; // value never reached by sn
} else {
nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
if (nack_index < rlc_pP->control_pdu_info.num_nack) {
nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
}
}
if ((nack_index < rlc_pP->control_pdu_info.num_nack) && (nack_index > 0)) {
if (rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn != rlc_pP->control_pdu_info.nack_list[nack_index-1].nack_sn) {
sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK;
else if (nack_sn != ack_sn) {
/* general case*/
nack_sn = ack_sn;
}
else {
/*specific case when the sender did not have enough TBS to fill all SOStart SOEnd for this NACK_SN */
break;
}
} else {
sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK;
}
sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK;
}
}
/* Check for Stopping TpollReTx */
if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) &&
(RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) {
rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
rlc_pP->poll_sn = RLC_SN_UNDEFINED;
}
/* Update vtA */
} else {
LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
status = FALSE;
}
} else {
LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
status = FALSE;
}
if (status) {
/* Check for Stopping TpollReTx */
if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) &&
(RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) {
rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
rlc_pP->poll_sn = RLC_SN_UNDEFINED;
}
//TODO : this part does not cover all cases of Data Cnf and move it at the end of Status PDU processing
sn_cursor = rlc_pP->vt_a;
/* Handle all acked PDU up to and excluding sn_data_cnf */
while (sn_cursor != sn_data_cnf) {
rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_cursor);
sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
}
// Handle last SN. TO DO : case of PDU partially ACKED with SDU to be data conf
if (data_cnf_so_stop == 0x7FFF) {
rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_data_cnf);
}
/* Update vtA and vtMS */
rlc_pP->vt_a = vt_a_new;
rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK;
}
*first_byte_ppP = (uint8_t*)((uint64_t)*first_byte_ppP + initial_pdu_size - *tb_size_in_bytes_pP);
......
......@@ -113,9 +113,10 @@ typedef struct rlc_am_tx_data_pdu_management {
uint8_t retx_hole_index; /*!< \brief Next index of registered holes to retransmit. */
sdu_size_t header_and_payload_size; /*!< \brief Size of the PDU in bytes, including header and payload. */
sdu_size_t payload_size; /*!< \brief Size of the PDU payload in bytes. */
sdu_size_t retx_payload_size; /*!< \brief Size of the PDU payload to be retransmitted in bytes including all Segment portions. */
rlc_sn_t sn; /*!< \brief Sequence number of the PDU. */
sdu_size_t nack_so_start; /*!< \brief Lowest NACK start segment offset, must be set to 0 if global NACK. */
sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size if global NACK */
sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size - 1 if global NACK */
int8_t nb_sdus; /*!< \brief Number of sdu having segments in this pdu. */
int8_t retx_count; /*!< \brief Counts the number of already occurred retransmissions of an AMD PDU (see subclause 5.2.1). */
......
......@@ -90,8 +90,12 @@ rlc_am_check_timer_poll_retransmit(
sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id);
if ((rlc_pP->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc_pP->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) {
rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit = 1;
if (rlc_pP->tx_data_pdu_buffer[sn].retx_count == rlc_pP->tx_data_pdu_buffer[sn].retx_count_next) {
rlc_pP->tx_data_pdu_buffer[sn].retx_count_next ++;
}
rlc_pP->retrans_num_pdus += 1;
rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[sn].payload_size;
break;
}
else
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment