rlc_um_segment.c 31.6 KB
Newer Older
1
2
3
4
5
/*
 * 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
Cedric Roux's avatar
Cedric Roux committed
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 * 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_SEGMENT_C 1
24
25
26
27
28
//-----------------------------------------------------------------------------
#include "platform_types.h"
#include "platform_constants.h"
//-----------------------------------------------------------------------------
#include <assert.h>
29
#include "assertions.h"
knopp's avatar
mutexes    
knopp committed
30
#include "msc.h"
31
32
33
34
35
36
37
#include "list.h"
#include "rlc_um.h"
#include "rlc_primitives.h"
#include "UTIL/LOG/log.h"

//-----------------------------------------------------------------------------
void
knopp's avatar
mutexes    
knopp committed
38
rlc_um_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP)
39
{
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
  list_t              pdus;
  signed int          pdu_remaining_size;
  signed int          test_pdu_remaining_size;

  int                 nb_bytes_to_transmit = rlc_pP->nb_bytes_requested_by_mac;
  rlc_um_pdu_sn_10_t *pdu_p;
  struct mac_tb_req  *pdu_tb_req_p;
  mem_block_t        *pdu_mem_p;
  char               *data;
  char               *data_sdu_p;
  rlc_um_e_li_t      *e_li_p;
  struct rlc_um_tx_sdu_management *sdu_mngt_p;
  unsigned int       li_length_in_bytes;
  unsigned int       test_li_length_in_bytes;
  unsigned int       test_remaining_size_to_substract;
  unsigned int       test_remaining_num_li_to_substract;
  unsigned int       continue_fill_pdu_with_sdu;
  unsigned int       num_fill_sdu;
  unsigned int       test_num_li;
  unsigned int       fill_num_li;
  mem_block_t        *sdu_in_buffer = NULL;
  unsigned int       data_pdu_size;

  unsigned int       fi_first_byte_pdu_is_first_byte_sdu;
  unsigned int       fi_last_byte_pdu_is_last_byte_sdu;
  unsigned int       fi;
  unsigned int       max_li_overhead;

  if (nb_bytes_to_transmit < 3) {
69
#if TRACE_RLC_UM_SEGMENT
70
71
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" NO SEGMENTATION nb_bytes to transmit = %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
72
          nb_bytes_to_transmit);
gauthier's avatar
gauthier committed
73
#endif
74
75
76
77
78
79
80
    return;
  }

  list_init (&pdus, NULL);    // param string identifying the list is NULL
  pdu_mem_p = NULL;

  // not fine locking
knopp's avatar
mutexes    
knopp committed
81
  RLC_UM_MUTEX_LOCK(&rlc_pP->lock_input_sdus, ctxt_pP, rlc_pP);
82
83
84

  while ((list_get_head(&rlc_pP->input_sdus)) && (nb_bytes_to_transmit > 0)) {

85
#if TRACE_RLC_UM_SEGMENT
86
87
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" nb_bytes_to_transmit %d BO %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
88
89
90
91
92
93
94
95
96
97
98
99
100
101
          nb_bytes_to_transmit,
          rlc_pP->buffer_occupancy);
#endif

    // pdu_p management
    if (!pdu_mem_p) {
      if (rlc_pP->input_sdus.nb_elements <= 1) {
        max_li_overhead = 0;
      } else {
        max_li_overhead = (((rlc_pP->input_sdus.nb_elements - 1) * 3) / 2) + ((rlc_pP->input_sdus.nb_elements - 1) % 2);
      }

      if  (nb_bytes_to_transmit >= (rlc_pP->buffer_occupancy + rlc_pP->tx_header_min_length_in_bytes + max_li_overhead)) {
        data_pdu_size = rlc_pP->buffer_occupancy + rlc_pP->tx_header_min_length_in_bytes + max_li_overhead;
102
#if TRACE_RLC_UM_SEGMENT
103
104
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" alloc PDU size %d bytes to contain not all bytes requested by MAC but all BO of RLC@1\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
105
106
107
108
              data_pdu_size);
#endif
      } else {
        data_pdu_size = nb_bytes_to_transmit;
109
#if TRACE_RLC_UM_SEGMENT
110
111
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" alloc PDU size %d bytes to contain all bytes requested by MAC@1\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
112
113
114
115
              data_pdu_size);
#endif
      }

116
      if (!(pdu_mem_p = get_free_mem_block (data_pdu_size + sizeof(struct mac_tb_req), __func__))) {
117
#if TRACE_RLC_UM_SEGMENT
118
119
        LOG_E(RLC, PROTOCOL_RLC_UM_CTXT_FMT" ERROR COULD NOT GET NEW PDU, EXIT\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP));
120
#endif
knopp's avatar
mutexes    
knopp committed
121
        RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
122
        return;
123
124
      }

125
#if TRACE_RLC_UM_SEGMENT
126
127
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" get new PDU %d bytes\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
128
129
130
131
132
133
134
135
            data_pdu_size);
#endif
      pdu_remaining_size = data_pdu_size - 2;
      pdu_p        = (rlc_um_pdu_sn_10_t*) (&pdu_mem_p->data[sizeof(struct mac_tb_req)]);
      pdu_tb_req_p = (struct mac_tb_req*) (pdu_mem_p->data);

      memset (pdu_mem_p->data, 0, sizeof (rlc_um_pdu_sn_10_t)+sizeof(struct mac_tb_req));
      li_length_in_bytes = 1;
136
    }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

    //----------------------------------------
    // compute how many SDUS can fill the PDU
    //----------------------------------------
    continue_fill_pdu_with_sdu = 1;
    num_fill_sdu               = 0;
    test_num_li                = 0;
    sdu_in_buffer              = list_get_head(&rlc_pP->input_sdus);
    test_pdu_remaining_size    = pdu_remaining_size;
    test_li_length_in_bytes    = 1;
    test_remaining_size_to_substract   = 0;
    test_remaining_num_li_to_substract = 0;


    while ((sdu_in_buffer) && (continue_fill_pdu_with_sdu > 0)) {
      sdu_mngt_p = ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data));

      if (sdu_mngt_p->sdu_remaining_size > test_pdu_remaining_size) {
        // no LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
      } else if (sdu_mngt_p->sdu_remaining_size == test_pdu_remaining_size) {
        // fi will indicate end of PDU is end of SDU, no need for LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
      } else if ((sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3)) == test_pdu_remaining_size ) {
        // no LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
175
        //pdu_remaining_size = pdu_remaining_size - (test_li_length_in_bytes ^ 3);
176
177
178
179
180
181
182
183
      } else if ((sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3)) < test_pdu_remaining_size ) {
        test_num_li += 1;
        num_fill_sdu += 1;
        test_pdu_remaining_size = test_pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3));
        test_remaining_size_to_substract = test_li_length_in_bytes ^ 3;
        test_remaining_num_li_to_substract = 1;
        test_li_length_in_bytes = test_li_length_in_bytes ^ 3;
      } else {
184
#if TRACE_RLC_UM_SEGMENT
185
186
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" sdu_mngt_p->sdu_remaining_size=%d test_pdu_remaining_size=%d test_li_length_in_bytes=%d\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
              sdu_mngt_p->sdu_remaining_size,
              test_pdu_remaining_size,
              test_li_length_in_bytes ^ 3);
#endif
        // reduce the size of the PDU
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
        pdu_remaining_size = pdu_remaining_size - 1;
      }

      sdu_in_buffer = sdu_in_buffer->next;
    }

    if (test_remaining_num_li_to_substract > 0) {
      // there is a LI that is not necessary
      test_num_li = test_num_li - 1;
      pdu_remaining_size = pdu_remaining_size - test_remaining_size_to_substract;
    }

    //----------------------------------------
    // Do the real filling of the pdu_p
    //----------------------------------------
212
#if TRACE_RLC_UM_SEGMENT
213
214
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" data shift %d Bytes num_li %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
215
216
          ((test_num_li*3) +1) >> 1,
          test_num_li);
gauthier's avatar
gauthier committed
217
218
#endif

219
220
221
222
223
224
225
    data = ((char*)(&pdu_p->data[((test_num_li*3) +1) >> 1]));
    e_li_p = (rlc_um_e_li_t*)(pdu_p->data);
    continue_fill_pdu_with_sdu          = 1;
    li_length_in_bytes                  = 1;
    fill_num_li                         = 0;
    fi_first_byte_pdu_is_first_byte_sdu = 0;
    fi_last_byte_pdu_is_last_byte_sdu   = 0;
226

227
228
229
230
231
232
233
234
235
236
237
238
    sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);

    if (
      ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data))->sdu_remaining_size ==
      ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data))->sdu_size) {
      fi_first_byte_pdu_is_first_byte_sdu = 1;
    }

    while ((sdu_in_buffer) && (continue_fill_pdu_with_sdu > 0)) {
      sdu_mngt_p = ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data));

      if (sdu_mngt_p->sdu_segmented_size == 0) {
239
#if TRACE_RLC_UM_SEGMENT
240
241
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" GET NEW SDU %p AVAILABLE SIZE %d Bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
242
243
244
245
              sdu_mngt_p,
              sdu_mngt_p->sdu_remaining_size);
#endif
      } else {
246
#if TRACE_RLC_UM_SEGMENT
247
248
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" GET AGAIN SDU %p REMAINING AVAILABLE SIZE %d Bytes / %d Bytes \n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
249
250
251
252
253
254
255
256
257
              sdu_mngt_p,
              sdu_mngt_p->sdu_remaining_size,
              sdu_mngt_p->sdu_size);
#endif
      }

      data_sdu_p = (char *) &(sdu_in_buffer->data[sizeof (struct rlc_um_tx_sdu_management) + sdu_mngt_p->sdu_segmented_size]);

      if (sdu_mngt_p->sdu_remaining_size > pdu_remaining_size) {
258
#if TRACE_RLC_UM_SEGMENT
259
260
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling all remaining PDU with %d bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
261
              pdu_remaining_size);
262
263
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" pdu_mem_p %p pdu_mem_p->data %p pdu_p %p pdu_p->data %p data %p data_sdu_p %p pdu_remaining_size %d\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
              pdu_mem_p,
              pdu_mem_p->data,
              pdu_p,
              pdu_p->data,
              data,
              data_sdu_p,
              pdu_remaining_size);
#endif

        memcpy(data, data_sdu_p, pdu_remaining_size);
        sdu_mngt_p->sdu_remaining_size = sdu_mngt_p->sdu_remaining_size - pdu_remaining_size;
        sdu_mngt_p->sdu_segmented_size = sdu_mngt_p->sdu_segmented_size + pdu_remaining_size;
        fi_last_byte_pdu_is_last_byte_sdu = 0;
        // no LI
        rlc_pP->buffer_occupancy -= pdu_remaining_size;
        continue_fill_pdu_with_sdu = 0;
        pdu_remaining_size = 0;
      } else if (sdu_mngt_p->sdu_remaining_size == pdu_remaining_size) {
282
#if TRACE_RLC_UM_SEGMENT
283
284
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Exactly Filling remaining PDU with %d remaining bytes of SDU\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
285
286
287
288
289
290
291
              pdu_remaining_size);
#endif
        memcpy(data, data_sdu_p, pdu_remaining_size);

        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
292
        free_mem_block (sdu_in_buffer, __func__);
293
294
295
296
297
298
299
300
301
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
        sdu_mngt_p    = NULL;


        fi_last_byte_pdu_is_last_byte_sdu = 1;
        // fi will indicate end of PDU is end of SDU, no need for LI
        continue_fill_pdu_with_sdu = 0;
        pdu_remaining_size = 0;
      } else if ((sdu_mngt_p->sdu_remaining_size + (li_length_in_bytes ^ 3)) < pdu_remaining_size ) {
302
#if TRACE_RLC_UM_SEGMENT
303
304
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling  PDU with %d all remaining bytes of SDU\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
              sdu_mngt_p->sdu_remaining_size);
#endif
        memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size);
        data = &data[sdu_mngt_p->sdu_remaining_size];
        li_length_in_bytes = li_length_in_bytes ^ 3;
        fill_num_li += 1;

        if (li_length_in_bytes  == 2) {
          if (fill_num_li == test_num_li) {
            //e_li_p->e1  = 0;
            e_li_p->b1 = 0;
          } else {
            //e_li_p->e1  = 1;
            e_li_p->b1 =  0x80;
          }

          //e_li_p->li1 = sdu_mngt_p->sdu_remaining_size;
          e_li_p->b1 = e_li_p->b1 | (sdu_mngt_p->sdu_remaining_size >> 4);
          e_li_p->b2 = sdu_mngt_p->sdu_remaining_size << 4;
324
#if TRACE_RLC_UM_SEGMENT
325
326
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" set e_li_p->b1=%02X set e_li_p->b2=%02X fill_num_li=%d test_num_li=%d\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
327
328
329
330
331
332
333
334
335
336
                e_li_p->b1,
                e_li_p->b2,
                fill_num_li,
                test_num_li);
#endif
        } else {
          if (fill_num_li != test_num_li) {
            //e_li_p->e2  = 1;
            e_li_p->b2  = e_li_p->b2 | 0x08;
          }
337

338
339
340
          //e_li_p->li2 = sdu_mngt_p->sdu_remaining_size;
          e_li_p->b2 = e_li_p->b2 | (sdu_mngt_p->sdu_remaining_size >> 8);
          e_li_p->b3 = sdu_mngt_p->sdu_remaining_size & 0xFF;
341
#if TRACE_RLC_UM_SEGMENT
342
343
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" set e_li_p->b2=%02X set e_li_p->b3=%02X fill_num_li=%d test_num_li=%d\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
344
345
346
                e_li_p->b2,
                e_li_p->b3,
                fill_num_li,
gauthier's avatar
gauthier committed
347
348
                test_num_li);
#endif
349
350
          e_li_p++;
        }
351

352
        pdu_remaining_size = pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + li_length_in_bytes);
353

354
355
356
        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
357
        free_mem_block (sdu_in_buffer, __func__);
358
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
359
360
361
        sdu_mngt_p    = NULL;

      } else {
362
#if TRACE_RLC_UM_SEGMENT
363
364
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling  PDU with %d all remaining bytes of SDU and reduce TB size by %d bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
365
366
              sdu_mngt_p->sdu_remaining_size,
              pdu_remaining_size - sdu_mngt_p->sdu_remaining_size);
gauthier's avatar
gauthier committed
367
#endif
368
369
370
//#if !EXMIMO
//        assert(1!=1);
//#endif
371
372
373
374
375
376
377
378
        memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size);
        // reduce the size of the PDU
        continue_fill_pdu_with_sdu = 0;
        fi_last_byte_pdu_is_last_byte_sdu = 1;
        pdu_remaining_size = pdu_remaining_size - sdu_mngt_p->sdu_remaining_size;
        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
379
        free_mem_block (sdu_in_buffer, __func__);
380
381
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
        sdu_mngt_p    = NULL;
382

383
384
      }
    }
385

386
387
388
389
390
391
392
393
394
395
    // set framing info
    if (fi_first_byte_pdu_is_first_byte_sdu) {
      fi = 0;
    } else {
      fi = 2;
    }

    if (!fi_last_byte_pdu_is_last_byte_sdu) {
      fi = fi + 1;
    }
396

397
398
399
400
401
402
    pdu_p->b1 =  (fi << 3); //pdu_p->b1 |

    // set fist e bit
    if (fill_num_li > 0) {
      pdu_p->b1 = pdu_p->b1 | 0x04;
    }
403

404
405
406
407
408
409
410
    pdu_p->b1 = pdu_p->b1 | ((rlc_pP->vt_us >> 8) & 0x03);
    pdu_p->b2 = rlc_pP->vt_us & 0xFF;
    rlc_pP->vt_us = rlc_pP->vt_us+1;

    pdu_tb_req_p->data_ptr        = (unsigned char*)pdu_p;
    pdu_tb_req_p->tb_size = data_pdu_size - pdu_remaining_size;
    list_add_tail_eurecom (pdu_mem_p, &rlc_pP->pdus_to_mac_layer);
411
#if TRACE_RLC_PAYLOAD
412
    rlc_util_print_hex_octets(RLC, pdu_mem_p->data, data_pdu_size);
gauthier's avatar
   
gauthier committed
413
#endif
414
415
416
    AssertFatal( pdu_tb_req_p->tb_size > 0 , "SEGMENT10: FINAL RLC UM PDU LENGTH %d", pdu_tb_req_p->tb_size);
    pdu_p = NULL;
    pdu_mem_p = NULL;
417

418
419
420
421
    //nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size;
    nb_bytes_to_transmit = 0; // 1 PDU only
  }

knopp's avatar
mutexes    
knopp committed
422
  RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
423
424
425
}
//-----------------------------------------------------------------------------
void
knopp's avatar
mutexes    
knopp committed
426
rlc_um_segment_5 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP)
427
{
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  list_t              pdus;
  signed int          pdu_remaining_size      = 0;
  signed int          test_pdu_remaining_size = 0;

  int                 nb_bytes_to_transmit = rlc_pP->nb_bytes_requested_by_mac;
  rlc_um_pdu_sn_5_t  *pdu_p                = NULL;
  struct mac_tb_req  *pdu_tb_req_p         = NULL;
  mem_block_t        *pdu_mem_p            = NULL;
  char               *data                 = NULL;
  char               *data_sdu_p           = NULL;
  rlc_um_e_li_t      *e_li_p               = NULL;
  struct rlc_um_tx_sdu_management *sdu_mngt_p           = NULL;
  unsigned int       li_length_in_bytes                 = 0;
  unsigned int       test_li_length_in_bytes            = 0;
  unsigned int       test_remaining_size_to_substract   = 0;
  unsigned int       test_remaining_num_li_to_substract = 0;
  unsigned int       continue_fill_pdu_with_sdu         = 0;
  unsigned int       num_fill_sdu                       = 0;
  unsigned int       test_num_li                        = 0;
  unsigned int       fill_num_li                        = 0;
  mem_block_t        *sdu_in_buffer                     = NULL;
  unsigned int       data_pdu_size                      = 0;

  unsigned int       fi_first_byte_pdu_is_first_byte_sdu = 0;
  unsigned int       fi_last_byte_pdu_is_last_byte_sdu   = 0;
  unsigned int       fi                                  = 0;
  unsigned int       max_li_overhead                     = 0;

  if (nb_bytes_to_transmit < 2) {
457
#if TRACE_RLC_UM_SEGMENT
458
459
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" NO SEGMENTATION5 nb_bytes to transmit = %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
460
          nb_bytes_to_transmit);
gauthier's avatar
gauthier committed
461
#endif
462
463
464
465
466
467
    return;
  }

  list_init (&pdus, NULL);    // param string identifying the list is NULL
  pdu_mem_p = NULL;

knopp's avatar
mutexes    
knopp committed
468
  RLC_UM_MUTEX_LOCK(&rlc_pP->lock_input_sdus, ctxt_pP, rlc_pP);
469
470

  while ((list_get_head(&rlc_pP->input_sdus)) && (nb_bytes_to_transmit > 0)) {
471
#if TRACE_RLC_UM_SEGMENT
472
473
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT"nb_bytes_to_transmit %d BO %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
474
475
476
477
478
479
480
481
482
483
484
485
486
487
          nb_bytes_to_transmit,
          rlc_pP->buffer_occupancy);
#endif

    // pdu_p management
    if (!pdu_mem_p) {
      if (rlc_pP->input_sdus.nb_elements <= 1) {
        max_li_overhead = 0;
      } else {
        max_li_overhead = (((rlc_pP->input_sdus.nb_elements - 1) * 3) / 2) + ((rlc_pP->input_sdus.nb_elements - 1) % 2);
      }

      if  (nb_bytes_to_transmit >= (rlc_pP->buffer_occupancy + rlc_pP->tx_header_min_length_in_bytes + max_li_overhead)) {
        data_pdu_size = rlc_pP->buffer_occupancy + rlc_pP->tx_header_min_length_in_bytes + max_li_overhead;
488
#if TRACE_RLC_UM_SEGMENT
489
490
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" alloc PDU size %d bytes to contain not all bytes requested by MAC but all BO of RLC@1\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
491
492
493
494
              data_pdu_size);
#endif
      } else {
        data_pdu_size = nb_bytes_to_transmit;
495
#if TRACE_RLC_UM_SEGMENT
496
497
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" alloc PDU size %d bytes to contain all bytes requested by MAC@1\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
498
499
500
501
              data_pdu_size);
#endif
      }

502
      if (!(pdu_mem_p = get_free_mem_block (data_pdu_size + sizeof(struct mac_tb_req), __func__))) {
503
#if TRACE_RLC_UM_SEGMENT
504
505
        LOG_E(RLC, PROTOCOL_RLC_UM_CTXT_FMT" ERROR COULD NOT GET NEW PDU, EXIT\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP));
506
#endif
knopp's avatar
mutexes    
knopp committed
507
        RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
508
        return;
509
510
      }

511
#if TRACE_RLC_UM_SEGMENT
512
513
      LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" get new PDU %d bytes\n",
            PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
514
            data_pdu_size);
gauthier's avatar
gauthier committed
515
#endif
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
      pdu_remaining_size = data_pdu_size - 1;
      pdu_p        = (rlc_um_pdu_sn_5_t*) (&pdu_mem_p->data[sizeof(struct mac_tb_req)]);
      pdu_tb_req_p = (struct mac_tb_req*) (pdu_mem_p->data);

      memset (pdu_mem_p->data, 0, sizeof (rlc_um_pdu_sn_5_t)+sizeof(struct mac_tb_req));
      li_length_in_bytes = 1;
    }

    //----------------------------------------
    // compute how many SDUS can fill the PDU
    //----------------------------------------
    continue_fill_pdu_with_sdu = 1;
    num_fill_sdu               = 0;
    test_num_li                = 0;
    sdu_in_buffer              = list_get_head(&rlc_pP->input_sdus);
    test_pdu_remaining_size    = pdu_remaining_size;
    test_li_length_in_bytes    = 1;
    test_remaining_size_to_substract   = 0;
    test_remaining_num_li_to_substract = 0;


    while ((sdu_in_buffer) && (continue_fill_pdu_with_sdu > 0)) {
      sdu_mngt_p = ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data));

      if (sdu_mngt_p->sdu_remaining_size > test_pdu_remaining_size) {
        // no LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
      } else if (sdu_mngt_p->sdu_remaining_size == test_pdu_remaining_size) {
        // fi will indicate end of PDU is end of SDU, no need for LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
      } else if ((sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3)) == test_pdu_remaining_size ) {
        // no LI
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
        pdu_remaining_size = pdu_remaining_size - (test_li_length_in_bytes ^ 3);
        data_pdu_size -=  (test_li_length_in_bytes ^ 3);//modifier pour duy
      } else if ((sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3)) < test_pdu_remaining_size ) {
        test_num_li += 1;
        num_fill_sdu += 1;
        test_pdu_remaining_size = test_pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + (test_li_length_in_bytes ^ 3));
        test_remaining_size_to_substract = test_li_length_in_bytes ^ 3;
        test_remaining_num_li_to_substract = 1;
        test_li_length_in_bytes = test_li_length_in_bytes ^ 3;
      } else {
571
#if TRACE_RLC_UM_SEGMENT
572
573
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" sdu_mngt_p->sdu_remaining_size=%d test_pdu_remaining_size=%d test_li_length_in_bytes=%d\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
574
575
576
577
578
579
580
581
582
583
584
585
586
              sdu_mngt_p->sdu_remaining_size,
              test_pdu_remaining_size,
              test_li_length_in_bytes ^ 3);
#endif
        // reduce the size of the PDU
        continue_fill_pdu_with_sdu = 0;
        num_fill_sdu += 1;
        test_pdu_remaining_size = 0;
        test_remaining_size_to_substract = 0;
        test_remaining_num_li_to_substract = 0;
        pdu_remaining_size = pdu_remaining_size - 1;
        data_pdu_size -= 1;//modifier pour duy
      }
gauthier's avatar
gauthier committed
587

588
589
590
591
592
593
594
595
596
597
598
599
      sdu_in_buffer = sdu_in_buffer->next;
    }

    if (test_remaining_num_li_to_substract > 0) {
      // there is a LI that is not necessary
      test_num_li = test_num_li - 1;
      pdu_remaining_size = pdu_remaining_size - test_remaining_size_to_substract;
    }

    //----------------------------------------
    // Do the real filling of the pdu_p
    //----------------------------------------
600
#if TRACE_RLC_UM_SEGMENT
601
602
    LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" data shift %d Bytes num_li %d\n",
          PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
          ((test_num_li*3) +1) >> 1,
          test_num_li);
#endif

    data = ((char*)(&pdu_p->data[((test_num_li*3) +1) >> 1]));
    e_li_p = (rlc_um_e_li_t*)(pdu_p->data);
    continue_fill_pdu_with_sdu          = 1;
    li_length_in_bytes                  = 1;
    fill_num_li                         = 0;
    fi_first_byte_pdu_is_first_byte_sdu = 0;
    fi_last_byte_pdu_is_last_byte_sdu   = 0;

    sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);

    if (
      ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data))->sdu_remaining_size ==
      ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data))->sdu_size) {
      fi_first_byte_pdu_is_first_byte_sdu = 1;
    }

    while ((sdu_in_buffer) && (continue_fill_pdu_with_sdu > 0)) {
      sdu_mngt_p = ((struct rlc_um_tx_sdu_management *) (sdu_in_buffer->data));

      if (sdu_mngt_p->sdu_segmented_size == 0) {
627
#if TRACE_RLC_UM_SEGMENT
628
629
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" GET NEW SDU %p AVAILABLE SIZE %d Bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
630
631
632
633
              sdu_mngt_p,
              sdu_mngt_p->sdu_remaining_size);
#endif
      } else {
634
#if TRACE_RLC_UM_SEGMENT
635
636
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" GET AGAIN SDU %p REMAINING AVAILABLE SIZE %d Bytes / %d Bytes \n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
637
638
639
640
641
642
643
644
645
              sdu_mngt_p,
              sdu_mngt_p->sdu_remaining_size,
              sdu_mngt_p->sdu_size);
#endif
      }

      data_sdu_p = (char*) &(sdu_in_buffer->data[sizeof (struct rlc_um_tx_sdu_management) + sdu_mngt_p->sdu_segmented_size]);

      if (sdu_mngt_p->sdu_remaining_size > pdu_remaining_size) {
646
#if TRACE_RLC_UM_SEGMENT
647
648
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling all remaining PDU with %d bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
649
              pdu_remaining_size);
650
651
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" pdu_mem_p %p pdu_p %p pdu_p->data %p data %p data_sdu_p %p pdu_remaining_size %d\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
              pdu_mem_p,
              pdu_p,
              pdu_p->data,
              data,
              data_sdu_p,
              pdu_remaining_size);
#endif

        memcpy(data, data_sdu_p, pdu_remaining_size);
        sdu_mngt_p->sdu_remaining_size = sdu_mngt_p->sdu_remaining_size - pdu_remaining_size;
        sdu_mngt_p->sdu_segmented_size = sdu_mngt_p->sdu_segmented_size + pdu_remaining_size;
        fi_last_byte_pdu_is_last_byte_sdu = 0;
        // no LI
        rlc_pP->buffer_occupancy -= pdu_remaining_size;
        continue_fill_pdu_with_sdu = 0;
        pdu_remaining_size = 0;
      } else if (sdu_mngt_p->sdu_remaining_size == pdu_remaining_size) {
669
#if TRACE_RLC_UM_SEGMENT
670
671
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Exactly Filling remaining PDU with %d remaining bytes of SDU\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
672
673
674
675
676
677
              pdu_remaining_size);
#endif
        memcpy(data, data_sdu_p, pdu_remaining_size);
        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
678
        free_mem_block (sdu_in_buffer, __func__);
679
680
681
682
683
684
685
686
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
        sdu_mngt_p    = NULL;

        fi_last_byte_pdu_is_last_byte_sdu = 1;
        // fi will indicate end of PDU is end of SDU, no need for LI
        continue_fill_pdu_with_sdu = 0;
        pdu_remaining_size = 0;
      } else if ((sdu_mngt_p->sdu_remaining_size + (li_length_in_bytes ^ 3)) < pdu_remaining_size ) {
687
#if TRACE_RLC_UM_SEGMENT
688
689
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling  PDU with %d all remaining bytes of SDU\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
              sdu_mngt_p->sdu_remaining_size);
#endif
        memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size);
        data = &data[sdu_mngt_p->sdu_remaining_size];
        li_length_in_bytes = li_length_in_bytes ^ 3;
        fill_num_li += 1;

        if (li_length_in_bytes  == 2) {
          if (fill_num_li == test_num_li) {
            //e_li_p->e1  = 0;
            e_li_p->b1 = 0;
          } else {
            //e_li_p->e1  = 1;
            e_li_p->b1 =  0x80;
          }

          //e_li_p->li1 = sdu_mngt_p->sdu_remaining_size;
          e_li_p->b1 = e_li_p->b1 | (sdu_mngt_p->sdu_remaining_size >> 4);
          e_li_p->b2 = sdu_mngt_p->sdu_remaining_size << 4;
709
#if TRACE_RLC_UM_SEGMENT
710
711
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" set e_li_p->b1=%02X set e_li_p->b2=%02X fill_num_li=%d test_num_li=%d\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
712
713
714
715
716
717
718
719
720
721
                e_li_p->b1,
                e_li_p->b2,
                fill_num_li,
                test_num_li);
#endif
        } else {
          if (fill_num_li != test_num_li) {
            //e_li_p->e2  = 1;
            e_li_p->b2  = e_li_p->b2 | 0x08;
          }
722

723
724
725
          //e_li_p->li2 = sdu_mngt_p->sdu_remaining_size;
          e_li_p->b2 = e_li_p->b2 | (sdu_mngt_p->sdu_remaining_size >> 8);
          e_li_p->b3 = sdu_mngt_p->sdu_remaining_size & 0xFF;
726
#if TRACE_RLC_UM_SEGMENT
727
728
          LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" set e_li_p->b2=%02X set e_li_p->b3=%02X fill_num_li=%d test_num_li=%d\n",
                PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
729
730
731
                e_li_p->b2,
                e_li_p->b3,
                fill_num_li,
gauthier's avatar
gauthier committed
732
733
                test_num_li);
#endif
734
735
          e_li_p++;
        }
736

737
        pdu_remaining_size = pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + li_length_in_bytes);
738

739
740
741
        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
742
        free_mem_block (sdu_in_buffer, __func__);
743
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
744
745
746
        sdu_mngt_p    = NULL;

      } else {
747
#if TRACE_RLC_UM_SEGMENT
748
749
        LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" Filling  PDU with %d all remaining bytes of SDU and reduce TB size by %d bytes\n",
              PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
750
751
              sdu_mngt_p->sdu_remaining_size,
              pdu_remaining_size - sdu_mngt_p->sdu_remaining_size);
gauthier's avatar
gauthier committed
752
#endif
753
754
755
756
757
758
759
760
761
        assert(1!=1);
        memcpy(data, data_sdu_p, sdu_mngt_p->sdu_remaining_size);
        // reduce the size of the PDU
        continue_fill_pdu_with_sdu = 0;
        fi_last_byte_pdu_is_last_byte_sdu = 1;
        pdu_remaining_size = pdu_remaining_size - sdu_mngt_p->sdu_remaining_size;
        // free SDU
        rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
        sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
762
        free_mem_block (sdu_in_buffer, __func__);
763
764
765
766
        sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
        sdu_mngt_p    = NULL;
      }
    }
767

768
769
770
771
772
773
    // set framing info
    if (fi_first_byte_pdu_is_first_byte_sdu) {
      fi = 0;
    } else {
      fi = 2;
    }
774

775
776
777
778
779
780
781
782
783
784
    if (!fi_last_byte_pdu_is_last_byte_sdu) {
      fi = fi + 1;
    }

    pdu_p->b1 =  (fi << 6); //pdu_p->b1 |

    // set fist e bit
    if (fill_num_li > 0) {
      pdu_p->b1 = pdu_p->b1 | 0x20;
    }
785

786
787
788
789
790
791
    pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_us & 0x1F);
    rlc_pP->vt_us = rlc_pP->vt_us+1;

    pdu_tb_req_p->data_ptr        = (unsigned char*)pdu_p;
    pdu_tb_req_p->tb_size         = data_pdu_size - pdu_remaining_size;
    list_add_tail_eurecom (pdu_mem_p, &rlc_pP->pdus_to_mac_layer);
792
#if TRACE_RLC_PAYLOAD
793
    rlc_util_print_hex_octets(RLC, (unsigned char*)pdu_mem_p->data, data_pdu_size);
gauthier's avatar
   
gauthier committed
794
#endif
795
796
797
798
    AssertFatal( pdu_tb_req_p->tb_size > 0 , "SEGMENT5: FINAL RLC UM PDU LENGTH %d", pdu_tb_req_p->tb_size);

    pdu_p = NULL;
    pdu_mem_p = NULL;
799

800
801
802
    //nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size;
    nb_bytes_to_transmit = 0; // 1 PDU only
  }
803

knopp's avatar
mutexes    
knopp committed
804
  RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
805
806
}