rlc_am_status_report.c 31.9 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;
gauthier's avatar
gauthier committed
271

272
  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
273

274
    rlc_am_tx_buffer_display(ctxt_pP, rlc_pP, " TX BUFFER BEFORE PROCESS OF STATUS PDU");
275
276
    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
277
278
279
          rlc_pP->vt_a,
          rlc_pP->vt_s,
          rlc_pP->poll_sn,
280
281
          rlc_pP->control_pdu_info.ack_sn);
    rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info);
282

283
    rlc_sn_t        ack_sn    = rlc_pP->control_pdu_info.ack_sn;
gauthier's avatar
gauthier committed
284
285
    rlc_sn_t        sn_cursor = rlc_pP->vt_a;
    rlc_sn_t        nack_sn;
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    unsigned int nack_index;

    // 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);
309
    assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU);
310

311
    if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) {
gauthier's avatar
gauthier committed
312
313
      rlc_pP->num_nack_so = 0;
      rlc_pP->num_nack_sn = 0;
314

315
      if (rlc_pP->control_pdu_info.num_nack == 0) {
316
317
318
        while (sn_cursor != ack_sn) {
          if (sn_cursor == rlc_pP->poll_sn) {
            rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
319
          }
320
321
322
323

          rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor);
          sn_cursor = (sn_cursor + 1)  & RLC_AM_SN_MASK;
        }
324
      } else {
325
        nack_index = 0;
326
        nack_sn   = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
327
328
329
330
331
332
333
334
335
336
337
338
339
340

        while (sn_cursor != ack_sn) {
          if (sn_cursor == rlc_pP->poll_sn) {
            rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
          }

          if (sn_cursor != nack_sn) {
            rlc_am_ack_pdu(ctxt_pP,
                           rlc_pP,
                           sn_cursor);
          } else {
            rlc_am_nack_pdu (ctxt_pP,
                             rlc_pP,
                             sn_cursor,
341
342
                             rlc_pP->control_pdu_info.nack_list[nack_index].so_start,
                             rlc_pP->control_pdu_info.nack_list[nack_index].so_end);
343
344
345

            nack_index = nack_index + 1;

346
            if (nack_index == rlc_pP->control_pdu_info.num_nack) {
347
348
              nack_sn = 0xFFFF; // value never reached by sn
            } else {
349
              nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn;
350
351
352
            }
          }

353
354
          if ((nack_index <  rlc_pP->control_pdu_info.num_nack) && (nack_index > 0)) {
            if (rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn != rlc_pP->control_pdu_info.nack_list[nack_index-1].nack_sn) {
355
356
357
358
              sn_cursor = (sn_cursor + 1)  & RLC_AM_SN_MASK;
            }
          } else {
            sn_cursor = (sn_cursor + 1)  & RLC_AM_SN_MASK;
359
          }
360
        }
361
362
      }
    } else {
363
364
      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));
365
366
    }
  } else {
367
368
    LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n",
          PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP));
369
  }
370

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

gauthier's avatar
gauthier committed
373
  free_mem_block(tb_pP);
374
  rlc_am_tx_buffer_display(ctxt_pP, rlc_pP, NULL);
375
376
}
//-----------------------------------------------------------------------------
377
378
int
rlc_am_write_status_pdu(
379
380
381
382
  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)
383
384
{
  unsigned int bit_pos       = 4; // range from 0 (MSB/left) to 7 (LSB/right)
gauthier's avatar
gauthier committed
385
  uint8_t*        byte_pos_p    = &rlc_am_pdu_sn_10_pP->b1;
gauthier's avatar
gauthier committed
386
387
  unsigned int index         = 0;
  unsigned int num_bytes     = 0;
388

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

gauthier's avatar
gauthier committed
391
  if (pdu_info_pP->num_nack > 0) {
392
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1, 1);
393
  } else {
394
    rlc_am_write8_bit_field(&byte_pos_p, &bit_pos, 1, 0);
395
  }
396

gauthier's avatar
gauthier committed
397
  for (index = 0; index < pdu_info_pP->num_nack ; index++) {
398
399
400
401
402
403
404
405
406
    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);
    }
407
  }
408

409
410
  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;
411

412
  if (bit_pos > 0) {
413
    num_bytes += 1;
414
  }
415

416
#if TRACE_RLC_AM_STATUS_CREATION
417
418
419
  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);
420
421
422
423
#endif
  return num_bytes;
}
//-----------------------------------------------------------------------------
424
425
void
rlc_am_send_status_pdu(
426
427
428
  const protocol_ctxt_t* const  ctxt_pP,
  rlc_am_entity_t *const rlc_pP
)
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
{
  // 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
452
453
454
455
456
457
458
459
460
461
  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;
462
463
464
465

  memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t));
  // header size
  nb_bits_to_transmit = nb_bits_to_transmit - 15;
466
#if TRACE_RLC_AM_STATUS_CREATION
467
468
  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),
469
        nb_bits_to_transmit);
gauthier's avatar
gauthier committed
470
  rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT");
471
472
#endif

gauthier's avatar
gauthier committed
473
  if (cursor_p != NULL) {
474
475
476
477
478
479
480
    pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
    sn_cursor             = pdu_info_cursor_p->sn;

    while (rlc_am_in_rx_window(ctxt_pP, rlc_pP, sn_cursor) == 0) {
      cursor_p                = cursor_p->next;
      previous_sn_cursor    = sn_cursor;

gauthier's avatar
gauthier committed
481
482
      pdu_info_cursor_p       = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
      sn_cursor             = pdu_info_cursor_p->sn;
483
#if TRACE_RLC_AM_STATUS_CREATION
484
485
      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),
486
487
488
489
490
491
492
493
494
495
496
497
            __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;
498
#if TRACE_RLC_AM_STATUS_CREATION
499
500
      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),
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
            __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;
517
#if TRACE_RLC_AM_STATUS_CREATION
518
519
            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),
520
521
522
523
524
525
                  __LINE__,
                  sn_cursor);
#endif
          } else {
            if (all_segments_received) {
              control_pdu_info.ack_sn = (sn_cursor + 1) & RLC_AM_SN_MASK;
526
#if TRACE_RLC_AM_STATUS_CREATION
527
528
              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),
529
530
531
532
533
                    __LINE__,
                    control_pdu_info.ack_sn);
#endif
            } else {
              control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
534
#if TRACE_RLC_AM_STATUS_CREATION
535
536
              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),
537
538
539
540
                    __LINE__,
                    control_pdu_info.ack_sn);
#endif
            }
541

542
543
544
545
            goto end_push_nack;
          }
        } while ((cursor_p != NULL) && (sn_cursor == previous_sn_cursor));
      }
546

547
548
549
550
551
552
553
554
555
556
557
558
559
      // -------------------------------------------------------------------------------
      // 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;
560
#if TRACE_RLC_AM_STATUS_CREATION
561
562
          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
563
                __LINE__,
564
                previous_sn_cursor);
565
#endif
566
567
        } else {
          control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
568
#if TRACE_RLC_AM_STATUS_CREATION
569
570
          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
571
                __LINE__,
572
573
                previous_sn_cursor,
                control_pdu_info.ack_sn);
574
#endif
575
576
577
          goto end_push_nack;
        }
      }
578

579
580
581
582
583
      // -------------------------------------------------------------------------------
      // not so simple case, a resegmented PDU(s) is missing
      // -------------------------------------------------------------------------------
      if (all_segments_received == 0) {
        waited_so = 0;
584
#if TRACE_RLC_AM_STATUS_CREATION
585
586
        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));
587
#endif
588
589
590
591
592
593
594

        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;
595
              control_pdu_info.nack_list[control_pdu_info.num_nack].e1        = 1;
596
              control_pdu_info.nack_list[control_pdu_info.num_nack].e2        = 1;
597
              control_pdu_info.num_nack += 1;
598
              nb_bits_to_transmit = nb_bits_to_transmit - 42;
599
#if TRACE_RLC_AM_STATUS_CREATION
600
601
              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),
602
603
604
605
606
607
                    __LINE__,
                    sn_cursor,
                    waited_so,
                    pdu_info_cursor_p->so - 1,
                    pdu_info_cursor_p->so,
                    waited_so);
608
#endif
609
610
611
612

              if (pdu_info_cursor_p->lsf == 1) { // last segment flag
                //waited_so = 0x7FF;
                waited_so = 0x7FFF;
613
#if TRACE_RLC_AM_STATUS_CREATION
614
615
                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),
616
                      __LINE__, sn_cursor);
617
#endif
618
619
620
                //break;
              } else {
                waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
621
#if TRACE_RLC_AM_STATUS_CREATION
622
623
                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),
624
625
626
                      __LINE__,
                      sn_cursor,
                      waited_so);
627
#endif
628
629
630
631
632
633
634
635
636
637
638
639
              }
            } 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;
            }
640

641
#if TRACE_RLC_AM_STATUS_CREATION
642
643
            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),
644
645
                  __LINE__,
                  sn_cursor, waited_so);
646
#endif
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
          }

          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;
675
#if TRACE_RLC_AM_STATUS_CREATION
676
677
            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),
678
679
680
681
                  __LINE__,
                  previous_sn_cursor,
                  waited_so,
                  0x7FFF);
682
683
#endif
          } else {
684
685
            control_pdu_info.ack_sn = previous_sn_cursor;
            goto end_push_nack;
686
          }
687
688
689
690
691
692
693
        }

        waited_so = 0;
      } else {
        waited_so = 0;
        cursor_p = cursor_p->next;
        previous_sn_cursor = sn_cursor;
694
      }
695
696
697
    }

    control_pdu_info.ack_sn = (previous_sn_cursor + 1) & RLC_AM_SN_MASK;
698
  } else {
699
    control_pdu_info.ack_sn = rlc_pP->vr_r;
700
#if TRACE_RLC_AM_STATUS_CREATION
701
702
    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),
703
704
          __LINE__,
          control_pdu_info.ack_sn);
705
706
707
708
#endif
  }

end_push_nack:
709

710
  if (control_pdu_info.num_nack > 0) {
711
    control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1  = 0;
712
  }
713

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

717
#if TRACE_RLC_AM_STATUS_CREATION
718
719
  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
720
721
722
        __LINE__,
        control_pdu_info.ack_sn,
        control_pdu_info.num_nack);
723
724
#endif
  // encode the control pdu
gauthier's avatar
gauthier committed
725
  pdu_size = rlc_pP->nb_bytes_requested_by_mac - ((nb_bits_to_transmit - 7 )>> 3);
726

727
#if TRACE_RLC_AM_STATUS_CREATION
728
729
  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),
730
731
        __LINE__,
        pdu_size);
732
#endif
733
  tb_p = get_free_mem_block(sizeof(struct mac_tb_req) + pdu_size);
gauthier's avatar
gauthier committed
734
735
  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
736
  ((struct mac_tb_req*)(tb_p->data))->data_ptr         = (uint8_t*)&(tb_p->data[sizeof(struct mac_tb_req)]);
737
738

  // warning reuse of pdu_size
739
  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
740
741
  ((struct mac_tb_req*)(tb_p->data))->tb_size  = pdu_size;
  //assert((((struct mac_tb_req*)(tb_p->data))->tb_size) < 3000);
742

743
#if TRACE_RLC_AM_STATUS_CREATION
744
745
  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
746
747
748
        pdu_size,
        rlc_pP->nb_bytes_requested_by_mac,
        nb_bits_to_transmit >> 3);
749
#endif
gauthier's avatar
gauthier committed
750
  assert(pdu_size == (rlc_pP->nb_bytes_requested_by_mac - (nb_bits_to_transmit >> 3)));
751
752

  // remaining bytes to transmit for RLC (retrans pdus and new data pdus)
gauthier's avatar
gauthier committed
753
  rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - pdu_size;
754
  // put pdu in trans
gauthier's avatar
gauthier committed
755
756
757
  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;
758
759

}