From 79242aaf54e8240cd5d0f121f7f9e3f1fef2c3df Mon Sep 17 00:00:00 2001
From: fnabet <fabrice.nabet@alcatelonetouch.com>
Date: Fri, 3 Feb 2017 17:02:42 +0100
Subject: [PATCH] RLC AM Tx changes

---
 openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c        | 122 +++++++++-
 .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h   |  61 +++--
 openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h |  10 +-
 openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c |   2 +
 .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c  |  21 +-
 .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c     |  55 +++--
 .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h     |   4 +-
 .../RLC/AM_v9.3.0/rlc_am_status_report.c      | 214 +++++++++---------
 .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h     |   5 +-
 9 files changed, 314 insertions(+), 180 deletions(-)

diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c
index 23baae3714..3e88a31496 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c
@@ -43,6 +43,109 @@
 #include "DL-AM-RLC.h"
 
 
+//-----------------------------------------------------------------------------
+uint32_t
+rlc_am_get_status_pdu_buffer_occupancy(
+  rlc_am_entity_t * const      rlc_pP){
+
+	//Compute Max Status PDU size according to what has been received and not received in the window [vrR vrMS[
+
+    // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1
+	uint32_t                    nb_bits_to_transmit	  = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS;
+	mem_block_t                  *cursor_p              = rlc_pP->receiver_buffer.head;
+    rlc_am_pdu_info_t            *pdu_info_cursor_p     = NULL;
+    int                           waited_so             = 0;
+
+	rlc_sn_t sn_cursor = rlc_pP->vr_r;
+	rlc_sn_t sn_prev = rlc_pP->vr_r;
+	rlc_sn_t sn_end = rlc_pP->vr_ms;
+	boolean_t	segment_loop_end	  = false;
+
+
+	if (sn_prev != sn_end)
+	{
+		while ((RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)) && (cursor_p != NULL))
+		{
+			pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
+			sn_cursor             = pdu_info_cursor_p->sn;
+
+			// Add holes between sn_prev and sn_cursor
+			while ((sn_prev != sn_cursor) && (sn_prev != sn_end))
+			{
+				  /* Add 1 NACK_SN + E1 + E2 */
+				  nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1));
+				  sn_prev = RLC_AM_NEXT_SN(sn_prev);
+			} //end while (sn_prev != sn_cursor)
+
+			/* Handle case sn_cursor is partially received */
+			/* Each gap will add NACK_SN + E1 + E2 + SOStart + SOEnd */
+			if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) && (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)))
+			{
+                 /* Check lsf */
+				  segment_loop_end = (pdu_info_cursor_p->lsf == 1);
+
+	    		  /* Fill for [0 SO[ if SO not null */
+	    		  if (pdu_info_cursor_p->so) {
+	    			  nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
+	                  waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
+	                  /* Go to next segment */
+	                  cursor_p = cursor_p->next;
+	                  if (cursor_p != NULL)
+	                  {
+		                  pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
+	                  }
+	    		  }
+	    		  else {
+	        		  waited_so = pdu_info_cursor_p->payload_size;
+	    		  }
+
+	    		  /* Fill following gaps if any */
+	    		  while (!segment_loop_end)
+	    		  {
+	    			  if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor))
+	    			  {
+		                  /* Check lsf */
+	    				  segment_loop_end = (pdu_info_cursor_p->lsf == 1);
+
+            			  if (waited_so < pdu_info_cursor_p->so) {
+    	                      nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
+            			  }
+            			  else {
+            				  /* contiguous segment: only update waited_so */
+            				  /* Assuming so and payload_size updated according to duplication removal done at reception ... */
+            				  waited_so += pdu_info_cursor_p->payload_size;
+            			  }
+
+            			  /* Go to next received PDU or PDU Segment */
+            			  cursor_p = cursor_p->next;
+    	                  if (cursor_p != NULL)
+    	                  {
+    		                  pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
+    	                  }
+	    			  }
+	    			  else
+	    			  {
+	    				  /* Fill last gap assuming LSF is not received */
+	    				  nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
+	    				  segment_loop_end = true;
+	    			  }
+	    		  } // end while (!segment_loop_end)
+			} // end if segments
+			else
+			{
+				 /* Go to next received PDU or PDU Segment */
+				 cursor_p = cursor_p->next;
+			}
+
+			sn_prev = RLC_AM_NEXT_SN(sn_cursor);
+		}
+	} // end if (sn_prev != sn_end)
+
+	// round up to the greatest byte
+	return ((nb_bits_to_transmit + 7) >> 3);
+
+}
+
 //-----------------------------------------------------------------------------
 uint32_t
 rlc_am_get_buffer_occupancy_in_bytes (
@@ -54,26 +157,24 @@ rlc_am_get_buffer_occupancy_in_bytes (
 
   // priority of control trafic
   rlc_pP->status_buffer_occupancy = 0;
-  if (rlc_pP->status_requested) {
-    if (rlc_pP->t_status_prohibit.running == 0) {
+  if ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK)) {
+      rlc_pP->status_buffer_occupancy = rlc_am_get_status_pdu_buffer_occupancy(rlc_pP);
 #if TRACE_RLC_AM_BO
 
-      if (((15  +  rlc_pP->num_nack_sn*(10+1)  +  rlc_pP->num_nack_so*(15+15+1) + 7) >> 3) > 0) {
-        LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n",
-              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
-              ((15  +  rlc_pP->num_nack_sn*(10+1)  +  rlc_pP->num_nack_so*(15+15+1) + 7) >> 3));
-      }
+      LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n",
+            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
+			rlc_pP->status_buffer_occupancy);
 
 #endif
-      rlc_pP->status_buffer_occupancy = ((15  +  rlc_pP->num_nack_sn*(10+1)  +  rlc_pP->num_nack_so*(15+15+1) + 7) >> 3);
-    }
   }
 
   // data traffic
   if (rlc_pP->nb_sdu_no_segmented <= 1) {
     max_li_overhead = 0;
   } else {
-    max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2);
+  	/* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/
+	  uint32_t num_li = rlc_pP->nb_sdu_no_segmented - 1;
+      max_li_overhead = num_li + (num_li >> 1) + (num_li & 1);
   }
 
   if (rlc_pP->sdu_buffer_occupancy == 0) {
@@ -372,6 +473,7 @@ rlc_am_get_pdus (
         }
     }*/
     // 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;
 
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h
index 77bf31db86..a2fc95aba5 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h
@@ -72,24 +72,11 @@
 #    define RLC_AM_MAX_HOLES_REPORT_PER_PDU       16
 /** @} */
 
-/* Common to Data and Status PDU */
-#define RLC_AM_SN_BITS                         10
-#define RLC_AM_PDU_D_C_BITS                	   1
-#define RLC_AM_PDU_E_BITS                	   1
-
-/* STATUS PDU */
-#define RLC_AM_STATUS_PDU_CPT_STATUS           0
-
-#define RLC_AM_STATUS_PDU_CPT_OFFSET           4
-#define RLC_AM_STATUS_PDU_CPT_LENGTH           3
-
-#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET        2
-
-#define RLC_AM_STATUS_PDU_SO_LENGTH            15
-
-#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES     0x7FFF
+#define	RLC_AM_POLL_PDU_INFINITE				0xFFFF
+#define	RLC_AM_POLL_BYTE_INFINITE				0xFFFFFFFF
 
 /* 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))
 
@@ -99,10 +86,52 @@
 #define RLC_AM_DIFF_SN(sn,snref)       (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO))
 #define RLC_AM_SN_IN_WINDOW(sn,snref)  (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO))
 
+#define RLC_SET_BIT(x,offset)      ((x) |= (1 << (offset)))
+#define RLC_GET_BIT(x,offset)      (((x) & (1 << (offset))) >> (offset))
+#define RLC_CLEAR_BIT(x,offset)    ((x) &= ~(1 << (offset)))
+
 #define RLC_SET_EVENT(x,event)         ((x) |= (event))
 #define RLC_GET_EVENT(x,event)         ((x) & (event))
 #define RLC_CLEAR_EVENT(x,event)       ((x) &= (~(event)))
 
+/* Common to Data and Status PDU */
+#define RLC_AM_SN_BITS				10
+#define RLC_AM_PDU_D_C_BITS          1
+#define RLC_AM_PDU_E_BITS            1
+#define RLC_AM_PDU_FI_BITS           2
+#define RLC_AM_PDU_POLL_BITS         1
+#define RLC_AM_PDU_RF_BITS           1
+
+
+#define EURL_AM_PDU_LSF_BITS                1
+
+
+/* AM Data PDU */
+#define RLC_AM_PDU_E_OFFSET                2
+#define RLC_AM_PDU_FI_OFFSET               (RLC_AM_PDU_E_OFFSET + RLC_AM_PDU_E_BITS)
+#define RLC_AM_PDU_POLL_OFFSET             (RLC_AM_PDU_FI_OFFSET + RLC_AM_PDU_FI_BITS)
+#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_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))
+
+/* STATUS PDU */
+#define RLC_AM_STATUS_PDU_CPT_STATUS           0
+
+#define RLC_AM_STATUS_PDU_CPT_OFFSET           4
+#define RLC_AM_STATUS_PDU_CPT_LENGTH           3
+
+#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET        2
+
+#define RLC_AM_STATUS_PDU_SO_LENGTH            15
+
+#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES     0x7FFF
+
+
 /* Uplink STATUS PDU trigger events */
 #define RLC_AM_STATUS_NOT_TRIGGERED               0
 #define RLC_AM_STATUS_TRIGGERED_POLL              0x01    /* Status Report is triggered by a received poll */
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h
index 581c4969e0..45d0a5d489 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h
@@ -69,17 +69,15 @@ typedef struct rlc_am_entity_s {
   pthread_mutex_t      lock_input_sdus;
   rlc_am_tx_sdu_management_t   *input_sdus;           /*!< \brief Input SDU buffer (for SDUs coming from upper layers). */
   signed int      nb_sdu;                             /*!< \brief Total number of valid rlc_am_tx_sdu_management_t in input_sdus[]. */
-  signed int      nb_sdu_no_segmented;                /*!< \brief Total number of SDUs not segmented and partially segmented. */
+  signed int      nb_sdu_no_segmented;                /*!< \brief Total number of SDUs not segmented and partially segmented. nb_sdu_no_segmented = next_sdu_index - current_sdu_index */
   signed int      next_sdu_index;                     /*!< \brief Next SDU index in input_sdus array where for a new incoming SDU. */
-  signed int      current_sdu_index;                  /*!< \brief Current SDU index in input_sdus array to be segmented. */
+  signed int      current_sdu_index;                  /*!< \brief Current SDU index in input_sdus array to be segmented which is not segmented or partially segmented. */
 
 
   rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer;       /*!< \brief Retransmission buffer. */
   signed int      retrans_num_pdus;                          /*!< \brief Number of PDUs in the retransmission buffer. */
   signed int      retrans_num_bytes;                         /*!< \brief Number of bytes in the retransmission buffer. */
   signed int      retrans_num_bytes_to_retransmit;           /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */
-  unsigned int    num_nack_so;                               /*!< \brief Number of segment offsets asked to be retransmitted by peer RLC entity. */
-  unsigned int    num_nack_sn;                               /*!< \brief Number of segment asked to be retransmitted by peer RLC entity. */
   boolean_t       force_poll;                                /*!< \brief force poll due to t_poll_retransmit time-out. */
 
   //---------------------------------------------------------------------
@@ -137,7 +135,7 @@ typedef struct rlc_am_entity_s {
   //-----------------------------
   uint16_t           max_retx_threshold; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to limit the number of retransmissions of an AMD PDU. */
   uint16_t           poll_pdu;           /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollPDU PDUs. */
-  uint16_t           poll_byte;          /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */
+  uint32_t           poll_byte;          /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */
 
   //---------------------------------------------------------------------
   // STATISTICS
@@ -176,7 +174,7 @@ typedef struct rlc_am_entity_s {
   //---------------------------------------------------------------------
   // OUTPUTS
   //---------------------------------------------------------------------
-  sdu_size_t        nb_bytes_requested_by_mac;  /*!< \brief Number of bytes requested by lower layer for next transmission. */
+  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. */
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c
index 0f0b0e75e1..4122fd0e66 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c
@@ -56,6 +56,8 @@ void rlc_am_free_in_sdu(
       rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE;
     }
 
+    // TODO : this loop is useless as UL SDUs are transmitted and acknowledged in sequence
+    // even with PDCP UL SDU discard functionality
     while ((rlcP->current_sdu_index != rlcP->next_sdu_index) &&
            (rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) {
       rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE;
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
index 7fb801b33d..a52c9bee33 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
@@ -55,7 +55,6 @@ void rlc_am_nack_pdu (
   int          sdu_index;
 
   if (mb_p != NULL) {
-    rlc_pP->num_nack_sn += 1;
     assert(so_startP <= so_endP);
 
     //-----------------------------------------
@@ -69,10 +68,6 @@ void rlc_am_nack_pdu (
       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) {
@@ -283,7 +278,7 @@ mem_block_t* rlc_am_retransmit_get_copy (
 
     pdu_mngt->flags.retransmit = 0;
 
-    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size);
+    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size,false);
     return mb_copy;
   } else {
     return NULL;
@@ -745,7 +740,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment(
       return NULL;
     }
 
-    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size);
+    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",
@@ -843,10 +838,12 @@ void rlc_am_retransmit_any_pdu(
         // 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_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size,false);
+        //BugFix: polling is checked and done in function above !
+        //pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20;
+        //BugFix : pdu_without_poll and byte_without_poll are reset only if a Poll is transmitted
+        //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;
@@ -877,7 +874,7 @@ void rlc_am_retransmit_any_pdu(
       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);
+      rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size,false);
       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;
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
index 893588d65e..af4f67f303 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
@@ -39,7 +39,8 @@ void rlc_am_pdu_polling (
   const protocol_ctxt_t* const  ctxt_pP,
   rlc_am_entity_t *const rlc_pP,
   rlc_am_pdu_sn_10_t *const pdu_pP,
-  const int16_t payload_sizeP)
+  const int16_t payload_sizeP,
+  boolean_t is_new_pdu)
 {
   // 5.2.2 Polling
   // An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity.
@@ -68,41 +69,50 @@ void rlc_am_pdu_polling (
   //         - start t-PollRetransmit;
   //     - else:
   //         - restart t-PollRetransmit;
-  rlc_pP->c_pdu_without_poll     += 1;
-  rlc_pP->c_byte_without_poll    += payload_sizeP;
+
+  if (is_new_pdu) {
+	  if (rlc_pP->poll_pdu != RLC_AM_POLL_PDU_INFINITE) {
+		  rlc_pP->c_pdu_without_poll     += 1;
+	  }
+
+	  if (rlc_pP->poll_byte != RLC_AM_POLL_BYTE_INFINITE) {
+		  rlc_pP->c_byte_without_poll    += payload_sizeP;
+	  }
+  }
 
   if (
-    (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) ||
-    (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) ||
+    ((is_new_pdu) && ((rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) ||
+    (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte))) ||
     ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) ||
     (rlc_pP->vt_s == rlc_pP->vt_ms) ||
-    (rlc_pP->force_poll == TRUE)
+    (rlc_pP->force_poll == true)
   ) {
-	rlc_pP->force_poll = FALSE;
+	rlc_pP->force_poll = false;
 
-    if (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) {
+    if ((is_new_pdu) && (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu)) {
       LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM PDU THRESHOLD %d  HAS BEEN REACHED\n",
             PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
             rlc_pP->poll_pdu);
-    } else
-    if (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) {
+    }
+    if ((is_new_pdu) && (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte)) {
       LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM BYTES THRESHOLD %d  HAS BEEN REACHED\n",
             PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
             rlc_pP->poll_byte);
-    } else
+    }
     if ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) {
       LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX BUFFERS ARE EMPTY\n",
             PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
-    } else
+    }
     if (rlc_pP->vt_s == rlc_pP->vt_ms) {
       LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE OF WINDOW STALLING\n",
             PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
     }
 
-    pdu_pP->b1 = pdu_pP->b1 | 0x20;
+    RLC_AM_PDU_SET_POLL(pdu_pP->b1);
     rlc_pP->c_pdu_without_poll     = 0;
     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;
     //optimisation if (!rlc_pP->t_poll_retransmit.running) {
     rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP);
@@ -110,7 +120,8 @@ void rlc_am_pdu_polling (
     //optimisation     rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out;
     //optimisation }
   } else {
-    pdu_pP->b1 = pdu_pP->b1 & 0xDF;
+	  // Not sure this is necessary
+	RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1);
   }
 }
 //-----------------------------------------------------------------------------
@@ -178,7 +189,9 @@ void rlc_am_segment_10 (
       if (rlc_pP->nb_sdu_no_segmented <= 1) {
         max_li_overhead = 0;
       } else {
-        max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2);
+    	/* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/
+    	test_num_li = rlc_pP->nb_sdu_no_segmented - 1;
+        max_li_overhead = test_num_li + (test_num_li >> 1) + (test_num_li & 1);
       }
 
       LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] max_li_overhead %d\n",
@@ -485,11 +498,11 @@ void rlc_am_segment_10 (
       fi = fi + 1;
     }
 
-    pdu_p->b1 = pdu_p->b1 | (fi << 3);
+    pdu_p->b1 = pdu_p->b1 | (fi << RLC_AM_PDU_FI_OFFSET);
 
     // set fist e bit
     if (fill_num_li > 0) {
-      pdu_p->b1 = pdu_p->b1 | 0x04;
+    	RLC_AM_PDU_SET_E(pdu_p->b1);
     }
 
     LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] SEND PDU SN %04d  SIZE %d BYTES PAYLOAD SIZE %d BYTES\n",
@@ -501,8 +514,9 @@ void rlc_am_segment_10 (
     rlc_pP->stat_tx_data_pdu   += 1;
     rlc_pP->stat_tx_data_bytes += (data_pdu_size - pdu_remaining_size);
 
-    //pdu_p->sn = rlc_pP->vt_s;
-    pdu_p->b1 = pdu_p->b1 | 0x80; // DATA/CONTROL field is DATA PDU
+    // set DATA/CONTROL field is DATA PDU(1)
+    RLC_AM_PDU_SET_D_C(pdu_p->b1);
+    // set sn = rlc_pP->vt_s;
     pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_s >> 8);
     pdu_p->b2 = rlc_pP->vt_s & 0xFF;
     rlc_pP->vt_s = (rlc_pP->vt_s+1) & RLC_AM_SN_MASK;
@@ -511,13 +525,14 @@ void rlc_am_segment_10 (
     pdu_tb_req_p->tb_size         = data_pdu_size - pdu_remaining_size;
 //#warning "why 3000: changed to RLC_SDU_MAX_SIZE "
     assert(pdu_tb_req_p->tb_size < RLC_SDU_MAX_SIZE );
-    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size);
+    rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size,true);
 
     //list_add_tail_eurecom (pdu_mem_p, &rlc_pP->segmentation_pdu_list);
     pdu_mngt_p->mem_block  = pdu_mem_p;
     pdu_mngt_p->first_byte = (unsigned char*)pdu_p;
     pdu_mngt_p->header_and_payload_size  = data_pdu_size - pdu_remaining_size;
     pdu_mngt_p->retx_count = -1;
+    pdu_mngt_p->flags.transmitted = 1;
 
     rlc_pP->retrans_num_pdus  += 1;
     rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size;
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h
index 6b67758b80..b52b3e5aaa 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h
@@ -51,14 +51,14 @@
 #            endif
 #        endif
 
-/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const  ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP)
+/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const  ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu)
 * \brief      Set or not the poll bit in the PDU header depending on RLC AM protocol variables.
 * \param[in]  ctxt_pP          Running context.
 * \param[in]  rlcP           RLC AM protocol instance pointer.
 * \param[in]  pduP           Pointer on the header of the PDU in order to be able to set the poll bit if necessary.
 * \param[in]  payload_sizeP  Size of the payload of the PDU.
 */
-protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const  ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP);)
+protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const  ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu);)
 
 /*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const  ctxt_pP, rlc_am_entity_t * const rlcP)
 * \brief      Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit).
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
index 4cc987d301..6495c722df 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c
@@ -309,8 +309,6 @@ rlc_am_receive_process_control_pdu(
     assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU);
 
     if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) {
-      rlc_pP->num_nack_so = 0;
-      rlc_pP->num_nack_sn = 0;
 
       if (rlc_pP->control_pdu_info.num_nack == 0) {
         while (sn_cursor != ack_sn) {
@@ -462,7 +460,6 @@ rlc_am_send_status_pdu(
   mem_block_t                  *tb_p                  = NULL;
   sdu_size_t                    pdu_size              = 0;
   boolean_t						status_report_completed	= false;
-  boolean_t						lsf_received		  = false;
   boolean_t						segment_loop_end	  = false;
 
   memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t));
@@ -479,30 +476,20 @@ rlc_am_send_status_pdu(
 
 	  control_pdu_info.ack_sn = rlc_pP->vr_ms;
 	  status_report_completed = true;
+#if TRACE_RLC_AM_STATUS_CREATION
+          LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d ALL ACK WITH ACK_SN %04d\n",
+                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
+                __LINE__,
+				rlc_pP->vr_ms);
+#endif
   }
-  else if (cursor_p != NULL) {
+  else if ((cursor_p != NULL) && ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)) <= nb_bits_to_transmit)) {
 
     pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
     sn_cursor             = pdu_info_cursor_p->sn;
 
-    // Not very clear why this is needed
-    // commenting
-#if 0
-    while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) {
-      cursor_p                = cursor_p->next;
-      previous_sn_cursor    = sn_cursor;
-
-      pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
-      sn_cursor             = pdu_info_cursor_p->sn;
-#if TRACE_RLC_AM_STATUS_CREATION
-      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d FIND VR(R) <= SN sn_cursor %04d -> %04d\n",
-            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
-            __LINE__,
-            previous_sn_cursor,
-            sn_cursor);
-#endif
-    }
-#endif
+    /* Set E1 bit for the presence of first NACK_SN/E1/E2 */
+    control_pdu_info.e1 = 1;
 
     // 12 bits = size of NACK_SN field + E1, E2 bits
     // 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits
@@ -512,20 +499,17 @@ rlc_am_send_status_pdu(
       pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
       sn_cursor             = pdu_info_cursor_p->sn;
       all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;
-      // E1 bit is set at the end
 
       /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */
       while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) {
     	  if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) {
     		  /* Fill NACK_SN infos */
-    		  if (control_pdu_info.num_nack) {
-    			  /* Set E1 of previous NACK_SN */
-    			  control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 1;
-    		  }
               control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_nack;
               control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = 0;
               control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
               control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 0;
+              /* Set E1 for next NACK_SN. The last one will be cleared */
+              control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
               control_pdu_info.num_nack += 1;
               nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1));
 #if TRACE_RLC_AM_STATUS_CREATION
@@ -541,45 +525,52 @@ rlc_am_send_status_pdu(
     		  /* latest value of sn_nack shall be used as ACK_SN */
     		  control_pdu_info.ack_sn = sn_nack;
     		  status_report_completed = true;
+#if TRACE_RLC_AM_STATUS_CREATION
+          LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NOT ENOUGH TBS STOP WITH ACK_SN %04d\n",
+                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
+                __LINE__,
+				sn_nack);
+#endif
     		  break;
     	  }
       }
 
       /* Now process all Segments of sn_cursor if PDU not fully received */
-      if ((!status_report_completed) && (all_segments_received == 0) && (sn_nack != rlc_pP->vr_ms)) {
+      if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) {
     	  AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id);
 
     	  /* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */
     	  if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
-			  /* Set E1 of previous NACK_SN */
-    		  if (control_pdu_info.num_nack) {
-    			  control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 1;
-    		  }
     		  /* Init loop flags */
-    		  lsf_received = false;
-    		  segment_loop_end	  = false;
+              /* Check lsf */
+    		  segment_loop_end = (pdu_info_cursor_p->lsf == 1);
 
     		  /* Init first SO Start according to first segment */
     		  if (pdu_info_cursor_p->so) {
-    			  waited_so = 0;
     			  /* Fill the first SO */
                   control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_cursor;
                   control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = 0;
                   control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = pdu_info_cursor_p->so - 1;
                   control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
+                  /* Set E1 for next NACK_SN. The last one will be cleared */
+                  control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
                   control_pdu_info.num_nack += 1;
                   nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
 #if TRACE_RLC_AM_STATUS_CREATION
             LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n",
                   PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                   __LINE__,
-                  previous_sn_cursor,
-                  waited_so,
-                  0x7FFF);
+				  sn_cursor,
+                  0,
+				  pdu_info_cursor_p->so - 1);
 #endif
                   waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
                   /* Go to next segment */
                   cursor_p = cursor_p->next;
+                  if (cursor_p != NULL)
+                  {
+	                  pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
+                  }
     		  }
     		  else {
         		  waited_so = pdu_info_cursor_p->payload_size;
@@ -587,79 +578,73 @@ rlc_am_send_status_pdu(
 
     		  /* Find the first discontinuity and then fill SOStart/SOEnd */
     		  while (!segment_loop_end) {
-    			  if (cursor_p != NULL) {
-
-        		      pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
-
-        		      if (pdu_info_cursor_p->sn == sn_cursor) {
-            		      /* PDU segment is for the same SN*/
-            			  if (waited_so < pdu_info_cursor_p->so) {
-            				  /* SO is greater than previous received portion : gap identified to fill */
-            				  if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
-            					  /* Set E1 of previous NACK_SN */
-            		    		  if (control_pdu_info.num_nack) {
-            		    			  control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 1;
-            		    		  }
-
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_cursor;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = waited_so;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = pdu_info_cursor_p->so;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
-        	                      control_pdu_info.num_nack += 1;
-        	                      nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
-            				  }
-            				  else {
-            		    		  /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
-            		    		  control_pdu_info.ack_sn = sn_cursor;
-            		    		  status_report_completed = true;
-            		    		  segment_loop_end = true;
-            		    		  break;
-            				  }
-
-            			  }
-            			  else {
-            				  /* Assuming so and payload_size updated according to duplication removal done at reception ... */
-            				  waited_so += pdu_info_cursor_p->payload_size;
-            			  }
-
-        		      } //end if (pdu_info_cursor_p->sn == sn_cursor)
-        		      else if (!lsf_received) {
-        		    	  /* We just switched to next SN, fill last gap if not end received */
-        		    	  if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
-        	   		    	  /* Set E1 of previously received NACK */
-        	    		    	  control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 1;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_cursor;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = waited_so;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
-        	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
-        	                      control_pdu_info.num_nack += 1;
-        	                      nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
-        		    	  }
-        		    	  else {
-        		    		  /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
-        		    		  control_pdu_info.ack_sn = sn_cursor;
-        		    		  status_report_completed = true;
-        		    	  }
-
-        		    	  segment_loop_end = true;
-        		    	  continue; //in order not to go to next cursor
-        		      } // end if (!lsf_received)
-
-        			  /* Go to next received PDU or PDU Segment */
-        			  cursor_p = cursor_p->next;
-
-    			  } //end if (cursor_p != NULL)
-    			  else if (!lsf_received) {
-    				  /* Previous PDU segment was the last one and had lsf indication : fill the latest gap */
+    			  if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) {
+
+					  /* PDU segment is for the same SN*/
+					  /* Check lsf */
+					  segment_loop_end = (pdu_info_cursor_p->lsf == 1);
+
+					  if (waited_so < pdu_info_cursor_p->so) {
+						  /* SO is greater than previous received portion : gap identified to fill */
+						  if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
+							  control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_cursor;
+							  control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = waited_so;
+							  control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = pdu_info_cursor_p->so;
+							  control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
+							  /* Set E1 for next NACK_SN. The last one will be cleared */
+							  control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
+							  control_pdu_info.num_nack += 1;
+							  nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
+#if TRACE_RLC_AM_STATUS_CREATION
+		LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n",
+			  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
+			  __LINE__,
+			  sn_cursor,
+			  waited_so,
+			  pdu_info_cursor_p->so);
+#endif
+						  }
+						  else {
+							  /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
+							  control_pdu_info.ack_sn = sn_cursor;
+							  status_report_completed = true;
+							  segment_loop_end = true;
+							  break;
+						  }
+					  }
+					  else {
+						  /* contiguous segment: only update waited_so */
+						  /* Assuming so and payload_size updated according to duplication removal done at reception ... */
+						  waited_so += pdu_info_cursor_p->payload_size;
+					  }
+
+					  /* Go to next received PDU or PDU Segment */
+					  cursor_p = cursor_p->next;
+	                  if (cursor_p != NULL)
+	                  {
+		                  pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
+	                  }
+
+    			  } //end if (cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)
+    			  else {
+    				  /* Previous PDU segment was the last one and did not have lsf indication : fill the latest gap */
     		    	  if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) {
-    	   		    	  /* Set E1 of previously received NACK */
-    	    		    	  control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 1;
     	                      control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = sn_cursor;
     	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_start  = waited_so;
     	                      control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
     	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
+    	                      /* Set E1 for next NACK_SN. The last one will be cleared */
+    	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
     	                      control_pdu_info.num_nack += 1;
     	                      nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1));
+#if TRACE_RLC_AM_STATUS_CREATION
+            LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING LAST NACK %04d SO START %05d SO END %05d\n",
+                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
+                  __LINE__,
+				  sn_cursor,
+				  waited_so,
+				  RLC_AM_STATUS_PDU_SO_END_ALL_BYTES);
+#endif
      		    	  }
     		    	  else {
     		    		  /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */
@@ -677,16 +662,23 @@ rlc_am_send_status_pdu(
     		  control_pdu_info.ack_sn = sn_nack;
     		  status_report_completed = true;
     	  }
+      } // end while on all PDU segments of sn_cursor
+      else {
+    	  /* Go to next received PDU or PDU segment if sn_cursor is fully received */
+    	  cursor_p = cursor_p->next;
       }
 
       /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */
-      if ((sn_nack != rlc_pP->vr_ms) && (all_segments_received)) {
-    	  sn_nack = RLC_AM_NEXT_SN(sn_nack);
-    	  cursor_p = cursor_p->next;
+      if (sn_nack != rlc_pP->vr_ms) {
+    	  sn_nack = RLC_AM_NEXT_SN(sn_cursor);
       }
 
 
-    }
+    } // End main while NACK_SN
+
+    /* Clear E1 of last nack_sn entry */
+	AssertFatal (control_pdu_info.num_nack, "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id);
+    control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 0;
 
     /* Set ACK_SN unless it was set before */
     if (!status_report_completed){
@@ -694,12 +686,8 @@ rlc_am_send_status_pdu(
     	control_pdu_info.ack_sn = sn_nack;
     }
 
-    if (control_pdu_info.num_nack) {
-    	control_pdu_info.e1 = 1;
-    }
-
-
   } else {
+	/* reception buffer empty or not enough TBS for filling at least 1 NACK_SN + E1 + E2 */
     control_pdu_info.ack_sn = rlc_pP->vr_r;
 #if TRACE_RLC_AM_STATUS_CREATION
     LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d  = VR(R)\n",
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h
index 4892090716..5ca98c88be 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h
@@ -88,9 +88,12 @@ typedef struct rlc_am_tx_sdu_management {
 * \brief Structure containing PDU variables related to its retransmission.
 */
 typedef struct pdu_management_flags {
+  uint8_t transmitted:1;            /*!< \brief Boolean telling that this PDU is not empty and has been at least transmitted once. */
   uint8_t ack:1;            /*!< \brief Boolean telling that this PDU has been acknowledged. */
+  uint8_t nack:1;            /*!< \brief Boolean telling that this PDU has been acknowledged negatively. */
   uint8_t retransmit:1;       /*!< \brief Boolean telling a retransmission is scheduled for this PDU. */
-  uint8_t dummy:6;            /*!< \brief Free bits. */
+  uint8_t max_retransmit:1;       /*!< \brief Boolean telling max retransmission has been hit for this PDU. */
+  uint8_t dummy:3;            /*!< \brief Free bits. */
 } pdu_management_flags_t;
 
 
-- 
2.26.2