rlc_um_dar.c 44.8 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_UM_MODULE 1
#define RLC_UM_DAR_C 1
24
#include "platform_types.h"
gauthier's avatar
gauthier committed
25
#include "assertions.h"
26
//-----------------------------------------------------------------------------
knopp's avatar
mutexes    
knopp committed
27
#include "msc.h"
28
29
30
31
32
33
#include "rlc.h"
#include "rlc_um.h"
#include "rlc_primitives.h"
#include "mac_primitives.h"
#include "list.h"
#include "UTIL/LOG/log.h"
34
#include "UTIL/LOG/vcd_signal_dumper.h"
35
36

//-----------------------------------------------------------------------------
37
signed int rlc_um_get_pdu_infos(
38
  const protocol_ctxt_t* const ctxt_pP,
39
  const rlc_um_entity_t* const rlc_pP,
40
41
42
43
  rlc_um_pdu_sn_10_t   * const header_pP,
  const sdu_size_t             total_sizeP,
  rlc_um_pdu_info_t    * const pdu_info_pP,
  const uint8_t                sn_lengthP)
44
{
45
46
  sdu_size_t         sum_li = 0;
  memset(pdu_info_pP, 0, sizeof (rlc_um_pdu_info_t));
47

48
  pdu_info_pP->num_li = 0;
49

50
  AssertFatal( total_sizeP > 0 , "RLC UM PDU LENGTH %d", total_sizeP);
51

52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  if (sn_lengthP == 10) {
    pdu_info_pP->fi           = (header_pP->b1 >> 3) & 0x03;
    pdu_info_pP->e            = (header_pP->b1 >> 2) & 0x01;
    pdu_info_pP->sn           = header_pP->b2 + (((uint16_t)(header_pP->b1 & 0x03)) << 8);
    pdu_info_pP->header_size  = 2;
    pdu_info_pP->payload      = &header_pP->data[0];
  } else if (sn_lengthP == 5) {
    pdu_info_pP->fi           = (header_pP->b1 >> 6) & 0x03;
    pdu_info_pP->e            = (header_pP->b1 >> 5) & 0x01;
    pdu_info_pP->sn           = header_pP->b1 & 0x1F;
    pdu_info_pP->header_size  = 1;
    pdu_info_pP->payload      = &header_pP->b2;
  } else {
    AssertFatal( sn_lengthP == 5 || sn_lengthP == 10, "RLC UM SN LENGTH %d", sn_lengthP);
  }
67

gauthier's avatar
gauthier committed
68

69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  if (pdu_info_pP->e) {
    rlc_am_e_li_t      *e_li_p;
    unsigned int li_length_in_bytes  = 1;
    unsigned int li_to_read          = 1;

    e_li_p = (rlc_am_e_li_t*)(pdu_info_pP->payload);

    while (li_to_read)  {
      li_length_in_bytes = li_length_in_bytes ^ 3;

      if (li_length_in_bytes  == 2) {
        AssertFatal( total_sizeP >= ((uint64_t)(&e_li_p->b2) - (uint64_t)header_pP),
                     "DECODING PDU TOO FAR PDU size %d", total_sizeP);
        pdu_info_pP->li_list[pdu_info_pP->num_li] = ((uint16_t)(e_li_p->b1 << 4)) & 0x07F0;
        pdu_info_pP->li_list[pdu_info_pP->num_li] |= (((uint8_t)(e_li_p->b2 >> 4)) & 0x000F);
        li_to_read = e_li_p->b1 & 0x80;
        pdu_info_pP->header_size  += 2;
      } else {
        AssertFatal( total_sizeP >= ((uint64_t)(&e_li_p->b3) - (uint64_t)header_pP),
                     "DECODING PDU TOO FAR PDU size %d", total_sizeP);
        pdu_info_pP->li_list[pdu_info_pP->num_li] = ((uint16_t)(e_li_p->b2 << 8)) & 0x0700;
        pdu_info_pP->li_list[pdu_info_pP->num_li] |=  e_li_p->b3;
        li_to_read = e_li_p->b2 & 0x08;
        e_li_p++;
        pdu_info_pP->header_size  += 1;
      }

      AssertFatal( pdu_info_pP->num_li <= RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU,
97
98
                   PROTOCOL_RLC_UM_CTXT_FMT"[GET PDU INFO]  SN %04d TOO MANY LIs ",
                   PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
99
100
101
102
103
104
105
106
                   pdu_info_pP->sn);

      sum_li += pdu_info_pP->li_list[pdu_info_pP->num_li];
      pdu_info_pP->num_li = pdu_info_pP->num_li + 1;

      if (pdu_info_pP->num_li > RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU) {
        return -2;
      }
107
    }
108
109
110
111
112

    if (li_length_in_bytes  == 2) {
      pdu_info_pP->payload = &e_li_p->b3;
    } else {
      pdu_info_pP->payload = &e_li_p->b1;
113
    }
114
115
116
117
118
119
120
121
122
  }

  pdu_info_pP->payload_size = total_sizeP - pdu_info_pP->header_size;

  if (pdu_info_pP->payload_size > sum_li) {
    pdu_info_pP->hidden_size = pdu_info_pP->payload_size - sum_li;
  }

  return 0;
123
124
}
//-----------------------------------------------------------------------------
125
126
127
128
129
130
131
132
int rlc_um_read_length_indicators(unsigned char**data_ppP, rlc_um_e_li_t* e_liP, unsigned int* li_array_pP, unsigned int *num_li_pP, sdu_size_t *data_size_pP)
{
  int          continue_loop = 1;
  unsigned int e1  = 0;
  unsigned int li1 = 0;
  unsigned int e2  = 0;
  unsigned int li2 = 0;
  *num_li_pP = 0;
133
  int pdu_size = *data_size_pP;
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

  while ((continue_loop)) {
    //msg("[RLC_UM] e_liP->b1 = %02X\n", e_liP->b1);
    //msg("[RLC_UM] e_liP->b2 = %02X\n", e_liP->b2);
    e1 = ((unsigned int)e_liP->b1 & 0x00000080) >> 7;
    li1 = (((unsigned int)e_liP->b1 & 0x0000007F) << 4) + (((unsigned int)e_liP->b2 & 0x000000F0) >> 4);
    li_array_pP[*num_li_pP] = li1;
    *data_size_pP = *data_size_pP - li1 - 2;
    *num_li_pP = *num_li_pP +1;

    if ((e1)) {
      e2 = ((unsigned int)e_liP->b2 & 0x00000008) >> 3;
      li2 = (((unsigned int)e_liP->b2 & 0x00000007) << 8) + ((unsigned int)e_liP->b3 & 0x000000FF);
      li_array_pP[*num_li_pP] = li2;
      *data_size_pP = *data_size_pP - li2 - 1;
      *num_li_pP = *num_li_pP +1;

151
152
153
154
155
156
157
158
159
160
161
162
163
      if (!(*data_size_pP >= 0)) LOG_E(RLC, "Invalid data_size=%d! (pdu_size=%d loop=%d e1=%d e2=%d li2=%d e_liP=%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x)\n",
          *data_size_pP, pdu_size, continue_loop, e1, e2, li2,
          (e_liP-(continue_loop-1)+0)->b1,
          (e_liP-(continue_loop-1)+0)->b2,
          (e_liP-(continue_loop-1)+0)->b3,
          (e_liP-(continue_loop-1)+1)->b1,
          (e_liP-(continue_loop-1)+1)->b2,
          (e_liP-(continue_loop-1)+1)->b3,
          (e_liP-(continue_loop-1)+2)->b1,
          (e_liP-(continue_loop-1)+2)->b2,
          (e_liP-(continue_loop-1)+2)->b3);
      // AssertFatal(*data_size_pP >= 0, "Invalid data_size!");

164
165
166
167
      if (e2 == 0) {
        continue_loop = 0;
      } else {
        e_liP++;
168
        continue_loop++;
169
170
      }
    } else {
171
172
173
174
175
176
177
178
179
180
181
      if (!(*data_size_pP >= 0)) LOG_E(RLC, "Invalid data_size=%d! (pdu_size=%d loop=%d e1=%d li1=%d e_liP=%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x)\n",
          *data_size_pP, pdu_size, continue_loop, e1, li1,
          (e_liP-(continue_loop-1)+0)->b1,
          (e_liP-(continue_loop-1)+0)->b2,
          (e_liP-(continue_loop-1)+0)->b3,
          (e_liP-(continue_loop-1)+1)->b1,
          (e_liP-(continue_loop-1)+1)->b2,
          (e_liP-(continue_loop-1)+1)->b3,
          (e_liP-(continue_loop-1)+2)->b1,
          (e_liP-(continue_loop-1)+2)->b2,
          (e_liP-(continue_loop-1)+2)->b3);
182
      continue_loop = 0;
183
      // AssertFatal(*data_size_pP >= 0, "Invalid data_size!");
184
185
    }

Cedric Roux's avatar
Cedric Roux committed
186
    if (*num_li_pP > RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU) {
187
      return -1;
188
    }
189
190
191
  }

  *data_ppP = *data_ppP + (((*num_li_pP*3) +1) >> 1);
192
193
194
195
196
197
198
199
200
  if (*data_size_pP > 0) {
    return 0;
  } else if (*data_size_pP == 0) {
    LOG_W(RLC, "Last RLC SDU size is zero!\n");
    return -1;
  } else {
    LOG_W(RLC, "Last RLC SDU size is negative %d!\n", *data_size_pP);
    return -1;
  }
201
202
}
//-----------------------------------------------------------------------------
203
204
void
rlc_um_try_reassembly(
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t *            rlc_pP,
  rlc_sn_t                     start_snP,
  rlc_sn_t                     end_snP)
{
  mem_block_t        *pdu_mem_p              = NULL;
  struct mac_tb_ind  *tb_ind_p               = NULL;
  rlc_um_e_li_t      *e_li_p                 = NULL;
  unsigned char      *data_p                 = NULL;
  int                 e                      = 0;
  int                 fi                     = 0;
  sdu_size_t          size                   = 0;
  rlc_sn_t            sn                     = 0;
  unsigned int        continue_reassembly    = 0;
  unsigned int        num_li                 = 0;
  unsigned int        li_array[RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU];
  int                 i                      = 0;
  int                 reassembly_start_index = 0;

gauthier's avatar
gauthier committed
224
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_TRY_REASSEMBLY,VCD_FUNCTION_IN);
225

226
227
228
  if (end_snP < 0)   {
    end_snP   = end_snP   + rlc_pP->rx_sn_modulo;
  }
229

230
231
232
  if (start_snP < 0) {
    start_snP = start_snP + rlc_pP->rx_sn_modulo;
  }
233

234
#if TRACE_RLC_UM_DAR
235
236
  LOG_D(RLC,  PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY FROM PDU SN=%03d+1  TO  PDU SN=%03d   SN Length = %d bits (%s:%u)\n",
        PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
237
238
        rlc_pP->last_reassemblied_sn,
        end_snP,
239
240
241
        rlc_pP->rx_sn_length,
        __FILE__,
        __LINE__);
gauthier's avatar
gauthier committed
242
#endif
243

244
245
  // nothing to be reassemblied
  if (start_snP == end_snP) {
gauthier's avatar
gauthier committed
246
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_TRY_REASSEMBLY,VCD_FUNCTION_OUT);
247
248
249
250
251
252
253
254
    return;
  }

  continue_reassembly = 1;
  //sn = (rlc_pP->last_reassemblied_sn + 1) % rlc_pP->rx_sn_modulo;
  sn = start_snP;

  //check_mem_area();
255

256
257
  while (continue_reassembly) {
    if ((pdu_mem_p = rlc_pP->dar_buffer[sn])) {
258

259
      if ((rlc_pP->last_reassemblied_sn+1)%rlc_pP->rx_sn_modulo != sn) {
260
#if TRACE_RLC_UM_DAR
261
262
263
        LOG_W(RLC,
              PROTOCOL_RLC_UM_CTXT_FMT" FINDING a HOLE in RLC UM SN: CLEARING OUTPUT SDU BECAUSE NEW SN (%03d) TO REASSEMBLY NOT CONTIGUOUS WITH LAST REASSEMBLIED SN (%03d) (%s:%u)\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
264
              sn,
265
266
267
              rlc_pP->last_reassemblied_sn,
              __FILE__,
              __LINE__);
268
#endif
269
270
271
272
273
274
275
        rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);
      }

      rlc_pP->last_reassemblied_sn = sn;
      tb_ind_p = (struct mac_tb_ind *)(pdu_mem_p->data);

      if (rlc_pP->rx_sn_length == 10) {
276
#if TRACE_RLC_UM_DAR
277
278
279
280
281
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY 10 PDU SN=%03d\n (%s:%u)",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
              sn,
              __FILE__,
              __LINE__);
gauthier's avatar
gauthier committed
282
#endif
283
284
285
286
287
288
        e  = (((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->b1 & 0x04) >> 2;
        fi = (((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->b1 & 0x18) >> 3;
        e_li_p = (rlc_um_e_li_t*)((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->data;
        size   = tb_ind_p->size - 2;
        data_p = &tb_ind_p->data_ptr[2];
      } else {
289
#if TRACE_RLC_UM_DAR
290
291
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY 5 PDU SN=%03d Byte 0=%02X (%s:%u)\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
292
              sn,
293
294
295
              ((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1,
              __FILE__,
              __LINE__);
gauthier's avatar
gauthier committed
296
#endif
297
298
299
300
301
        e  = (((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1 & 0x00000020) >> 5;
        fi = (((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1 & 0x000000C0) >> 6;
        e_li_p = (rlc_um_e_li_t*)((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->data;
        size   = tb_ind_p->size - 1;
        data_p = &tb_ind_p->data_ptr[1];
302
#if TRACE_RLC_UM_DAR
303
304
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" e=%01X fi=%01X\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
305
              e,
306
307
308
              fi,
              __FILE__,
              __LINE__);
gauthier's avatar
gauthier committed
309
#endif
310
      }
311
      AssertFatal(size >= 0, "invalid size!");
312
313
      AssertFatal((e==0) || (e==1), "invalid e!");
      AssertFatal((fi >= 0) && (fi <= 3), "invalid fi!");
314
315
316
317

      if (e == RLC_E_FIXED_PART_DATA_FIELD_FOLLOW) {
        switch (fi) {
        case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU:
318
#if TRACE_RLC_UM_DAR
319
320
321
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU NO E_LI FI=11 (00) (%s:%u)\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                __FILE__,
322
                __LINE__);
gauthier's avatar
gauthier committed
323
#endif
324
325
326
327
328
329
330
331
332
333
          // one complete SDU
          //LGrlc_um_send_sdu(rlc_pP,ctxt_pP->frame,ctxt_pP->enb_flag); // may be not necessary
          rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);
          rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
          rlc_um_send_sdu(ctxt_pP, rlc_pP);
          rlc_pP->reassembly_missing_sn_detected = 0;

          break;

        case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU:
334
#if TRACE_RLC_UM_DAR
335
336
337
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU NO E_LI FI=10 (01) (%s:%u)\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                __FILE__,
338
                __LINE__);
gauthier's avatar
gauthier committed
339
#endif
340
341
342
343
344
345
346
347
          // one beginning segment of SDU in PDU
          //LG rlc_um_send_sdu(rlc_pP,ctxt_pP->frame,ctxt_pP->enb_flag); // may be not necessary
          rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);
          rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
          rlc_pP->reassembly_missing_sn_detected = 0;
          break;

        case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU:
348
#if TRACE_RLC_UM_DAR
349
350
351
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU NO E_LI FI=01 (10) (%s:%u)\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                __FILE__,
352
                __LINE__);
gauthier's avatar
gauthier committed
353
#endif
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

          // one last segment of SDU
          if (rlc_pP->reassembly_missing_sn_detected == 0) {
            rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
            rlc_um_send_sdu(ctxt_pP, rlc_pP);
          } else {
            //clear sdu already done
            rlc_pP->stat_rx_data_pdu_dropped += 1;
            rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size;
          }

          rlc_pP->reassembly_missing_sn_detected = 0;
          break;

        case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU:
369
#if TRACE_RLC_UM_DAR
370
371
372
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU NO E_LI FI=00 (11) (%s:%u)\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                __FILE__,
373
                __LINE__);
gauthier's avatar
gauthier committed
374
#endif
375
376
377
378
379

          if (rlc_pP->reassembly_missing_sn_detected == 0) {
            // one whole segment of SDU in PDU
            rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
          } else {
380
#if TRACE_RLC_UM_DAR
381
382
383
            LOG_W(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU NO E_LI FI=00 (11) MISSING SN DETECTED (%s:%u)\n",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                  __FILE__,
384
                  __LINE__);
385
#endif
386
387
388
389
390
            //LOG_D(RLC, "[MSC_NBOX][FRAME %05u][%s][RLC_UM][MOD %u/%u][RB %u][Missing SN detected][RLC_UM][MOD %u/%u][RB %u]\n",
            //      ctxt_pP->frame, rlc_pP->module_id,rlc_pP->rb_id, rlc_pP->module_id,rlc_pP->rb_id);
            rlc_pP->reassembly_missing_sn_detected = 1; // not necessary but for readability of the code
            rlc_pP->stat_rx_data_pdu_dropped += 1;
            rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size;
391
#if RLC_STOP_ON_LOST_PDU
392
            AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1,
393
394
395
396
                         PROTOCOL_RLC_UM_CTXT_FMT" MISSING PDU DETECTED (%s:%u)\n",
                         PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                         __FILE__,
                         __LINE__);
gauthier's avatar
gauthier committed
397
#endif
398
399
400
401
402
          }

          break;

        default:
403
          AssertFatal( 0 , PROTOCOL_RLC_UM_CTXT_FMT" fi=%d! TRY REASSEMBLY SHOULD NOT GO HERE (%s:%u)\n",
404
                       PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
405
                       fi,
406
407
                       __FILE__,
                       __LINE__);
408
409
410
411
412
        }
      } else {
        if (rlc_um_read_length_indicators(&data_p, e_li_p, li_array, &num_li, &size ) >= 0) {
          switch (fi) {
          case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU:
413
#if TRACE_RLC_UM_DAR
414
415
            LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU FI=11 (00) Li=",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
416
417
418
419
420
421

            for (i=0; i < num_li; i++) {
              LOG_D(RLC, "%d ",li_array[i]);
            }

            LOG_D(RLC, " remaining size %d\n",size);
gauthier's avatar
gauthier committed
422
#endif
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
            // N complete SDUs
            //LGrlc_um_send_sdu(rlc_pP,ctxt_pP->frame,ctxt_pP->enb_flag);
            rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);

            for (i = 0; i < num_li; i++) {
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, li_array[i]);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
              data_p = &data_p[li_array[i]];
            }

            if (size > 0) { // normally should always be > 0 but just for help debug
              // data_p is already ok, done by last loop above
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
            }

            rlc_pP->reassembly_missing_sn_detected = 0;
            break;

          case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU:
443
#if TRACE_RLC_UM_DAR
444
445
            LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU FI=10 (01) Li=",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
446
447
448
449
450
451

            for (i=0; i < num_li; i++) {
              LOG_D(RLC, "%d ",li_array[i]);
            }

            LOG_D(RLC, " remaining size %d\n",size);
gauthier's avatar
gauthier committed
452
#endif
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
            // N complete SDUs + one segment of SDU in PDU
            //LG rlc_um_send_sdu(rlc_pP,ctxt_pP->frame,ctxt_pP->enb_flag);
            rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);

            for (i = 0; i < num_li; i++) {
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, li_array[i]);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
              data_p = &data_p[li_array[i]];
            }

            if (size > 0) { // normally should always be > 0 but just for help debug
              // data_p is already ok, done by last loop above
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
            }

            rlc_pP->reassembly_missing_sn_detected = 0;
            break;

          case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU:
472
#if TRACE_RLC_UM_DAR
473
474
            LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU FI=01 (10) Li=",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
475
476
477
478
479
480

            for (i=0; i < num_li; i++) {
              LOG_D(RLC, "%d ",li_array[i]);
            }

            LOG_D(RLC, " remaining size %d\n",size);
481
#endif
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508

            if (rlc_pP->reassembly_missing_sn_detected) {
              reassembly_start_index = 1;
              data_p = &data_p[li_array[0]];
              //rlc_pP->stat_rx_data_pdu_dropped += 1;
              rlc_pP->stat_rx_data_bytes_dropped += li_array[0];
            } else {
              reassembly_start_index = 0;
            }

            // one last segment of SDU + N complete SDUs in PDU
            for (i = reassembly_start_index; i < num_li; i++) {
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, li_array[i]);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
              data_p = &data_p[li_array[i]];
            }

            if (size > 0) { // normally should always be > 0 but just for help debug
              // data_p is already ok, done by last loop above
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
            }

            rlc_pP->reassembly_missing_sn_detected = 0;
            break;

          case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU:
509
#if TRACE_RLC_UM_DAR
510
511
            LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRY REASSEMBLY PDU FI=00 (11) Li=",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
512

513
514
            for (i=0; i < num_li; i++) {
              LOG_D(RLC, "%d ",li_array[i]);
515
            }
516
517
518
519
520

            LOG_D(RLC, " remaining size %d\n",size);
#endif

            if (rlc_pP->reassembly_missing_sn_detected) {
521
#if TRACE_RLC_UM_DAR
522
523
524
525
526
              LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" DISCARD FIRST LI %d (%s:%u)",
                    PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                    li_array[0],
                    __FILE__,
                    __LINE__);
gauthier's avatar
gauthier committed
527
#endif
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
              reassembly_start_index = 1;
              data_p = &data_p[li_array[0]];
              //rlc_pP->stat_rx_data_pdu_dropped += 1;
              rlc_pP->stat_rx_data_bytes_dropped += li_array[0];
            } else {
              reassembly_start_index = 0;
            }

            for (i = reassembly_start_index; i < num_li; i++) {
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, li_array[i]);
              rlc_um_send_sdu(ctxt_pP, rlc_pP);
              data_p = &data_p[li_array[i]];
            }

            if (size > 0) { // normally should always be > 0 but just for help debug
              // data_p is already ok, done by last loop above
              rlc_um_reassembly (ctxt_pP, rlc_pP, data_p, size);
            } else {
546
              AssertFatal( 0 !=0, PROTOCOL_RLC_UM_CTXT_FMT" size=%d! SHOULD NOT GO HERE (%s:%u)\n",
547
                           PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
548
                           size,
549
550
                           __FILE__,
                           __LINE__);
551
552
553
554
555
556
557
558
              //rlc_pP->stat_rx_data_pdu_dropped += 1;
              rlc_pP->stat_rx_data_bytes_dropped += size;
            }

            rlc_pP->reassembly_missing_sn_detected = 0;
            break;

          default:
559
#if TRACE_RLC_UM_DAR
560
561
562
            LOG_W(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Missing SN detected (%s:%u)\n",
                  PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                  __FILE__,
563
                  __LINE__);
564
#endif
565
566
567
            rlc_pP->stat_rx_data_pdu_dropped += 1;
            rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size;

gauthier's avatar
gauthier committed
568
            rlc_pP->reassembly_missing_sn_detected = 1;
569
#if RLC_STOP_ON_LOST_PDU
gauthier's avatar
gauthier committed
570
            AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1,
571
572
573
574
                         PROTOCOL_RLC_UM_CTXT_FMT" MISSING PDU DETECTED (%s:%u)\n",
                         PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                         __FILE__,
                         __LINE__);
575
#endif
576
          }
577
578
579
580
581
        } else {
          rlc_pP->stat_rx_data_pdu_dropped += 1;
          rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size;
          rlc_pP->reassembly_missing_sn_detected = 1;

Cedric Roux's avatar
Cedric Roux committed
582
          LOG_W(RLC, "[SN %d] Bad RLC header! Discard this RLC PDU (size=%d)\n", sn, size);
583
        }
584
585
      }

586
#if TRACE_RLC_UM_DAR
587
588
589
590
591
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" REMOVE PDU FROM DAR BUFFER  SN=%03d (%s:%u)\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
            sn,
            __FILE__,
            __LINE__);
592
#endif
593
      free_mem_block(rlc_pP->dar_buffer[sn], __func__);
594
595
596
      rlc_pP->dar_buffer[sn] = NULL;
    } else {
      rlc_pP->last_reassemblied_missing_sn = sn;
597
#if TRACE_RLC_UM_DAR
598
599
600
601
602
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Missing SN %04d detected, clearing RX SDU (%s:%u)\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
            sn,
            __FILE__,
            __LINE__);
603
604
605
#endif
      rlc_pP->reassembly_missing_sn_detected = 1;
      rlc_um_clear_rx_sdu(ctxt_pP, rlc_pP);
606
#if RLC_STOP_ON_LOST_PDU
607
      AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1,
608
609
610
611
                   PROTOCOL_RLC_UM_CTXT_FMT" MISSING PDU DETECTED (%s:%u)\n",
                   PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
                   __FILE__,
                   __LINE__);
gauthier's avatar
gauthier committed
612
#endif
613
    }
614

615
616
617
618
619
620
621
    sn = (sn + 1) % rlc_pP->rx_sn_modulo;

    if ((sn == rlc_pP->vr_uh) || (sn == end_snP)) {
      continue_reassembly = 0;
    }
  }

622
#if TRACE_RLC_UM_DAR
623
624
  LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TRIED REASSEMBLY VR(UR)=%03d VR(UX)=%03d VR(UH)=%03d (%s:%u)\n",
        PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
625
626
        rlc_pP->vr_ur,
        rlc_pP->vr_ux,
627
628
629
        rlc_pP->vr_uh,
        __FILE__,
        __LINE__);
630
631
#endif

gauthier's avatar
gauthier committed
632
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_TRY_REASSEMBLY,VCD_FUNCTION_OUT);
633
634
}
//-----------------------------------------------------------------------------
635
636
void
rlc_um_stop_and_reset_timer_reordering(
637
638
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t *            rlc_pP)
639
{
640
#if TRACE_RLC_UM_DAR
641
642
  LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" [T-REORDERING] STOPPED AND RESET\n",
        PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
gauthier's avatar
gauthier committed
643
#endif
644
  rlc_pP->t_reordering.running         = 0;
645
646
  rlc_pP->t_reordering.ms_time_out     = 0;
  rlc_pP->t_reordering.ms_start        = 0;
647
  rlc_pP->t_reordering.timed_out       = 0;
648
649
}
//-----------------------------------------------------------------------------
650
651
void
rlc_um_start_timer_reordering(
652
653
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t *            rlc_pP)
654
{
655
  rlc_pP->t_reordering.timed_out       = 0;
656
657
658
659
660

  if (rlc_pP->t_reordering.ms_duration > 0) {
  rlc_pP->t_reordering.running         = 1;
    rlc_pP->t_reordering.ms_time_out      = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_reordering.ms_duration;
    rlc_pP->t_reordering.ms_start        = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP);
661
#if TRACE_RLC_UM_DAR
662
663
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" [T-REORDERING] STARTED (TIME-OUT = FRAME %05u)\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
gauthier's avatar
gauthier committed
664
        rlc_pP->t_reordering.ms_time_out);
gauthier's avatar
gauthier committed
665
#endif
666
  } else {
Cedric Roux's avatar
Cedric Roux committed
667
    LOG_T(RLC, PROTOCOL_RLC_UM_CTXT_FMT"[T-REORDERING] NOT STARTED, CAUSE CONFIGURED 0 ms\n",
668
669
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP));
  }
670
671
}
//-----------------------------------------------------------------------------
672
673
void
rlc_um_init_timer_reordering(
674
675
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP,
676
  const uint32_t  ms_durationP)
677
{
678
  rlc_pP->t_reordering.running         = 0;
679
680
681
  rlc_pP->t_reordering.ms_time_out     = 0;
  rlc_pP->t_reordering.ms_start        = 0;
  rlc_pP->t_reordering.ms_duration     = ms_durationP;
682
  rlc_pP->t_reordering.timed_out       = 0;
683
684
}
//-----------------------------------------------------------------------------
685
void rlc_um_check_timer_dar_time_out(
686
687
688
689
690
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP)
{
  signed int     in_window;
  rlc_usn_t      old_vr_ur;
gauthier's avatar
gauthier committed
691

692

gauthier's avatar
gauthier committed
693
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_CHECK_TIMER_DAR_TIME_OUT,VCD_FUNCTION_IN);
694
695
696
697
698
699
700
701

  if ((rlc_pP->t_reordering.running)) {
    if (
      // CASE 1:          start              time out
      //        +-----------+------------------+----------+
      //        |           |******************|          |
      //        +-----------+------------------+----------+
      //FRAME # 0                                     FRAME MAX
702
703
704
      ((rlc_pP->t_reordering.ms_start < rlc_pP->t_reordering.ms_time_out) &&
       ((PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) >= rlc_pP->t_reordering.ms_time_out) ||
        (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) < rlc_pP->t_reordering.ms_start)))                                   ||
705
706
707
708
709
      // CASE 2:        time out            start
      //        +-----------+------------------+----------+
      //        |***********|                  |**********|
      //        +-----------+------------------+----------+
      //FRAME # 0                                     FRAME MAX VALUE
710
711
712
      ((rlc_pP->t_reordering.ms_start > rlc_pP->t_reordering.ms_time_out) &&
       (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) < rlc_pP->t_reordering.ms_start) &&
       (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) >= rlc_pP->t_reordering.ms_time_out))
713
714
715
716
717
718
719
720
721
722
723
    ) {

      //if ((uint32_t)((uint32_t)rlc_pP->timer_reordering  + (uint32_t)rlc_pP->timer_reordering_init)   <= ctxt_pP->frame) {
      // 5.1.2.2.4   Actions when t-Reordering expires
      //  When t-Reordering expires, the receiving UM RLC entity shall:
      //  -update VR(UR) to the SN of the first UMD PDU with SN >= VR(UX) that has not been received;
      //  -reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not delivered before;
      //  -if VR(UH) > VR(UR):
      //      -start t-Reordering;
      //      -set VR(UX) to VR(UH).
      rlc_pP->stat_timer_reordering_timed_out += 1;
724
#if TRACE_RLC_UM_DAR
725
726
727
728
729
730
731
732
733
734
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT"*****************************************************\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT"*    T I M E  -  O U T                              *\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT"*****************************************************\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" TIMER t-Reordering expiration\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP));
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" timer_reordering=%d frame=%d expire ms %d\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
gauthier's avatar
gauthier committed
735
            rlc_pP->t_reordering.ms_duration,
736
            ctxt_pP->frame,
737
738
739
            rlc_pP->t_reordering.ms_time_out);
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" set VR(UR)=%03d to",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
740
741
742
743
744
745
746
747
748
749
750
751
            rlc_pP->vr_ur);
#endif

      if (pthread_mutex_trylock(&rlc_pP->lock_dar_buffer) == 0) {
        old_vr_ur   = rlc_pP->vr_ur;

        rlc_pP->vr_ur = rlc_pP->vr_ux;

        while (rlc_um_get_pdu_from_dar_buffer(ctxt_pP, rlc_pP, rlc_pP->vr_ur)) {
          rlc_pP->vr_ur = (rlc_pP->vr_ur+1)%rlc_pP->rx_sn_modulo;
        }

752
#if TRACE_RLC_UM_DAR
753
754
755
756
757
758
759
760
761
762
        LOG_D(RLC, " %d", rlc_pP->vr_ur);
        LOG_D(RLC, "\n");
#endif
        rlc_um_try_reassembly(ctxt_pP, rlc_pP ,old_vr_ur, rlc_pP->vr_ur);

        in_window = rlc_um_in_window(ctxt_pP, rlc_pP, rlc_pP->vr_ur,  rlc_pP->vr_uh,  rlc_pP->vr_uh);

        if (in_window == 2) {
          rlc_um_start_timer_reordering(ctxt_pP, rlc_pP);
          rlc_pP->vr_ux = rlc_pP->vr_uh;
763
#if TRACE_RLC_UM_DAR
764
765
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" restarting t-Reordering set VR(UX) to %d (VR(UH)>VR(UR))\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
766
767
768
                rlc_pP->vr_ux);
#endif
        } else {
769
#if TRACE_RLC_UM_DAR
770
771
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" STOP t-Reordering VR(UX) = %03d\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
772
                rlc_pP->vr_ux);
gauthier's avatar
gauthier committed
773
#endif
774
775
776
          rlc_um_stop_and_reset_timer_reordering(ctxt_pP, rlc_pP);
        }

knopp's avatar
mutexes    
knopp committed
777
        RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_dar_buffer);
778
779
780
781
      }
    }
  }

gauthier's avatar
gauthier committed
782
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_CHECK_TIMER_DAR_TIME_OUT,VCD_FUNCTION_OUT);
783
784
}
//-----------------------------------------------------------------------------
785
mem_block_t*
786
787
788
789
rlc_um_remove_pdu_from_dar_buffer(
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP,
  rlc_usn_t snP)
790
{
791
  mem_block_t * pdu_p     = rlc_pP->dar_buffer[snP];
792
#if TRACE_RLC_UM_DAR
793
794
  LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" REMOVE PDU FROM DAR BUFFER  SN=%03d\n",
        PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
795
796
797
798
799
        snP);
#endif
  rlc_pP->dar_buffer[snP] = NULL;
  return pdu_p;
}
800
//-----------------------------------------------------------------------------
801
mem_block_t*
802
803
804
rlc_um_get_pdu_from_dar_buffer(const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, rlc_usn_t snP)
{
  return rlc_pP->dar_buffer[snP];
805
806
}
//-----------------------------------------------------------------------------
807
void
808
rlc_um_store_pdu_in_dar_buffer(
809
810
811
812
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP,
  mem_block_t *pdu_pP,
  rlc_usn_t snP)
813
{
814
#if TRACE_RLC_UM_DAR
815
816
  LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" STORE PDU IN DAR BUFFER  SN=%03d  VR(UR)=%03d VR(UX)=%03d VR(UH)=%03d\n",
        PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
817
818
819
820
        snP,
        rlc_pP->vr_ur,
        rlc_pP->vr_ux,
        rlc_pP->vr_uh);
gauthier's avatar
gauthier committed
821
#endif
822
  rlc_pP->dar_buffer[snP] = pdu_pP;
823
824
825
826
827
828
829
830
}
//-----------------------------------------------------------------------------
// returns -2 if lower_bound  > sn
// returns -1 if higher_bound < sn
// returns  0 if lower_bound  < sn < higher_bound
// returns  1 if lower_bound  == sn
// returns  2 if higher_bound == sn
// returns  3 if higher_bound == sn == lower_bound
831
signed int
832
rlc_um_in_window(
833
834
835
836
837
838
839
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP,
  rlc_sn_t lower_boundP,
  rlc_sn_t snP,
  rlc_sn_t higher_boundP)
{
  rlc_sn_t modulus = (rlc_sn_t)rlc_pP->vr_uh - rlc_pP->rx_um_window_size;
840
#if TRACE_RLC_UM_RX
841
842
843
  rlc_sn_t     lower_bound  = lower_boundP;
  rlc_sn_t     higher_bound = higher_boundP;
  rlc_sn_t     sn           = snP;
844
#endif
845
846
847
  lower_boundP  = (lower_boundP  - modulus) % rlc_pP->rx_sn_modulo;
  higher_boundP = (higher_boundP - modulus) % rlc_pP->rx_sn_modulo;
  snP           = (snP           - modulus) % rlc_pP->rx_sn_modulo;
848

849
  if ( lower_boundP > snP) {
850
#if TRACE_RLC_UM_RX
851
852
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d not in WINDOW[%03d:%03d] (SN<LOWER BOUND)\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
853
854
855
          sn,
          lower_bound,
          higher_bound);
856
#endif
857
858
859
860
    return -2;
  }

  if ( higher_boundP < snP) {
861
#if TRACE_RLC_UM_RX
862
863
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d not in WINDOW[%03d:%03d] (SN>HIGHER BOUND) <=> %d not in WINDOW[%03d:%03d]\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
864
865
866
867
868
869
          sn,
          lower_bound,
          higher_bound,
          snP,
          lower_boundP,
          higher_boundP);
870
#endif
871
872
873
874
875
    return -1;
  }

  if ( lower_boundP == snP) {
    if ( higher_boundP == snP) {
876
#if TRACE_RLC_UM_RX
877
878
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d  in WINDOW[%03d:%03d] (SN=HIGHER BOUND=LOWER BOUND)\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
879
880
881
            sn,
            lower_bound,
            higher_bound);
882
#endif
883
884
885
      return 3;
    }

886
#if TRACE_RLC_UM_RX
887
888
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d  in WINDOW[%03d:%03d] (SN=LOWER BOUND)\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
889
890
891
          sn,
          lower_bound,
          higher_bound);
892
#endif
893
894
895
896
    return 1;
  }

  if ( higher_boundP == snP) {
897
#if TRACE_RLC_UM_RX
898
899
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d  in WINDOW[%03d:%03d] (SN=HIGHER BOUND)\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
900
901
902
          sn,
          lower_bound,
          higher_bound);
903
#endif
904
905
906
907
    return 2;
  }

  return 0;
908
909
910

}
//-----------------------------------------------------------------------------
911
signed int
912
rlc_um_in_reordering_window(
913
914
915
916
917
918
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const rlc_pP,
  const rlc_sn_t snP)
{
  rlc_sn_t   modulus = (signed int)rlc_pP->vr_uh - rlc_pP->rx_um_window_size;
  rlc_sn_t   sn_mod = (snP - modulus) % rlc_pP->rx_sn_modulo;
919

920
921
  if ( 0 <= sn_mod) {
    if (sn_mod < rlc_pP->rx_um_window_size) {
922
#if TRACE_RLC_UM_DAR
923
924
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d IN REORDERING WINDOW[%03d:%03d[ SN %d IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
925
926
927
928
929
930
931
932
            sn_mod,
            0,
            rlc_pP->rx_um_window_size,
            snP,
            (signed int)rlc_pP->vr_uh - rlc_pP->rx_um_window_size,
            rlc_pP->vr_uh,
            rlc_pP->vr_ur,
            rlc_pP->vr_uh);
gauthier's avatar
gauthier committed
933
#endif
934
      return 0;
935
    }
936
937
  }

938
#if TRACE_RLC_UM_DAR
939
940

  if (modulus < 0) {
941
942
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d NOT IN REORDERING WINDOW[%03d:%03d[ SN %d NOT IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
943
944
945
946
947
948
949
950
951
          sn_mod,
          modulus + 1024,
          rlc_pP->rx_um_window_size,
          snP,
          modulus + 1024 ,
          rlc_pP->vr_uh,
          rlc_pP->vr_ur,
          rlc_pP->vr_uh);
  } else {
952
953
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" %d NOT IN REORDERING WINDOW[%03d:%03d[ SN %d NOT IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
954
955
956
957
958
959
960
961
962
963
          sn_mod,
          modulus,
          rlc_pP->rx_um_window_size,
          snP,
          modulus ,
          rlc_pP->vr_uh,
          rlc_pP->vr_ur,
          rlc_pP->vr_uh);
  }

gauthier's avatar
gauthier committed
964
#endif
965
  return -1;
966
967
968
}
//-----------------------------------------------------------------------------
void
969
rlc_um_receive_process_dar (
970
971
972
973
974
  const protocol_ctxt_t* const ctxt_pP,
  rlc_um_entity_t * const      rlc_pP,
  mem_block_t *                pdu_mem_pP,
  rlc_um_pdu_sn_10_t * const   pdu_pP,
  const sdu_size_t             tb_sizeP)
975
{
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
  // 36.322v9.3.0 section 5.1.2.2.1:
  // The receiving UM RLC entity shall maintain a reordering window according to state variable VR(UH) as follows:
  //      -a SN falls within the reordering window if (VR(UH) – UM_Window_Size) <= SN < VR(UH);
  //      -a SN falls outside of the reordering window otherwise.
  // When receiving an UMD PDU from lower layer, the receiving UM RLC entity shall:
  //      -either discard the received UMD PDU or place it in the reception buffer (see sub clause 5.1.2.2.2);
  //      -if the received UMD PDU was placed in the reception buffer:
  //          -update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop t-Reordering as needed (see sub clause 5.1.2.2.3);
  // When t-Reordering expires, the receiving UM RLC entity shall:
  // -   update state variables, reassemble and deliver RLC SDUs to upper layer and start t-Reordering as needed (see sub clause 5.1.2.2.4).



  // When an UMD PDU with SN = x is received from lower layer, the receiving UM RLC entity shall:
  // -if VR(UR) < x < VR(UH) and the UMD PDU with SN = x has been received before; or
  // -if (VR(UH) – UM_Window_Size) <= x < VR(UR):
  //      -discard the received UMD PDU;
  // -else:
  //      -place the received UMD PDU in the reception buffer.

  rlc_sn_t sn = -1;
  signed int in_window;
998

gauthier's avatar
gauthier committed
999
  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_RECEIVE_PROCESS_DAR, VCD_FUNCTION_IN);
1000
1001
1002
1003
1004
1005

  if (rlc_pP->rx_sn_length == 10) {
    sn = ((pdu_pP->b1 & 0x00000003) << 8) + pdu_pP->b2;
  } else if (rlc_pP->rx_sn_length == 5) {
    sn = pdu_pP->b1 & 0x1F;
  } else {
1006
    free_mem_block(pdu_mem_pP, __func__);
1007
1008
  }

knopp's avatar
mutexes    
knopp committed
1009
  RLC_UM_MUTEX_LOCK(&rlc_pP->lock_dar_buffer, ctxt_pP, rlc_pP);
1010
1011

  in_window = rlc_um_in_window(ctxt_pP, rlc_pP, rlc_pP->vr_uh - rlc_pP->rx_um_window_size, sn, rlc_pP->vr_ur);
1012

1013
#if TRACE_RLC_PAYLOAD
1014
  rlc_util_print_hex_octets(RLC, &pdu_pP->b1, tb_sizeP);
gauthier's avatar
   
gauthier committed
1015
#endif
1016

1017
1018
1019
1020
1021
1022
1023
  // rlc_um_in_window() returns -2 if lower_bound  > sn
  // rlc_um_in_window() returns -1 if higher_bound < sn
  // rlc_um_in_window() returns  0 if lower_bound  < sn < higher_bound
  // rlc_um_in_window() returns  1 if lower_bound  == sn
  // rlc_um_in_window() returns  2 if higher_bound == sn
  // rlc_um_in_window() returns  3 if higher_bound == sn == lower_bound
  if ((in_window == 1) || (in_window == 0)) {
1024
#if TRACE_RLC_UM_DAR
1025
1026
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" RX PDU  VR(UH) – UM_Window_Size) <= SN %d < VR(UR) -> GARBAGE\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
1027
          sn);
gauthier's avatar
gauthier committed
1028
#endif
1029
1030
    rlc_pP->stat_rx_data_pdu_out_of_window   += 1;
    rlc_pP->stat_rx_data_bytes_out_of_window += tb_sizeP;
1031
    free_mem_block(pdu_mem_pP, __func__);
1032
    pdu_mem_pP = NULL;
knopp's avatar
mutexes    
knopp committed
1033
    RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_dar_buffer);
gauthier's avatar
gauthier committed
1034
    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_RECEIVE_PROCESS_DAR, VCD_FUNCTION_OUT);
1035
1036
1037
1038
1039
1040
1041
    return;
  }

  if ((rlc_um_get_pdu_from_dar_buffer(ctxt_pP, rlc_pP, sn))) {
    in_window = rlc_um_in_window(ctxt_pP, rlc_pP, rlc_pP->vr_ur, sn, rlc_pP->vr_uh);

    if (in_window == 0) {
1042
#if TRACE_RLC_UM_DAR
1043
1044
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" RX PDU  VR(UR) < SN %d < VR(UH) and RECEIVED BEFORE-> GARBAGE\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
1045
            sn);
gauthier's avatar
gauthier committed
1046
#endif
1047
1048
1049
      //discard the PDU
      rlc_pP->stat_rx_data_pdus_duplicate  += 1;
      rlc_pP->stat_rx_data_bytes_duplicate += tb_sizeP;
1050
      free_mem_block(pdu_mem_pP, __func__);
1051
      pdu_mem_pP = NULL;
knopp's avatar
mutexes    
knopp committed
1052
      RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_dar_buffer);
gauthier's avatar
gauthier committed
1053
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_RLC_UM_RECEIVE_PROCESS_DAR, VCD_FUNCTION_OUT);
1054
1055
1056
1057
1058
1059
      return;
    }

    // 2 lines to avoid memory leaks
    rlc_pP->stat_rx_data_pdus_duplicate  += 1;
    rlc_pP->stat_rx_data_bytes_duplicate += tb_sizeP;
1060
#if TRACE_RLC_UM_DAR
1061
1062
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" RX PDU SN %03d REMOVE OLD PDU BEFORE STORING NEW PDU\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
1063
          sn);
gauthier's avatar
gauthier committed
1064
#endif
1065
    mem_block_t *pdu = rlc_um_remove_pdu_from_dar_buffer(ctxt_pP, rlc_pP, sn);
1066
    free_mem_block(pdu, __func__);
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  }

  rlc_um_store_pdu_in_dar_buffer(ctxt_pP, rlc_pP, pdu_mem_pP, sn);


  // -if x falls outside of the reordering window:
  //      -update VR(UH) to x + 1;
  //      -reassemble RLC SDUs from any UMD PDUs with SN that falls outside of
  //       the reordering window, remove RLC headers when doing so and deliver
  //       the reassembled RLC SDUs to upper layer in ascending order of the
  //       RLC SN if not delivered before;
  //
  //      -if VR(UR) falls outside of the reordering window:
  //          -set VR(UR) to (VR(UH) – UM_Window_Size);
  if (rlc_um_in_reordering_window(ctxt_pP, rlc_pP, sn) < 0) {
1082
#if TRACE_RLC_UM_DAR
1083
1084
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" RX PDU  SN %d OUTSIDE REORDERING WINDOW VR(UH)=%d UM_Window_Size=%d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
1085
1086
1087
          sn,
          rlc_pP->vr_uh,
          rlc_pP->rx_um_window_size);
gauthier's avatar
gauthier committed
1088
#endif
1089
    rlc_pP->vr_uh = (sn + 1) % rlc_pP->rx_sn_modulo;
1090

1091
1092
    if (rlc_um_in_reordering_window(ctxt_pP, rlc_pP, rlc_pP->vr_ur) != 0) {
      in_window = rlc_pP->vr_uh - rlc_pP->rx_um_window_size;
1093

1094
1095
1096
      if (in_window < 0) {
        in_window = in_window + rlc_pP->rx_sn_modulo;
      }
1097

1098
1099
      rlc_um_try_reassembly(ctxt_pP, rlc_pP, rlc_pP->vr_ur, in_window);
    }
1100

1101
1102

    if (rlc_um_in_reordering_window(ctxt_pP, rlc_pP, rlc_pP->vr_ur) < 0) {
1103
#if TRACE_RLC_UM_DAR
1104
1105
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" VR(UR) %d OUTSIDE REORDERING WINDOW SET TO VR(UH) – UM_Window_Size = %d\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP, rlc_pP),
1106
1107
            rlc_pP->vr_ur,
            in_window);
gauthier's avatar
gauthier committed
1108
#endif
1109
      rlc_pP->vr_ur = in_window;
1110
    }
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126