rlc_am_status_report.c 50.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * 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
 */

22
23
#define RLC_AM_MODULE 1
#define RLC_AM_STATUS_REPORT_C 1
24
//-----------------------------------------------------------------------------
gauthier's avatar
gauthier committed
25
#include <string.h>
26
27
28
//-----------------------------------------------------------------------------
#include "platform_types.h"
//-----------------------------------------------------------------------------
29
#if ENABLE_ITTI
gauthier's avatar
   
gauthier committed
30
31
# include "intertask_interface.h"
#endif
gauthier's avatar
gauthier committed
32
#include "assertions.h"
33
34
35
36
#include "list.h"
#include "rlc_am.h"
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
37

38
#   if ENABLE_ITTI
gauthier's avatar
   
gauthier committed
39
//-----------------------------------------------------------------------------
40
41
void
rlc_am_itti_display_status_ind_infos(
42
43
44
  const protocol_ctxt_t* const            ctxt_pP,
  const rlc_am_entity_t *const            rlc_pP,
  const rlc_am_control_pdu_info_t *const  pdu_info_pP)
gauthier's avatar
   
gauthier committed
45
{
46
47
48
  char                 message_string[1000];
  size_t               message_string_size = 0;
  MessageDef          *msg_p;
gauthier's avatar
   
gauthier committed
49

50
  int num_nack;
gauthier's avatar
   
gauthier committed
51

52
53
54
  if (!pdu_info_pP->d_c) {
    message_string_size += sprintf(&message_string[message_string_size], "Bearer      : %u\n", rlc_pP->rb_id);
    message_string_size += sprintf(&message_string[message_string_size], "CONTROL PDU ACK SN %04d", pdu_info_pP->ack_sn);
gauthier's avatar
   
gauthier committed
55

56
57
58
59
60
61
62
63
64
    for (num_nack = 0; num_nack < pdu_info_pP->num_nack; num_nack++) {
      if (pdu_info_pP->nack_list[num_nack].e2) {
        message_string_size += sprintf(&message_string[message_string_size], "\n\tNACK SN %04d SO START %05d SO END %05d",  pdu_info_pP->nack_list[num_nack].nack_sn,
                                       pdu_info_pP->nack_list[num_nack].so_start,
                                       pdu_info_pP->nack_list[num_nack].so_end);
      } else {
        message_string_size += sprintf(&message_string[message_string_size], "\n\tNACK SN %04d",  pdu_info_pP->nack_list[num_nack].nack_sn);
      }
    }
gauthier's avatar
   
gauthier committed
65

66
    message_string_size += sprintf(&message_string[message_string_size], "\n");
gauthier's avatar
   
gauthier committed
67

68
69
70
71
    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);

72
    itti_send_msg_to_task(TASK_UNKNOWN, ctxt_pP->instance, msg_p);
73
  }
gauthier's avatar
   
gauthier committed
74
75
76
77
}

#   endif

78
//-----------------------------------------------------------------------------
79
uint16_t rlc_am_read_bit_field(
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
  uint8_t** data_ppP,
  unsigned int* bit_pos_pP,
  const signed int bits_to_readP)
{
  uint16_t        value     = 0;
  unsigned int bits_read = 0;
  signed int bits_to_read = bits_to_readP;

  do {
    // bits read > bits to read
    if ((8 - *bit_pos_pP) > bits_to_read) {
      bits_read = 8 - *bit_pos_pP;
      value = (value << bits_to_read) | ((((uint16_t)(**data_ppP)) & (uint16_t)(0x00FF >> *bit_pos_pP)) >> (bits_read -
                                         bits_to_read));
      *bit_pos_pP = *bit_pos_pP + bits_to_read;
      return value;
      // bits read == bits to read
    } else if ((8 - *bit_pos_pP) == bits_to_read) {
      value = (value << bits_to_read) | (((uint16_t)(**data_ppP)) & (uint16_t)(0x00FF >> *bit_pos_pP));
      *bit_pos_pP = 0;
      *data_ppP = *data_ppP + 1;
      return value;
      // bits read < bits to read
    } else {
      bits_read = 8 - *bit_pos_pP;
      value = (value << bits_read) | ((((uint16_t)(**data_ppP)) & (uint16_t)(0x00FF >> *bit_pos_pP)));
      *bit_pos_pP = 0;
      *data_ppP = *data_ppP + 1;
      bits_to_read = bits_to_read - bits_read;
    }
  } while (bits_to_read > 0);

  return value;
113
114
}
//-----------------------------------------------------------------------------
115
116
void
rlc_am_write8_bit_field(
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
  uint8_t** data_ppP,
  unsigned int* bit_pos_pP,
  const signed int bits_to_writeP,
  const uint8_t valueP)
{
  unsigned int available_bits;
  signed int bits_to_write= bits_to_writeP;

  do {
    available_bits = 8 - *bit_pos_pP;

    // available_bits > bits to write
    if (available_bits > bits_to_write) {
      **data_ppP = **data_ppP | (((valueP & (((uint8_t)0xFF) >> (available_bits - bits_to_write)))) << (available_bits -
                                 bits_to_write));
      *bit_pos_pP = *bit_pos_pP + bits_to_write;
      return;
      // bits read == bits to read
    } else if (available_bits == bits_to_write) {
      **data_ppP = **data_ppP | (valueP & (((uint8_t)0xFF) >> (8 - bits_to_write)));
      *bit_pos_pP = 0;
      *data_ppP = *data_ppP + 1;
      return;
      // available_bits < bits to write
    } else {
      **data_ppP = **data_ppP  | (valueP >> (bits_to_write - available_bits));
      *bit_pos_pP = 0;
      *data_ppP = *data_ppP + 1;
      bits_to_write = bits_to_write - available_bits;
    }
  } while (bits_to_write > 0);
148
149
}
//-----------------------------------------------------------------------------
150
151
void
rlc_am_write16_bit_field(
152
153
154
155
156
157
  uint8_t** data_ppP,
  unsigned int* bit_pos_pP,
  signed int bits_to_writeP,
  const uint16_t valueP)
{
  assert(bits_to_writeP <= 16);
158

159
160
161
162
163
164
  if (bits_to_writeP > 8) {
    rlc_am_write8_bit_field(data_ppP,bit_pos_pP,  bits_to_writeP - 8, (uint8_t)(valueP >> 8));
    rlc_am_write8_bit_field(data_ppP,bit_pos_pP,  8, (uint8_t)(valueP & 0x00FF));
  } else {
    rlc_am_write8_bit_field(data_ppP,bit_pos_pP,  bits_to_writeP, (uint8_t)(valueP & 0x00FF));
  }
165
166
}
//-----------------------------------------------------------------------------
167
168
signed int
rlc_am_get_control_pdu_infos(
169
170
171
  rlc_am_pdu_sn_10_t* const        header_pP,
  sdu_size_t * const               total_size_pP,
  rlc_am_control_pdu_info_t* const pdu_info_pP)
172
{
173
174
175
176
177
178
179
180
  memset(pdu_info_pP, 0, sizeof (rlc_am_control_pdu_info_t));

  pdu_info_pP->d_c = header_pP->b1 >> 7;


  if (!pdu_info_pP->d_c) {
    pdu_info_pP->cpt    = (header_pP->b1 >> 4) & 0x07;

181
182
183
    if (pdu_info_pP->cpt != 0x00) {
      return -3;
    }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

    pdu_info_pP->ack_sn = ((header_pP->b2 >> 2) & 0x3F) | (((uint16_t)(header_pP->b1 & 0x0F)) << 6);
    pdu_info_pP->e1     = (header_pP->b2 >> 1) & 0x01;
    //*total_size_pP -= 1;

    if (pdu_info_pP->e1) {
      unsigned int nack_to_read  = 1;
      unsigned int bit_pos       = 7; // range from 0 (MSB/left) to 7 (LSB/right)
      uint8_t*        byte_pos_p      = &header_pP->b2;

      while (nack_to_read)  {
        pdu_info_pP->nack_list[pdu_info_pP->num_nack].nack_sn = rlc_am_read_bit_field(&byte_pos_p, &bit_pos, 10);
        pdu_info_pP->nack_list[pdu_info_pP->num_nack].e1      = rlc_am_read_bit_field(&byte_pos_p, &bit_pos, 1);
        pdu_info_pP->nack_list[pdu_info_pP->num_nack].e2      = rlc_am_read_bit_field(&byte_pos_p, &bit_pos, 1);

        // READ SOstart, SOend field
        if (pdu_info_pP->nack_list[pdu_info_pP->num_nack].e2) {
          pdu_info_pP->nack_list[pdu_info_pP->num_nack].so_start = rlc_am_read_bit_field(&byte_pos_p, &bit_pos, 15);
          pdu_info_pP->nack_list[pdu_info_pP->num_nack].so_end   = rlc_am_read_bit_field(&byte_pos_p, &bit_pos, 15);
gauthier's avatar
gauthier committed
203
        } else {
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
          pdu_info_pP->nack_list[pdu_info_pP->num_nack].so_start = 0;
          // all 15 bits set to 1 (indicate that the missing portion of the AMD PDU includes all bytes
          // to the last byte of the AMD PDU)
          pdu_info_pP->nack_list[pdu_info_pP->num_nack].so_end   = 0x7FFF;
        }

        pdu_info_pP->num_nack = pdu_info_pP->num_nack + 1;

        if (!pdu_info_pP->nack_list[pdu_info_pP->num_nack - 1].e1) {
          nack_to_read = 0;
          *total_size_pP = *total_size_pP - (sdu_size_t)((uint64_t)byte_pos_p + (uint64_t)((bit_pos + 7)/8) - (uint64_t)header_pP);
          return 0;
        }

        if (pdu_info_pP->num_nack == RLC_AM_MAX_NACK_IN_STATUS_PDU) {
          *total_size_pP = *total_size_pP - (sdu_size_t)((uint64_t)byte_pos_p + (uint64_t)((bit_pos + 7)/8) - (uint64_t)header_pP);
          return -2;
221
        }
222
223
224
      }

      *total_size_pP = *total_size_pP - (sdu_size_t)((uint64_t)byte_pos_p + (uint64_t)((bit_pos + 7)/8) - (uint64_t)header_pP);
225
    } else {
226
      *total_size_pP = *total_size_pP - 2;
227
    }
228
229
230
231
232

    return 0;
  } else {
    return -1;
  }
233
234
}
//-----------------------------------------------------------------------------
235
236
void
rlc_am_display_control_pdu_infos(
237
238
  const rlc_am_control_pdu_info_t* const pdu_info_pP
)
239
{
240
  int num_nack;
241

242
243
  if (!pdu_info_pP->d_c) {
    LOG_T(RLC, "CONTROL PDU ACK SN %04d", pdu_info_pP->ack_sn);
244

245
246
247
248
249
250
251
252
    for (num_nack = 0; num_nack < pdu_info_pP->num_nack; num_nack++) {
      if (pdu_info_pP->nack_list[num_nack].e2) {
        LOG_T(RLC, "\n\tNACK SN %04d SO START %05d SO END %05d",  pdu_info_pP->nack_list[num_nack].nack_sn,
              pdu_info_pP->nack_list[num_nack].so_start,
              pdu_info_pP->nack_list[num_nack].so_end);
      } else {
        LOG_T(RLC, "\n\tNACK SN %04d",  pdu_info_pP->nack_list[num_nack].nack_sn);
      }
253
    }
254
255
256
257
258

    LOG_T(RLC, "\n");
  } else {
    LOG_E(RLC, "CAN'T DISPLAY CONTROL INFO: PDU IS DATA PDU\n");
  }
259
260
}
//-----------------------------------------------------------------------------
261
262
void
rlc_am_receive_process_control_pdu(
263
264
265
266
267
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP,
  mem_block_t* const tb_pP,
  uint8_t** first_byte_ppP,
  sdu_size_t * const tb_size_in_bytes_pP)
268
{
269
270
  rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)*first_byte_ppP;
  sdu_size_t          initial_pdu_size   = *tb_size_in_bytes_pP;
271
272
273
274
275
276
277
278
  rlc_sn_t        ack_sn    = rlc_pP->control_pdu_info.ack_sn;
  rlc_sn_t        sn_cursor = rlc_pP->vt_a;
  rlc_sn_t		vt_a_new  = rlc_pP->vt_a;
  rlc_sn_t		sn_data_cnf;
  rlc_sn_t        nack_sn,prev_nack_sn;
  sdu_size_t		data_cnf_so_stop = 0x7FFF;
  unsigned int nack_index;
  boolean_t status = TRUE;
gauthier's avatar
gauthier committed
279

280
  if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, tb_size_in_bytes_pP, &rlc_pP->control_pdu_info) >= 0) {
gauthier's avatar
gauthier committed
281

282
    rlc_am_tx_buffer_display(ctxt_pP, rlc_pP, " TX BUFFER BEFORE PROCESS OF STATUS PDU");
283
284
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RX CONTROL PDU VT(A) %04d VT(S) %04d POLL_SN %04d ACK_SN %04d\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
gauthier's avatar
gauthier committed
285
286
287
          rlc_pP->vt_a,
          rlc_pP->vt_s,
          rlc_pP->poll_sn,
288
289
          rlc_pP->control_pdu_info.ack_sn);
    rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info);
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312


    // 5.2.1 Retransmission
    //
    // The transmitting side of an AM RLC entity can receive a negative acknowledgement (notification of reception failure
    // by its peer AM RLC entity) for an AMD PDU or a portion of an AMD PDU by the following:
    //     - STATUS PDU from its peer AM RLC entity.
    //
    // When receiving a negative acknowledgement for an AMD PDU or a portion of an AMD PDU by a STATUS PDU from
    // its peer AM RLC entity, the transmitting side of the AM RLC entity shall:
    //     - if the SN of the corresponding AMD PDU falls within the range VT(A) <= SN < VT(S):
    //         - consider the AMD PDU or the portion of the AMD PDU for which a negative acknowledgement was
    //           received for retransmission.

    // 5.2.2.2    Reception of a STATUS report
    // Upon reception of a STATUS report from the receiving RLC AM entity the
    // transmitting side of an AM RLC entity shall:
    // - if the STATUS report comprises a positive or negative
    //     acknowledgement for the RLC data PDU with sequence number equal to
    //     POLL_SN:
    //     - if t-PollRetransmit is running:
    //         - stop and reset t-PollRetransmit.
    assert(ack_sn < RLC_AM_SN_MODULO);
313
    assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU);
314

315
    /* Note : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */
316
317
318
    /* and meaning the report is not complete due to not enough ressources to fill all SOStart/SOEnd of this NACK_SN */
    if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a))
    {
319
      if (rlc_pP->control_pdu_info.num_nack == 0) {
320
321
        while (sn_cursor != ack_sn) {
          rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor);
322
          sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
323
        }
324
325
326

        vt_a_new = ack_sn;
        sn_data_cnf = RLC_AM_PREV_SN(vt_a_new);
327
      } else {
328
        nack_index = 0;
329
        nack_sn   = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
330
        prev_nack_sn = 0x3FFF;
331

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
        while (sn_cursor != nack_sn) {
            rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor);
            sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
        }

        vt_a_new = nack_sn;

        // catch DataCfn
        rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn];
        if (tx_data_pdu_buffer_p->retx_payload_size == tx_data_pdu_buffer_p->payload_size) {
        	sn_data_cnf   = RLC_AM_PREV_SN(nack_sn);
        }
        else if (tx_data_pdu_buffer_p->nack_so_start != 0) {
        	sn_data_cnf       = nack_sn;
        	data_cnf_so_stop    = tx_data_pdu_buffer_p->nack_so_start - 1;
        }
        else {
        	sn_data_cnf       = RLC_AM_PREV_SN(nack_sn);
        }


        while ((sn_cursor != ack_sn) && (status)) {
354
355
356
357
358
          if (sn_cursor != nack_sn) {
            rlc_am_ack_pdu(ctxt_pP,
                           rlc_pP,
                           sn_cursor);
          } else {
359
        	status = rlc_am_nack_pdu (ctxt_pP,
360
                             rlc_pP,
361
362
							 nack_sn,
							 prev_nack_sn,
363
364
                             rlc_pP->control_pdu_info.nack_list[nack_index].so_start,
                             rlc_pP->control_pdu_info.nack_list[nack_index].so_end);
365
366

            nack_index = nack_index + 1;
367
            prev_nack_sn = nack_sn;
368

369
370
            if (nack_index < rlc_pP->control_pdu_info.num_nack) {
               nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
371
            }
372
373
374
375
376
377
378
            else if (nack_sn != ack_sn) {
            	/* general case*/
            	nack_sn = ack_sn;
            }
            else {
            	/*specific case when the sender did not have enough TBS to fill all SOStart SOEnd for this NACK_SN */
            	break;
379
            }
380
          }
381
          sn_cursor = (sn_cursor + 1)  & RLC_AM_SN_MASK;
382
        }
383
      }
384
385


386
    } else {
387
388
      LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
389
      status = FALSE;
390
391
    }
  } else {
392
393
    LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
    status = FALSE;
  }

  if (status) {
      /* Check for Stopping TpollReTx */
      if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) &&
          (RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) {
        rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
        rlc_pP->poll_sn = RLC_SN_UNDEFINED;
      }

      //TODO : this part does not cover all cases of Data Cnf and move it at the end of Status PDU processing
      sn_cursor = rlc_pP->vt_a;

      /* Handle all acked PDU up to and excluding sn_data_cnf */
      while (sn_cursor != sn_data_cnf) {
    	  rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_cursor);
    	  sn_cursor = RLC_AM_NEXT_SN(sn_cursor);
      }

      // Handle last SN. TO DO : case of PDU partially ACKED with SDU to be data conf
      if (data_cnf_so_stop == 0x7FFF) {
    	  rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_data_cnf);
      }

      /* Update vtA and vtMS */
      rlc_pP->vt_a = vt_a_new;
      rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK;
422
  }
423

gauthier's avatar
gauthier committed
424
  *first_byte_ppP = (uint8_t*)((uint64_t)*first_byte_ppP + initial_pdu_size - *tb_size_in_bytes_pP);
winckel's avatar
winckel committed
425

426
  free_mem_block(tb_pP, __func__);
427
  rlc_am_tx_buffer_display(ctxt_pP, rlc_pP, NULL);
428
429
}
//-----------------------------------------------------------------------------
430
431
int
rlc_am_write_status_pdu(
432
433
434
435
  const protocol_ctxt_t* const     ctxt_pP,
  rlc_am_entity_t *const           rlc_pP,
  rlc_am_pdu_sn_10_t* const        rlc_am_pdu_sn_10_pP,
  rlc_am_control_pdu_info_t* const pdu_info_pP)
436
437
{
  unsigned int bit_pos       = 4; // range from 0 (MSB/left) to 7 (LSB/right)
gauthier's avatar
gauthier committed
438
  uint8_t*        byte_pos_p    = &rlc_am_pdu_sn_10_pP->b1;
gauthier's avatar
gauthier committed
439
440
  unsigned int index         = 0;
  unsigned int num_bytes     = 0;
441

gauthier's avatar
gauthier committed
442
  rlc_am_write16_bit_field(&byte_pos_p, &bit_pos, 10, pdu_info_pP->ack_sn);
443

gauthier's avatar
gauthier committed
444
  if (pdu_info_pP->num_nack > 0) {
445
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1, 1);
446
  } else {
447
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1, 0);
448
  }
449

gauthier's avatar
gauthier committed
450
  for (index = 0; index < pdu_info_pP->num_nack ; index++) {
451
452
453
454
455
456
457
458
459
    rlc_am_write16_bit_field(&byte_pos_p, &bit_pos, 10, pdu_info_pP->nack_list[index].nack_sn);
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1,  pdu_info_pP->nack_list[index].e1);
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1,  pdu_info_pP->nack_list[index].e2);

    // if SO_START SO_END fields
    if (pdu_info_pP->nack_list[index].e2 > 0) {
      rlc_am_write16_bit_field(&byte_pos_p, &bit_pos, 15, pdu_info_pP->nack_list[index].so_start);
      rlc_am_write16_bit_field(&byte_pos_p, &bit_pos, 15, pdu_info_pP->nack_list[index].so_end);
    }
460
  }
461

462
463
  ptrdiff_t diff = byte_pos_p - &rlc_am_pdu_sn_10_pP->b1; // this is the difference in terms of typeof(byte_pos_p), which is uint8_t
  num_bytes = diff;
464

465
  if (bit_pos > 0) {
466
    num_bytes += 1;
467
  }
468

469
#if TRACE_RLC_AM_STATUS_CREATION
470
471
472
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WROTE STATUS PDU %d BYTES\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
        num_bytes);
473
474
475
476
#endif
  return num_bytes;
}
//-----------------------------------------------------------------------------
477
478
void
rlc_am_send_status_pdu(
479
480
481
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP
)
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
{
  // 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.
  //
  // When constructing a STATUS PDU, the AM RLC entity shall:
  //     - for the AMD PDUs with SN such that VR(R) <= SN < VR(MR) that has not been completely received yet, in
  //       increasing SN of PDUs and increasing byte segment order within PDUs, starting with SN = VR(R) up to
  //       the point where the resulting STATUS PDU still fits to the total size of RLC PDU(s) indicated by lower layer:
  //         - for an AMD PDU for which no byte segments have been received yet::
  //             - include in the STATUS PDU a NACK_SN which is set to the SN of the AMD PDU;
  //         - for a continuous sequence of byte segments of a partly received AMD PDU that have not been received yet:
  //             - include in the STATUS PDU a set of NACK_SN, SOstart and SOend
  //     - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the
  //       resulting STATUS PDU.

fnabet's avatar
fnabet committed
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
  signed int                    nb_bits_to_transmit   = rlc_pP->nb_bytes_requested_by_mac << 3;
  // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1
  signed int                    nb_bits_transmitted	  = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS;
  rlc_am_control_pdu_info_t     control_pdu_info;
  rlc_am_pdu_info_t            *pdu_info_cursor_p     = NULL;
  rlc_sn_t                      sn_cursor             = 0;
  rlc_sn_t                      sn_nack               = rlc_pP->vr_r;
  mem_block_t                  *cursor_p              = rlc_pP->receiver_buffer.head;
  int                           all_segments_received = 0;
  int                           waited_so             = 0;
  mem_block_t                  *tb_p                  = NULL;
  sdu_size_t                    pdu_size              = 0;
  boolean_t						status_report_completed	= false;
  boolean_t						segment_loop_end	  = false;

  memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t));

#if TRACE_RLC_AM_STATUS_CREATION
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] nb_bits_to_transmit %d (15 already allocated for header)\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
        nb_bits_to_transmit);
  rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT");
#endif

  /* Handle no NACK first */
  if (rlc_pP->vr_r == rlc_pP->vr_ms) {

	  control_pdu_info.ack_sn = rlc_pP->vr_ms;
	  status_report_completed = true;
fnabet's avatar
fnabet committed
534
535
536
537
538
539
#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
fnabet's avatar
fnabet committed
540
  }
fnabet's avatar
fnabet committed
541
  else if ((cursor_p != NULL) && ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)) <= nb_bits_to_transmit)) {
fnabet's avatar
fnabet committed
542
543
544
545

    pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
    sn_cursor             = pdu_info_cursor_p->sn;

fnabet's avatar
fnabet committed
546
547
    /* Set E1 bit for the presence of first NACK_SN/E1/E2 */
    control_pdu_info.e1 = 1;
fnabet's avatar
fnabet committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565

    // 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
    while ((!status_report_completed) && (RLC_AM_DIFF_SN(sn_nack,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))
    		&& (cursor_p != NULL) && (nb_bits_transmitted <= 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;
      all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;

      /* 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 */
              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;
fnabet's avatar
fnabet committed
566
567
              /* Set E1 for next NACK_SN. The last one will be cleared */
              control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
fnabet's avatar
fnabet committed
568
              control_pdu_info.num_nack += 1;
fnabet's avatar
fnabet committed
569
              nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1));
fnabet's avatar
fnabet committed
570
571
572
573
574
575
576
577
578
579
580
581
582
#if TRACE_RLC_AM_STATUS_CREATION
          LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d\n",
                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
                __LINE__,
				sn_nack);
#endif
    		  sn_nack = RLC_AM_NEXT_SN(sn_nack);
    	  }
    	  else {
    		  /* Not enough UL TBS*/
    		  /* latest value of sn_nack shall be used as ACK_SN */
    		  control_pdu_info.ack_sn = sn_nack;
    		  status_report_completed = true;
fnabet's avatar
fnabet committed
583
584
585
586
587
588
#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
fnabet's avatar
fnabet committed
589
590
591
592
593
    		  break;
    	  }
      }

      /* Now process all Segments of sn_cursor if PDU not fully received */
fnabet's avatar
fnabet committed
594
      if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) {
fnabet's avatar
fnabet committed
595
596
597
598
599
    	  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) {
    		  /* Init loop flags */
fnabet's avatar
fnabet committed
600
601
              /* Check lsf */
    		  segment_loop_end = (pdu_info_cursor_p->lsf == 1);
fnabet's avatar
fnabet committed
602
603
604
605
606
607
608
609

    		  /* Init first SO Start according to first segment */
    		  if (pdu_info_cursor_p->so) {
    			  /* 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;
fnabet's avatar
fnabet committed
610
611
                  /* Set E1 for next NACK_SN. The last one will be cleared */
                  control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
fnabet's avatar
fnabet committed
612
613
614
615
616
617
                  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__,
fnabet's avatar
fnabet committed
618
619
620
				  sn_cursor,
                  0,
				  pdu_info_cursor_p->so - 1);
fnabet's avatar
fnabet committed
621
622
623
624
#endif
                  waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
                  /* Go to next segment */
                  cursor_p = cursor_p->next;
fnabet's avatar
fnabet committed
625
626
627
628
                  if (cursor_p != NULL)
                  {
	                  pdu_info_cursor_p     = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
                  }
fnabet's avatar
fnabet committed
629
630
631
632
633
634
635
    		  }
    		  else {
        		  waited_so = pdu_info_cursor_p->payload_size;
    		  }

    		  /* Find the first discontinuity and then fill SOStart/SOEnd */
    		  while (!segment_loop_end) {
fnabet's avatar
fnabet committed
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
    			  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 */
fnabet's avatar
fnabet committed
686
687
688
689
690
    		    	  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    = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES;
    	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
fnabet's avatar
fnabet committed
691
692
    	                      /* Set E1 for next NACK_SN. The last one will be cleared */
    	                      control_pdu_info.nack_list[control_pdu_info.num_nack].e1  = 1;
fnabet's avatar
fnabet committed
693
694
    	                      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));
fnabet's avatar
fnabet committed
695
696
697
698
699
700
701
702
#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
fnabet's avatar
fnabet committed
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
     		    	  }
    		    	  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;
    			  }
    		  } //end  while (!segment_loop_end)
    	  } // end if enough resource for transmitting at least one SOStart/SOEnd
    	  else {
    		  /* Not enough UL TBS to set at least one SOStart/SOEnd */
    		  /* latest value of sn_nack shall be used as ACK_SN */
    		  control_pdu_info.ack_sn = sn_nack;
    		  status_report_completed = true;
    	  }
fnabet's avatar
fnabet committed
720
721
722
723
      } // 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;
fnabet's avatar
fnabet committed
724
725
726
      }

      /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */
fnabet's avatar
fnabet committed
727
728
      if (sn_nack != rlc_pP->vr_ms) {
    	  sn_nack = RLC_AM_NEXT_SN(sn_cursor);
fnabet's avatar
fnabet committed
729
730
731
      }


fnabet's avatar
fnabet committed
732
733
734
735
736
    } // 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;
fnabet's avatar
fnabet committed
737
738
739
740
741
742
743
744

    /* Set ACK_SN unless it was set before */
    if (!status_report_completed){

    	control_pdu_info.ack_sn = sn_nack;
    }

  } else {
fnabet's avatar
fnabet committed
745
	/* reception buffer empty or not enough TBS for filling at least 1 NACK_SN + E1 + E2 */
fnabet's avatar
fnabet committed
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
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
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
    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",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
          __LINE__,
          control_pdu_info.ack_sn);
#endif
  }


  //msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] nb_bits_to_transmit %d\n",
  //     rlc_pP->module_id, rlc_pP->rb_id, ctxt_pP->frame,nb_bits_to_transmit);

#if TRACE_RLC_AM_STATUS_CREATION
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d NUM NACK %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
        __LINE__,
        control_pdu_info.ack_sn,
        control_pdu_info.num_nack);
#endif


  /* encode the control pdu */
  pdu_size = (nb_bits_transmitted + 7) >> 3;
  AssertFatal (pdu_size <= rlc_pP->nb_bytes_requested_by_mac, "RLC AM Tx Status PDU Data size=%d bigger than remaining TBS=%d nb_bits_transmitted=%d LcId=%d\n",
		  pdu_size,rlc_pP->nb_bytes_requested_by_mac,nb_bits_transmitted, rlc_pP->channel_id);


#if TRACE_RLC_AM_STATUS_CREATION
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d forecast pdu_size %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
        __LINE__,
        pdu_size);
#endif
  tb_p = get_free_mem_block(sizeof(struct mac_tb_req) + pdu_size, __func__);
  memset(tb_p->data, 0, sizeof(struct mac_tb_req) + pdu_size);
  //estimation only ((struct mac_tb_req*)(tb_p->data))->tb_size  = pdu_size;
  ((struct mac_tb_req*)(tb_p->data))->data_ptr         = (uint8_t*)&(tb_p->data[sizeof(struct mac_tb_req)]);

  // warning reuse of pdu_size
  // TODO : rlc_am_write_status_pdu should be rewritten as not very tested ...
  pdu_size = rlc_am_write_status_pdu(ctxt_pP, rlc_pP,(rlc_am_pdu_sn_10_t*)(((struct mac_tb_req*)(tb_p->data))->data_ptr), &control_pdu_info);
  ((struct mac_tb_req*)(tb_p->data))->tb_size  = pdu_size;
  //assert((((struct mac_tb_req*)(tb_p->data))->tb_size) < 3000);

#if TRACE_RLC_AM_STATUS_CREATION
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] SEND STATUS PDU SIZE %d, rlc_pP->nb_bytes_requested_by_mac %d, nb_bits_to_transmit>>3 %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
        pdu_size,
        rlc_pP->nb_bytes_requested_by_mac,
        nb_bits_to_transmit >> 3);
#endif

  AssertFatal (pdu_size == ((nb_bits_transmitted + 7) >> 3), "RLC AM Tx Status PDU Data encoding size=%d different than expected=%d LcId=%d\n",
  		  pdu_size,((nb_bits_transmitted + 7) >> 3), rlc_pP->channel_id);

  // remaining bytes to transmit for RLC (retrans pdus and new data pdus)
  rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - pdu_size;
  // put pdu in trans
  list_add_head(tb_p, &rlc_pP->control_pdu_list);
  rlc_pP->stat_tx_control_pdu   += 1;
  rlc_pP->stat_tx_control_bytes += pdu_size;

}


#if 0
//-----------------------------------------------------------------------------
void
rlc_am_send_status_pdu_backup(
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP
)
{
  // 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.
  //
  // When constructing a STATUS PDU, the AM RLC entity shall:
  //     - for the AMD PDUs with SN such that VR(R) <= SN < VR(MR) that has not been completely received yet, in
  //       increasing SN of PDUs and increasing byte segment order within PDUs, starting with SN = VR(R) up to
  //       the point where the resulting STATUS PDU still fits to the total size of RLC PDU(s) indicated by lower layer:
  //         - for an AMD PDU for which no byte segments have been received yet::
  //             - include in the STATUS PDU a NACK_SN which is set to the SN of the AMD PDU;
  //         - for a continuous sequence of byte segments of a partly received AMD PDU that have not been received yet:
  //             - include in the STATUS PDU a set of NACK_SN, SOstart and SOend
  //     - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the
  //       resulting STATUS PDU.

gauthier's avatar
gauthier committed
842
843
844
845
846
847
848
849
850
851
  signed int                    nb_bits_to_transmit   = rlc_pP->nb_bytes_requested_by_mac << 3;
  rlc_am_control_pdu_info_t     control_pdu_info;
  rlc_am_pdu_info_t            *pdu_info_cursor_p     = NULL;
  rlc_sn_t                      previous_sn_cursor    = (rlc_pP->vr_r - 1) & RLC_AM_SN_MASK;
  rlc_sn_t                      sn_cursor             = 0;
  mem_block_t                  *cursor_p              = rlc_pP->receiver_buffer.head;
  int                           all_segments_received = 0;
  int                           waited_so             = 0;
  mem_block_t                  *tb_p                  = NULL;
  sdu_size_t                    pdu_size              = 0;
852
853
854
855

  memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t));
  // header size
  nb_bits_to_transmit = nb_bits_to_transmit - 15;
856
#if TRACE_RLC_AM_STATUS_CREATION
857
858
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] nb_bits_to_transmit %d (15 already allocated for header)\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
859
        nb_bits_to_transmit);
gauthier's avatar
gauthier committed
860
  rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT");
861
862
#endif

fnabet's avatar
fnabet committed
863

gauthier's avatar
gauthier committed
864
  if (cursor_p != NULL) {
865
866
867
    pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
    sn_cursor             = pdu_info_cursor_p->sn;

fnabet's avatar
fnabet committed
868
    while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) {
869
870
871
      cursor_p                = cursor_p->next;
      previous_sn_cursor    = sn_cursor;

gauthier's avatar
gauthier committed
872
873
      pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
      sn_cursor             = pdu_info_cursor_p->sn;
874
#if TRACE_RLC_AM_STATUS_CREATION
875
876
      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),
877
878
879
880
881
882
883
884
885
886
887
888
            __LINE__,
            previous_sn_cursor,
            sn_cursor);
#endif
    }

    // 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
    while ((cursor_p != NULL) && (nb_bits_to_transmit >= 12)) {
      pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
      all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;
      sn_cursor             = pdu_info_cursor_p->sn;
889
#if TRACE_RLC_AM_STATUS_CREATION
890
891
      LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d LOOPING sn_cursor %04d previous sn_cursor %04d \n",
            PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
            __LINE__,
            sn_cursor,
            previous_sn_cursor);
#endif

      // -------------------------------------------------------------------------------
      // case resegmentation : several PDUs related to the same SN queued in list
      // -------------------------------------------------------------------------------
      if (sn_cursor == previous_sn_cursor) {
        do {
          cursor_p = cursor_p->next;

          if (cursor_p != NULL) {
            pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
            all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;
            sn_cursor             = pdu_info_cursor_p->sn;
908
#if TRACE_RLC_AM_STATUS_CREATION
909
910
            LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NOW sn_cursor %04d \n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
911
912
913
914
915
916
                  __LINE__,
                  sn_cursor);
#endif
          } else {
            if (all_segments_received) {
              control_pdu_info.ack_sn = (sn_cursor + 1) & RLC_AM_SN_MASK;
917
#if TRACE_RLC_AM_STATUS_CREATION
918
919
              LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK SN %04d \n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
920
921
922
923
924
                    __LINE__,
                    control_pdu_info.ack_sn);
#endif
            } else {
              control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
925
#if TRACE_RLC_AM_STATUS_CREATION
926
927
              LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK SN %04d (CASE PREVIOUS SN)\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
928
929
930
931
                    __LINE__,
                    control_pdu_info.ack_sn);
#endif
            }
932

933
934
935
936
            goto end_push_nack;
          }
        } while ((cursor_p != NULL) && (sn_cursor == previous_sn_cursor));
      }
937

938
939
940
941
942
943
944
945
946
947
948
949
950
      // -------------------------------------------------------------------------------
      // simple case, PDU(s) is/are missing
      // -------------------------------------------------------------------------------
      while (((previous_sn_cursor + 1) & RLC_AM_SN_MASK) != sn_cursor) {
        if (nb_bits_to_transmit > 12) {
          previous_sn_cursor = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
          control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = previous_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    = 0x7ff;
          control_pdu_info.nack_list[control_pdu_info.num_nack].e1        = 1;
          control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 0;
          control_pdu_info.num_nack += 1;
          nb_bits_to_transmit = nb_bits_to_transmit - 12;
951
#if TRACE_RLC_AM_STATUS_CREATION
952
953
          LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d\n",
                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
gauthier's avatar
gauthier committed
954
                __LINE__,
955
                previous_sn_cursor);
956
#endif
957
958
        } else {
          control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
959
#if TRACE_RLC_AM_STATUS_CREATION
960
961
          LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NO MORE BITS FOR SENDING NACK %04d -> ABORT AND SET FINAL ACK %04d\n",
                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
gauthier's avatar
gauthier committed
962
                __LINE__,
963
964
                previous_sn_cursor,
                control_pdu_info.ack_sn);
965
#endif
966
967
968
          goto end_push_nack;
        }
      }
969

970
971
972
973
974
      // -------------------------------------------------------------------------------
      // not so simple case, a resegmented PDU(s) is missing
      // -------------------------------------------------------------------------------
      if (all_segments_received == 0) {
        waited_so = 0;
975
#if TRACE_RLC_AM_STATUS_CREATION
976
977
        LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] if (all_segments_received == 0) \n",
              PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
978
#endif
979
980
981
982
983
984
985

        do {
          if (pdu_info_cursor_p->so > waited_so) {
            if (nb_bits_to_transmit >= 42) {
              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 - 1;
986
              control_pdu_info.nack_list[control_pdu_info.num_nack].e1        = 1;
987
              control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
988
              control_pdu_info.num_nack += 1;
989
              nb_bits_to_transmit = nb_bits_to_transmit - 42;
990
#if TRACE_RLC_AM_STATUS_CREATION
991
992
              LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d (CASE SO %d > WAITED SO %d)\n",
                    PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
993
994
995
996
997
998
                    __LINE__,
                    sn_cursor,
                    waited_so,
                    pdu_info_cursor_p->so - 1,
                    pdu_info_cursor_p->so,
                    waited_so);
999
#endif
1000
1001
1002
1003

              if (pdu_info_cursor_p->lsf == 1) { // last segment flag
                //waited_so = 0x7FF;
                waited_so = 0x7FFF;
1004
#if TRACE_RLC_AM_STATUS_CREATION
1005
1006
                LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d SN %04d SET WAITED SO 0x7FFF)\n",
                      PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
1007
                      __LINE__, sn_cursor);
1008
#endif
1009
1010
1011
                //break;
              } else {
                waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
1012
#if TRACE_RLC_AM_STATUS_CREATION
1013
1014
                LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d SN %04d SET WAITED SO %d @1\n",
                      PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
1015
1016
1017
                      __LINE__,
                      sn_cursor,
                      waited_so);
1018
#endif
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
              }
            } else {
              control_pdu_info.ack_sn = sn_cursor;
              goto end_push_nack;
            }
          } else { //else { // pdu_info_cursor_p->so <= waited_so
            waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;

            if (pdu_info_cursor_p->lsf == 1) { // last segment flag
              //waited_so = 0x7FF;
              waited_so = 0x7FFF;
            }
1031

1032
#if TRACE_RLC_AM_STATUS_CREATION
1033
1034
            LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d SN %04d SET WAITED SO %d @2\n",
                  PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
1035
1036
                  __LINE__,
                  sn_cursor, waited_so);
1037
#endif
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
          }

          cursor_p = cursor_p->next;

          if (cursor_p != NULL) {
            pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
            all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received;
            previous_sn_cursor    = sn_cursor;
            sn_cursor             = pdu_info_cursor_p->sn;
          } else {
            // LG control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
            control_pdu_info.ack_sn = previous_sn_cursor;
            goto end_push_nack;
          }
        } while ((cursor_p != NULL) && (sn_cursor == previous_sn_cursor));

        // may be last segment of PDU not received
        //if ((sn_cursor != previous_sn_cursor) && (waited_so != 0x7FF)) {
        if ((sn_cursor != previous_sn_cursor) && (waited_so != 0x7FFF)) {
          if (nb_bits_to_transmit >= 42) {
            control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn   = previous_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    = 0x7FF;
            control_pdu_info.nack_list[control_pdu_info.num_nack].so_end    = 0x7FFF;
            control_pdu_info.nack_list[control_pdu_info.num_nack].e1        = 1;
            control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
            control_pdu_info.num_nack += 1;
            nb_bits_to_transmit = nb_bits_to_transmit - 42;
1066
#if TRACE_RLC_AM_STATUS_CREATION
1067
1068
            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),
1069
1070
1071
1072
                  __LINE__,
                  previous_sn_cursor,
                  waited_so,
                  0x7FFF);
1073
1074
#endif
          } else {
1075
1076
            control_pdu_info.ack_sn = previous_sn_cursor;
            goto end_push_nack;
1077
          }
1078
1079
1080
1081
1082
1083
1084
        }

        waited_so = 0;
      } else {
        waited_so = 0;
        cursor_p = cursor_p->next;
        previous_sn_cursor = sn_cursor;
1085
      }
1086
1087
1088
    }

    control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
1089
  } else {
1090
    control_pdu_info.ack_sn = rlc_pP->vr_r;
1091
#if TRACE_RLC_AM_STATUS_CREATION
1092
1093
    LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d  = VR(R)\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
1094
1095
          __LINE__,
          control_pdu_info.ack_sn);
1096
1097
1098
1099
#endif
  }

end_push_nack:
1100

1101
  if (control_pdu_info.num_nack > 0) {
1102
    control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 0;
1103
  }
1104

gauthier's avatar
gauthier committed
1105
  //msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] nb_bits_to_transmit %d\n",
1106
  //     rlc_pP->module_id, rlc_pP->rb_id, ctxt_pP->frame,nb_bits_to_transmit);
1107

1108
#if TRACE_RLC_AM_STATUS_CREATION
1109
1110
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d NUM NACK %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
gauthier's avatar
gauthier committed
1111
1112
1113
        __LINE__,
        control_pdu_info.ack_sn,
        control_pdu_info.num_nack);
1114
1115
#endif
  // encode the control pdu
gauthier's avatar
gauthier committed
1116
  pdu_size = rlc_pP->nb_bytes_requested_by_mac - ((nb_bits_to_transmit - 7 )>> 3);
1117

1118
#if TRACE_RLC_AM_STATUS_CREATION
1119
1120
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d forecast pdu_size %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
1121
1122
        __LINE__,
        pdu_size);
1123
#endif
1124
  tb_p = get_free_mem_block(sizeof(struct mac_tb_req) + pdu_size, __func__);
gauthier's avatar
gauthier committed
1125
1126
  memset(tb_p->data, 0, sizeof(struct mac_tb_req) + pdu_size);
  //estimation only ((struct mac_tb_req*)(tb_p->data))->tb_size  = pdu_size;
gauthier's avatar
gauthier committed
1127
  ((struct mac_tb_req*)(tb_p->data))->data_ptr         = (uint8_t*)&(tb_p->data[sizeof(struct mac_tb_req)]);
1128
1129

  // warning reuse of pdu_size
1130
  pdu_size = rlc_am_write_status_pdu(ctxt_pP, rlc_pP,(rlc_am_pdu_sn_10_t*)(((struct mac_tb_req*)(tb_p->data))->data_ptr), &control_pdu_info);
gauthier's avatar
gauthier committed
1131
1132
  ((struct mac_tb_req*)(tb_p->data))->tb_size  = pdu_size;
  //assert((((struct mac_tb_req*)(tb_p->data))->tb_size) < 3000);
1133

1134
#if TRACE_RLC_AM_STATUS_CREATION
1135
1136
  LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] SEND STATUS PDU SIZE %d, rlc_pP->nb_bytes_requested_by_mac %d, nb_bits_to_transmit>>3 %d\n",
        PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
gauthier's avatar
gauthier committed
1137
1138
1139
        pdu_size,
        rlc_pP->nb_bytes_requested_by_mac,
        nb_bits_to_transmit >> 3);
1140
#endif
gauthier's avatar
gauthier committed
1141
  assert(pdu_size == (rlc_pP->nb_bytes_requested_by_mac - (nb_bits_to_transmit >> 3)));
1142
1143

  // remaining bytes to transmit for RLC (retrans pdus and new data pdus)
gauthier's avatar
gauthier committed
1144
  rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - pdu_size;
1145
  // put pdu in trans
gauthier's avatar
gauthier committed
1146
1147
1148
  list_add_head(tb_p, &rlc_pP->control_pdu_list);
  rlc_pP->stat_tx_control_pdu   += 1;
  rlc_pP->stat_tx_control_bytes += pdu_size;
1149
1150

}
fnabet's avatar
fnabet committed
1151
1152
#endif