Files
openairinterface5g/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um_segment.c
T
Cedric Roux 26d68e9c5e hotfix: fix bad RLC UM packet creation
Running TCP DL traffic with one connected UE showed a lot of
fluctuations in throughput. After analysis it was found that
sometimes the RLC UM PDU was not correct. It contained one byte
more than it should. On the receiver side, the TCP packet
contained in the RLC packet seems to be rejected by the TCP
stack of the UE (it has one byte more than it should),
leading to a brutal reduction of the throughput, probably due
to some congestion detection in the TCP implementation.
Or something.

This hotfix seems to solve the problem. Using iperf in downlink
with a 5MHz eNB, we see no more fluctuations, the traffic is
very steady at 16.8Mb/s, as reported by the iperf server running
on the phone. (17.5 in the PHY plot of the T tracer.)

A rewrite of both the MAC and RLC UM packet generation is needed.
The code is way too complex for what it does and may contain
several similar problems that only trigger in specific rare
conditions.
2018-03-02 12:02:06 +01:00

807 lines
32 KiB
C

/*
* 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.1 (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
*/
#define RLC_UM_MODULE 1
#define RLC_UM_SEGMENT_C 1
//-----------------------------------------------------------------------------
#include "platform_types.h"
#include "platform_constants.h"
//-----------------------------------------------------------------------------
#include <assert.h>
#include "assertions.h"
#include "msc.h"
#include "list.h"
#include "rlc_um.h"
#include "rlc_primitives.h"
#include "UTIL/LOG/log.h"
//-----------------------------------------------------------------------------
void
rlc_um_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP)
{
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) {
#if TRACE_RLC_UM_SEGMENT
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),
nb_bytes_to_transmit);
#endif
return;
}
list_init (&pdus, NULL); // param string identifying the list is NULL
pdu_mem_p = NULL;
// not fine locking
RLC_UM_MUTEX_LOCK(&rlc_pP->lock_input_sdus, ctxt_pP, rlc_pP);
while ((list_get_head(&rlc_pP->input_sdus)) && (nb_bytes_to_transmit > 0)) {
#if TRACE_RLC_UM_SEGMENT
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),
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;
#if TRACE_RLC_UM_SEGMENT
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),
data_pdu_size);
#endif
} else {
data_pdu_size = nb_bytes_to_transmit;
#if TRACE_RLC_UM_SEGMENT
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),
data_pdu_size);
#endif
}
if (!(pdu_mem_p = get_free_mem_block (data_pdu_size + sizeof(struct mac_tb_req), __func__))) {
#if TRACE_RLC_UM_SEGMENT
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));
#endif
RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
return;
}
#if TRACE_RLC_UM_SEGMENT
LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" get new PDU %d bytes\n",
PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
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;
}
//----------------------------------------
// 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);
} 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 {
#if TRACE_RLC_UM_SEGMENT
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),
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
//----------------------------------------
#if TRACE_RLC_UM_SEGMENT
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),
((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) {
#if TRACE_RLC_UM_SEGMENT
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),
sdu_mngt_p,
sdu_mngt_p->sdu_remaining_size);
#endif
} else {
#if TRACE_RLC_UM_SEGMENT
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),
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) {
#if TRACE_RLC_UM_SEGMENT
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),
pdu_remaining_size);
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),
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) {
#if TRACE_RLC_UM_SEGMENT
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),
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);
free_mem_block (sdu_in_buffer, __func__);
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 ) {
#if TRACE_RLC_UM_SEGMENT
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),
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;
#if TRACE_RLC_UM_SEGMENT
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),
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;
}
//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;
#if TRACE_RLC_UM_SEGMENT
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),
e_li_p->b2,
e_li_p->b3,
fill_num_li,
test_num_li);
#endif
e_li_p++;
}
pdu_remaining_size = pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + li_length_in_bytes);
// free SDU
rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
free_mem_block (sdu_in_buffer, __func__);
sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
sdu_mngt_p = NULL;
} else {
#if TRACE_RLC_UM_SEGMENT
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),
sdu_mngt_p->sdu_remaining_size,
pdu_remaining_size - sdu_mngt_p->sdu_remaining_size);
#endif
//#if !EXMIMO
// assert(1!=1);
//#endif
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);
free_mem_block (sdu_in_buffer, __func__);
sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
sdu_mngt_p = NULL;
}
}
// 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;
}
pdu_p->b1 = (fi << 3); //pdu_p->b1 |
// set fist e bit
if (fill_num_li > 0) {
pdu_p->b1 = pdu_p->b1 | 0x04;
}
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);
#if TRACE_RLC_PAYLOAD
rlc_util_print_hex_octets(RLC, pdu_mem_p->data, data_pdu_size);
#endif
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;
//nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size;
nb_bytes_to_transmit = 0; // 1 PDU only
}
RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
}
//-----------------------------------------------------------------------------
void
rlc_um_segment_5 (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t *rlc_pP)
{
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) {
#if TRACE_RLC_UM_SEGMENT
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),
nb_bytes_to_transmit);
#endif
return;
}
list_init (&pdus, NULL); // param string identifying the list is NULL
pdu_mem_p = NULL;
RLC_UM_MUTEX_LOCK(&rlc_pP->lock_input_sdus, ctxt_pP, rlc_pP);
while ((list_get_head(&rlc_pP->input_sdus)) && (nb_bytes_to_transmit > 0)) {
#if TRACE_RLC_UM_SEGMENT
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),
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;
#if TRACE_RLC_UM_SEGMENT
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),
data_pdu_size);
#endif
} else {
data_pdu_size = nb_bytes_to_transmit;
#if TRACE_RLC_UM_SEGMENT
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),
data_pdu_size);
#endif
}
if (!(pdu_mem_p = get_free_mem_block (data_pdu_size + sizeof(struct mac_tb_req), __func__))) {
#if TRACE_RLC_UM_SEGMENT
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));
#endif
RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
return;
}
#if TRACE_RLC_UM_SEGMENT
LOG_D(RLC, PROTOCOL_RLC_UM_CTXT_FMT" get new PDU %d bytes\n",
PROTOCOL_RLC_UM_CTXT_ARGS(ctxt_pP,rlc_pP),
data_pdu_size);
#endif
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 {
#if TRACE_RLC_UM_SEGMENT
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),
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
}
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
//----------------------------------------
#if TRACE_RLC_UM_SEGMENT
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),
((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) {
#if TRACE_RLC_UM_SEGMENT
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),
sdu_mngt_p,
sdu_mngt_p->sdu_remaining_size);
#endif
} else {
#if TRACE_RLC_UM_SEGMENT
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),
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) {
#if TRACE_RLC_UM_SEGMENT
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),
pdu_remaining_size);
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),
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) {
#if TRACE_RLC_UM_SEGMENT
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),
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);
free_mem_block (sdu_in_buffer, __func__);
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 ) {
#if TRACE_RLC_UM_SEGMENT
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),
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;
#if TRACE_RLC_UM_SEGMENT
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),
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;
}
//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;
#if TRACE_RLC_UM_SEGMENT
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),
e_li_p->b2,
e_li_p->b3,
fill_num_li,
test_num_li);
#endif
e_li_p++;
}
pdu_remaining_size = pdu_remaining_size - (sdu_mngt_p->sdu_remaining_size + li_length_in_bytes);
// free SDU
rlc_pP->buffer_occupancy -= sdu_mngt_p->sdu_remaining_size;
sdu_in_buffer = list_remove_head(&rlc_pP->input_sdus);
free_mem_block (sdu_in_buffer, __func__);
sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
sdu_mngt_p = NULL;
} else {
#if TRACE_RLC_UM_SEGMENT
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),
sdu_mngt_p->sdu_remaining_size,
pdu_remaining_size - sdu_mngt_p->sdu_remaining_size);
#endif
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);
free_mem_block (sdu_in_buffer, __func__);
sdu_in_buffer = list_get_head(&rlc_pP->input_sdus);
sdu_mngt_p = NULL;
}
}
// 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;
}
pdu_p->b1 = (fi << 6); //pdu_p->b1 |
// set fist e bit
if (fill_num_li > 0) {
pdu_p->b1 = pdu_p->b1 | 0x20;
}
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);
#if TRACE_RLC_PAYLOAD
rlc_util_print_hex_octets(RLC, (unsigned char*)pdu_mem_p->data, data_pdu_size);
#endif
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;
//nb_bytes_to_transmit = nb_bytes_to_transmit - data_pdu_size;
nb_bytes_to_transmit = 0; // 1 PDU only
}
RLC_UM_MUTEX_UNLOCK(&rlc_pP->lock_input_sdus);
}