rlc_am.c 59.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.0  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */
gauthier's avatar
gauthier committed
21

22
23
#define RLC_AM_MODULE 1
#define RLC_AM_C 1
24
25
26
27
//-----------------------------------------------------------------------------
#include "platform_types.h"
#include "platform_constants.h"
//-----------------------------------------------------------------------------
28
#if ENABLE_ITTI
gauthier's avatar
gauthier committed
29
30
# include "intertask_interface.h"
#endif
31
#include "assertions.h"
knopp's avatar
mutexes    
knopp committed
32
#include "msc.h"
33
#include "hashtable.h"
34
35
36
37
38
39
40
41
42
43
#include "rlc_am.h"
#include "rlc_am_segment.h"
#include "rlc_am_timer_poll_retransmit.h"
#include "mac_primitives.h"
#include "rlc_primitives.h"
#include "list.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
#include "UL-AM-RLC.h"
#include "DL-AM-RLC.h"
44

gauthier's avatar
gauthier committed
45

fnabet's avatar
fnabet committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//-----------------------------------------------------------------------------
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);

}

149
//-----------------------------------------------------------------------------
gauthier's avatar
gauthier committed
150
uint32_t
151
rlc_am_get_buffer_occupancy_in_bytes (
152
153
  const protocol_ctxt_t* const ctxt_pP,
  rlc_am_entity_t * const      rlc_pP)
154
155
{
  // priority of control trafic
Bilel's avatar
Bilel committed
156
  rlc_pP->status_buffer_occupancy = 0;
fnabet's avatar
fnabet committed
157
158
  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);
159
#if TRACE_RLC_AM_BO
160

fnabet's avatar
fnabet committed
161
162
163
      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);
164
165

#endif
166
167
168
  }


169
#if TRACE_RLC_AM_BO
170

171
  if ((rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead) > 0) {
172
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : STATUS  BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->status_buffer_occupancy);
173
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : RETRANS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->retrans_num_bytes_to_retransmit);
174
175
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : SDU     BUFFER %d bytes + li_overhead %d bytes header_overhead %d bytes (nb sdu not segmented %d)\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
176
          rlc_pP->sdu_buffer_occupancy,
177
178
          0,
          0,
179
          rlc_pP->nb_sdu_no_segmented);
180
  }
181

182
#endif
183
  return rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy;
184
185
}
//-----------------------------------------------------------------------------
186
187
void
rlc_am_release (
188
189
190
  const protocol_ctxt_t* const ctxt_pP,
  rlc_am_entity_t * const      rlc_pP
)
191
{
192
  // empty
193
194
}
//-----------------------------------------------------------------------------
195
196
void
config_req_rlc_am (
197
198
199
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t             srb_flagP,
  rlc_am_info_t  * const       config_am_pP,
200
  const rb_id_t                rb_idP,
201
  const logical_chan_id_t      chan_idP 
202
)
203
{
204
205
  rlc_union_t       *rlc_union_p = NULL;
  rlc_am_entity_t *l_rlc_p         = NULL;
206
  hash_key_t       key           = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
207
208
209
210
211
212
213
  hashtable_rc_t   h_rc;

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    l_rlc_p = &rlc_union_p->rlc.am;
    LOG_D(RLC,
214
215
          PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ (max_retx_threshold=%d poll_pdu=%d poll_byte=%d t_poll_retransmit=%d t_reord=%d t_status_prohibit=%d)\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
216
217
218
219
220
221
222
          config_am_pP->max_retx_threshold,
          config_am_pP->poll_pdu,
          config_am_pP->poll_byte,
          config_am_pP->t_poll_retransmit,
          config_am_pP->t_reordering,
          config_am_pP->t_status_prohibit);
    rlc_am_init(ctxt_pP, l_rlc_p);
223
    rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP);
224
225
226
227
228
229
230
231
    rlc_am_configure(ctxt_pP, l_rlc_p,
                     config_am_pP->max_retx_threshold,
                     config_am_pP->poll_pdu,
                     config_am_pP->poll_byte,
                     config_am_pP->t_poll_retransmit,
                     config_am_pP->t_reordering,
                     config_am_pP->t_status_prohibit);
  } else {
232
233
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ RLC NOT FOUND\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p));
234
  }
235
}
fnabet's avatar
fnabet committed
236
uint16_t pollPDU_tab[PollPDU_pInfinity+1]= {4,8,16,32,64,128,256,RLC_AM_POLL_PDU_INFINITE}; //PollPDU_pInfinity is chosen to 0xFFFF for now
237
uint32_t maxRetxThreshold_tab[UL_AM_RLC__maxRetxThreshold_t32+1]= {1,2,3,4,6,8,16,32};
fnabet's avatar
fnabet committed
238
uint32_t pollByte_tab[PollByte_spare1]= {25000,50000,75000,100000,125000,250000,375000,500000,750000,1000000,1250000,1500000,2000000,3000000,RLC_AM_POLL_BYTE_INFINITE}; // PollByte_kBinfinity is chosen to 0xFFFFFFFF for now
239
240
241
uint32_t PollRetransmit_tab[T_PollRetransmit_spare9]= {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,300,350,400,450,500};
uint32_t am_t_Reordering_tab[T_Reordering_spare1]= {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200};
uint32_t t_StatusProhibit_tab[T_StatusProhibit_spare8]= {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,300,350,400,450,500};
242
243

//-----------------------------------------------------------------------------
244
void config_req_rlc_am_asn1 (
245
246
247
  const protocol_ctxt_t* const         ctxt_pP,
  const srb_flag_t                     srb_flagP,
  const struct RLC_Config__am  * const config_am_pP,
248
  const rb_id_t                        rb_idP,
249
  const logical_chan_id_t              chan_idP)
250
{
251
  rlc_union_t     *rlc_union_p   = NULL;
gauthier's avatar
gauthier committed
252
  rlc_am_entity_t *l_rlc_p         = NULL;
253
  hash_key_t       key           = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
254
255
256
  hashtable_rc_t   h_rc;

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);
257

258
  if (h_rc == HASH_TABLE_OK) {
259
260
261
262
263
264
265
266
267
    l_rlc_p = &rlc_union_p->rlc.am;

    if ((config_am_pP->ul_AM_RLC.maxRetxThreshold <= UL_AM_RLC__maxRetxThreshold_t32) &&
        (config_am_pP->ul_AM_RLC.pollPDU<=PollPDU_pInfinity) &&
        (config_am_pP->ul_AM_RLC.pollByte<PollByte_spare1) &&
        (config_am_pP->ul_AM_RLC.t_PollRetransmit<T_PollRetransmit_spare9) &&
        (config_am_pP->dl_AM_RLC.t_Reordering<T_Reordering_spare1) &&
        (config_am_pP->dl_AM_RLC.t_StatusProhibit<T_StatusProhibit_spare8) ) {

gauthier's avatar
gauthier committed
268
      MSC_LOG_RX_MESSAGE(
269
270
271
272
273
274
275
276
277
278
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE,
        NULL,
        0,
        MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ t_PollRetx %u t_Reord %u t_StatusPro %u",
        MSC_AS_TIME_ARGS(ctxt_pP),
        PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
        PollRetransmit_tab[config_am_pP->ul_AM_RLC.t_PollRetransmit],
        am_t_Reordering_tab[config_am_pP->dl_AM_RLC.t_Reordering],
        t_StatusProhibit_tab[config_am_pP->dl_AM_RLC.t_StatusProhibit]);
gauthier's avatar
gauthier committed
279

280
281
      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CONFIG_REQ (max_retx_threshold=%d poll_pdu=%d poll_byte=%d t_poll_retransmit=%d t_reord=%d t_status_prohibit=%d)\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
282
283
284
285
286
287
288
289
            maxRetxThreshold_tab[config_am_pP->ul_AM_RLC.maxRetxThreshold],
            pollPDU_tab[config_am_pP->ul_AM_RLC.pollPDU],
            pollByte_tab[config_am_pP->ul_AM_RLC.pollByte],
            PollRetransmit_tab[config_am_pP->ul_AM_RLC.t_PollRetransmit],
            am_t_Reordering_tab[config_am_pP->dl_AM_RLC.t_Reordering],
            t_StatusProhibit_tab[config_am_pP->dl_AM_RLC.t_StatusProhibit]);

      rlc_am_init(ctxt_pP, l_rlc_p);
290
      rlc_am_set_debug_infos(ctxt_pP, l_rlc_p, srb_flagP, rb_idP, chan_idP);
291
292
293
294
295
296
297
298
      rlc_am_configure(ctxt_pP, l_rlc_p,
                       maxRetxThreshold_tab[config_am_pP->ul_AM_RLC.maxRetxThreshold],
                       pollPDU_tab[config_am_pP->ul_AM_RLC.pollPDU],
                       pollByte_tab[config_am_pP->ul_AM_RLC.pollByte],
                       PollRetransmit_tab[config_am_pP->ul_AM_RLC.t_PollRetransmit],
                       am_t_Reordering_tab[config_am_pP->dl_AM_RLC.t_Reordering],
                       t_StatusProhibit_tab[config_am_pP->dl_AM_RLC.t_StatusProhibit]);
    } else {
gauthier's avatar
gauthier committed
299
      MSC_LOG_RX_DISCARDED_MESSAGE(
300
301
302
303
304
305
306
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
        (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RRC_ENB:MSC_RRC_UE,
        NULL,
        0,
        MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" CONFIG-REQ",
        MSC_AS_TIME_ARGS(ctxt_pP),
        PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p));
gauthier's avatar
gauthier committed
307

308
      LOG_D(RLC,
Cedric Roux's avatar
Cedric Roux committed
309
            PROTOCOL_RLC_AM_CTXT_FMT"ILLEGAL CONFIG_REQ (max_retx_threshold=%ld poll_pdu=%ld poll_byte=%ld t_poll_retransmit=%ld t_reord=%ld t_status_prohibit=%ld), RLC-AM NOT CONFIGURED\n",
310
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
311
312
313
314
315
316
317
            config_am_pP->ul_AM_RLC.maxRetxThreshold,
            config_am_pP->ul_AM_RLC.pollPDU,
            config_am_pP->ul_AM_RLC.pollByte,
            config_am_pP->ul_AM_RLC.t_PollRetransmit,
            config_am_pP->dl_AM_RLC.t_Reordering,
            config_am_pP->dl_AM_RLC.t_StatusProhibit);
    }
318
  } else {
319
320
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT"CONFIG_REQ RLC NOT FOUND\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p));
321
  }
322
323
}

324
//-----------------------------------------------------------------------------
325
void rlc_am_stat_req (
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  const protocol_ctxt_t* const         ctxt_pP,
  rlc_am_entity_t * const              rlc_pP,
  unsigned int* stat_tx_pdcp_sdu,
  unsigned int* stat_tx_pdcp_bytes,
  unsigned int* stat_tx_pdcp_sdu_discarded,
  unsigned int* stat_tx_pdcp_bytes_discarded,
  unsigned int* stat_tx_data_pdu,
  unsigned int* stat_tx_data_bytes,
  unsigned int* stat_tx_retransmit_pdu_by_status,
  unsigned int* stat_tx_retransmit_bytes_by_status,
  unsigned int* stat_tx_retransmit_pdu,
  unsigned int* stat_tx_retransmit_bytes,
  unsigned int* stat_tx_control_pdu,
  unsigned int* stat_tx_control_bytes,
  unsigned int* stat_rx_pdcp_sdu,
  unsigned int* stat_rx_pdcp_bytes,
  unsigned int* stat_rx_data_pdus_duplicate,
  unsigned int* stat_rx_data_bytes_duplicate,
  unsigned int* stat_rx_data_pdu,
  unsigned int* stat_rx_data_bytes,
  unsigned int* stat_rx_data_pdu_dropped,
  unsigned int* stat_rx_data_bytes_dropped,
  unsigned int* stat_rx_data_pdu_out_of_window,
  unsigned int* stat_rx_data_bytes_out_of_window,
  unsigned int* stat_rx_control_pdu,
  unsigned int* stat_rx_control_bytes,
  unsigned int* stat_timer_reordering_timed_out,
  unsigned int* stat_timer_poll_retransmit_timed_out,
  unsigned int* stat_timer_status_prohibit_timed_out)
355
{
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
  *stat_tx_pdcp_sdu                     = rlc_pP->stat_tx_pdcp_sdu;
  *stat_tx_pdcp_bytes                   = rlc_pP->stat_tx_pdcp_bytes;
  *stat_tx_pdcp_sdu_discarded           = rlc_pP->stat_tx_pdcp_sdu_discarded;
  *stat_tx_pdcp_bytes_discarded         = rlc_pP->stat_tx_pdcp_bytes_discarded;
  *stat_tx_data_pdu                     = rlc_pP->stat_tx_data_pdu;
  *stat_tx_data_bytes                   = rlc_pP->stat_tx_data_bytes;
  *stat_tx_retransmit_pdu_by_status     = rlc_pP->stat_tx_retransmit_pdu_by_status;
  *stat_tx_retransmit_bytes_by_status   = rlc_pP->stat_tx_retransmit_bytes_by_status;
  *stat_tx_retransmit_pdu               = rlc_pP->stat_tx_retransmit_pdu;
  *stat_tx_retransmit_bytes             = rlc_pP->stat_tx_retransmit_bytes;
  *stat_tx_control_pdu                  = rlc_pP->stat_tx_control_pdu;
  *stat_tx_control_bytes                = rlc_pP->stat_tx_control_bytes;
  *stat_rx_pdcp_sdu                     = rlc_pP->stat_rx_pdcp_sdu;
  *stat_rx_pdcp_bytes                   = rlc_pP->stat_rx_pdcp_bytes;
  *stat_rx_data_pdus_duplicate          = rlc_pP->stat_rx_data_pdus_duplicate;
  *stat_rx_data_bytes_duplicate         = rlc_pP->stat_rx_data_bytes_duplicate;
  *stat_rx_data_pdu                     = rlc_pP->stat_rx_data_pdu;
  *stat_rx_data_bytes                   = rlc_pP->stat_rx_data_bytes;
  *stat_rx_data_pdu_dropped             = rlc_pP->stat_rx_data_pdu_dropped;
  *stat_rx_data_bytes_dropped           = rlc_pP->stat_rx_data_bytes_dropped;
  *stat_rx_data_pdu_out_of_window       = rlc_pP->stat_rx_data_pdu_out_of_window;
  *stat_rx_data_bytes_out_of_window     = rlc_pP->stat_rx_data_bytes_out_of_window;
  *stat_rx_control_pdu                  = rlc_pP->stat_rx_control_pdu;
  *stat_rx_control_bytes                = rlc_pP->stat_rx_control_bytes;
  *stat_timer_reordering_timed_out      = rlc_pP->stat_timer_reordering_timed_out;
  *stat_timer_poll_retransmit_timed_out = rlc_pP->stat_timer_poll_retransmit_timed_out;
  *stat_timer_status_prohibit_timed_out = rlc_pP->stat_timer_status_prohibit_timed_out;
383
384
385
386

}
//-----------------------------------------------------------------------------
void
387
rlc_am_get_pdus (
388
389
390
  const protocol_ctxt_t* const ctxt_pP,
  rlc_am_entity_t * const      rlc_pP
)
391
{
392
  //int display_flag = 0;
393
394
395
396
397
398
399
400
  // 5.1.3.1 Transmit operations
  // 5.1.3.1.1
  // General
  // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control PDUs over RLC data PDUs.
  // The transmitting side of an AM RLC entity shall prioritize retransmission of RLC data PDUs over transmission of new
  // AMD PDUs.


401
402
403
404
405
406
407
408
  switch (rlc_pP->protocol_state) {

  case RLC_NULL_STATE:
    break;

  case RLC_DATA_TRANSFER_READY_STATE:

    // TRY TO SEND CONTROL PDU FIRST
fnabet's avatar
fnabet committed
409
410
    if ((rlc_pP->nb_bytes_requested_by_mac >= 2) &&
    		((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK))) {
411
412
413
414
415
416
417
418
419
420
421
      // When STATUS reporting has been triggered, the receiving side of an AM RLC entity shall:
      // - if t-StatusProhibit is not running:
      //     - at the first transmission opportunity indicated by lower layer, construct a STATUS PDU and deliver it to lower layer;
      // - else:
      //     - at the first transmission opportunity indicated by lower layer after t-StatusProhibit expires, construct a single
      //       STATUS PDU even if status reporting was triggered several times while t-StatusProhibit was running and
      //       deliver it to lower layer;
      //
      // When a STATUS PDU has been delivered to lower layer, the receiving side of an AM RLC entity shall:
      //     - start t-StatusProhibit.

fnabet's avatar
fnabet committed
422
423
424
425
      rlc_am_send_status_pdu(ctxt_pP, rlc_pP);
      mem_block_t* pdu = list_remove_head(&rlc_pP->control_pdu_list);

      if (pdu) {
426
          list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer);
fnabet's avatar
fnabet committed
427
          RLC_AM_CLEAR_ALL_STATUS(rlc_pP->status_requested);
Bilel's avatar
Bilel committed
428
          rlc_pP->status_buffer_occupancy = 0;
429
430
431
432
          rlc_am_start_timer_status_prohibit(ctxt_pP, rlc_pP);
          return;
        }
      }
fnabet's avatar
fnabet committed
433
434
435
436
      else {
              LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" DELAYED SENT STATUS PDU (Available MAC Data %u)(T-PROHIBIT %u) (DELAY FLAG %u)\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
					rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED));
437
438
439
    }

    // THEN TRY TO SEND RETRANS PDU
440
      if ((rlc_pP->retrans_num_bytes_to_retransmit) && (rlc_pP->nb_bytes_requested_by_mac > 2)) {
441

442
443
      /* 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);
444

445
446
      if (pdu_retx != NULL) {
    	  list_add_tail_eurecom (pdu_retx, &rlc_pP->pdus_to_mac_layer);
447

448
          return;
449
450
451
      }
    }

452
453
    // 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)) {
454
455
456
457
458
459
460
461
462
463
464
465
466
467
      rlc_am_segment_10(ctxt_pP, rlc_pP);
      list_add_list (&rlc_pP->segmentation_pdu_list, &rlc_pP->pdus_to_mac_layer);

      if (rlc_pP->pdus_to_mac_layer.head != NULL) {
        rlc_pP->stat_tx_data_pdu                   += 1;
        rlc_pP->stat_tx_data_bytes                 += (((struct mac_tb_req*)(rlc_pP->pdus_to_mac_layer.head->data))->tb_size);
        return;
      }
    }


    break;

  default:
468
469
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" MAC_DATA_REQ UNKNOWN PROTOCOL STATE 0x%02X\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
470
471
          rlc_pP->protocol_state);
  }
472
473
474
}
//-----------------------------------------------------------------------------
void
475
rlc_am_rx (
476
477
478
479
  const protocol_ctxt_t* const ctxt_pP,
  void * const                 arg_pP,
  struct mac_data_ind          data_indP
)
480
{
gauthier's avatar
gauthier committed
481
  rlc_am_entity_t *rlc = (rlc_am_entity_t *) arg_pP;
482
483
484

  switch (rlc->protocol_state) {

485
  case RLC_NULL_STATE:
Cedric Roux's avatar
Cedric Roux committed
486
    LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR MAC_DATA_IND IN RLC_NULL_STATE\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP, rlc));
487
488
    list_free (&data_indP.data);
    break;
489

490
491
492
  case RLC_DATA_TRANSFER_READY_STATE:
    rlc_am_receive_routing (ctxt_pP, rlc, data_indP);
    break;
493

494
  default:
Cedric Roux's avatar
Cedric Roux committed
495
    LOG_E(RLC, PROTOCOL_RLC_AM_CTXT_FMT" TX UNKNOWN PROTOCOL STATE 0x%02X\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP, rlc), rlc->protocol_state);
496
497
498
499
500
  }
}

//-----------------------------------------------------------------------------
struct mac_status_resp
501
rlc_am_mac_status_indication (
502
503
504
  const protocol_ctxt_t* const ctxt_pP,
  void * const                 rlc_pP,
  const uint16_t               tb_sizeP,
505
506
  struct mac_status_ind        tx_statusP,
  const eNB_flag_t enb_flagP)
507
508
{
  struct mac_status_resp  status_resp;
gauthier's avatar
gauthier committed
509
510
511
  uint16_t  sdu_size = 0;
  uint16_t  sdu_remaining_size = 0;
  int32_t diff_time=0;
gauthier's avatar
gauthier committed
512
  rlc_am_entity_t *rlc = (rlc_am_entity_t *) rlc_pP;
513

514
515
516
517
518
  status_resp.buffer_occupancy_in_bytes        = 0;
  status_resp.buffer_occupancy_in_pdus         = 0;
  status_resp.head_sdu_remaining_size_to_send  = 0;
  status_resp.head_sdu_creation_time           = 0;
  status_resp.head_sdu_is_segmented            = 0;
519
520
  status_resp.rlc_info.rlc_protocol_state = rlc->protocol_state;

Cedric Roux's avatar
Cedric Roux committed
521
522
523
524
525
526
527
528
529
  /* TODO: remove this hack. Problem is: there is a race.
   * UE comes. SRB2 is configured via message to RRC.
   * At some point the RLC AM is created but not configured yet.
   * At this moment (I think) MAC calls mac_rlc_status_ind
   * which calls this function. But the init was not finished yet
   * and we have a crash below when testing mem_block != NULL.
   */
  if (rlc->input_sdus == NULL) return status_resp;

530
  if (rlc->last_absolute_subframe_status_indication != (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP))) {
531
532
533
    rlc_am_check_timer_poll_retransmit(ctxt_pP, rlc);
    rlc_am_check_timer_reordering(ctxt_pP, rlc);
    rlc_am_check_timer_status_prohibit(ctxt_pP, rlc);
534
  }
535

536
  rlc->last_absolute_subframe_status_indication = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP);
537
538
539

  rlc->nb_bytes_requested_by_mac = tb_sizeP;

540
  status_resp.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, rlc);
541

542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  // For eNB scheduler : Add Max RLC header size for new PDU
  // For UE : do not add RLC header part to be compliant with BSR definition in 36.321
  if (enb_flagP == ENB_FLAG_YES) {
	  uint32_t max_li_overhead = 0;
	  uint32_t header_overhead = 0;

	   if (rlc->nb_sdu_no_segmented > 1) {
	   	/* 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->nb_sdu_no_segmented - 1;
	       max_li_overhead = num_li + (num_li >> 1) + (num_li & 1);
	   }

	   if (rlc->sdu_buffer_occupancy > 0) {
	     header_overhead = 2;
	   }

	   status_resp.buffer_occupancy_in_bytes += (header_overhead + max_li_overhead);
  }


562
  if ((rlc->input_sdus[rlc->current_sdu_index].mem_block != NULL) && (status_resp.buffer_occupancy_in_bytes)) {
563

564
565
566
    //status_resp.buffer_occupancy_in_bytes += ((rlc_am_entity_t *) rlc)->tx_header_min_length_in_bytes;
    status_resp.buffer_occupancy_in_pdus = rlc->nb_sdu;
    diff_time =   ctxt_pP->frame - ((rlc_am_tx_sdu_management_t *) (rlc->input_sdus[rlc->current_sdu_index].mem_block->data))->sdu_creation_time;
gauthier's avatar
gauthier committed
567

568
    status_resp.head_sdu_creation_time = (diff_time > 0 ) ? (uint32_t) diff_time :  (uint32_t)(0xffffffff - diff_time + ctxt_pP->frame) ;
gauthier's avatar
gauthier committed
569

570
571
    sdu_size            = ((rlc_am_tx_sdu_management_t *) (rlc->input_sdus[rlc->current_sdu_index].mem_block->data))->sdu_size;
    sdu_remaining_size  = ((rlc_am_tx_sdu_management_t *) (rlc->input_sdus[rlc->current_sdu_index].mem_block->data))->sdu_remaining_size;
gauthier's avatar
gauthier committed
572

573
574
575
576
577
578
579
    status_resp.head_sdu_remaining_size_to_send = sdu_remaining_size;

    if (sdu_size == sdu_remaining_size)  {
      status_resp.head_sdu_is_segmented = 0;
    } else {
      status_resp.head_sdu_is_segmented = 1;
    }
gauthier's avatar
gauthier committed
580

581
  } else {
582
583
584
585
586
587
588
589
	  /* Not so many possibilities ... */
	  /* either buffer_occupancy_in_bytes = 0 and that's it */
	  /* or we have segmented all received SDUs and buffer occupancy is then made of retransmissions and/or status pdu pending */
	  /* then consider only retransmission buffer for the specific BO values used by eNB scheduler (not used up to now...) */
	  if (rlc->retrans_num_bytes_to_retransmit) {
		  status_resp.buffer_occupancy_in_pdus = rlc->retrans_num_pdus;
		  status_resp.head_sdu_remaining_size_to_send = rlc->retrans_num_bytes_to_retransmit;
		  status_resp.head_sdu_is_segmented = 1;
590
	  }
591
  }
592
#if MESSAGE_CHART_GENERATOR_RLC_MAC
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  MSC_LOG_RX_MESSAGE(
    (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
    (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_MAC_ENB:MSC_MAC_UE,
    NULL,0,
    MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS-IND %u",
    MSC_AS_TIME_ARGS(ctxt_pP),
    PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc),
    tb_sizeP);
  MSC_LOG_TX_MESSAGE(
    (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
    (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_MAC_ENB:MSC_MAC_UE,
    NULL,0,
    MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS-RESP BO:%u/n%u(%u)  %s sdu remain %u",
    MSC_AS_TIME_ARGS(ctxt_pP),
    PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, rlc),
    status_resp.buffer_occupancy_in_bytes,
    status_resp.buffer_occupancy_in_pdus,rlc->nb_sdu,
    (status_resp.head_sdu_is_segmented)?"sdu seg":"sdu not seg",
    status_resp.head_sdu_remaining_size_to_send);
#endif
613

614
#if TRACE_RLC_AM_TX_STATUS
615

616
  if (tb_sizeP > 0) {
617
618
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" MAC_STATUS_INDICATION (DATA) %d bytes -> %d bytes\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
619
620
621
622
623
624
625
626
627
628
          tb_sizeP,
          status_resp.buffer_occupancy_in_bytes);
    /*if ((tx_statusP.tx_status == MAC_TX_STATUS_SUCCESSFUL) && (tx_statusP.no_pdu)) {
        msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] MAC_STATUS_INDICATION  TX STATUS   SUCCESSFUL %d PDUs\n",rlc->module_id,
    rlc->rb_id, ctxt_pP->frame, tx_statusP.no_pdu);
    }
    if ((tx_statusP.tx_status == MAC_TX_STATUS_UNSUCCESSFUL) && (tx_statusP.no_pdu)) {
        msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] MAC_STATUS_INDICATION  TX STATUS UNSUCCESSFUL %d PDUs\n",rlc->module_id, rlc->rb_id,
    ctxt_pP->frame, tx_statusP.no_pdu);
    }*/
629
  }
630

631
632
633
#endif
  return status_resp;
}
634
635
636
637
638
639
640
641
642
643
644

//-----------------------------------------------------------------------------
void
rlc_am_set_nb_bytes_requested_by_mac (
  void * const            rlc_pP,
  const tb_size_t         tb_sizeP
)
{
	((rlc_am_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP;
}

645
646
//-----------------------------------------------------------------------------
struct mac_data_req
647
rlc_am_mac_data_request (
648
  const protocol_ctxt_t* const ctxt_pP,
649
650
  void * const                 rlc_pP,
  const eNB_flag_t        enb_flagP
651
)
652
653
{
  struct mac_data_req data_req;
gauthier's avatar
gauthier committed
654
655
  rlc_am_entity_t *l_rlc_p = (rlc_am_entity_t *) rlc_pP;
  unsigned int nb_bytes_requested_by_mac = ((rlc_am_entity_t *) rlc_pP)->nb_bytes_requested_by_mac;
656
#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR
gauthier's avatar
gauthier committed
657
658
659
  rlc_am_pdu_info_t   pdu_info;
  rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p;
  mem_block_t        *tb_p;
660
  tb_size_t           tb_size_in_bytes;
gauthier's avatar
gauthier committed
661
662
663
  int                 num_nack;
  char                message_string[9000];
  size_t              message_string_size = 0;
664
#   if ENABLE_ITTI
gauthier's avatar
gauthier committed
665
  MessageDef         *msg_p;
666
#   endif
gauthier's avatar
gauthier committed
667
  int                 octet_index, index;
Cedric Roux's avatar
Cedric Roux committed
668
669
670
671
672
673
  /* for no gcc warnings */
  (void)num_nack;
  (void)message_string;
  (void)message_string_size;
  (void)octet_index;
  (void)index;
gauthier's avatar
gauthier committed
674
#endif
675
676

  list_init (&data_req.data, NULL);
677
  rlc_am_get_pdus (ctxt_pP, l_rlc_p);
gauthier's avatar
gauthier committed
678
  list_add_list (&l_rlc_p->pdus_to_mac_layer, &data_req.data);
679

gauthier's avatar
gauthier committed
680
  //((rlc_am_entity_t *) rlc_pP)->tx_pdus += data_req.data.nb_elements;
681
  if ((nb_bytes_requested_by_mac + data_req.data.nb_elements) > 0) {
682
683
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" MAC_DATA_REQUEST %05d BYTES REQUESTED -> %d TBs\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p),
684
685
          nb_bytes_requested_by_mac,
          data_req.data.nb_elements);
686
  }
687

688
689
690
691
  if (enb_flagP) {
	  // redundant in UE MAC Tx processing and not used in eNB ...
	  data_req.buffer_occupancy_in_bytes   = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, l_rlc_p);
  }
gauthier's avatar
gauthier committed
692
  data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state;
693

694
#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR
695

696
  if (data_req.data.nb_elements > 0) {
gauthier's avatar
gauthier committed
697

698
    tb_p = data_req.data.head;
gauthier's avatar
gauthier committed
699

700
    while (tb_p != NULL) {
gauthier's avatar
gauthier committed
701

702
703
      rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)((struct mac_tb_req *) (tb_p->data))->data_ptr;
      tb_size_in_bytes   = ((struct mac_tb_req *) (tb_p->data))->tb_size;
gauthier's avatar
gauthier committed
704

705
      if ((((struct mac_tb_req *) (tb_p->data))->data_ptr[0] & RLC_DC_MASK) == RLC_DC_DATA_PDU ) {
706
        if (rlc_am_get_data_pdu_infos(ctxt_pP,l_rlc_p,rlc_am_pdu_sn_10_p, tb_size_in_bytes, &pdu_info) >= 0) {
707
#if MESSAGE_CHART_GENERATOR
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" DATA SN %u size %u RF %u P %u FI %u",
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
                                         pdu_info.sn,
                                         tb_size_in_bytes,
                                         pdu_info.rf,
                                         pdu_info.p,
                                         pdu_info.fi);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], " LSF %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], " SO %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "| HE:");

            for (index=0; index < pdu_info.num_li; index++) {
gauthier's avatar
gauthier committed
728
              message_string_size += sprintf(&message_string[message_string_size], " LI %u", pdu_info.li_list[index]);
729
730
731
            }
          }

gauthier's avatar
gauthier committed
732
          MSC_LOG_TX_MESSAGE(
733
734
735
736
737
738
739
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif
740
#   if ENABLE_ITTI
741
          message_string_size = 0;
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", tb_size_in_bytes);
          message_string_size += sprintf(&message_string[message_string_size], "Header size : %u\n", pdu_info.header_size);
          message_string_size += sprintf(&message_string[message_string_size], "Payload size: %u\n", pdu_info.payload_size);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA REQ: AMD PDU segment\n\n");
          } else {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA REQ: AMD PDU\n\n");
          }

          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  RF        : %u\n", pdu_info.rf);
          message_string_size += sprintf(&message_string[message_string_size], "  P         : %u\n", pdu_info.p);
          message_string_size += sprintf(&message_string[message_string_size], "  FI        : %u\n", pdu_info.fi);
          message_string_size += sprintf(&message_string[message_string_size], "  E         : %u\n", pdu_info.e);
          message_string_size += sprintf(&message_string[message_string_size], "  SN        : %u\n", pdu_info.sn);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "  LSF       : %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], "  SO        : %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "\nHeader extension  : \n");

            for (index=0; index < pdu_info.num_li; index++) {
              message_string_size += sprintf(&message_string[message_string_size], "  LI        : %u\n", pdu_info.li_list[index]);
            }
          }

          message_string_size += sprintf(&message_string[message_string_size], "\nPayload  : \n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");
          message_string_size += sprintf(&message_string[message_string_size], "      |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |\n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");

          for (octet_index = 0; octet_index < pdu_info.payload_size; octet_index++) {
            if ((octet_index % 16) == 0) {
              if (octet_index != 0) {
                message_string_size += sprintf(&message_string[message_string_size], " |\n");
gauthier's avatar
gauthier committed
783
              }
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809

              message_string_size += sprintf(&message_string[message_string_size], " %04d |", octet_index);
            }

            /*
             * Print every single octet in hexadecimal form
             */
            message_string_size += sprintf(&message_string[message_string_size], " %02x", pdu_info.payload[octet_index]);
            /*
             * Align newline and pipes according to the octets in groups of 2
             */
          }

          /*
           * Append enough spaces and put final pipe
           */
          for (index = octet_index; index < 16; ++index) {
            message_string_size += sprintf(&message_string[message_string_size], "   ");
          }

          message_string_size += sprintf(&message_string[message_string_size], " |\n");

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_DATA_PDU_REQ, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_data_pdu_req.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_data_pdu_req.text, message_string, message_string_size);

810
          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);
811
812
813
814
815
816

# else
          rlc_am_display_data_pdu_infos(ctxt_pP, l_rlc_p, &pdu_info);
# endif
        }
      } else {
817
        if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, &tb_size_in_bytes, &l_rlc_p->control_pdu_info) >= 0) {
818
          tb_size_in_bytes   = ((struct mac_tb_req *) (tb_p->data))->tb_size; //tb_size_in_bytes modified by rlc_am_get_control_pdu_infos!
819
#if MESSAGE_CHART_GENERATOR
820
821
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
gauthier's avatar
gauthier committed
822
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS ACK_SN %u",
823
824
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
825
                                         l_rlc_p->control_pdu_info.ack_sn);
gauthier's avatar
gauthier committed
826

827
828
          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
829
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u SO START %u SO END %u",
830
831
832
            		  l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);
833
834
835

            } else {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u",
836
            		  l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
837
838
839
            }
          }

gauthier's avatar
gauthier committed
840
          MSC_LOG_TX_MESSAGE(
841
842
843
844
845
846
847
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif
848
#   if ENABLE_ITTI
849
          message_string_size = 0;
850
851
852
853
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", tb_size_in_bytes);
          message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA REQ: STATUS PDU\n\n");
          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
854
855
856
857
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", l_rlc_p->control_pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  CPT       : %u\n", l_rlc_p->control_pdu_info.cpt);
          message_string_size += sprintf(&message_string[message_string_size], "  ACK_SN    : %u\n", l_rlc_p->control_pdu_info.ack_sn);
          message_string_size += sprintf(&message_string[message_string_size], "  E1        : %u\n", l_rlc_p->control_pdu_info.e1);
858

859
860
          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
861
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d SO START %05d SO END %05d",
862
863
864
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);
865
            } else {
866
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d",  l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
867
            }
868
          }
869
870
871
872
873

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_STATUS_PDU_REQ, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_status_pdu_req.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_status_pdu_req.text, message_string, message_string_size);

874
          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);
875
876
877

#   endif
        }
878
      }
879
880
881

      tb_p = tb_p->next;
    }
882
  }
883

gauthier's avatar
gauthier committed
884
#endif
885
886
887
888
  return data_req;
}
//-----------------------------------------------------------------------------
void
889
rlc_am_mac_data_indication (
890
891
892
893
  const protocol_ctxt_t* const ctxt_pP,
  void * const                 rlc_pP,
  struct mac_data_ind          data_indP
)
894
{
895
  rlc_am_entity_t*           l_rlc_p = (rlc_am_entity_t*) rlc_pP;
896
897
898
  /*rlc_am_control_pdu_info_t control_pdu_info;
  int                       num_li;
  int16_t                     tb_size;*/
899
#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR
gauthier's avatar
gauthier committed
900
901
902
  rlc_am_pdu_info_t   pdu_info;
  rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p;
  mem_block_t        *tb_p;
903
  sdu_size_t          tb_size_in_bytes;
gauthier's avatar
gauthier committed
904
905
906
  int                 num_nack;
  char                message_string[7000];
  size_t              message_string_size = 0;
907
#   if ENABLE_ITTI
gauthier's avatar
gauthier committed
908
  MessageDef         *msg_p;
909
#   endif
gauthier's avatar
gauthier committed
910
  int                 octet_index, index;
Cedric Roux's avatar
Cedric Roux committed
911
912
913
914
915
916
  /* for no gcc warnings */
  (void)num_nack;
  (void)message_string;
  (void)message_string_size;
  (void)octet_index;
  (void)index;
gauthier's avatar
gauthier committed
917
#endif
918

919
920
  (void)l_rlc_p; /* avoid gcc warning "unused variable" */

921
#if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR
922

gauthier's avatar
gauthier committed
923
924
  if (data_indP.data.nb_elements > 0) {

925
    tb_p = data_indP.data.head;
gauthier's avatar
gauthier committed
926

927
    while (tb_p != NULL) {
gauthier's avatar
gauthier committed
928

929
930
      rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)((struct mac_tb_ind *) (tb_p->data))->data_ptr;
      tb_size_in_bytes   = ((struct mac_tb_ind *) (tb_p->data))->size;
gauthier's avatar
gauthier committed
931

932
      if ((((struct mac_tb_ind *) (tb_p->data))->data_ptr[0] & RLC_DC_MASK) == RLC_DC_DATA_PDU ) {
933
        if (rlc_am_get_data_pdu_infos(ctxt_pP,l_rlc_p,rlc_am_pdu_sn_10_p, tb_size_in_bytes, &pdu_info) >= 0) {
934
#if MESSAGE_CHART_GENERATOR
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" DATA SN %u size %u RF %u P %u FI %u",
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
                                         pdu_info.sn,
                                         tb_size_in_bytes,
                                         pdu_info.rf,
                                         pdu_info.p,
                                         pdu_info.fi);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], " LSF %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], " SO %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "| HE:");

            for (index=0; index < pdu_info.num_li; index++) {
gauthier's avatar
gauthier committed
955
              message_string_size += sprintf(&message_string[message_string_size], " LI %u", pdu_info.li_list[index]);
956
957
958
            }
          }

gauthier's avatar
gauthier committed
959
          MSC_LOG_RX_MESSAGE(
960
961
962
963
964
965
966
967
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif

968
#   if ENABLE_ITTI && TRACE_RLC_AM_PDU
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", tb_size_in_bytes);
          message_string_size += sprintf(&message_string[message_string_size], "Header size : %u\n", pdu_info.header_size);
          message_string_size += sprintf(&message_string[message_string_size], "Payload size: %u\n", pdu_info.payload_size);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: AMD PDU segment\n\n");
          } else {
            message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: AMD PDU\n\n");
          }

          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  RF        : %u\n", pdu_info.rf);
          message_string_size += sprintf(&message_string[message_string_size], "  P         : %u\n", pdu_info.p);
          message_string_size += sprintf(&message_string[message_string_size], "  FI        : %u\n", pdu_info.fi);
          message_string_size += sprintf(&message_string[message_string_size], "  E         : %u\n", pdu_info.e);
          message_string_size += sprintf(&message_string[message_string_size], "  SN        : %u\n", pdu_info.sn);

          if (pdu_info.rf) {
            message_string_size += sprintf(&message_string[message_string_size], "  LSF       : %u\n", pdu_info.lsf);
            message_string_size += sprintf(&message_string[message_string_size], "  SO        : %u\n", pdu_info.so);
          }

          if (pdu_info.e) {
            message_string_size += sprintf(&message_string[message_string_size], "\nHeader extension  : \n");

            for (index=0; index < pdu_info.num_li; index++) {
              message_string_size += sprintf(&message_string[message_string_size], "  LI        : %u\n", pdu_info.li_list[index]);
            }
          }

          message_string_size += sprintf(&message_string[message_string_size], "\nPayload  : \n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");
          message_string_size += sprintf(&message_string[message_string_size], "      |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |\n");
          message_string_size += sprintf(&message_string[message_string_size], "------+-------------------------------------------------|\n");

          for (octet_index = 0; octet_index < pdu_info.payload_size; octet_index++) {
            if ((octet_index % 16) == 0) {
              if (octet_index != 0) {
                message_string_size += sprintf(&message_string[message_string_size], " |\n");
gauthier's avatar
gauthier committed
1010
              }
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036

              message_string_size += sprintf(&message_string[message_string_size], " %04d |", octet_index);
            }

            /*
             * Print every single octet in hexadecimal form
             */
            message_string_size += sprintf(&message_string[message_string_size], " %02x", pdu_info.payload[octet_index]);
            /*
             * Align newline and pipes according to the octets in groups of 2
             */
          }

          /*
           * Append enough spaces and put final pipe
           */
          for (index = octet_index; index < 16; ++index) {
            message_string_size += sprintf(&message_string[message_string_size], "   ");
          }

          message_string_size += sprintf(&message_string[message_string_size], " |\n");

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_DATA_PDU_IND, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_data_pdu_ind.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_data_pdu_ind.text, message_string, message_string_size);

1037
          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);
1038
1039
1040
1041
1042
1043

# else
          rlc_am_display_data_pdu_infos(ctxt_pP, l_rlc_p, &pdu_info);
# endif
        }
      } else {
1044
        if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, &tb_size_in_bytes, &l_rlc_p->control_pdu_info) >= 0) {
1045
#if MESSAGE_CHART_GENERATOR
1046
1047
          message_string_size = 0;
          message_string_size += sprintf(&message_string[message_string_size],
gauthier's avatar
gauthier committed
1048
                                         MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" STATUS size ACK_SN %u",
1049
1050
                                         MSC_AS_TIME_ARGS(ctxt_pP),
                                         PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
1051
                                         l_rlc_p->control_pdu_info.ack_sn);
gauthier's avatar
gauthier committed
1052

1053
1054
          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
1055
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u SO START %u SO END %u",
1056
1057
1058
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);
1059
1060
1061

            } else {
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %u",
1062
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
1063
1064
1065
            }
          }

gauthier's avatar
gauthier committed
1066
          MSC_LOG_RX_MESSAGE(
1067
1068
1069
1070
1071
1072
1073
1074
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
            (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_UE:MSC_RLC_ENB,
            (char*)rlc_am_pdu_sn_10_p,
            tb_size_in_bytes,
            message_string);

#endif

1075
#   if ENABLE_ITTI && TRACE_RLC_AM_PDU
1076
          message_string_size = 0;
1077
1078
1079
1080
          message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", l_rlc_p->rb_id);
          message_string_size += sprintf(&message_string[message_string_size], "PDU size    : %u\n", ((struct mac_tb_ind *) (tb_p->data))->size);
          message_string_size += sprintf(&message_string[message_string_size], "PDU type    : RLC AM DATA IND: STATUS PDU\n\n");
          message_string_size += sprintf(&message_string[message_string_size], "Header      :\n");
1081
1082
1083
1084
          message_string_size += sprintf(&message_string[message_string_size], "  D/C       : %u\n", l_rlc_p->control_pdu_info.d_c);
          message_string_size += sprintf(&message_string[message_string_size], "  CPT       : %u\n", l_rlc_p->control_pdu_info.cpt);
          message_string_size += sprintf(&message_string[message_string_size], "  ACK_SN    : %u\n", l_rlc_p->control_pdu_info.ack_sn);
          message_string_size += sprintf(&message_string[message_string_size], "  E1        : %u\n", l_rlc_p->control_pdu_info.e1);
1085

1086
1087
          for (num_nack = 0; num_nack < l_rlc_p->control_pdu_info.num_nack; num_nack++) {
            if (l_rlc_p->control_pdu_info.nack_list[num_nack].e2) {
1088
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d SO START %05d SO END %05d",
1089
1090
1091
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_start,
                                             l_rlc_p->control_pdu_info.nack_list[num_nack].so_end);
1092
            } else {
1093
              message_string_size += sprintf(&message_string[message_string_size], "  NACK SN %04d",  l_rlc_p->control_pdu_info.nack_list[num_nack].nack_sn);
1094
            }
gauthier's avatar
gauthier committed
1095
          }
1096
1097
1098
1099
1100

          msg_p = itti_alloc_new_message_sized (ctxt_pP->enb_flag > 0 ? TASK_RLC_ENB:TASK_RLC_UE , RLC_AM_STATUS_PDU_IND, message_string_size + sizeof (IttiMsgText));
          msg_p->ittiMsg.rlc_am_status_pdu_ind.size = message_string_size;
          memcpy(&msg_p->ittiMsg.rlc_am_status_pdu_ind.text, message_string, message_string_size);

1101
          itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);
1102
1103
1104

#   endif
        }
gauthier's avatar
gauthier committed
1105
      }
1106
1107
1108

      tb_p = tb_p->next;
    }
gauthier's avatar
gauthier committed
1109
  }
1110

gauthier's avatar
gauthier committed
1111
#endif
1112
  rlc_am_rx (ctxt_pP, rlc_pP, data_indP);
1113
1114
1115
1116
}

//-----------------------------------------------------------------------------
void
1117
rlc_am_data_req (
1118
1119
1120
  const protocol_ctxt_t* const ctxt_pP,
  void * const                rlc_pP,
  mem_block_t * const         sdu_pP)
1121
{
gauthier's avatar
gauthier committed
1122
  rlc_am_entity_t     *l_rlc_p = (rlc_am_entity_t *) rlc_pP;
gauthier's avatar
gauthier committed
1123
1124
1125
1126
  uint32_t             mui;
  uint16_t             data_offset;
  uint16_t             data_size;
  uint8_t              conf;
1127
#if TRACE_RLC_AM_PDU
gauthier's avatar
gauthier committed
1128
1129
  char                 message_string[7000];
  size_t               message_string_size = 0;
1130
#if ENABLE_ITTI
gauthier's avatar
gauthier committed
1131
  MessageDef          *msg_p;
gauthier's avatar
gauthier committed
1132
#endif
gauthier's avatar
gauthier committed
1133
1134
  int                  octet_index, index;
#endif
1135

knopp's avatar
mutexes    
knopp committed
1136
  RLC_AM_MUTEX_LOCK(&l_rlc_p->lock_input_sdus, ctxt_pP, l_rlc_p);
1137

gauthier's avatar
gauthier committed
1138
1139
1140
  if ((l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].mem_block == NULL) &&
      (l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].flags.segmented == 0) &&
      (((l_rlc_p->next_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE) != l_rlc_p->current_sdu_index)) {
1141
1142


1143
1144
    memset(&l_rlc_p->input_sdus[l_rlc_p->next_sdu_index], 0, sizeof(rlc_am_tx_sdu_management_t));
    l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].mem_block = sdu_pP;
1145

1146
1147
1148
1149
    mui         = ((struct rlc_am_data_req *) (sdu_pP->data))->mui;
    data_offset = ((struct rlc_am_data_req *) (sdu_pP->data))->data_offset;
    data_size   = ((struct rlc_am_data_req *) (sdu_pP->data))->data_size;
    conf        = ((struct rlc_am_data_req *) (sdu_pP->data))->conf;
gauthier's avatar
gauthier committed
1150
1151

    MSC_LOG_RX_MESSAGE(
1152
1153
1154
1155
1156
1157
1158
1159
1160
      (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,
      (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE,
      (const char*)(&sdu_pP->data[data_offset]),
      data_size,
      MSC_AS_TIME_FMT" "PROTOCOL_RLC_AM_MSC_FMT" DATA-REQ size %u mui %u",
      MSC_AS_TIME_ARGS(ctxt_pP),
      PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP, l_rlc_p),
      data_size,
      mui);
gauthier's avatar
gauthier committed
1161

1162

1163
#if TRACE_RLC_AM_PDU
1164
1165
<