git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5156 818b1a75-f10b-46b9-bf7c-635c3b92a50f
600 lines
24 KiB
C
Executable File
600 lines
24 KiB
C
Executable File
/*******************************************************************************
|
|
Eurecom OpenAirInterface 2
|
|
Copyright(c) 1999 - 2014 Eurecom
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms and conditions of the GNU General Public License,
|
|
version 2, as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
The full GNU General Public License is included in this distribution in
|
|
the file called "COPYING".
|
|
|
|
Contact Information
|
|
Openair Admin: openair_admin@eurecom.fr
|
|
Openair Tech : openair_tech@eurecom.fr
|
|
Forums : http://forums.eurecom.fsr/openairinterface
|
|
Address : EURECOM,
|
|
Campus SophiaTech,
|
|
450 Route des Chappes,
|
|
CS 50193
|
|
06904 Biot Sophia Antipolis cedex,
|
|
FRANCE
|
|
*******************************************************************************/
|
|
/***************************************************************************
|
|
rlc_am_receiver.c -
|
|
-------------------
|
|
AUTHOR : Lionel GAUTHIER
|
|
COMPANY : EURECOM
|
|
EMAIL : Lionel.Gauthier@eurecom.fr
|
|
|
|
***************************************************************************/
|
|
#include "rtos_header.h"
|
|
#include "platform_types.h"
|
|
//-----------------------------------------------------------------------------
|
|
#include "rlc_am_entity.h"
|
|
#include "rlc_def.h"
|
|
#include "rlc_am_structs.h"
|
|
#include "rlc_am_constants.h"
|
|
#include "rlc_am_reassembly_proto_extern.h"
|
|
#include "rlc_am_proto_extern.h"
|
|
#include "rlc_am_util_proto_extern.h"
|
|
#include "mem_block.h"
|
|
|
|
//#define DEBUG_RECEIVER_BUFFER
|
|
//#define DEBUG_REASSEMBLY
|
|
//#define DEBUG_STATUS
|
|
//-----------------------------------------------------------------------------
|
|
void receiver_retransmission_management (struct rlc_am_entity *rlcP, mem_block_t * pduP, struct rlc_am_pdu_header *rlc_headerP);
|
|
void free_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP);
|
|
void insert_into_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP, mem_block_t * pduP);
|
|
void process_receiver_buffer_15 (struct rlc_am_entity *rlcP);
|
|
void process_receiver_buffer_7 (struct rlc_am_entity *rlcP);
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
receiver_retransmission_management (struct rlc_am_entity *rlcP, mem_block_t * pduP, struct rlc_am_pdu_header *rlc_headerP)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
|
|
uint16_t id;
|
|
uint16_t id_index;
|
|
|
|
/* From TS25.3222 V5.0.0
|
|
Upon reception of an AMD PDU, the Receiver shall:
|
|
- update VR(R), VR(H) and VR(MR) state variables for each received AMD PDU (see clause 9.4);
|
|
- if a received AMD PDU includes a "Polling bit" set to "1", or "Missing PDU Indicator" is configured and the
|
|
Receiver detects that a PDU is missing:
|
|
- initiate the STATUS PDU transfer procedure;
|
|
- reassemble the received AMD PDUs into RLC SDUs;
|
|
- if "In-Sequence Delivery" is configured:
|
|
- deliver the RLC SDUs in-sequence (i.e. in the same order as the RLC SDUs were originally transmitted by
|
|
the peer entity) to upper layers through the AM-SAP.
|
|
- otherwise: (NOT IMPLEMENTED)
|
|
- deliver the RLC SDUs in arbitrary order to upper layers through the AM-SAP. */
|
|
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg("[RLC_AM][DEBUG] receiver_retransmission_management() received PDU %p\n", pduP);
|
|
display_protocol_vars_rlc_am(rlcP);
|
|
#endif
|
|
|
|
id = (((uint16_t) (rlc_headerP->byte1 & RLC_AM_SN_1ST_PART_MASK)) << 5) | ((rlc_headerP->byte2 & RLC_AM_SN_2ND_PART_MASK) >> 3);
|
|
|
|
// general case
|
|
((struct rlc_am_rx_pdu_management *) (pduP->data))->sn = id;
|
|
|
|
id_index = id % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg("[RLC][RB %d][DEBUG] receiver_retransmission_management() received PDU %04X :\n", rlcP->rb_id, id);
|
|
//display_protocol_vars_rlc_am(rlcP);
|
|
#endif
|
|
|
|
// test poll bit for status pdu transmission;
|
|
if ((rlc_headerP->byte2 & RLC_AM_P_STATUS_REPORT_MASK) == RLC_AM_P_STATUS_REPORT_REQUESTED) {
|
|
rlcP->send_status_pdu_requested = 1;
|
|
#ifdef DEBUG_STATUS
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] STATUS REQUESTED BY PEER\n", rlcP->rb_id);
|
|
#endif
|
|
}
|
|
|
|
if (id == rlcP->vr_r) {
|
|
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p VR(R)=0x%04X id_index=0x%02X VR(H)=0x%04X\n", rlcP->rb_id, pduP, rlcP->vr_r, id_index, rlcP->vr_h);
|
|
#endif
|
|
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
|
// update vr_h;
|
|
if (rlcP->vr_h == id) {
|
|
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
|
}
|
|
adjust_vr_r_mr (rlcP);
|
|
} else {
|
|
|
|
rlcP->send_status_pdu_requested = 1;
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn=0x%04X id_index=0x%02X VR(R)=0x%04X VR(H)=0x%04X WILL SEND STATUS\n", rlcP->rb_id, pduP, id, id_index, rlcP->vr_r, rlcP->vr_h);
|
|
#endif
|
|
//------------------------------------;
|
|
// CASE VR(R)<VR(H)<VR(MR);
|
|
//------------------------------------;
|
|
if ((rlcP->vr_r <= rlcP->vr_h) && (rlcP->vr_h <= rlcP->vr_mr) && (id < rlcP->vr_mr) && (id > rlcP->vr_r)) {
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
|
|
|
// CASE VR(R)<VR(H)<id<VR(MR);
|
|
if (id >= rlcP->vr_h) {
|
|
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
|
}
|
|
//------------------------------------;
|
|
// CASE id<VR(MR)<VR(R)<VR(H);
|
|
//------------------------------------;
|
|
// CASE VR(MR)<VR(R)<VR(H)<id;
|
|
} else if (((rlcP->vr_mr < rlcP->vr_r) && (rlcP->vr_h >= rlcP->vr_r) && (id < rlcP->vr_mr)) || ((rlcP->vr_mr < rlcP->vr_r) && (rlcP->vr_h >= rlcP->vr_r) && (id > rlcP->vr_r))) {
|
|
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
|
if ((id >= rlcP->vr_h) || (id < rlcP->vr_mr)) {
|
|
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
|
}
|
|
//------------------------------------;
|
|
// CASE VR(H)<VR(MR)<VR(R);
|
|
//------------------------------------;
|
|
} else if ((rlcP->vr_h <= rlcP->vr_mr) && (rlcP->vr_mr < rlcP->vr_r)) {
|
|
if (id < rlcP->vr_mr) {
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
|
|
|
if (id >= rlcP->vr_h) {
|
|
rlcP->vr_h = (id + 1) & SN_12BITS_MASK;
|
|
}
|
|
} else if (id > rlcP->vr_r) {
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X IN REVERSED WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
insert_into_receiver_buffer (rlcP, id_index, pduP);
|
|
} else {
|
|
// discard this PDU;
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X OUT OF WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
rlcP->stat_rx_data_pdu_out_of_window += 1;
|
|
free_mem_block (pduP);
|
|
}
|
|
//------------------------------------;
|
|
// REJECT;
|
|
//------------------------------------;
|
|
} else {
|
|
// discard this PDU;
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] RECEIVED %p sn 0x%04X OUT OF WINDOW\n", rlcP->rb_id, pduP, id);
|
|
#endif
|
|
rlcP->stat_rx_data_pdu_out_of_window += 1;
|
|
free_mem_block (pduP);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
free_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
if (indexP < rlcP->recomputed_configured_rx_window_size) {
|
|
if (rlcP->receiver_buffer[indexP]) {
|
|
#ifdef DEBUG_FREE_RECEIVER_BUFFER
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] FREE PDU %p index 0x%4X\n", rlcP->rb_id, rlcP->receiver_buffer[indexP], indexP);
|
|
#endif
|
|
free_mem_block (rlcP->receiver_buffer[indexP]);
|
|
rlcP->receiver_buffer[indexP] = NULL;
|
|
}
|
|
return;
|
|
}
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR free_receiver_buffer() invalid index in array 0x%2X\n", rlcP->rb_id, indexP);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
insert_into_receiver_buffer (struct rlc_am_entity *rlcP, uint16_t indexP, mem_block_t * pduP)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
if (pduP) {
|
|
if (indexP < rlcP->recomputed_configured_rx_window_size) {
|
|
#ifdef DEBUG_RECEIVER_BUFFER
|
|
if (rlcP->receiver_buffer[indexP] != NULL) {
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() location is not NULL, index in array = 0x%2X\n", rlcP->rb_id, indexP);
|
|
display_protocol_vars_rlc_am (rlcP);
|
|
}
|
|
#endif
|
|
// last received is good
|
|
if (rlcP->receiver_buffer[indexP] != NULL) {
|
|
free_mem_block (rlcP->receiver_buffer[indexP]);
|
|
}
|
|
rlcP->receiver_buffer[indexP] = pduP;
|
|
return;
|
|
}
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() invalid index in array 0x%2X\n", rlcP->rb_id, indexP);
|
|
return;
|
|
}
|
|
msg ("[RLC_AM][RB %d][RECEIVER_BUFFER] ERROR insert_into_receiver_buffer() pdu is NULL index 0x%2X\n", rlcP->rb_id, indexP);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
process_receiver_buffer_15 (struct rlc_am_entity *rlcP)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
|
|
struct rlc_am_pdu_header *rlc_header;
|
|
mem_block_t *pdu;
|
|
uint16_t vr_r;
|
|
uint16_t working_sn;
|
|
uint16_t working_sn_index; // index in buffer
|
|
uint8_t *data_pdu;
|
|
uint16_t li[RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU];
|
|
uint16_t remaining_data_size;
|
|
uint8_t nb_li;
|
|
uint8_t li_index;
|
|
uint8_t li_start_index;
|
|
uint8_t reassembly_after_discard;
|
|
|
|
|
|
// should start reassembly with sn working_sn
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
vr_r = rlcP->vr_r;
|
|
reassembly_after_discard = 0;
|
|
while (rlcP->receiver_buffer[working_sn_index]) {
|
|
|
|
pdu = rlcP->receiver_buffer[working_sn_index];
|
|
nb_li = 0;
|
|
li_index = 0;
|
|
rlc_header = (struct rlc_am_pdu_header *) (((struct rlc_am_rx_pdu_management *) (pdu->data))->first_byte);
|
|
|
|
if ((rlcP->discard_reassembly_start_sn == ((struct rlc_am_rx_pdu_management *) (pdu->data))->sn)) {
|
|
|
|
rlcP->output_sdu_size_to_write = 0;
|
|
reassembly_after_discard = 1; // keep trace of entering in this block
|
|
|
|
if (!(rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
|
while ((li[nb_li] = ((((uint16_t) rlc_header->li_data_7[nb_li << 1]) << 8) + rlc_header->li_data_7[(nb_li << 1) + 1])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
|
|
|
li[nb_li] = li[nb_li] & (~(uint16_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
|
nb_li++;
|
|
}
|
|
nb_li++; // count the first li
|
|
}
|
|
// this variable may be changed by the reception of a mrw sufi
|
|
//li_start_index = rlcP->discard_reassembly_after_li + 1; // reassembly will start at this index
|
|
li_start_index = rlcP->discard_reassembly_after_li; // reassembly will start at this index
|
|
// after reception of sufi mrw the starting index for li will be 0
|
|
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0; // =-1
|
|
|
|
|
|
remaining_data_size = rlcP->pdu_size - 2 - (nb_li << 1);
|
|
data_pdu = (uint8_t *) (&rlc_header->li_data_7[nb_li << 1]);
|
|
|
|
while (li_index < nb_li) {
|
|
switch (li[li_index]) {
|
|
case RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
|
if (li_index >= li_start_index) {
|
|
send_sdu (rlcP);
|
|
}
|
|
break;
|
|
case RLC_LI_LAST_PDU_ONE_BYTE_SHORT:
|
|
if (li_index >= li_start_index) {
|
|
rlcP->output_sdu_size_to_write -= 1;
|
|
send_sdu (rlcP);
|
|
}
|
|
break;
|
|
case RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
|
case RLC_LI_PDU_PADDING:
|
|
remaining_data_size = 0;
|
|
break;
|
|
default: // li is length
|
|
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
|
if (li_index >= li_start_index) {
|
|
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
|
send_sdu (rlcP);
|
|
}
|
|
data_pdu = (uint8_t *) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
|
}
|
|
li_index++;
|
|
}
|
|
if ((remaining_data_size)) {
|
|
reassembly (data_pdu, remaining_data_size, rlcP);
|
|
remaining_data_size = 0;
|
|
}
|
|
|
|
|
|
free_receiver_buffer (rlcP, working_sn_index);
|
|
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID;
|
|
rlcP->last_reassemblied_sn = working_sn;
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
// patch to make the protocol working
|
|
// return 1 if sn1 > sn2
|
|
// return 0 if sn1 = sn2
|
|
// return -1 if sn1 < sn2
|
|
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
|
rlcP->vr_r = working_sn;
|
|
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
|
}
|
|
|
|
} else {
|
|
// exploit HE field info
|
|
if ((rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
|
reassembly ((uint8_t *) (rlc_header->li_data_7), rlcP->pdu_size - 2, rlcP);
|
|
} else {
|
|
while ((li[nb_li] = ((((uint16_t) rlc_header->li_data_7[nb_li << 1]) << 8) + rlc_header->li_data_7[(nb_li << 1) + 1])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
|
//while ((li[nb_li] = (rlc_header->li.li_data_15[nb_li].optional)) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
|
li[nb_li] = li[nb_li] & (~(uint16_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
|
nb_li++;
|
|
}
|
|
nb_li++;
|
|
|
|
remaining_data_size = rlcP->pdu_size - 2 - (nb_li << 1);
|
|
data_pdu = (uint8_t *) (&rlc_header->li_data_7[nb_li << 1]);
|
|
|
|
while (li_index < nb_li) {
|
|
switch (li[li_index]) {
|
|
case RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
|
send_sdu (rlcP);
|
|
break;
|
|
case RLC_LI_LAST_PDU_ONE_BYTE_SHORT:
|
|
rlcP->output_sdu_size_to_write -= 1;
|
|
send_sdu (rlcP);
|
|
break;
|
|
case RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
|
case RLC_LI_PDU_PADDING:
|
|
remaining_data_size = 0;
|
|
break;
|
|
default: // li is length
|
|
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
|
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
|
data_pdu = (uint8_t *) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
|
send_sdu (rlcP);
|
|
}
|
|
li_index++;
|
|
}
|
|
if ((remaining_data_size)) {
|
|
reassembly (data_pdu, remaining_data_size, rlcP);
|
|
remaining_data_size = 0;
|
|
}
|
|
}
|
|
free_receiver_buffer (rlcP, working_sn_index);
|
|
rlcP->last_reassemblied_sn = working_sn;
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
if ((reassembly_after_discard)) {
|
|
// return 1 if vr_r > working_sn
|
|
// return 0 if vr_r = working_sn
|
|
// return -1 if vr_r < working_sn
|
|
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
|
rlcP->vr_r = working_sn;
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X\n", rlcP->rb_id, rlcP->vr_r);
|
|
#endif
|
|
|
|
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void
|
|
process_receiver_buffer_7 (struct rlc_am_entity *rlcP)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
struct rlc_am_pdu_header *rlc_header;
|
|
mem_block_t *pdu;
|
|
uint16_t vr_r;
|
|
uint16_t working_sn;
|
|
uint16_t working_sn_index; // index in buffer
|
|
uint8_t *data_pdu;
|
|
uint8_t li[RLC_AM_SEGMENT_NB_MAX_LI_PER_PDU];
|
|
uint16_t remaining_data_size;
|
|
int8_t nb_li;
|
|
int8_t li_index;
|
|
int8_t li_start_index;
|
|
uint8_t reassembly_after_discard;
|
|
uint8_t sdu_sent=0;
|
|
|
|
// should start reassembly with sn working_sn
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
vr_r = rlcP->vr_r;
|
|
|
|
reassembly_after_discard = 0;
|
|
|
|
while (rlcP->receiver_buffer[working_sn_index]) {
|
|
|
|
pdu = rlcP->receiver_buffer[working_sn_index];
|
|
nb_li = 0;
|
|
li_index = 0;
|
|
rlc_header = (struct rlc_am_pdu_header *) (((struct rlc_am_rx_pdu_management *) (pdu->data))->first_byte);
|
|
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU %p SN 0x%04X (sdu_sent %d)\n", rlcP->rb_id, pdu, working_sn,sdu_sent);
|
|
#endif
|
|
if ((rlcP->discard_reassembly_start_sn == ((struct rlc_am_rx_pdu_management *) (pdu->data))->sn)) {
|
|
rlcP->output_sdu_size_to_write = 0;
|
|
reassembly_after_discard = 1; // keep trace of entering in this block
|
|
|
|
if (!(rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
|
while ((li[nb_li] = (rlc_header->li_data_7[nb_li])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
|
li[nb_li] = li[nb_li] & (~(uint8_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
|
nb_li++;
|
|
}
|
|
nb_li++; // count the first li
|
|
}
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU TO BE REASSEMBLIED AFTER DISCARD, START SN 0x%04X hex VR(R) 0x%04X\n", rlcP->rb_id, rlcP->discard_reassembly_start_sn, rlcP->vr_r);
|
|
#endif
|
|
|
|
// this variable may be changed by the reception of a mrw sufi
|
|
//li_start_index = rlcP->discard_reassembly_after_li + 1; // reassembly will start at this index
|
|
li_start_index = rlcP->discard_reassembly_after_li; // reassembly will start at this index
|
|
// after reception of sufi mrw the starting index for li will be 0
|
|
rlcP->discard_reassembly_after_li = RLC_AM_DISCARD_REASSEMBLY_AT_LI_INDEX_0; // =-1
|
|
|
|
remaining_data_size = rlcP->pdu_size - 2 - (nb_li);
|
|
data_pdu = (uint8_t *) (&rlc_header->li_data_7[nb_li]);
|
|
|
|
while (li_index < nb_li) {
|
|
switch (li[li_index]) {
|
|
case (uint8_t) RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_LAST_PDU_EXACTLY_FILLED REMAINING DATA SIZE %d, li_index %d, li_start_index %d\n", rlcP->rb_id, working_sn, remaining_data_size, li_index, li_start_index);
|
|
#endif
|
|
if (li_index >= li_start_index) {
|
|
send_sdu (rlcP);
|
|
sdu_sent=1;
|
|
}
|
|
break;
|
|
case (uint8_t) RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
|
case (uint8_t) RLC_LI_PDU_PADDING:
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_PDU_PADDING\n", rlcP->rb_id, working_sn);
|
|
#endif
|
|
remaining_data_size = 0;
|
|
break;
|
|
default: // li is length
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI SIZE %d\n", rlcP->rb_id, working_sn, li[li_index] >> 1);
|
|
#endif
|
|
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
|
if (li_index >= li_start_index) {
|
|
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
|
send_sdu (rlcP);
|
|
sdu_sent=1;
|
|
}
|
|
data_pdu = (uint8_t *) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
|
}
|
|
li_index++;
|
|
}
|
|
|
|
if ((remaining_data_size)) {
|
|
reassembly (data_pdu, remaining_data_size, rlcP);
|
|
remaining_data_size = 0;
|
|
}
|
|
|
|
free_receiver_buffer (rlcP, working_sn_index);
|
|
rlcP->discard_reassembly_start_sn = RLC_AM_SN_INVALID;
|
|
rlcP->last_reassemblied_sn = working_sn;
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
// return 1 if vr_r > working_sn
|
|
// return 0 if vr_r = working_sn
|
|
// return -1 if vr_r < working_sn
|
|
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
|
rlcP->vr_r = working_sn;
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X hex\n", rlcP->rb_id, rlcP->vr_r);
|
|
#endif
|
|
|
|
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
|
}
|
|
|
|
} else {
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg("[RLC][AM] Reassembly, No discard. rlc_header->byte2 %d\n");
|
|
#endif
|
|
// exploit HE field info
|
|
if ((rlc_header->byte2 & RLC_HE_MASK) == RLC_HE_SUCC_BYTE_CONTAINS_DATA) {
|
|
msg("WILL REASSEMBLY INDEX %04X\n", working_sn_index);
|
|
reassembly ((uint8_t *) (rlc_header->li_data_7), rlcP->pdu_size - 2, rlcP);
|
|
} else {
|
|
while ((li[nb_li] = (rlc_header->li_data_7[nb_li])) & RLC_E_NEXT_FIELD_IS_LI_E) {
|
|
li[nb_li] = li[nb_li] & (~(uint8_t) RLC_E_NEXT_FIELD_IS_LI_E);
|
|
nb_li++;
|
|
}
|
|
nb_li++;
|
|
|
|
remaining_data_size = rlcP->pdu_size - 2 - nb_li;
|
|
data_pdu = (uint8_t *) (&rlc_header->li_data_7[nb_li]);
|
|
|
|
while (li_index < nb_li) {
|
|
|
|
switch (li[li_index]) {
|
|
case (uint8_t) RLC_LI_LAST_PDU_EXACTLY_FILLED:
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_LAST_PDU_EXACTLY_FILLED NUM LI %d\n", rlcP->rb_id, working_sn,nb_li);
|
|
#endif
|
|
send_sdu (rlcP);
|
|
|
|
sdu_sent=1;
|
|
break;
|
|
case (uint8_t) RLC_LI_PDU_PIGGY_BACKED_STATUS: // ignore
|
|
case (uint8_t) RLC_LI_PDU_PADDING:
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI RLC_LI_PDU_PADDING\n", rlcP->rb_id, working_sn);
|
|
#endif
|
|
remaining_data_size = 0;
|
|
break;
|
|
default: // li is length
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] PDU SN 0x%04X GET LI SIZE %d Bytes\n", rlcP->rb_id, working_sn, li[li_index] >> 1);
|
|
#endif
|
|
remaining_data_size = remaining_data_size - (li[li_index] >> 1);
|
|
|
|
reassembly (data_pdu, (li[li_index] >> 1), rlcP);
|
|
data_pdu = (uint8_t *) ((uint32_t) data_pdu + (li[li_index] >> 1));
|
|
send_sdu (rlcP);
|
|
sdu_sent=1;
|
|
}
|
|
li_index++;
|
|
}
|
|
if ((remaining_data_size)) {
|
|
//msg("WILL REASSEMBLY INDEX %04X\n", working_sn_index);
|
|
reassembly (data_pdu, remaining_data_size, rlcP);
|
|
remaining_data_size = 0;
|
|
}
|
|
}
|
|
free_receiver_buffer (rlcP, working_sn_index);
|
|
rlcP->last_reassemblied_sn = working_sn;
|
|
working_sn = (rlcP->last_reassemblied_sn + 1) & SN_12BITS_MASK;
|
|
working_sn_index = working_sn % rlcP->recomputed_configured_rx_window_size;
|
|
|
|
if ((reassembly_after_discard)) {
|
|
// return 1 if vr_r > working_sn
|
|
// return 0 if vr_r = working_sn
|
|
// return -1 if vr_r < working_sn
|
|
if (rlc_am_comp_sn (rlcP, rlcP->vr_r, rlcP->vr_r, working_sn) < 0) {
|
|
rlcP->vr_r = working_sn;
|
|
#ifdef DEBUG_REASSEMBLY
|
|
msg ("[RLC_AM][RB %d][REASSEMBLY] DETECTED PDU AFTER DISCARD ADJUST VR(R) 0x%04X\n", rlcP->rb_id, rlcP->vr_r);
|
|
#endif
|
|
|
|
rlcP->vr_mr = (rlcP->vr_r + rlcP->configured_rx_window_size - 1) & SN_12BITS_MASK;
|
|
}
|
|
}
|
|
}
|
|
msg("receiver_buffer[%d] %p (sdu_sent %d)\n",working_sn_index,rlcP->receiver_buffer[working_sn_index],sdu_sent);
|
|
}
|
|
// if (sdu_sent == 0) {
|
|
// msg("[RLC_AM][RB %d][REASSEMBLY] Forcing send_sdu (sent_sdu == 0)\n",rlcP->rb_id);
|
|
// send_sdu(rlcP);
|
|
// }
|
|
}
|