/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is
   included in this distribution in the file called "COPYING". If not,
   see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr

  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

 *******************************************************************************/
#define RLC_AM_MODULE
#define RLC_AM_RETRANSMIT_C
//-----------------------------------------------------------------------------
//#include "rtos_header.h"
//-----------------------------------------------------------------------------
#include "rlc_am.h"
#include "rlc.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
//#define TRACE_RLC_AM_RESEGMENT
//#define TRACE_RLC_AM_FORCE_TRAFFIC
//#define TRACE_RLC_AM_NACK
//#define TRACE_RLC_AM_ACK
//-----------------------------------------------------------------------------
void 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)
//-----------------------------------------------------------------------------
{
  // 5.2.1 Retransmission
  // ...
  // When an AMD PDU or a portion of an AMD PDU is considered for retransmission, the transmitting side of the AM
  // RLC entity shall:
  //     - if the AMD PDU is considered for retransmission for the first time:
  //         - set the RETX_COUNT associated with the AMD PDU to zero;
  //     - else, if it (the AMD PDU or the portion of the AMD PDU that is considered for retransmission) is not pending
  //            for retransmission already, or a portion of it is not pending for retransmission already:
  //         - increment the RETX_COUNT;
  //     - if RETX_COUNT = maxRetxThreshold:
  //         - indicate to upper layers that max retransmission has been reached.


  mem_block_t* mb_p         = rlc_pP->pdu_retrans_buffer[snP].mem_block;
  int          pdu_sdu_index;
  int          sdu_index;

  if (mb_p != NULL) {
    rlc_pP->num_nack_sn += 1;
    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->pdu_retrans_buffer[snP].last_nack_time != ctxt_pP->frame) {
      rlc_pP->pdu_retrans_buffer[snP].last_nack_time = ctxt_pP->frame;
      rlc_am_clear_holes(ctxt_pP, rlc_pP, snP);
    }

    if (!((so_startP == 0) && (so_endP == 0x7FFF))) {
      rlc_pP->num_nack_so += 1;
    }

    rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP);

    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;
    }

    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->pdu_retrans_buffer[snP].retx_count,
          rlc_pP->first_retrans_pdu_sn);

    rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 1;

    if (rlc_pP->pdu_retrans_buffer[snP].retx_count == -1) {
      rlc_pP->pdu_retrans_buffer[snP].retx_count = 0;
      rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size;
    } else {
      rlc_pP->pdu_retrans_buffer[snP].retx_count += 1;
    }

    if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= rlc_pP->max_retx_threshold) {
      for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) {
        sdu_index = rlc_pP->pdu_retrans_buffer[snP].sdus_index[pdu_sdu_index];
        assert(pdu_sdu_index < RLC_AM_MAX_SDU_IN_PDU);
        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) {
#ifdef 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_NO);
#else
          rlc_data_conf(ctxt_pP, rlc_pP->rb_id, rlc_pP->input_sdus[sdu_index].mui, RLC_SDU_CONFIRM_NO, rlc_pP->is_data_plane);
#endif
          rlc_pP->stat_tx_pdcp_sdu_discarded   += 1;
          rlc_pP->stat_tx_pdcp_bytes_discarded += rlc_pP->input_sdus[sdu_index].sdu_size;
          rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index);
        }
      }
    }
  } else {
    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);
  }
}
//-----------------------------------------------------------------------------
void rlc_am_ack_pdu (
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP,
  const rlc_sn_t snP)
//-----------------------------------------------------------------------------
{
  mem_block_t* mb_p         = rlc_pP->pdu_retrans_buffer[snP].mem_block;
  int          pdu_sdu_index;
  int          sdu_index;

  rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0;

  if ((rlc_pP->pdu_retrans_buffer[snP].flags.ack == 0) && (mb_p != NULL)) {
    //if (mb_pP != NULL) {
    free_mem_block(mb_p);
    rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL;
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] ACK PDU SN %05d previous retx_count %d \n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          snP,
          rlc_pP->pdu_retrans_buffer[snP].retx_count);
    rlc_pP->retrans_num_pdus  -= 1;
    rlc_pP->retrans_num_bytes -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size;

    if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= 0) {
      rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size;
    }

    for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) {
      sdu_index = rlc_pP->pdu_retrans_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)) {
#ifdef 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->pdu_retrans_buffer[snP].flags.ack = 1;

    if (snP == rlc_pP->vt_a) {
      //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1;
      do {
        memset(&rlc_pP->pdu_retrans_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->pdu_retrans_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->pdu_retrans_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),
          snP);

    if (mb_p != NULL) {
      free_mem_block(mb_p);
      rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL;
    }

    if (rlc_pP->pdu_retrans_buffer[snP].flags.ack > 0) {
      if (snP == rlc_pP->vt_a) {
        //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1;
        do {
          memset(&rlc_pP->pdu_retrans_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->pdu_retrans_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);
      }
    }
  }
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_copy (
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP,
  const rlc_sn_t snP)
//-----------------------------------------------------------------------------
{
  mem_block_t* mb_original_p = rlc_pP->pdu_retrans_buffer[snP].mem_block;

  if (mb_original_p != NULL) {

    rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->pdu_retrans_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);
    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;

    pdu_mngt->flags.retransmit = 0;

    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size);
    return mb_copy;
  } else {
    return NULL;
  }
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_subsegment(
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP,
  const rlc_sn_t snP,
  sdu_size_t * const sizeP /* in-out*/)
//-----------------------------------------------------------------------------
{

  // 5.2 ARQ procedures
  // ARQ procedures are only performed by an AM RLC entity.
  // 5.2.1 Retransmission
  // The transmitting side of an AM RLC entity can receive a negative acknowledgement (notification of reception failure
  // by its peer AM RLC entity) for an AMD PDU or a portion of an AMD PDU by the following:
  // - STATUS PDU from its peer AM RLC entity.
  //
  // When receiving a negative acknowledgement for an AMD PDU or a portion of an AMD PDU by a STATUS PDU from
  // its peer AM RLC entity, the transmitting side of the AM RLC entity shall:
  //     - if the SN of the corresponding AMD PDU falls within the range VT(A) <= SN < VT(S):
  //         - consider the AMD PDU or the portion of the AMD PDU for which a negative acknowledgement was
  //           received for retransmission.
  //
  // When an AMD PDU or a portion of an AMD PDU is considered for retransmission, the transmitting side of the AM
  // RLC entity shall:
  //     - if the AMD PDU is considered for retransmission for the first time:
  //         - set the RETX_COUNT associated with the AMD PDU to zero;
  //     - else, if it (the AMD PDU or the portion of the AMD PDU that is considered for retransmission) is not pending
  //       for retransmission already, or a portion of it is not pending for retransmission already:
  //         - increment the RETX_COUNT;
  //     - if RETX_COUNT = maxRetxThreshold:
  //         - indicate to upper layers that max retransmission has been reached.
  //
  // When retransmitting an AMD PDU, the transmitting side of an AM RLC entity shall:
  //     - if the AMD PDU can entirely fit within the total size of RLC PDU(s) indicated by lower layer at the particular
  //       transmission opportunity:
  //         - deliver the AMD PDU as it is except for the P field (the P field should be set according to sub clause 5.2.2) to
  //           lower layer;
  //     - otherwise:
  //         - segment the AMD PDU, form a new AMD PDU segment which will fit within the total size of RLC PDU(s)
  //           indicated by lower layer at the particular transmission opportunity and deliver the new AMD PDU segment
  //           to lower layer.
  //
  // When retransmitting a portion of an AMD PDU, the transmitting side of an AM RLC entity shall:
  //    - segment the portion of the AMD PDU as necessary, form a new AMD PDU segment which will fit within the
  //    total size of RLC PDU(s) indicated by lower layer at the particular transmission opportunity and deliver the new
  //    AMD PDU segment to lower layer.
  //
  // When forming a new AMD PDU segment, the transmitting side of an AM RLC entity shall:
  //    - only map the Data field of the original AMD PDU to the Data field of the new AMD PDU segment;
  //    - set the header of the new AMD PDU segment in accordance with the description in sub clause 6.;
  //    - set the P field according to sub clause 5.2.2.

  mem_block_t*           mb_original_p     = rlc_pP->pdu_retrans_buffer[snP].mem_block;

  if (mb_original_p != NULL) {
    mem_block_t*           mb_sub_segment_p  = get_free_mem_block(*sizeP + sizeof(struct mac_tb_req));
    rlc_am_pdu_sn_10_t*    pdu_original_p    = (rlc_am_pdu_sn_10_t*) (&mb_original_p->data[sizeof(struct mac_tb_req)]);
    rlc_am_pdu_sn_10_t*    pdu_sub_segment_p = (rlc_am_pdu_sn_10_t*) (&mb_sub_segment_p->data[sizeof(struct mac_tb_req)]);
    rlc_am_pdu_info_t      pdu_info;
    int                    max_copy_payload_size;
    //LG avoid WARNING int                    test_max_copy_payload_size;
    int                    test_pdu_copy_size          = 0;

    ((struct mac_tb_req*)(mb_sub_segment_p->data))->data_ptr         = (uint8_t*)&(mb_sub_segment_p->data[sizeof(struct mac_tb_req)]);

    if (rlc_am_get_data_pdu_infos(ctxt_pP, rlc_pP, pdu_original_p, rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size, &pdu_info) >= 0) {
      int li_index = 0;
      int start_offset       = rlc_pP->pdu_retrans_buffer[snP].nack_so_start;
      int stop_offset        = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop;

      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] ORIGINAL PDU SN %04d:\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            snP);
      rlc_am_display_data_pdu_infos(ctxt_pP, rlc_pP, &pdu_info);

      // all 15 bits set to 1 (indicate that the missing portion of the AMD PDU includes all bytes
      // to the last byte of the AMD PDU)
      if (stop_offset == 0x7FFF) {
        rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].payload_size - 1;
        stop_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop;
        LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] UPDATED RETRANS PDU SN %04d nack_so_stop FROM 0x7FFF to %05d\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              snP,
              stop_offset);
      }

      // FIXED PART AMD PDU SEGMENT HEADER
      // 6.2.1.5 AMD PDU segment
      // AMD PDU segment consists of a Data field and an AMD PDU segment header.
      //
      // AMD PDU segment header consists of a fixed part (fields that are present for every AMD PDU segment) and an
      // extension part (fields that are present for an AMD PDU segment when necessary). The fixed part of the AMD PDU
      // segment header itself is byte aligned and consists of a D/C, a RF, a P, a FI, an E, a SN, a LSF and a SO. The extension
      // part of the AMD PDU segment header itself is byte aligned and consists of E(s) and LI(s).
      //
      // An AMD PDU segment header consists of an extension part only when more than one Data field elements are present
      // in the AMD PDU segment, in which case an E and a LI are present for every Data field element except the last.
      // Furthermore, when an AMD PDU segment header consists of an odd number of LI(s), four padding bits follow after the
      // last LI.

      pdu_sub_segment_p->b1 = (pdu_original_p->b1 & 0x83) | 0x40;
      pdu_sub_segment_p->b2 = pdu_original_p->b2;
      pdu_sub_segment_p->data[0] = ((uint8_t)(start_offset >> 8));
      pdu_sub_segment_p->data[1] = ((uint8_t)(start_offset & 0xFF));

      *sizeP = *sizeP - 4;


      int            continue_fill_pdu_with_pdu  = 1;
      int            test_pdu_remaining_size     = *sizeP;
      int            test_num_li                 = 0;
      int            fill_num_li                    ;
      int            test_li_sum                 = 0;
      int            not_test_fi                 = 0; // by default not 1st byte and not last byte af a SDU
      int            test_start_offset;
      unsigned int   test_li_length_in_bytes     = 1;
      int16_t          test_li_list[RLC_AM_MAX_SDU_IN_PDU];
      uint8_t*          fill_payload_p;
      //int            test_fi_last_byte_pdu_is_last_byte_sdu = 0;
      //int            test_fi_first_byte_pdu_is_first_byte_sdu = 0;

      rlc_am_e_li_t* e_li_sub_segment            = (rlc_am_e_li_t*)(&pdu_sub_segment_p->data[2]);
      //int            first_enter_in_start_offset_lt_li_sum = 1;
      int            not_fi_original                 = ((pdu_original_p->b1 & 0x18) >> 3) ^ 3;

      //-------------------------------------------------------
      // set MAX payload size that can be copied
      // first constraint : the size of the hole to retransmit
      rlc_am_get_next_hole(ctxt_pP, rlc_pP, snP, &start_offset, &stop_offset);
      max_copy_payload_size = stop_offset - start_offset + 1;
      assert(max_copy_payload_size > 0);
      assert(test_pdu_remaining_size > 0);
      LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] HOLE FOUND SO %d -> %d\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            start_offset,
            stop_offset);
      LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] ORIGINAL FI %d\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            (pdu_original_p->b1 & 0x18) >> 3);

      // second constraint the size of the pdu_p requested by MAC layer
      if (max_copy_payload_size > test_pdu_remaining_size) {
        LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] CUT max_copy_payload_size with test_pdu_remaining_size %d -> %d\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              max_copy_payload_size,
              test_pdu_remaining_size);
        max_copy_payload_size = test_pdu_remaining_size;
      }


      if (start_offset == 0) {
        not_test_fi = (not_fi_original & 0x02);
      }

      test_start_offset = start_offset;

      //.find the li corresponding to the nack_so_start (start_offset)
      if (pdu_info.num_li > 0) {
        LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] ORIGINAL NUM LI %d\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              pdu_info.num_li);

        while ((li_index < pdu_info.num_li) && (continue_fill_pdu_with_pdu)) {
          LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] FIND LI %d\n",
                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                pdu_info.li_list[li_index]);

          if (max_copy_payload_size > test_pdu_remaining_size) {
            LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] CUT max_copy_payload_size with test_pdu_remaining_size %d -> %d\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  max_copy_payload_size,
                  test_pdu_remaining_size);
            max_copy_payload_size = test_pdu_remaining_size;
          }

          assert(max_copy_payload_size >= 0);
          assert(test_pdu_remaining_size >= 0);

          test_li_sum               += pdu_info.li_list[li_index];

          //---------------------------------------------------------------
          if (test_start_offset < test_li_sum) {

            LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] test_start_offset < test_li_sum  %d < %d\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  test_start_offset,
                  test_li_sum);
            /*if (test_max_copy_payload_size > (test_li_sum - test_start_offset)) {
                #ifdef TRACE_RLC_AM_RESEGMENT
                LOG_D(RLC, "[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u][RE-SEGMENT] CUT test_max_copy_payload_size with test_li_sum - test_start_offset %d -> %d\n",ctxt_pP->frame, rlc_pP->module_id, rlc_pP->rb_id,  test_max_copy_payload_size, test_li_sum - test_start_offset);
                #endif
                test_max_copy_payload_size = test_li_sum - test_start_offset;
            }*/

            if ((max_copy_payload_size + test_start_offset) < test_li_sum) {
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (max_copy_payload_size %d + test_start_offset %d) < test_li_sum %d\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    max_copy_payload_size,
                    test_start_offset,
                    test_li_sum);
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPY SO %d -> %d  %d BYTES\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    test_start_offset ,
                    test_start_offset + max_copy_payload_size - 1,
                    max_copy_payload_size );
              assert(max_copy_payload_size > 0);
              continue_fill_pdu_with_pdu = 0;
              test_pdu_copy_size         = test_pdu_copy_size + max_copy_payload_size;
              test_start_offset          = test_start_offset + max_copy_payload_size;
              not_test_fi                = not_test_fi & 0x02;  // clear b0, last byte does not correspond to last byte of a SDU
              max_copy_payload_size      = 0;

            } else if ((max_copy_payload_size + test_start_offset) == test_li_sum) {
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (max_copy_payload_size + test_start_offset) == test_li_sum %d == %d\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    (max_copy_payload_size + test_start_offset) ,
                    test_li_sum);
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPY SO %d -> %d  %d BYTES\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    test_start_offset ,
                    test_start_offset + max_copy_payload_size - 1,
                    max_copy_payload_size );
              assert(max_copy_payload_size > 0);
              continue_fill_pdu_with_pdu = 0;
              test_pdu_copy_size         = test_pdu_copy_size + max_copy_payload_size;
              test_start_offset          = test_start_offset + max_copy_payload_size;
              not_test_fi                = not_test_fi | 0x01;// set b0, last byte does correspond to last byte of a SDU
              max_copy_payload_size      = 0;

            } else if ((max_copy_payload_size + test_start_offset - (test_li_length_in_bytes ^ 3)) > test_li_sum) {
              LOG_T(RLC,
                    PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (max_copy_payload_size + test_start_offset - (test_li_length_in_bytes ^ 3)) > test_li_sum %d > %d\n SET LI %d\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    (max_copy_payload_size + test_start_offset)  + (test_li_length_in_bytes ^ 3),
                    test_li_sum,
                    test_li_sum - test_start_offset);
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPY SO %d -> %d  %d BYTES\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    test_start_offset ,
                    test_li_sum - 1,
                    test_li_sum - test_start_offset );
              assert((test_li_sum - test_start_offset) > 0);
              test_li_list[test_num_li++] = test_li_sum - test_start_offset;
              test_pdu_copy_size          = test_pdu_copy_size + test_li_sum - test_start_offset;
              test_li_length_in_bytes      = test_li_length_in_bytes ^ 3;

              test_pdu_remaining_size     = test_pdu_remaining_size - test_li_sum + test_start_offset -
                                            test_li_length_in_bytes;

              max_copy_payload_size       = max_copy_payload_size - test_li_sum + test_start_offset - test_li_length_in_bytes;
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] NOW max_copy_payload_size %d BYTES test_start_offset %d\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    max_copy_payload_size,
                    test_li_sum);
              // normally the next while itereation will add bytes to PDU
              //not_test_fi = not_test_fi | 0x01;  // set b0, last byte does correspond to last byte of a SDU
              test_start_offset           = test_li_sum;

            } else {
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (test_max_copy_payload_size + test_start_offset ) > test_li_sum %d > %d\n NO REMAINING SIZE FOR LI",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    (max_copy_payload_size + test_start_offset),
                    test_li_sum);
              LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPY SO %d -> %d  %d BYTES\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                    test_start_offset ,
                    test_li_sum - 1,
                    test_li_sum - test_start_offset );
              assert((test_li_sum - test_start_offset) > 0);
              continue_fill_pdu_with_pdu = 0;
              test_pdu_copy_size         = test_pdu_copy_size + test_li_sum - test_start_offset;

              test_pdu_remaining_size    = test_pdu_remaining_size - test_li_sum + test_start_offset;

              max_copy_payload_size      = max_copy_payload_size - test_li_sum + test_start_offset;
              test_start_offset          = test_li_sum;
              not_test_fi                = not_test_fi | 0x01;  // set b0, last byte does correspond to last byte of a SDU
            }

            //---------------------------------------------------------------
            // start offset start at the begining of a SDU
            // and it cant be the first data field of the original PDU
          } else if (test_start_offset == test_li_sum) {
            LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (test_start_offset == test_li_sum) %d == %d\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  test_start_offset ,
                  test_li_sum);

            if ((test_num_li == 0) && (test_pdu_copy_size == 0)) {
              not_test_fi = not_test_fi | 0x02;  // set b1, first byte does correspond to first byte of a SDU
            }
          }

          li_index = li_index + 1;
        }

        if ((continue_fill_pdu_with_pdu > 0) &&
            (li_index    == pdu_info.num_li) &&
            (pdu_info.hidden_size       > 0) &&
            (test_pdu_remaining_size    > 0) &&
            (max_copy_payload_size      > 0) ) {

          if (max_copy_payload_size > test_pdu_remaining_size) {
            LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] TRYING HIDDEN SIZE...CUT max_copy_payload_size with test_pdu_remaining_size %d -> %d\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  max_copy_payload_size,
                  test_pdu_remaining_size);
            max_copy_payload_size = test_pdu_remaining_size;
          }

          // remaining bytes to fill, redundant check, but ...
          if  ((max_copy_payload_size + test_start_offset) >= (pdu_info.hidden_size + test_li_sum)) {
            test_pdu_copy_size += (pdu_info.hidden_size  + test_li_sum - test_start_offset);
            LOG_T(RLC,
                  PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPYING WHOLE REMAINING SIZE %d (max_copy_payload_size %d, test_start_offset %d, pdu_info.hidden_size %d test_li_sum %d test_pdu_copy_size %d)\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  pdu_info.hidden_size  + test_li_sum - test_start_offset,
                  max_copy_payload_size,
                  test_start_offset,
                  pdu_info.hidden_size,
                  test_li_sum,
                  test_pdu_copy_size);
            test_start_offset   = pdu_info.hidden_size   + test_li_sum;
            not_test_fi = (not_test_fi & 0x2) | (not_fi_original & 0x1);  // set b0 idendical to the b0 of the non segmented PDU
          } else {
            LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COPYING REMAINING SIZE %d (/%d)\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                  max_copy_payload_size,
                  pdu_info.hidden_size);
            test_pdu_copy_size += max_copy_payload_size;
            test_start_offset = test_start_offset + max_copy_payload_size;
            not_test_fi = not_test_fi & 0x2;  // clear b0 because no SDU ending in this PDU
          }
        }
      } else { // num_li == 0
        LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] (num_li == 0)\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
        test_pdu_copy_size = max_copy_payload_size;

        if ((stop_offset ==  (start_offset + max_copy_payload_size - 1)) && (stop_offset == rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) {
          not_test_fi = (not_test_fi & 0x2) | (not_fi_original & 0x1);  // set b0 idendical to the b0 of the non segmented PDU
        } else {
          not_test_fi = not_test_fi & 0x2;  // clear b0 because no SDU ending in this PDU
        }
      }

      //---------------------------------------------------------------
      /*if (stop_offset == (rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) {
              test_fi = (test_fi & 0x02) | (fi_original & 0x01);
      }*/
      //---------------------------------------------------------------
      // write FI field in header
      //---------------------------------------------------------------
      pdu_sub_segment_p->b1 = pdu_sub_segment_p->b1 | (((not_test_fi << 3) ^ 0x18) & 0x18);
      //---------------------------------------------------------------
      // fill the segment pdu_p with Lis and data
      //---------------------------------------------------------------
      LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] fill the segment pdu_p with Lis and data, test_num_li %d\n",
            test_num_li);

      if (test_num_li > 0) {
        pdu_sub_segment_p->b1 = pdu_sub_segment_p->b1 | 0x04; // set E bit
        test_li_length_in_bytes = 1;

        for (fill_num_li=0; fill_num_li < test_num_li; fill_num_li++) {
          test_li_length_in_bytes = test_li_length_in_bytes ^ 3;

          if (test_li_length_in_bytes  == 2) {
            if (fill_num_li == (test_num_li - 1)) {
              e_li_sub_segment->b1 = 0;
            } else {
              e_li_sub_segment->b1 =  0x80;
            }

            e_li_sub_segment->b1 = e_li_sub_segment->b1 | (test_li_list[fill_num_li] >> 4);
            e_li_sub_segment->b2 = test_li_list[fill_num_li] << 4;
            fill_payload_p         = (uint8_t*)(&e_li_sub_segment->b3);
            *sizeP               = *sizeP - 2;
          } else {
            if (fill_num_li != (test_num_li - 1)) {
              e_li_sub_segment->b2  = e_li_sub_segment->b2 | 0x08;
            }

            e_li_sub_segment->b2 = e_li_sub_segment->b2 | (test_li_list[fill_num_li] >> 8);
            e_li_sub_segment->b3 = test_li_list[fill_num_li] & 0xFF;
            e_li_sub_segment++;
            fill_payload_p         = (uint8_t*)e_li_sub_segment;
            *sizeP               = *sizeP - 1;
          }

          LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RB %u][RE-SEGMENT] ADD LI %d\n",
                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                test_li_list[fill_num_li]);
        }
      } else {
        LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RB %u][RE-SEGMENT] ADD NO LI\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
        fill_payload_p = (uint8_t*)e_li_sub_segment;
      }

      //---------------------------------------------------------------
      // copy payload to retransmit
      //---------------------------------------------------------------
      memcpy(fill_payload_p,
             &rlc_pP->pdu_retrans_buffer[snP].payload[start_offset],
             test_pdu_copy_size);

      ((struct mac_tb_req*)(mb_sub_segment_p->data))->tb_size  = (tb_size_t)(((uint64_t)fill_payload_p)+ test_pdu_copy_size) - ((uint64_t)(&pdu_sub_segment_p->b1));

      // set LSF
      if ((test_pdu_copy_size + start_offset) == rlc_pP->pdu_retrans_buffer[snP].payload_size) {
        pdu_sub_segment_p->data[0] = pdu_sub_segment_p->data[0] | 0x80;

        rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0;

        LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d SO %d %d BYTES PAYLOAD %d BYTES LSF!\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              snP,
              start_offset,
              ((struct mac_tb_req*)(mb_sub_segment_p->data))->tb_size,
              test_pdu_copy_size);
      } else {
        LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d SO %d %d BYTES PAYLOAD %d BYTES\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              snP,
              start_offset,
              ((struct mac_tb_req*)(mb_sub_segment_p->data))->tb_size,
              test_pdu_copy_size);
      }

      LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] *sizeP %d = *sizeP %d - test_pdu_copy_size %d\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            *sizeP - test_pdu_copy_size, *sizeP,
            test_pdu_copy_size);

      *sizeP = *sizeP - test_pdu_copy_size;
      //---------------------------------------------------------------
      // update nack_so_start
      //---------------------------------------------------------------
      rlc_am_remove_hole(ctxt_pP, rlc_pP, snP, start_offset, test_pdu_copy_size+start_offset - 1);
      //rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].nack_so_start + test_pdu_copy_size;
      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d NOW nack_so_start %d nack_so_stop %d\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            snP,
            rlc_pP->pdu_retrans_buffer[snP].nack_so_start,
            rlc_pP->pdu_retrans_buffer[snP].nack_so_stop);
      /*if (rlc_pP->pdu_retrans_buffer[snP].nack_so_start == rlc_pP->pdu_retrans_buffer[snP].nack_so_stop) {
          rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0;
          rlc_pP->pdu_retrans_buffer[snP].nack_so_stop  = 0x7FFF;
      }*/
    } else {
      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COULD NOT GET INFO FOR DATA PDU SN %04d -> RETURN NULL\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            snP);
      return NULL;
    }

    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size);
    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",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          snP);
    assert(3==4);
    return NULL;
  }
}
//-----------------------------------------------------------------------------
void rlc_am_tx_buffer_display (
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t* const rlc_pP,
  char* const message_pP)
//-----------------------------------------------------------------------------
{
  rlc_sn_t       sn = rlc_pP->vt_a;
  int            i, loop = 0;

  if (message_pP) {
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" Retransmission buffer %s VT(A)=%04d VT(S)=%04d:",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          message_pP,
          rlc_pP->vt_a,
          rlc_pP->vt_s);
  } else {
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" Retransmission buffer VT(A)=%04d VT(S)=%04d:",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          rlc_pP->vt_a,
          rlc_pP->vt_s);
  }

  while (rlc_pP->vt_s != sn) {
    if (rlc_pP->pdu_retrans_buffer[sn].mem_block) {
      if ((loop % 1) == 0) {
        LOG_D(RLC, "\nTX SN:\t");
      }

      if (rlc_pP->pdu_retrans_buffer[sn].flags.retransmit) {
        LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size,
              rlc_pP->pdu_retrans_buffer[sn].retx_count);
      } else {
        LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size,
              rlc_pP->pdu_retrans_buffer[sn].retx_count);
      }

      if (rlc_pP->pdu_retrans_buffer[sn].num_holes == 0) {
        LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].nack_so_start, rlc_pP->pdu_retrans_buffer[sn].nack_so_stop);
      } else {
        for (i=0; i<rlc_pP->pdu_retrans_buffer[sn].num_holes; i++) {
          assert(i < RLC_AM_MAX_HOLES_REPORT_PER_PDU);
          LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].hole_so_start[i], rlc_pP->pdu_retrans_buffer[sn].hole_so_stop[i]);
        }
      }

      loop++;
    }

    sn = (sn + 1) & RLC_AM_SN_MASK;
  }

  LOG_D(RLC, "\n");
}
//-----------------------------------------------------------------------------
void rlc_am_retransmit_any_pdu(
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t* const rlc_pP)
//-----------------------------------------------------------------------------
{
  rlc_sn_t             sn           = (rlc_pP->vt_s - 1) & RLC_AM_SN_MASK;
  rlc_sn_t             sn_end       = (rlc_pP->vt_a - 1) & RLC_AM_SN_MASK;
  int                  found_pdu    = 0;
  rlc_sn_t             found_pdu_sn = 0; // avoid warning
  mem_block_t*         pdu_p        = NULL;
  rlc_am_pdu_sn_10_t*  pdu_sn_10_p  = NULL;

  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] rlc_am_retransmit_any_pdu()\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));

  while (sn != sn_end) {
    if (rlc_pP->pdu_retrans_buffer[sn].mem_block != NULL) {
      if (!found_pdu) {
        found_pdu = 1;
        found_pdu_sn = sn;
      }

      if (rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) {
        LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] RE-SEND DATA PDU SN %04d\n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
              sn);
        rlc_am_nack_pdu (ctxt_pP, rlc_pP, sn, 0, 0x7FFF);
        // no need for update rlc_pP->nb_bytes_requested_by_mac
        pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn);
        pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]);
        rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size);
        pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20;
        rlc_pP->c_pdu_without_poll     = 0;
        rlc_pP->c_byte_without_poll    = 0;
        //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
        rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
        rlc_pP->stat_tx_data_pdu                   += 1;
        rlc_pP->stat_tx_retransmit_pdu             += 1;
        rlc_pP->stat_tx_data_bytes                 += ((struct mac_tb_req*)(pdu_p->data))->tb_size;
        rlc_pP->stat_tx_retransmit_bytes           += ((struct mac_tb_req*)(pdu_p->data))->tb_size;
        list_add_tail_eurecom (pdu_p, &rlc_pP->pdus_to_mac_layer);
        return;
      }
    }

    sn = (sn - 1) & RLC_AM_SN_MASK;
  }

  // no pdu_p with correct size has been found
  // so re-segment a pdu_p if possible
  if (found_pdu) {
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] SEND SEGMENT OF DATA PDU SN %04d\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          found_pdu_sn);

    if (rlc_pP->nb_bytes_requested_by_mac > 4) {
      rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF);
      pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac);
      pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]);
      rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size);
      pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20;
      rlc_pP->c_pdu_without_poll     = 0;
      rlc_pP->c_byte_without_poll    = 0;
      //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
      rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
      rlc_pP->stat_tx_data_pdu                   += 1;
      rlc_pP->stat_tx_retransmit_pdu             += 1;
      rlc_pP->stat_tx_data_bytes                 += ((struct mac_tb_req*)(pdu_p->data))->tb_size;
      rlc_pP->stat_tx_retransmit_bytes           += ((struct mac_tb_req*)(pdu_p->data))->tb_size;
      list_add_tail_eurecom (pdu_p, &rlc_pP->pdus_to_mac_layer);
      return;
    } else {
      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] ... BUT NOT ENOUGH BYTES ALLOWED BY MAC %0d\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
            rlc_pP->nb_bytes_requested_by_mac);
    }
  }
}