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;