/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that 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 OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see <http://www.gnu.org/licenses/>. Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ #define RLC_UM_MODULE #define RLC_UM_DAR_C #include "platform_types.h" #include "assertions.h" //----------------------------------------------------------------------------- #include "rlc.h" #include "rlc_um.h" #include "rlc_primitives.h" #include "mac_primitives.h" #include "list.h" #include "MAC_INTERFACE/extern.h" #include "UTIL/LOG/log.h" #define TRACE_RLC_UM_DAR 1 //#define TRACE_RLC_UM_RX 1 //----------------------------------------------------------------------------- signed int rlc_um_get_pdu_infos( const frame_t frameP, rlc_um_pdu_sn_10_t * const header_pP, const sdu_size_t total_sizeP, rlc_um_pdu_info_t * const pdu_info_pP, const uint8_t sn_lengthP) //----------------------------------------------------------------------------- { sdu_size_t sum_li = 0; memset(pdu_info_pP, 0, sizeof (rlc_um_pdu_info_t)); pdu_info_pP->num_li = 0; AssertFatal( total_sizeP > 0 , "RLC UM PDU LENGTH %d", total_sizeP); if (sn_lengthP == 10) { pdu_info_pP->fi = (header_pP->b1 >> 3) & 0x03; pdu_info_pP->e = (header_pP->b1 >> 2) & 0x01; pdu_info_pP->sn = header_pP->b2 + (((uint16_t)(header_pP->b1 & 0x03)) << 8); pdu_info_pP->header_size = 2; pdu_info_pP->payload = &header_pP->data[0]; } else if (sn_lengthP == 5) { pdu_info_pP->fi = (header_pP->b1 >> 6) & 0x03; pdu_info_pP->e = (header_pP->b1 >> 5) & 0x01; pdu_info_pP->sn = header_pP->b1 & 0x1F; pdu_info_pP->header_size = 1; pdu_info_pP->payload = &header_pP->b2; } else { AssertFatal( sn_lengthP == 5 || sn_lengthP == 10, "RLC UM SN LENGTH %d", sn_lengthP); } if (pdu_info_pP->e) { rlc_am_e_li_t *e_li_p; unsigned int li_length_in_bytes = 1; unsigned int li_to_read = 1; e_li_p = (rlc_am_e_li_t*)(pdu_info_pP->payload); while (li_to_read) { li_length_in_bytes = li_length_in_bytes ^ 3; if (li_length_in_bytes == 2) { AssertFatal( total_sizeP >= ((uint64_t)(&e_li_p->b2) - (uint64_t)header_pP), "DECODING PDU TOO FAR PDU size %d", total_sizeP); pdu_info_pP->li_list[pdu_info_pP->num_li] = ((uint16_t)(e_li_p->b1 << 4)) & 0x07F0; pdu_info_pP->li_list[pdu_info_pP->num_li] |= (((uint8_t)(e_li_p->b2 >> 4)) & 0x000F); li_to_read = e_li_p->b1 & 0x80; pdu_info_pP->header_size += 2; } else { AssertFatal( total_sizeP >= ((uint64_t)(&e_li_p->b3) - (uint64_t)header_pP), "DECODING PDU TOO FAR PDU size %d", total_sizeP); pdu_info_pP->li_list[pdu_info_pP->num_li] = ((uint16_t)(e_li_p->b2 << 8)) & 0x0700; pdu_info_pP->li_list[pdu_info_pP->num_li] |= e_li_p->b3; li_to_read = e_li_p->b2 & 0x08; e_li_p++; pdu_info_pP->header_size += 1; } AssertFatal( pdu_info_pP->num_li <= RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU, "[FRAME %05u][RLC_UM][MOD XX][RB XX][GET PDU INFO] SN %04d TOO MANY LIs ", frameP, pdu_info_pP->sn); sum_li += pdu_info_pP->li_list[pdu_info_pP->num_li]; pdu_info_pP->num_li = pdu_info_pP->num_li + 1; if (pdu_info_pP->num_li > RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU) { return -2; } } if (li_length_in_bytes == 2) { pdu_info_pP->payload = &e_li_p->b3; } else { pdu_info_pP->payload = &e_li_p->b1; } } pdu_info_pP->payload_size = total_sizeP - pdu_info_pP->header_size; if (pdu_info_pP->payload_size > sum_li) { pdu_info_pP->hidden_size = pdu_info_pP->payload_size - sum_li; } return 0; } //----------------------------------------------------------------------------- int rlc_um_read_length_indicators(unsigned char**data_ppP, rlc_um_e_li_t* e_liP, unsigned int* li_array_pP, unsigned int *num_li_pP, sdu_size_t *data_size_pP) { //----------------------------------------------------------------------------- int continue_loop = 1; unsigned int e1 = 0; unsigned int li1 = 0; unsigned int e2 = 0; unsigned int li2 = 0; *num_li_pP = 0; while ((continue_loop)) { //msg("[RLC_UM] e_liP->b1 = %02X\n", e_liP->b1); //msg("[RLC_UM] e_liP->b2 = %02X\n", e_liP->b2); e1 = ((unsigned int)e_liP->b1 & 0x00000080) >> 7; li1 = (((unsigned int)e_liP->b1 & 0x0000007F) << 4) + (((unsigned int)e_liP->b2 & 0x000000F0) >> 4); li_array_pP[*num_li_pP] = li1; *data_size_pP = *data_size_pP - li1 - 2; *num_li_pP = *num_li_pP +1; if ((e1)) { e2 = ((unsigned int)e_liP->b2 & 0x00000008) >> 3; li2 = (((unsigned int)e_liP->b2 & 0x00000007) << 8) + ((unsigned int)e_liP->b3 & 0x000000FF); li_array_pP[*num_li_pP] = li2; *data_size_pP = *data_size_pP - li2 - 1; *num_li_pP = *num_li_pP +1; if (e2 == 0) { continue_loop = 0; } else { e_liP++; } } else { continue_loop = 0; } if (*num_li_pP >= RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU) { return -1; } } *data_ppP = *data_ppP + (((*num_li_pP*3) +1) >> 1); return 0; } //----------------------------------------------------------------------------- void rlc_um_try_reassembly(rlc_um_entity_t *rlc_pP, frame_t frameP, eNB_flag_t eNB_flagP, rlc_sn_t start_snP, rlc_sn_t end_snP) { //----------------------------------------------------------------------------- mem_block_t *pdu_mem_p = NULL; struct mac_tb_ind *tb_ind_p = NULL; rlc_um_e_li_t *e_li_p = NULL; unsigned char *data_p = NULL; int e = 0; int fi = 0; sdu_size_t size = 0; rlc_sn_t sn = 0; unsigned int continue_reassembly = 0; unsigned int num_li = 0; unsigned int li_array[RLC_UM_SEGMENT_NB_MAX_LI_PER_PDU]; int i = 0; int reassembly_start_index = 0; if (end_snP < 0) end_snP = end_snP + rlc_pP->rx_sn_modulo; if (start_snP < 0) start_snP = start_snP + rlc_pP->rx_sn_modulo; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY FROM PDU SN=%03d+1 TO PDU SN=%03d SN Length = %d bits\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->last_reassemblied_sn, end_snP, rlc_pP->rx_sn_length); #endif // nothing to be reassemblied if (start_snP == end_snP) { return; } continue_reassembly = 1; //sn = (rlc_pP->last_reassemblied_sn + 1) % rlc_pP->rx_sn_modulo; sn = start_snP; //check_mem_area(); while (continue_reassembly) { if ((pdu_mem_p = rlc_pP->dar_buffer[sn])) { if ((rlc_pP->last_reassemblied_sn+1)%rlc_pP->rx_sn_modulo != sn) { #if defined (TRACE_RLC_UM_DAR) LOG_W(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] FINDING a HOLE in RLC UM SN: CLEARING OUTPUT SDU BECAUSE NEW SN (%03d) TO REASSEMBLY NOT CONTIGUOUS WITH LAST REASSEMBLIED SN (%03d)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, rlc_pP->last_reassemblied_sn); #endif rlc_um_clear_rx_sdu(rlc_pP); } rlc_pP->last_reassemblied_sn = sn; tb_ind_p = (struct mac_tb_ind *)(pdu_mem_p->data); if (rlc_pP->rx_sn_length == 10) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY 10 PDU SN=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif e = (((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->b1 & 0x04) >> 2; fi = (((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->b1 & 0x18) >> 3; e_li_p = (rlc_um_e_li_t*)((rlc_um_pdu_sn_10_t*)(tb_ind_p->data_ptr))->data; size = tb_ind_p->size - 2; data_p = &tb_ind_p->data_ptr[2]; } else { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY 5 PDU SN=%03d Byte 0=%02X\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, ((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1); #endif e = (((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1 & 0x00000020) >> 5; fi = (((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->b1 & 0x000000C0) >> 6; e_li_p = (rlc_um_e_li_t*)((rlc_um_pdu_sn_5_t*)(tb_ind_p->data_ptr))->data; size = tb_ind_p->size - 1; data_p = &tb_ind_p->data_ptr[1]; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] e=%01X fi=%01X\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, e, fi); #endif } if (e == RLC_E_FIXED_PART_DATA_FIELD_FOLLOW) { switch (fi) { case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU NO E_LI FI=11 (00)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif // one complete SDU //LGrlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); // may be not necessary rlc_um_clear_rx_sdu(rlc_pP); rlc_um_reassembly (data_p, size, rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU NO E_LI FI=10 (01)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif // one beginning segment of SDU in PDU //LG rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); // may be not necessary rlc_um_clear_rx_sdu(rlc_pP); rlc_um_reassembly (data_p, size, rlc_pP,frameP); rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU NO E_LI FI=01 (10)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif // one last segment of SDU if (rlc_pP->reassembly_missing_sn_detected == 0) { rlc_um_reassembly (data_p, size, rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); } else { //clear sdu already done rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size; } rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU NO E_LI FI=00 (11)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif if (rlc_pP->reassembly_missing_sn_detected == 0) { // one whole segment of SDU in PDU rlc_um_reassembly (data_p, size, rlc_pP,frameP); } else { #if defined (TRACE_RLC_UM_DAR) LOG_W(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU NO E_LI FI=00 (11) MISSING SN DETECTED\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif //LOG_D(RLC, "[MSC_NBOX][FRAME %05u][%s][RLC_UM][MOD %u/%u][RB %u][Missing SN detected][RLC_UM][MOD %u/%u][RB %u]\n", // frameP, rlc_pP->module_id,rlc_pP->rb_id, rlc_pP->module_id,rlc_pP->rb_id); rlc_pP->reassembly_missing_sn_detected = 1; // not necessary but for readability of the code rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size; #if defined(RLC_STOP_ON_LOST_PDU) AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] MISSING PDU DETECTED\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif } break; default: AssertFatal( 0 , "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY SHOULD NOT GO HERE\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); } } else { if (rlc_um_read_length_indicators(&data_p, e_li_p, li_array, &num_li, &size ) >= 0) { switch (fi) { case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU FI=11 (00) Li=", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); for (i=0; i < num_li; i++) { LOG_D(RLC, "%d ",li_array[i]); } LOG_D(RLC, " remaining size %d\n",size); #endif // N complete SDUs //LGrlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); rlc_um_clear_rx_sdu(rlc_pP); for (i = 0; i < num_li; i++) { rlc_um_reassembly (data_p, li_array[i], rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); data_p = &data_p[li_array[i]]; } if (size > 0) { // normally should always be > 0 but just for help debug // data_p is already ok, done by last loop above rlc_um_reassembly (data_p, size, rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); } rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU FI=10 (01) Li=", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); for (i=0; i < num_li; i++) { LOG_D(RLC, "%d ",li_array[i]); } LOG_D(RLC, " remaining size %d\n",size); #endif // N complete SDUs + one segment of SDU in PDU //LG rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); rlc_um_clear_rx_sdu(rlc_pP); for (i = 0; i < num_li; i++) { rlc_um_reassembly (data_p, li_array[i], rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); data_p = &data_p[li_array[i]]; } if (size > 0) { // normally should always be > 0 but just for help debug // data_p is already ok, done by last loop above rlc_um_reassembly (data_p, size, rlc_pP,frameP); } rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU FI=01 (10) Li=", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); for (i=0; i < num_li; i++) { LOG_D(RLC, "%d ",li_array[i]); } LOG_D(RLC, " remaining size %d\n",size); #endif if (rlc_pP->reassembly_missing_sn_detected) { reassembly_start_index = 1; data_p = &data_p[li_array[0]]; //rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += li_array[0]; } else { reassembly_start_index = 0; } // one last segment of SDU + N complete SDUs in PDU for (i = reassembly_start_index; i < num_li; i++) { rlc_um_reassembly (data_p, li_array[i], rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); data_p = &data_p[li_array[i]]; } if (size > 0) { // normally should always be > 0 but just for help debug // data_p is already ok, done by last loop above rlc_um_reassembly (data_p, size, rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); } rlc_pP->reassembly_missing_sn_detected = 0; break; case RLC_FI_1ST_BYTE_DATA_IS_NOT_1ST_BYTE_SDU_LAST_BYTE_DATA_IS_NOT_LAST_BYTE_SDU: #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRY REASSEMBLY PDU FI=00 (11) Li=", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); for (i=0; i < num_li; i++) { LOG_D(RLC, "%d ",li_array[i]); } LOG_D(RLC, " remaining size %d\n",size); #endif if (rlc_pP->reassembly_missing_sn_detected) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] DISCARD FIRST LI %d", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, li_array[0]); #endif reassembly_start_index = 1; data_p = &data_p[li_array[0]]; //rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += li_array[0]; } else { reassembly_start_index = 0; } for (i = reassembly_start_index; i < num_li; i++) { rlc_um_reassembly (data_p, li_array[i], rlc_pP,frameP); rlc_um_send_sdu(rlc_pP,frameP,eNB_flagP); data_p = &data_p[li_array[i]]; } if (size > 0) { // normally should always be > 0 but just for help debug // data_p is already ok, done by last loop above rlc_um_reassembly (data_p, size, rlc_pP,frameP); } else { AssertFatal( 0 !=0, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] SHOULD NOT GO HERE\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); //rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += size; } rlc_pP->reassembly_missing_sn_detected = 0; break; default: #if defined (TRACE_RLC_UM_DAR) LOG_W(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] Missing SN detected\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_ind_p->size; rlc_pP->reassembly_missing_sn_detected = 1; #if defined(RLC_STOP_ON_LOST_PDU) AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] MISSING PDU DETECTED\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif } } } #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] REMOVE PDU FROM DAR BUFFER SN=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif free_mem_block(rlc_pP->dar_buffer[sn]); rlc_pP->dar_buffer[sn] = NULL; } else { rlc_pP->last_reassemblied_missing_sn = sn; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] Missing SN %04d detected, clearing RX SDU\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif rlc_pP->reassembly_missing_sn_detected = 1; rlc_um_clear_rx_sdu(rlc_pP); #if defined(RLC_STOP_ON_LOST_PDU) AssertFatal( rlc_pP->reassembly_missing_sn_detected == 1, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] MISSING PDU DETECTED\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif } sn = (sn + 1) % rlc_pP->rx_sn_modulo; if ((sn == rlc_pP->vr_uh) || (sn == end_snP)){ continue_reassembly = 0; } } #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TRIED REASSEMBLY VR(UR)=%03d VR(UX)=%03d VR(UH)=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ur, rlc_pP->vr_ux, rlc_pP->vr_uh); #endif } //----------------------------------------------------------------------------- void rlc_um_stop_and_reset_timer_reordering(rlc_um_entity_t *rlc_pP,frame_t frameP) //----------------------------------------------------------------------------- { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u][T-REORDERING] STOPPED AND RESET\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); #endif rlc_pP->t_reordering.running = 0; rlc_pP->t_reordering.frame_time_out = 0; rlc_pP->t_reordering.frame_start = 0; rlc_pP->t_reordering.timed_out = 0; } //----------------------------------------------------------------------------- void rlc_um_start_timer_reordering(rlc_um_entity_t *rlc_pP,frame_t frameP) //----------------------------------------------------------------------------- { rlc_pP->t_reordering.running = 1; rlc_pP->t_reordering.frame_time_out = frameP + rlc_pP->t_reordering.time_out; rlc_pP->t_reordering.frame_start = frameP; rlc_pP->t_reordering.timed_out = 0; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u][T-REORDERING] STARTED (TIME-OUT = FRAME %05u)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->t_reordering.frame_time_out); #endif } //----------------------------------------------------------------------------- void rlc_um_init_timer_reordering(rlc_um_entity_t *rlc_pP, uint32_t time_outP) //----------------------------------------------------------------------------- { rlc_pP->t_reordering.running = 0; rlc_pP->t_reordering.frame_time_out = 0; rlc_pP->t_reordering.frame_start = 0; rlc_pP->t_reordering.time_out = time_outP; rlc_pP->t_reordering.timed_out = 0; } //----------------------------------------------------------------------------- void rlc_um_check_timer_dar_time_out(rlc_um_entity_t *rlc_pP, frame_t frameP, eNB_flag_t eNB_flagP) { //----------------------------------------------------------------------------- signed int in_window; rlc_usn_t old_vr_ur; if ((rlc_pP->t_reordering.running)) { if ( // CASE 1: start time out // +-----------+------------------+----------+ // | |******************| | // +-----------+------------------+----------+ //FRAME # 0 FRAME MAX ((rlc_pP->t_reordering.frame_start < rlc_pP->t_reordering.frame_time_out) && ((frameP >= rlc_pP->t_reordering.frame_time_out) || (frameP < rlc_pP->t_reordering.frame_start))) || // CASE 2: time out start // +-----------+------------------+----------+ // |***********| |**********| // +-----------+------------------+----------+ //FRAME # 0 FRAME MAX VALUE ((rlc_pP->t_reordering.frame_start > rlc_pP->t_reordering.frame_time_out) && (frameP < rlc_pP->t_reordering.frame_start) && (frameP >= rlc_pP->t_reordering.frame_time_out)) ) { //if ((uint32_t)((uint32_t)rlc_pP->timer_reordering + (uint32_t)rlc_pP->timer_reordering_init) <= frameP) { // 5.1.2.2.4 Actions when t-Reordering expires // When t-Reordering expires, the receiving UM RLC entity shall: // -update VR(UR) to the SN of the first UMD PDU with SN >= VR(UX) that has not been received; // -reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in ascending order of the RLC SN if not delivered before; // -if VR(UH) > VR(UR): // -start t-Reordering; // -set VR(UX) to VR(UH). rlc_pP->stat_timer_reordering_timed_out += 1; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u]*****************************************************\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u]* T I M E - O U T *\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u]*****************************************************\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] TIMER t-Reordering expiration\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id); LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] timer_reordering=%d frameP=%d expire frameP %d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->t_reordering.time_out, rlc_pP->t_reordering.frame_time_out, frameP); LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] set VR(UR)=%03d to", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ur); #endif old_vr_ur = rlc_pP->vr_ur; rlc_pP->vr_ur = rlc_pP->vr_ux; while (rlc_um_get_pdu_from_dar_buffer(rlc_pP, rlc_pP->vr_ur)) { rlc_pP->vr_ur = (rlc_pP->vr_ur+1)%rlc_pP->rx_sn_modulo; } LOG_D(RLC, " %d", rlc_pP->vr_ur); LOG_D(RLC, "\n"); rlc_um_try_reassembly(rlc_pP,frameP,eNB_flagP,old_vr_ur, rlc_pP->vr_ur); in_window = rlc_um_in_window(rlc_pP, frameP, rlc_pP->vr_ur, rlc_pP->vr_uh, rlc_pP->vr_uh); if (in_window == 2) { rlc_um_start_timer_reordering(rlc_pP, frameP); rlc_pP->vr_ux = rlc_pP->vr_uh; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] restarting t-Reordering set VR(UX) to %d (VR(UH)>VR(UR))\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ux); #endif } else { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] STOP t-Reordering VR(UX) = %03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ux); #endif rlc_um_stop_and_reset_timer_reordering(rlc_pP, frameP); } } } } //----------------------------------------------------------------------------- inline mem_block_t * rlc_um_remove_pdu_from_dar_buffer(rlc_um_entity_t *rlc_pP, rlc_usn_t snP) { //----------------------------------------------------------------------------- mem_block_t * pdu_p = rlc_pP->dar_buffer[snP]; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME ?????][%s][RLC_UM][MOD %u/%u][%s %u] REMOVE PDU FROM DAR BUFFER SN=%03d\n", (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, snP); #endif rlc_pP->dar_buffer[snP] = NULL; return pdu_p; } //----------------------------------------------------------------------------- inline mem_block_t * rlc_um_get_pdu_from_dar_buffer(rlc_um_entity_t *rlc_pP, rlc_usn_t snP) { //----------------------------------------------------------------------------- return rlc_pP->dar_buffer[snP]; } //----------------------------------------------------------------------------- inline void rlc_um_store_pdu_in_dar_buffer(rlc_um_entity_t *rlc_pP, frame_t frameP, mem_block_t *pdu_pP, rlc_usn_t snP) { //----------------------------------------------------------------------------- #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] STORE PDU IN DAR BUFFER SN=%03d VR(UR)=%03d VR(UX)=%03d VR(UH)=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, snP, rlc_pP->vr_ur, rlc_pP->vr_ux, rlc_pP->vr_uh); #endif rlc_pP->dar_buffer[snP] = pdu_pP; } //----------------------------------------------------------------------------- // returns -2 if lower_bound > sn // returns -1 if higher_bound < sn // returns 0 if lower_bound < sn < higher_bound // returns 1 if lower_bound == sn // returns 2 if higher_bound == sn // returns 3 if higher_bound == sn == lower_bound inline signed int rlc_um_in_window(rlc_um_entity_t *rlc_pP, frame_t frameP, rlc_sn_t lower_boundP, rlc_sn_t snP, rlc_sn_t higher_boundP) { //----------------------------------------------------------------------------- rlc_sn_t modulus = (rlc_sn_t)rlc_pP->vr_uh - rlc_pP->rx_um_window_size; #ifdef TRACE_RLC_UM_RX rlc_sn_t lower_bound = lower_boundP; rlc_sn_t higher_bound = higher_boundP; rlc_sn_t sn = snP; #endif lower_boundP = (lower_boundP - modulus) % rlc_pP->rx_sn_modulo; higher_boundP = (higher_boundP - modulus) % rlc_pP->rx_sn_modulo; snP = (snP - modulus) % rlc_pP->rx_sn_modulo; if ( lower_boundP > snP) { #ifdef TRACE_RLC_UM_RX LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d not in WINDOW[%03d:%03d] (SN<LOWER BOUND)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, lower_bound, higher_bound); #endif return -2; } if ( higher_boundP < snP) { #ifdef TRACE_RLC_UM_RX LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d not in WINDOW[%03d:%03d] (SN>HIGHER BOUND) <=> %d not in WINDOW[%03d:%03d]\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, lower_bound, higher_bound, snP, lower_boundP, higher_boundP); #endif return -1; } if ( lower_boundP == snP) { if ( higher_boundP == snP) { #ifdef TRACE_RLC_UM_RX LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d in WINDOW[%03d:%03d] (SN=HIGHER BOUND=LOWER BOUND)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, lower_bound, higher_bound); #endif return 3; } #ifdef TRACE_RLC_UM_RX LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d in WINDOW[%03d:%03d] (SN=LOWER BOUND)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, lower_bound, higher_bound); #endif return 1; } if ( higher_boundP == snP) { #ifdef TRACE_RLC_UM_RX LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d in WINDOW[%03d:%03d] (SN=HIGHER BOUND)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, lower_bound, higher_bound); #endif return 2; } return 0; } //----------------------------------------------------------------------------- inline signed int rlc_um_in_reordering_window(rlc_um_entity_t *rlc_pP, frame_t frameP, rlc_sn_t snP) { //----------------------------------------------------------------------------- rlc_sn_t modulus = (signed int)rlc_pP->vr_uh - rlc_pP->rx_um_window_size; rlc_sn_t sn = snP; snP = (snP - modulus) % rlc_pP->rx_sn_modulo; if ( 0 <= snP) { if (snP < rlc_pP->rx_um_window_size) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d IN REORDERING WINDOW[%03d:%03d[ SN %d IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, snP, 0, rlc_pP->rx_um_window_size, sn, (signed int)rlc_pP->vr_uh - rlc_pP->rx_um_window_size, rlc_pP->vr_uh, rlc_pP->vr_ur, rlc_pP->vr_uh); #endif return 0; } } #if defined (TRACE_RLC_UM_DAR) if (modulus < 0) { LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d NOT IN REORDERING WINDOW[%03d:%03d[ SN %d NOT IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, snP, modulus + 1024, rlc_pP->rx_um_window_size, sn, modulus + 1024 , rlc_pP->vr_uh, rlc_pP->vr_ur, rlc_pP->vr_uh); } else { LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] %d NOT IN REORDERING WINDOW[%03d:%03d[ SN %d NOT IN [%03d:%03d[ VR(UR)=%03d VR(UH)=%03d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, snP, modulus, rlc_pP->rx_um_window_size, sn, modulus , rlc_pP->vr_uh, rlc_pP->vr_ur, rlc_pP->vr_uh); } #endif return -1; } //----------------------------------------------------------------------------- void rlc_um_receive_process_dar (rlc_um_entity_t *rlc_pP, frame_t frameP, eNB_flag_t eNB_flagP, mem_block_t *pdu_mem_pP,rlc_um_pdu_sn_10_t *pdu_pP, sdu_size_t tb_sizeP) { //----------------------------------------------------------------------------- // 36.322v9.3.0 section 5.1.2.2.1: // The receiving UM RLC entity shall maintain a reordering window according to state variable VR(UH) as follows: // -a SN falls within the reordering window if (VR(UH) – UM_Window_Size) <= SN < VR(UH); // -a SN falls outside of the reordering window otherwise. // When receiving an UMD PDU from lower layer, the receiving UM RLC entity shall: // -either discard the received UMD PDU or place it in the reception buffer (see sub clause 5.1.2.2.2); // -if the received UMD PDU was placed in the reception buffer: // -update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop t-Reordering as needed (see sub clause 5.1.2.2.3); // When t-Reordering expires, the receiving UM RLC entity shall: // - update state variables, reassemble and deliver RLC SDUs to upper layer and start t-Reordering as needed (see sub clause 5.1.2.2.4). // When an UMD PDU with SN = x is received from lower layer, the receiving UM RLC entity shall: // -if VR(UR) < x < VR(UH) and the UMD PDU with SN = x has been received before; or // -if (VR(UH) – UM_Window_Size) <= x < VR(UR): // -discard the received UMD PDU; // -else: // -place the received UMD PDU in the reception buffer. rlc_sn_t sn = -1; signed int in_window; if (rlc_pP->rx_sn_length == 10) { sn = ((pdu_pP->b1 & 0x00000003) << 8) + pdu_pP->b2; } else if (rlc_pP->rx_sn_length == 5) { sn = pdu_pP->b1 & 0x1F; } else { free_mem_block(pdu_mem_pP); } in_window = rlc_um_in_window(rlc_pP, frameP, rlc_pP->vr_uh - rlc_pP->rx_um_window_size, sn, rlc_pP->vr_ur); rlc_util_print_hex_octets(RLC, &pdu_pP->b1, tb_sizeP); // rlc_um_in_window() returns -2 if lower_bound > sn // rlc_um_in_window() returns -1 if higher_bound < sn // rlc_um_in_window() returns 0 if lower_bound < sn < higher_bound // rlc_um_in_window() returns 1 if lower_bound == sn // rlc_um_in_window() returns 2 if higher_bound == sn // rlc_um_in_window() returns 3 if higher_bound == sn == lower_bound if ((in_window == 1) || (in_window == 0)){ #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] RX PDU VR(UH) – UM_Window_Size) <= SN %d < VR(UR) -> GARBAGE\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif rlc_pP->stat_rx_data_pdu_out_of_window += 1; rlc_pP->stat_rx_data_bytes_out_of_window += tb_sizeP; free_mem_block(pdu_mem_pP); pdu_mem_pP = NULL; return; } if ((rlc_um_get_pdu_from_dar_buffer(rlc_pP, sn))) { in_window = rlc_um_in_window(rlc_pP, frameP, rlc_pP->vr_ur, sn, rlc_pP->vr_uh); if (in_window == 0){ #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] RX PDU VR(UR) < SN %d < VR(UH) and RECEIVED BEFORE-> GARBAGE\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif //discard the PDU rlc_pP->stat_rx_data_pdus_duplicate += 1; rlc_pP->stat_rx_data_bytes_duplicate += tb_sizeP; free_mem_block(pdu_mem_pP); pdu_mem_pP = NULL; return; } // 2 lines to avoid memory leaks rlc_pP->stat_rx_data_pdus_duplicate += 1; rlc_pP->stat_rx_data_bytes_duplicate += tb_sizeP; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] RX PDU SN %03d REMOVE OLD PDU BEFORE STORING NEW PDU\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn); #endif mem_block_t *pdu = rlc_um_remove_pdu_from_dar_buffer(rlc_pP, sn); free_mem_block(pdu); } rlc_um_store_pdu_in_dar_buffer(rlc_pP, frameP, pdu_mem_pP, sn); // -if x falls outside of the reordering window: // -update VR(UH) to x + 1; // -reassemble RLC SDUs from any UMD PDUs with SN that falls outside of // the reordering window, remove RLC headers when doing so and deliver // the reassembled RLC SDUs to upper layer in ascending order of the // RLC SN if not delivered before; // // -if VR(UR) falls outside of the reordering window: // -set VR(UR) to (VR(UH) – UM_Window_Size); if (rlc_um_in_reordering_window(rlc_pP, frameP, sn) < 0) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] RX PDU SN %d OUTSIDE REORDERING WINDOW VR(UH)=%d UM_Window_Size=%d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, sn, rlc_pP->vr_uh, rlc_pP->rx_um_window_size); #endif rlc_pP->vr_uh = (sn + 1) % rlc_pP->rx_sn_modulo; if (rlc_um_in_reordering_window(rlc_pP, frameP, rlc_pP->vr_ur) != 0) { in_window = rlc_pP->vr_uh - rlc_pP->rx_um_window_size; if (in_window < 0) { in_window = in_window + rlc_pP->rx_sn_modulo; } rlc_um_try_reassembly(rlc_pP, frameP, eNB_flagP, rlc_pP->vr_ur, in_window); } if (rlc_um_in_reordering_window(rlc_pP, frameP, rlc_pP->vr_ur) < 0) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] VR(UR) %d OUTSIDE REORDERING WINDOW SET TO VR(UH) – UM_Window_Size = %d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ur, in_window); #endif rlc_pP->vr_ur = in_window; } } // -if the reception buffer contains an UMD PDU with SN = VR(UR): // -update VR(UR) to the SN of the first UMD PDU with SN > current // VR(UR) that has not been received; // -reassemble RLC SDUs from any UMD PDUs with SN < updated VR(UR), // remove RLC headers when doing so and deliver the reassembled RLC // SDUs to upper layer in ascending order of the RLC SN if not // delivered before; if ((sn == rlc_pP->vr_ur) && rlc_um_get_pdu_from_dar_buffer(rlc_pP, rlc_pP->vr_ur)) { //sn_tmp = rlc_pP->vr_ur; do { rlc_pP->vr_ur = (rlc_pP->vr_ur+1) % rlc_pP->rx_sn_modulo; } while (rlc_um_get_pdu_from_dar_buffer(rlc_pP, rlc_pP->vr_ur) && (rlc_pP->vr_ur != rlc_pP->vr_uh)); rlc_um_try_reassembly(rlc_pP, frameP, eNB_flagP, sn, rlc_pP->vr_ur); } // -if t-Reordering is running: // -if VR(UX) <= VR(UR); or // -if VR(UX) falls outside of the reordering window and VR(UX) is not // equal to VR(UH):: // -stop and reset t-Reordering; if (rlc_pP->t_reordering.running) { if (rlc_pP->vr_uh != rlc_pP->vr_ux) { in_window = rlc_um_in_reordering_window(rlc_pP, frameP, rlc_pP->vr_ux); if (in_window < 0) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] STOP and RESET t-Reordering because VR(UX) falls outside of the reordering window and VR(UX)=%d is not equal to VR(UH)=%d -or- VR(UX) <= VR(UR)\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ux, rlc_pP->vr_uh); #endif rlc_um_stop_and_reset_timer_reordering(rlc_pP, frameP); } } } if (rlc_pP->t_reordering.running) { in_window = rlc_um_in_window(rlc_pP, frameP, rlc_pP->vr_ur, rlc_pP->vr_ux, rlc_pP->vr_uh); if ((in_window == -2) || (in_window == 1)) { #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] STOP and RESET t-Reordering because VR(UX) falls outside of the reordering window and VR(UX)=%d is not equal to VR(UH)=%d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ux, rlc_pP->vr_uh); #endif rlc_um_stop_and_reset_timer_reordering(rlc_pP, frameP); } } // -if t-Reordering is not running (includes the case when t-Reordering is // stopped due to actions above): // -if VR(UH) > VR(UR): // -start t-Reordering; // -set VR(UX) to VR(UH). if (rlc_pP->t_reordering.running == 0) { in_window = rlc_um_in_window(rlc_pP, frameP, rlc_pP->vr_ur, rlc_pP->vr_uh, rlc_pP->vr_uh); if (in_window == 2) { rlc_um_start_timer_reordering(rlc_pP, frameP); rlc_pP->vr_ux = rlc_pP->vr_uh; #if defined (TRACE_RLC_UM_DAR) LOG_D(RLC, "[FRAME %05u][%s][RLC_UM][MOD %u/%u][%s %u] RESTART t-Reordering set VR(UX) to VR(UH) =%d\n", frameP, (rlc_pP->is_enb) ? "eNB" : "UE", rlc_pP->enb_module_id, rlc_pP->ue_module_id, (rlc_pP->is_data_plane) ? "DRB" : "SRB", rlc_pP->rb_id, rlc_pP->vr_ux); #endif } } }