Commit 353334f6 authored by fnabet's avatar fnabet

RLC AM Rx PDU Segment changes

parent 01530385
...@@ -35,34 +35,72 @@ boolean_t rlc_am_rx_check_vr_reassemble( ...@@ -35,34 +35,72 @@ boolean_t rlc_am_rx_check_vr_reassemble(
const protocol_ctxt_t* const ctxt_pP, const protocol_ctxt_t* const ctxt_pP,
const rlc_am_entity_t* const rlc_pP) const rlc_am_entity_t* const rlc_pP)
{ {
mem_block_t* cursor_p = NULL; mem_block_t* cursor_p = rlc_pP->receiver_buffer.head;
cursor_p = rlc_pP->receiver_buffer.head; rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = NULL;
sdu_size_t next_waited_so = 0;
boolean_t reassemble = FALSE; boolean_t reassemble = FALSE;
if (cursor_p != NULL) { if (cursor_p != NULL) {
rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
rlc_usn_t sn_ref = pdu_info_p->sn; rlc_usn_t sn_ref = pdu_info_p->sn;
if (sn_ref != rlc_pP->vr_r) { if (sn_ref != rlc_pP->vr_r) {
/* Case vrR has advanced from head : most likely case */
reassemble = TRUE; reassemble = TRUE;
/* Handle first SN if it is made of PDU segments : set them all to be reassembled */
if (pdu_info_p->rf) {
pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
next_waited_so = 0;
AssertFatal(pdu_cursor_mgnt_p->all_segments_received > 0,"AM Rx Check Reassembly head SN=%d with PDU segments != vrR=%d should be fully received LCID=%d\n",
sn_ref,rlc_pP->vr_r,rlc_pP->channel_id);
while ((cursor_p != NULL) && (pdu_info_p->sn == sn_ref) && (pdu_info_p->so == next_waited_so)) {
if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) {
pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING;
}
next_waited_so += pdu_info_p->payload_size;
cursor_p = cursor_p->next;
if (cursor_p != NULL) {
pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
}
} }
/* jump up to vrR */ /* Now jump up to vrR */
while ((RLC_AM_DIFF_SN(pdu_info_p->sn,sn_ref) < RLC_AM_DIFF_SN(rlc_pP->vr_r,sn_ref)) && (cursor_p != NULL)) { while ((RLC_AM_DIFF_SN(pdu_info_p->sn,sn_ref) < RLC_AM_DIFF_SN(rlc_pP->vr_r,sn_ref)) && (cursor_p != NULL)) {
if ((pdu_info_p->rf) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO)) {
((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING;
}
cursor_p = cursor_p->next; cursor_p = cursor_p->next;
if (cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
} }
/* Handle vrR if it is made of incomplete PDU Segments */
if ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r)) { if ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r)) {
pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
next_waited_so = 0;
AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received SNHead=%d LCID=%d\n",
rlc_pP->vr_r,sn_ref,rlc_pP->channel_id);
while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) {
if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) {
pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING;
}
next_waited_so += pdu_info_p->payload_size;
cursor_p = cursor_p->next;
if (cursor_p != NULL) {
pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
}
}
} /* end sn_ref != rlc_pP->vr_r */
else {
/* case vrR = partially received */ /* case vrR = partially received */
rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
sdu_size_t next_waited_so = 0; pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received LCID=%d\n", next_waited_so = 0;
AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly SNHead=vr=%d should be partly received LCID=%d\n",
rlc_pP->vr_r,rlc_pP->channel_id); rlc_pP->vr_r,rlc_pP->channel_id);
while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) { while ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r) && (pdu_info_p->so == next_waited_so)) {
if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) { if (pdu_cursor_mgnt_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO) {
...@@ -76,8 +114,7 @@ boolean_t rlc_am_rx_check_vr_reassemble( ...@@ -76,8 +114,7 @@ boolean_t rlc_am_rx_check_vr_reassemble(
pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
} }
} } /*end sn_ref == rlc_pP->vr_r */
} }
return reassemble; return reassemble;
} }
...@@ -287,9 +324,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( ...@@ -287,9 +324,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment(
mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; mem_block_t* cursor_p = rlc_pP->receiver_buffer.head;
mem_block_t* previous_cursor_p = NULL; mem_block_t* previous_cursor_p = NULL;
mem_block_t* next_cursor_p = NULL; mem_block_t* next_cursor_p = NULL;
boolean_t prev_segment_found = FALSE; uint16_t so_start_min = 0;
boolean_t next_segment_found = FALSE;
uint16_t so_start = 0;
uint16_t so_end = 0; uint16_t so_end = 0;
uint16_t so_start_segment = pdu_rx_info_p->so; uint16_t so_start_segment = pdu_rx_info_p->so;
uint16_t so_end_segment = pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1; uint16_t so_end_segment = pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1;
...@@ -334,120 +369,217 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( ...@@ -334,120 +369,217 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment(
return RLC_AM_DATA_PDU_STATUS_OK; return RLC_AM_DATA_PDU_STATUS_OK;
} }
/********************************************/
/* Now handle case cursor->sn = received SN */ /* Now handle case cursor->sn = received SN */
// Filter out SN duplicate /********************************************/
rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data);
// Filter out SN duplicate
if (pdu_cursor_mgnt_p->all_segments_received) { if (pdu_cursor_mgnt_p->all_segments_received) {
return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE;
} }
// Handle the remaining case : some PDU Segments already received for the same SN // Try to Handle the most likely cases first
// Try to insert the PDU according to its SO and SO+datalength of stored ones if (pdu_info_cursor_p->so == 0) {
// First find the segment just before the pdu to insert
while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { /* Loop on stored segments and find the stored segment containing received SOStart */
if (pdu_rx_info_p->so < pdu_info_cursor_p->so) { previous_cursor_p = cursor_p;
prev_segment_found = TRUE; pdu_info_previous_cursor_p = pdu_info_cursor_p;
break; while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)
&& ((pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size) <= so_start_segment)) {
previous_cursor_p = cursor_p;
pdu_info_previous_cursor_p = pdu_info_cursor_p;
cursor_p = cursor_p->next;
if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
}
// Most likely case : no duplicate, the segment is put after all stored segments which are contiguous
if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) || (pdu_info_cursor_p->so > so_end_segment)) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d] PDU SEGMENT INSERTED AFTER PDU SEGMENT WITH SOEND=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment,
pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1);
list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer);
return RLC_AM_DATA_PDU_STATUS_OK;
} }
// Duplicate case : Resume contiguous scan and update previous_cursor_p
so_start_min = pdu_info_previous_cursor_p->so;
so_end = so_start_min + pdu_info_previous_cursor_p->payload_size;
cursor_p = previous_cursor_p->next;
if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
}
while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)
&& (pdu_info_cursor_p->so == so_end)) {
previous_cursor_p = cursor_p; previous_cursor_p = cursor_p;
pdu_info_previous_cursor_p = pdu_info_cursor_p; pdu_info_previous_cursor_p = pdu_info_cursor_p;
so_end += pdu_info_cursor_p->payload_size;
cursor_p = cursor_p->next; cursor_p = cursor_p->next;
if (cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
} }
/* if not previously inserted, it will be put after the last segment if it was not LSF*/ /* Now discard the PDU segment if it is within so_start_min and so_end */
if (!prev_segment_found) { if ((so_start_min <= so_start_segment) && (so_end_segment < so_end)) {
if (pdu_info_previous_cursor_p->lsf == 0) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n",
prev_segment_found = TRUE; PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn);
next_segment_found = TRUE; // no more segment after the PDU return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE;
}
// Discard potential embedded segments in the received PDU segment
// The first one is discontigous
next_cursor_p = cursor_p; next_cursor_p = cursor_p;
AssertFatal(previous_cursor_p->next == next_cursor_p,"AM Rx PDU Segment store at the end error, SN=%d \n",pdu_rx_info_p->sn); while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) &&
(so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) {
/* Discard the segment */
cursor_p = next_cursor_p;
next_cursor_p = next_cursor_p->next;
list2_remove_element (cursor_p, &rlc_pP->receiver_buffer);
free_mem_block(cursor_p, __func__);
if (next_cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
} }
else
{
// the segment is duplicate
return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE;
} }
cursor_p = next_cursor_p;
//Remove duplicate at the begining
if (so_start_segment < pdu_info_previous_cursor_p->so) {
so_start_segment = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size;
}
else if (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size){
so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment);
} }
// Now remove duplicate at the end, only valid if cursor_p SN has the same received SN
if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
// Check that the Segment is not duplicate by scanning stored contiguous segments from previous_cursor_p if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) {
if ((previous_cursor_p != NULL) && (pdu_info_previous_cursor_p->sn == pdu_rx_info_p->sn)) { so_end_segment = pdu_info_cursor_p->so - 1;
}
}
so_start = pdu_info_previous_cursor_p->so; AssertFatal((so_start_segment <= so_end_segment) && (pdu_rx_info_p->so <= so_start_segment) &&
so_end = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1; (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1),
" AM RX PDU Segment Duplicate elimination error FirstSO=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n",
pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn);
pdu_info_cursor_p = pdu_info_previous_cursor_p; } // end pdu_info_cursor_p->so == 0
cursor_p = previous_cursor_p->next; else {
rlc_am_pdu_info_t* pdu_info_cursor_next_p = NULL; // Handle most likely case : PDU Segment without duplicate is inserted before first stored PDU segment
if (cursor_p != NULL) { if (so_end_segment < pdu_info_cursor_p->so) {
pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d SOEND=%d] PDU SEGMENT INSERTED BEFORE PDU SEGMENT WITH SOSTART=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment,so_end_segment,
pdu_info_cursor_p->so);
list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer);
return RLC_AM_DATA_PDU_STATUS_OK;
} }
while ((cursor_p != NULL) && (pdu_info_cursor_next_p->sn == pdu_rx_info_p->sn) // Handle duplicate case
&& (pdu_info_cursor_next_p->so == pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size)) { if (so_start_segment < pdu_info_cursor_p->so) {
so_end += pdu_info_cursor_next_p->payload_size; // First Case : only duplicate at the end
pdu_info_cursor_p = pdu_info_cursor_next_p; // Scan for embedded segments to be discarded
cursor_p = cursor_p->next; next_cursor_p = cursor_p;
while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) &&
(so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) {
/* Discard the segment */
cursor_p = next_cursor_p;
next_cursor_p = next_cursor_p->next;
list2_remove_element (cursor_p, &rlc_pP->receiver_buffer);
free_mem_block(cursor_p, __func__);
if (next_cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
}
}
cursor_p = next_cursor_p;
// Now remove duplicate at the end, only valid if cursor_p SN has the same received SN
if (cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) {
so_end_segment = pdu_info_cursor_p->so - 1;
} }
} }
/* Now discard the PDU segment if it is within so_start so_end */ AssertFatal((so_start_segment <= so_end_segment) &&
if ((so_start <= so_start_segment) && (so_end_segment <= so_end)) { (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1),
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n", " AM RX PDU Segment Duplicate elimination at the end error FirstSO!=0 SOStart=%d OldSOEnd=%d newSOEnd =%d SN=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_end_segment,pdu_rx_info_p->sn);
return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE;
}
else {
// Second Case: Duplicate at the begining and potentially at the end
/* Loop on stored segments and find the stored segment containing received SOStart */
previous_cursor_p = cursor_p;
pdu_info_previous_cursor_p = pdu_info_cursor_p;
while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)
&& ((pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size) <= so_start_segment)) {
previous_cursor_p = cursor_p;
pdu_info_previous_cursor_p = pdu_info_cursor_p;
cursor_p = cursor_p->next;
if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
} }
// Most likely case : no duplicate, the segment is put after all stored segments which are contiguous
if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) || (pdu_info_cursor_p->so > so_end_segment)) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d SOSTART=%d] PDU SEGMENT INSERTED AFTER PDU SEGMENT WITH SOEND=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,so_start_segment,
pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1);
// Now found the segment which will be right after the pdu to insert list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer);
if (!next_segment_found) { return RLC_AM_DATA_PDU_STATUS_OK;
/* special case if SN=vrR and some segments have been previously reassembled and not yet discarded */ }
/* update previous_cursor_p up to the last reassembled Segment */
if ((previous_cursor_p != NULL) && (pdu_rx_info_p->sn == rlc_pP->vr_r)) { // Now look for contiguous segments to check whether the received segment is not fully duplicate
if (((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) { so_start_min = pdu_info_previous_cursor_p->so;
pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info; so_end = so_start_min + pdu_info_previous_cursor_p->payload_size;
so_end = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size;
cursor_p = previous_cursor_p->next; cursor_p = previous_cursor_p->next;
if (cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)
while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && && (pdu_info_cursor_p->so == so_end)) {
(((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED)) {
AssertFatal(pdu_info_cursor_p->so == so_end,"AM Rx PDU Segment store contiguous reassembled error, SN=%d \n",pdu_rx_info_p->sn);
so_end += pdu_info_cursor_p->payload_size;
previous_cursor_p = cursor_p; previous_cursor_p = cursor_p;
pdu_info_previous_cursor_p = pdu_info_cursor_p;
so_end += pdu_info_cursor_p->payload_size;
cursor_p = cursor_p->next; cursor_p = cursor_p->next;
if (cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
} }
} }
}
/* Now discard the PDU segment if it is within so_start_min and so_end */
if ((so_start_min <= so_start_segment) && (so_end_segment < so_end)) {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] DISCARD : DUPLICATE SEGMENT SN=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn);
return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE;
} }
if (previous_cursor_p != NULL) { //Remove duplicate at the begining
cursor_p = previous_cursor_p->next; if (so_start_segment < pdu_info_previous_cursor_p->so) {
so_start_segment = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size;
} }
else { else if (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size){
cursor_p = rlc_pP->receiver_buffer.head; so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment);
} }
next_cursor_p = cursor_p;
if (next_cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
}
// Discard embedded segments in the received PDU segment // Now Scan for embedded segments to be discarded
next_cursor_p = cursor_p;
while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) &&
(pdu_rx_info_p->so + pdu_rx_info_p->payload_size >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size)) { (so_end_segment >= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) {
/* Discard the segment */ /* Discard the segment */
cursor_p = next_cursor_p; cursor_p = next_cursor_p;
next_cursor_p = next_cursor_p->next; next_cursor_p = next_cursor_p->next;
...@@ -458,19 +590,10 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( ...@@ -458,19 +590,10 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment(
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
} }
} }
} cursor_p = next_cursor_p;
/* Now remove duplicate bytes */
// remove duplicate at the begining, only valid if the segment is to be inserted after a PDU segment of the same SN
if (previous_cursor_p != NULL) {
pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info;
if ((pdu_info_previous_cursor_p->sn == pdu_rx_info_p->sn) && (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size)) {
so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment);
}
}
// remove duplicate at the end // Now remove duplicate at the end, only valid if cursor_p SN has the same received SN
if (next_cursor_p != NULL) { if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) { if ((pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (so_end_segment >= pdu_info_cursor_p->so)) {
...@@ -478,15 +601,19 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( ...@@ -478,15 +601,19 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment(
} }
} }
AssertFatal((so_start_segment <= so_end_segment) && (pdu_rx_info_p->so <= so_start_segment) && AssertFatal((so_start_segment <= so_end_segment) && (pdu_rx_info_p->so <= so_start_segment) &&
(so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1),
" AM RX PDU Segment Duplicate elimination error OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n", " AM RX PDU Segment Duplicate elimination error FirstSO!=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n",
pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn); pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn);
}
/* Last step : Insertion */ } // end pdu_info_cursor_p->so != 0
/* If some duplicate bytes had been removed, build a new PDU segment */
if ((pdu_rx_info_p->so != so_start_segment) || (so_end_segment != pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1)) {
/* Last step : duplicate bytes had been removed, build a new PDU segment */
AssertFatal((pdu_rx_info_p->so != so_start_segment) || (so_end_segment != pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1),
" AM RX PDU Segment Duplicate elimination error FirstSO!=0 OldSOStart=%d OldSOEnd=%d newSOStart=%d newSOEnd =%d SN=%d\n",
pdu_rx_info_p->so,pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1,so_start_segment,so_end_segment,pdu_rx_info_p->sn);
mem_block_t* trunc_segment = create_new_segment_from_pdu(tb_pP,so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1); mem_block_t* trunc_segment = create_new_segment_from_pdu(tb_pP,so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1);
if (trunc_segment != NULL) { if (trunc_segment != NULL) {
...@@ -508,25 +635,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( ...@@ -508,25 +635,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment(
else { else {
return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL;
} }
}
else
{
if (previous_cursor_p != NULL) {
pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info;
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d NOT EMPTY] PDU SEGMENT INSERTED AFTER PDU SN=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,
pdu_info_previous_cursor_p->sn);
list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer);
}
else {
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d NOT EMPTY] PDU SEGMENT INSERTED BEFORE PDU SN=%d\n",
PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn,
pdu_rx_info_p->sn);
list2_insert_before_element(tb_pP, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer);
}
return RLC_AM_DATA_PDU_STATUS_OK;
}
} }
rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu(
...@@ -1316,10 +1425,12 @@ rlc_am_rx_list_reassemble_rlc_sdus( ...@@ -1316,10 +1425,12 @@ rlc_am_rx_list_reassemble_rlc_sdus(
} }
/* Reset Management pointers */ /* Reset Management pointers */
if ((cursor_p != NULL) && if (cursor_p != NULL) {
((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == RLC_AM_NEXT_SN(sn)) ||
(((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING))) {
rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data));
/* Next SN must be the same or SN+1 */
if (RLC_AM_DIFF_SN(rlc_am_rx_pdu_management_p->pdu_info.sn,sn) > 1) {
return;
}
} }
else { else {
return; return;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment