From b77694e89c78497343631b64902614528c3adba9 Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 19 Jan 2017 11:40:03 +0100 Subject: [PATCH 01/36] main AM RX process PDU changes --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 36 ++++- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 3 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 7 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 136 +++++++++++++----- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 4 + .../RLC/AM_v9.3.0/rlc_am_status_report.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 22 +++ openair2/LAYER2/RLC/rlc_def.h | 1 + 8 files changed, 165 insertions(+), 46 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index dcc5f2de8f..b63c7e3132 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -51,7 +51,7 @@ # define RLC_AM_SDU_CONTROL_BUFFER_SIZE 128 /** Size of the retransmission buffer (number of PDUs). */ -# define RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE RLC_AM_SN_MODULO +# define RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE RLC_AM_WINDOW_SIZE /** PDU minimal header size in bytes. */ # define RLC_AM_HEADER_MIN_SIZE 2 @@ -69,6 +69,36 @@ # define RLC_AM_MAX_NACK_IN_STATUS_PDU 1023 /** Max holes created by NACK_SN with segment offsets for a PDU in the retransmission buffer. */ -# define RLC_AM_MAX_HOLES_REPORT_PER_PDU 32 +# define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16 /** @} */ -# endif + + +/* MACRO DEFINITIONS */ +#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) +#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1)) + +#define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1)) +#define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1)) + +#define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO)) +#define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO)) + +#define RLC_SET_EVENT(x,event) ((x) |= (event)) +#define RLC_GET_EVENT(x,event) ((x) & (event)) +#define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event))) + +/* Uplink STATUS PDU trigger events */ +#define RLC_AM_STATUS_NOT_TRIGGERED 0 +#define RLC_AM_STATUS_TRIGGERED_POLL 0x01 /* Status Report is triggered by a received poll */ +#define RLC_AM_STATUS_TRIGGERED_T_REORDERING 0x02 /* Status Report is triggered by Timer Reordering Expiry */ +#define RLC_AM_STATUS_TRIGGERED_DELAYED 0x10 /* Status is delayed until SN(receivedPoll) < VR(MS) */ +#define RLC_AM_STATUS_PROHIBIT 0x20 /* TimerStatusProhibit still running */ + +/* Status triggered (bit 5-7) will be concatenated with Poll triggered (bit 0-4) for RLCdec. RLC_AM_STATUS_TRIGGERED_DELAYED is not recorded. */ +#define RLC_AM_SET_STATUS(x,event) (RLC_SET_EVENT(x,event)) +#define RLC_AM_GET_STATUS(x,event) (RLC_GET_EVENT(x,event)) +#define RLC_AM_CLEAR_STATUS(x,event) (RLC_CLEAR_EVENT(x,event)) +#define RLC_AM_CLEAR_ALL_STATUS(x) ((x) = (RLC_AM_STATUS_NOT_TRIGGERED)) + + +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 42114d4269..581c4969e0 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -182,7 +182,8 @@ typedef struct rlc_am_entity_s { rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */ list_t segmentation_pdu_list; /*!< \brief List of "freshly" segmented PDUs. */ - boolean_t status_requested; /*!< \brief Status requested by peer. */ + uint8_t status_requested; /*!< \brief Status bitmap requested by peer. */ + rlc_sn_t sn_status_triggered_delayed; /*!< \brief SN of the last received poll for which Status is delayed until SN is out of Rx Window. */ frame_t last_frame_status_indication; /*!< \brief The last frame number a MAC status indication has been received by RLC. */ //----------------------------- // buffer occupancy measurements sent to MAC diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index cb03e28c4b..d08d010468 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -74,9 +74,10 @@ rlc_am_init( // RX state variables //rlc_pP->vr_r = 0; rlc_pP->vr_mr = rlc_pP->vr_r + RLC_AM_WINDOW_SIZE; - //rlc_pP->vr_x = 0; + rlc_pP->vr_x = RLC_SN_UNDEFINED; //rlc_pP->vr_ms = 0; //rlc_pP->vr_h = 0; + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; rlc_pP->last_frame_status_indication = 123456; // any value > 1 rlc_pP->first_retrans_pdu_sn = -1; @@ -128,9 +129,11 @@ rlc_am_reestablish( // RX state variables rlc_pP->vr_r = 0; rlc_pP->vr_mr = rlc_pP->vr_r + RLC_AM_WINDOW_SIZE; - rlc_pP->vr_x = 0; + rlc_pP->vr_x = RLC_SN_UNDEFINED; rlc_pP->vr_ms = 0; rlc_pP->vr_h = 0; + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + rlc_pP->status_requested = RLC_AM_STATUS_NOT_TRIGGERED; rlc_pP->last_frame_status_indication = 123456; // any value > 1 rlc_pP->first_retrans_pdu_sn = -1; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index d783684893..f2246e45f8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -40,14 +40,15 @@ rlc_am_get_data_pdu_infos( int16_t total_sizeP, rlc_am_pdu_info_t* pdu_info_pP) { - memset(pdu_info_pP, 0, sizeof (rlc_am_pdu_info_t)); + memset(pdu_info_pP, 0, sizeof (rlc_am_pdu_info_t)); - int16_t sum_li = 0; - pdu_info_pP->d_c = header_pP->b1 >> 7; - pdu_info_pP->num_li = 0; + int16_t sum_li = 0; + pdu_info_pP->d_c = header_pP->b1 >> 7; + pdu_info_pP->num_li = 0; - if (pdu_info_pP->d_c) { + AssertFatal (pdu_info_pP->d_c != 0, "RLC AM Rx PDU Data D/C Header Error LcId=%d\n", rlc_pP->channel_id); + pdu_info_pP->rf = (header_pP->b1 >> 6) & 0x01; pdu_info_pP->p = (header_pP->b1 >> 5) & 0x01; pdu_info_pP->fi = (header_pP->b1 >> 3) & 0x03; @@ -117,12 +118,6 @@ rlc_am_get_data_pdu_infos( } return 0; - } else { - LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[GET DATA PDU INFO] SN %04d ERROR CONTROL PDU ", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - pdu_info_pP->sn); - return -1; - } } //----------------------------------------------------------------------------- void @@ -181,26 +176,22 @@ rlc_am_rx_update_vr_ms( do { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - if (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) { + if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) || + (rlc_pP->vr_ms != pdu_info_cursor_p->sn)) { + #if TRACE_RLC_AM_RX LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[UPDATE VR(MS)] UPDATED VR(MS) %04d -> %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->vr_ms, pdu_info_cursor_p->sn); #endif - rlc_pP->vr_ms = pdu_info_cursor_p->sn; + return; } + rlc_pP->vr_ms = RLC_AM_NEXT_SN(pdu_info_cursor_p->sn); cursor_p = cursor_p->next; - } while (cursor_p != NULL); + } while ((cursor_p != NULL) && (rlc_pP->vr_ms != rlc_pP->vr_h)); -#if TRACE_RLC_AM_RX - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[UPDATE VR(MS)] UPDATED VR(MS) %04d -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vr_ms, - (pdu_info_cursor_p->sn + 1) & RLC_AM_SN_MASK); -#endif - rlc_pP->vr_ms = (pdu_info_cursor_p->sn + 1) & RLC_AM_SN_MASK; } } // assumed the sn of the tb_p is equal to VR(R) @@ -322,18 +313,14 @@ rlc_am_receive_process_data_pdu ( // - discard the duplicate byte segments. rlc_am_pdu_info_t* pdu_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; rlc_am_pdu_sn_10_t* rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)first_byte_pP; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + boolean_t reassemble = false; if (rlc_am_get_data_pdu_infos(ctxt_pP,rlc_pP, rlc_am_pdu_sn_10_p, tb_size_in_bytesP, pdu_info_p) >= 0) { ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->all_segments_received = 0; - if (rlc_am_in_rx_window(ctxt_pP, rlc_pP, pdu_info_p->sn)) { - - if (pdu_info_p->p) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] POLL BIT SET, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; - } + if (RLC_AM_SN_IN_WINDOW(pdu_info_p->sn, rlc_pP->vr_r)) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] VR(R) %04d VR(H) %04d VR(MR) %04d VR(MS) %04d VR(X) %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -346,10 +333,8 @@ rlc_am_receive_process_data_pdu ( if (rlc_am_rx_list_insert_pdu(ctxt_pP, rlc_pP,tb_pP) < 0) { rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_size_in_bytesP; - free_mem_block (tb_pP, __func__); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED, STATUS REQUESTED:\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; #if RLC_STOP_ON_LOST_PDU AssertFatal( 0 == 1, PROTOCOL_RLC_AM_CTXT_FMT" LOST PDU DETECTED\n", @@ -394,12 +379,15 @@ rlc_am_receive_process_data_pdu ( rlc_am_rx_list_display(rlc_pP, "rlc_am_receive_process_data_pdu AFTER INSERTION "); #endif - if (rlc_am_sn_gte_vr_h(ctxt_pP, rlc_pP, pdu_info_p->sn) > 0) { - rlc_pP->vr_h = (pdu_info_p->sn + 1) & RLC_AM_SN_MASK; + /* 1) Update vrH if sn >= vrH */ + if (RLC_AM_DIFF_SN(pdu_info_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(rlc_pP->vr_h,rlc_pP->vr_r)) + { + rlc_pP->vr_h = RLC_AM_NEXT_SN(pdu_info_p->sn); } rlc_am_rx_check_all_byte_segments(ctxt_pP, rlc_pP, tb_pP); + /* 2) Reordering Window Processing: Update vr_ms if sn = vr_ms and all bytes received for sn */ if ((pdu_info_p->sn == rlc_pP->vr_ms) && (((rlc_am_rx_pdu_management_t*)(tb_pP->data))->all_segments_received)) { rlc_am_rx_update_vr_ms(ctxt_pP, rlc_pP, tb_pP); } @@ -410,20 +398,35 @@ rlc_am_receive_process_data_pdu ( rlc_pP->vr_mr = (rlc_pP->vr_r + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; } - rlc_am_rx_list_reassemble_rlc_sdus(ctxt_pP, rlc_pP); + reassemble = true; + //TODO : optimization : check whether a reassembly is needed by looking at LI, FI, SO, etc... + } //FNA: fix check VrX out of receiving window - if (rlc_pP->t_reordering.running) { - if ((rlc_pP->vr_x == rlc_pP->vr_r) || ((rlc_am_in_rx_window(ctxt_pP, rlc_pP, rlc_pP->vr_x) == 0) && (rlc_pP->vr_x != rlc_pP->vr_mr))) { + if ((rlc_pP->t_reordering.running) || ((rlc_pP->t_reordering.ms_duration == 0) && (rlc_pP->vr_x != RLC_SN_UNDEFINED))) { + if ((rlc_pP->vr_x == rlc_pP->vr_r) || (!(RLC_AM_SN_IN_WINDOW(rlc_pP->vr_x, rlc_pP->vr_r)) && (rlc_pP->vr_x != rlc_pP->vr_mr))) { rlc_am_stop_and_reset_timer_reordering(ctxt_pP, rlc_pP); + rlc_pP->vr_x = RLC_SN_UNDEFINED; } } if (!(rlc_pP->t_reordering.running)) { if (rlc_pP->vr_h != rlc_pP->vr_r) { // - if VR (H) > VR(R) translated to - if VR (H) != VR(R) - rlc_am_start_timer_reordering(ctxt_pP, rlc_pP); rlc_pP->vr_x = rlc_pP->vr_h; + if (rlc_pP->t_reordering.ms_duration != 0) { + rlc_am_start_timer_reordering(ctxt_pP, rlc_pP); + } + else { + /* specific case for no timer reordering configured */ + /* reordering window directly advances with vrH */ + rlc_pP->vr_ms = rlc_pP->vr_h; + + /* Trigger a Status and clear any existing Delay Flag */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_T_REORDERING); + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } } } } @@ -437,12 +440,67 @@ rlc_am_receive_process_data_pdu ( } else { rlc_pP->stat_rx_data_pdu_out_of_window += 1; rlc_pP->stat_rx_data_bytes_out_of_window += tb_size_in_bytesP; - free_mem_block (tb_pP, __func__); + pdu_status = RLC_AM_DATA_PDU_STATUS_SN_OUTSIDE_WINDOW; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, STATUS REQUESTED:\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - rlc_pP->status_requested = 1; } + + /* 3) Check for triggering a Tx Status PDU if a poll is received or if a pending status was delayed */ + if (pdu_info_p->p) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] POLL BIT SET, STATUS REQUESTED:\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + + /* Polling Info Saving for In and Out of Window PDU */ + /* avoid multi status trigger */ + if ((RLC_AM_GET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED)) || + !(RLC_AM_GET_STATUS(rlc_pP->status_requested,(RLC_AM_STATUS_TRIGGERED_POLL | RLC_AM_STATUS_TRIGGERED_T_REORDERING)))) + { + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_POLL); + + if ((pdu_status != RLC_AM_DATA_PDU_STATUS_OK) || ((pdu_status == RLC_AM_DATA_PDU_STATUS_OK) && + (!(RLC_AM_SN_IN_WINDOW(pdu_info_p->sn,rlc_pP->vr_r)) || + (RLC_AM_DIFF_SN(pdu_info_p->sn,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) + ) + ) + { + /* Conditions are met for sending a Status Report */ + /* Then clear Delay Flag and reset its corresponding sn */ + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } + else if (rlc_pP->sn_status_triggered_delayed == RLC_SN_UNDEFINED) + { + /* Delay status trigger if pdustatus OK and sn>= vr_ms */ + /* Note: vr_r and vr_ms have been updated */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = pdu_info_p->sn; + } + } + } + + /* ReEnable a previously delayed Status Trigger if PDU discarded or */ + /* sn no more in RxWindow due to RxWindow advance or sn < vr_ms */ + if ((RLC_AM_GET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED)) && + (pdu_status == RLC_AM_DATA_PDU_STATUS_OK) && + (!(RLC_AM_SN_IN_WINDOW(rlc_pP->sn_status_triggered_delayed,rlc_pP->vr_r)) || + (RLC_AM_DIFF_SN(rlc_pP->sn_status_triggered_delayed,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) + ) + { + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } + + } else { - free_mem_block (tb_pP, __func__); + pdu_status = RLC_AM_DATA_PDU_STATUS_HEADER_ERROR; + } + + if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { + /* Discard received block if out of window, duplicate or header error */ + free_mem_block (tb_pP, __func__); + } + else if (reassemble) { + /* Reassemble SDUs */ + rlc_am_rx_list_reassemble_rlc_sdus(ctxt_pP, rlc_pP); } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index a9f0bdbf7e..8e055406a1 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -49,6 +49,10 @@ rlc_am_rx_list_insert_pdu( cursor_p = rlc_pP->receiver_buffer.head; // it is assumed this pdu is in rx window + //TODO : check for duplicate + // should be rewrite + /* look for previous SN */ + if (cursor_p) { if (rlc_pP->vr_mr < rlc_pP->vr_r) { if (pdu_info_p->sn >= rlc_pP->vr_r) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index d687bf8606..cab0a5340a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -474,7 +474,7 @@ rlc_am_send_status_pdu( pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; sn_cursor = pdu_info_cursor_p->sn; - while (rlc_am_in_rx_window(ctxt_pP, rlc_pP, sn_cursor) == 0) { + while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) { cursor_p = cursor_p->next; previous_sn_cursor = sn_cursor; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index 02112fe736..4892090716 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -236,6 +236,28 @@ typedef struct rlc_am_rx_pdu_management { uint8_t all_segments_received; /*!< \brief Is all segments of PDU SN have been received. */ } rlc_am_rx_pdu_management_t; /** @} */ + +typedef enum rlc_am_rx_pdu_status +{ + /** PDU okay. */ + RLC_AM_DATA_PDU_STATUS_OK = 0, + /** SN outside RX window */ + RLC_AM_DATA_PDU_STATUS_SN_OUTSIDE_WINDOW = 1, + /** SN already available */ + RLC_AM_DATA_PDU_STATUS_SN_DUPLICATE = 2, + /** SN already available */ + RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE = 3, + /** Buffer full */ + RLC_AM_DATA_PDU_STATUS_BUFFER_FULL = 4, + /** Header Error (LI,SO...) */ + RLC_AM_DATA_PDU_STATUS_HEADER_ERROR = 5, + /** Unknown bearer */ + RLC_AM_DATA_PDU_STATUS_INVALID_BEARER = 6, + /** RLC in wrong state */ + RLC_AM_DATA_PDU_STATUS_WRONG_STATE = 7 + +} rlc_am_rx_pdu_status_t; + /*! \cond PRIVATE */ //----------------------------------------------------------------------------- // interlayers optimizations diff --git a/openair2/LAYER2/RLC/rlc_def.h b/openair2/LAYER2/RLC/rlc_def.h index 124ba509b5..929d66b70b 100644 --- a/openair2/LAYER2/RLC/rlc_def.h +++ b/openair2/LAYER2/RLC/rlc_def.h @@ -64,6 +64,7 @@ enum RLC_OPERATION_MODE { TRANSMITTER_ONLY = 0x00, // dimensions # define SN_12BITS_MASK 0x0FFF # define RLC_SN_OVERFLOW 0xFFFF +# define RLC_SN_UNDEFINED RLC_SN_OVERFLOW //---------------------------------------------------------- // DISCARD //---------------------------------------------------------- From 26d99fae5df2f4378cdd6b3d9233a383d47edf24 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 25 Jan 2017 17:06:37 +0100 Subject: [PATCH 02/36] add changes for Tx Status PDU report --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 22 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 17 + .../RLC/AM_v9.3.0/rlc_am_status_report.c | 350 ++++++++++++++++++ .../RLC/AM_v9.3.0/rlc_am_timer_reordering.c | 54 ++- .../AM_v9.3.0/rlc_am_timer_status_prohibit.c | 2 + 5 files changed, 417 insertions(+), 28 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 1d93055487..3050d00d6b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -323,7 +323,8 @@ rlc_am_get_pdus ( case RLC_DATA_TRANSFER_READY_STATE: // TRY TO SEND CONTROL PDU FIRST - if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->status_requested)) { + if ((rlc_pP->nb_bytes_requested_by_mac >= 2) && + ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK))) { // When STATUS reporting has been triggered, the receiving side of an AM RLC entity shall: // - if t-StatusProhibit is not running: // - at the first transmission opportunity indicated by lower layer, construct a STATUS PDU and deliver it to lower layer; @@ -334,22 +335,23 @@ rlc_am_get_pdus ( // // When a STATUS PDU has been delivered to lower layer, the receiving side of an AM RLC entity shall: // - start t-StatusProhibit. - if (rlc_pP->t_status_prohibit.running == 0) { - rlc_am_send_status_pdu(ctxt_pP, rlc_pP); - mem_block_t* pdu = list_remove_head(&rlc_pP->control_pdu_list); - if (pdu) { + rlc_am_send_status_pdu(ctxt_pP, rlc_pP); + mem_block_t* pdu = list_remove_head(&rlc_pP->control_pdu_list); + + if (pdu) { list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer); - rlc_pP->status_requested = 0; + RLC_AM_CLEAR_ALL_STATUS(rlc_pP->status_requested); rlc_pP->status_buffer_occupancy = 0; rlc_am_start_timer_status_prohibit(ctxt_pP, rlc_pP); + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); return; } - } else { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" DELAYED SENT STATUS PDU BECAUSE T-STATUS-PROHIBIT RUNNING (TIME-OUT %u)\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->t_status_prohibit.ms_time_out); } + else { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" DELAYED SENT STATUS PDU (Available MAC Data %u)(T-PROHIBIT %u) (DELAY FLAG %u)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED)); } /*while ((rlc_pP->nb_bytes_requested_by_mac > 0) && (stay_on_this_list)) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index b63c7e3132..77bf31db86 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -72,6 +72,22 @@ # define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16 /** @} */ +/* Common to Data and Status PDU */ +#define RLC_AM_SN_BITS 10 +#define RLC_AM_PDU_D_C_BITS 1 +#define RLC_AM_PDU_E_BITS 1 + +/* STATUS PDU */ +#define RLC_AM_STATUS_PDU_CPT_STATUS 0 + +#define RLC_AM_STATUS_PDU_CPT_OFFSET 4 +#define RLC_AM_STATUS_PDU_CPT_LENGTH 3 + +#define RLC_AM_STATUS_PDU_ACK_SN_OFFSET 2 + +#define RLC_AM_STATUS_PDU_SO_LENGTH 15 + +#define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES 0x7FFF /* MACRO DEFINITIONS */ #define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) @@ -93,6 +109,7 @@ #define RLC_AM_STATUS_TRIGGERED_T_REORDERING 0x02 /* Status Report is triggered by Timer Reordering Expiry */ #define RLC_AM_STATUS_TRIGGERED_DELAYED 0x10 /* Status is delayed until SN(receivedPoll) < VR(MS) */ #define RLC_AM_STATUS_PROHIBIT 0x20 /* TimerStatusProhibit still running */ +#define RLC_AM_STATUS_NO_TX_MASK (RLC_AM_STATUS_PROHIBIT | RLC_AM_STATUS_TRIGGERED_DELAYED) /* Status triggered (bit 5-7) will be concatenated with Poll triggered (bit 0-4) for RLCdec. RLC_AM_STATUS_TRIGGERED_DELAYED is not recorded. */ #define RLC_AM_SET_STATUS(x,event) (RLC_SET_EVENT(x,event)) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index cab0a5340a..4cc987d301 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -449,6 +449,353 @@ rlc_am_send_status_pdu( // - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the // resulting STATUS PDU. + signed int nb_bits_to_transmit = rlc_pP->nb_bytes_requested_by_mac << 3; + // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1 + signed int nb_bits_transmitted = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS; + rlc_am_control_pdu_info_t control_pdu_info; + rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; + rlc_sn_t sn_cursor = 0; + rlc_sn_t sn_nack = rlc_pP->vr_r; + mem_block_t *cursor_p = rlc_pP->receiver_buffer.head; + int all_segments_received = 0; + int waited_so = 0; + mem_block_t *tb_p = NULL; + sdu_size_t pdu_size = 0; + boolean_t status_report_completed = false; + boolean_t lsf_received = false; + boolean_t segment_loop_end = false; + + memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t)); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] nb_bits_to_transmit %d (15 already allocated for header)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + nb_bits_to_transmit); + rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT"); +#endif + + /* Handle no NACK first */ + if (rlc_pP->vr_r == rlc_pP->vr_ms) { + + control_pdu_info.ack_sn = rlc_pP->vr_ms; + status_report_completed = true; + } + else if (cursor_p != NULL) { + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + + // Not very clear why this is needed + // commenting +#if 0 + while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) { + cursor_p = cursor_p->next; + previous_sn_cursor = sn_cursor; + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d FIND VR(R) <= SN sn_cursor %04d -> %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + previous_sn_cursor, + sn_cursor); +#endif + } +#endif + + // 12 bits = size of NACK_SN field + E1, E2 bits + // 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits + while ((!status_report_completed) && (RLC_AM_DIFF_SN(sn_nack,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r)) + && (cursor_p != NULL) && (nb_bits_transmitted <= nb_bits_to_transmit)) { + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received; + // E1 bit is set at the end + + /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */ + while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) { + if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) { + /* Fill NACK_SN infos */ + if (control_pdu_info.num_nack) { + /* Set E1 of previous NACK_SN */ + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; + } + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 0; + control_pdu_info.num_nack += 1; + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_nack); +#endif + sn_nack = RLC_AM_NEXT_SN(sn_nack); + } + else { + /* Not enough UL TBS*/ + /* latest value of sn_nack shall be used as ACK_SN */ + control_pdu_info.ack_sn = sn_nack; + status_report_completed = true; + break; + } + } + + /* Now process all Segments of sn_cursor if PDU not fully received */ + if ((!status_report_completed) && (all_segments_received == 0) && (sn_nack != rlc_pP->vr_ms)) { + AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id); + + /* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + /* Set E1 of previous NACK_SN */ + if (control_pdu_info.num_nack) { + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; + } + /* Init loop flags */ + lsf_received = false; + segment_loop_end = false; + + /* Init first SO Start according to first segment */ + if (pdu_info_cursor_p->so) { + waited_so = 0; + /* Fill the first SO */ + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + previous_sn_cursor, + waited_so, + 0x7FFF); +#endif + waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; + /* Go to next segment */ + cursor_p = cursor_p->next; + } + else { + waited_so = pdu_info_cursor_p->payload_size; + } + + /* Find the first discontinuity and then fill SOStart/SOEnd */ + while (!segment_loop_end) { + if (cursor_p != NULL) { + + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + if (pdu_info_cursor_p->sn == sn_cursor) { + /* PDU segment is for the same SN*/ + if (waited_so < pdu_info_cursor_p->so) { + /* SO is greater than previous received portion : gap identified to fill */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + /* Set E1 of previous NACK_SN */ + if (control_pdu_info.num_nack) { + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; + } + + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + segment_loop_end = true; + break; + } + + } + else { + /* Assuming so and payload_size updated according to duplication removal done at reception ... */ + waited_so += pdu_info_cursor_p->payload_size; + } + + } //end if (pdu_info_cursor_p->sn == sn_cursor) + else if (!lsf_received) { + /* We just switched to next SN, fill last gap if not end received */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + /* Set E1 of previously received NACK */ + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + } + + segment_loop_end = true; + continue; //in order not to go to next cursor + } // end if (!lsf_received) + + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + + } //end if (cursor_p != NULL) + else if (!lsf_received) { + /* Previous PDU segment was the last one and had lsf indication : fill the latest gap */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + /* Set E1 of previously received NACK */ + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + } + + segment_loop_end = true; + } + } //end while (!segment_loop_end) + } // end if enough resource for transmitting at least one SOStart/SOEnd + else { + /* Not enough UL TBS to set at least one SOStart/SOEnd */ + /* latest value of sn_nack shall be used as ACK_SN */ + control_pdu_info.ack_sn = sn_nack; + status_report_completed = true; + } + } + + /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ + if ((sn_nack != rlc_pP->vr_ms) && (all_segments_received)) { + sn_nack = RLC_AM_NEXT_SN(sn_nack); + cursor_p = cursor_p->next; + } + + + } + + /* Set ACK_SN unless it was set before */ + if (!status_report_completed){ + + control_pdu_info.ack_sn = sn_nack; + } + + if (control_pdu_info.num_nack) { + control_pdu_info.e1 = 1; + } + + + } else { + control_pdu_info.ack_sn = rlc_pP->vr_r; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d = VR(R)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + control_pdu_info.ack_sn); +#endif + } + + + //msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] nb_bits_to_transmit %d\n", + // rlc_pP->module_id, rlc_pP->rb_id, ctxt_pP->frame,nb_bits_to_transmit); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d NUM NACK %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + control_pdu_info.ack_sn, + control_pdu_info.num_nack); +#endif + + + /* encode the control pdu */ + pdu_size = (nb_bits_transmitted + 7) >> 3; + AssertFatal (pdu_size <= rlc_pP->nb_bytes_requested_by_mac, "RLC AM Tx Status PDU Data size=%d bigger than remaining TBS=%d nb_bits_transmitted=%d LcId=%d\n", + pdu_size,rlc_pP->nb_bytes_requested_by_mac,nb_bits_transmitted, rlc_pP->channel_id); + + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d forecast pdu_size %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + pdu_size); +#endif + tb_p = get_free_mem_block(sizeof(struct mac_tb_req) + pdu_size, __func__); + memset(tb_p->data, 0, sizeof(struct mac_tb_req) + pdu_size); + //estimation only ((struct mac_tb_req*)(tb_p->data))->tb_size = pdu_size; + ((struct mac_tb_req*)(tb_p->data))->data_ptr = (uint8_t*)&(tb_p->data[sizeof(struct mac_tb_req)]); + + // warning reuse of pdu_size + // TODO : rlc_am_write_status_pdu should be rewritten as not very tested ... + pdu_size = rlc_am_write_status_pdu(ctxt_pP, rlc_pP,(rlc_am_pdu_sn_10_t*)(((struct mac_tb_req*)(tb_p->data))->data_ptr), &control_pdu_info); + ((struct mac_tb_req*)(tb_p->data))->tb_size = pdu_size; + //assert((((struct mac_tb_req*)(tb_p->data))->tb_size) < 3000); + +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] SEND STATUS PDU SIZE %d, rlc_pP->nb_bytes_requested_by_mac %d, nb_bits_to_transmit>>3 %d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_size, + rlc_pP->nb_bytes_requested_by_mac, + nb_bits_to_transmit >> 3); +#endif + + AssertFatal (pdu_size == ((nb_bits_transmitted + 7) >> 3), "RLC AM Tx Status PDU Data encoding size=%d different than expected=%d LcId=%d\n", + pdu_size,((nb_bits_transmitted + 7) >> 3), rlc_pP->channel_id); + + // remaining bytes to transmit for RLC (retrans pdus and new data pdus) + rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - pdu_size; + // put pdu in trans + list_add_head(tb_p, &rlc_pP->control_pdu_list); + rlc_pP->stat_tx_control_pdu += 1; + rlc_pP->stat_tx_control_bytes += pdu_size; + +} + + +#if 0 +//----------------------------------------------------------------------------- +void +rlc_am_send_status_pdu_backup( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP +) +{ + // When STATUS reporting has been triggered, the receiving side of an AM RLC entity shall: + // - if t-StatusProhibit is not running: + // - at the first transmission opportunity indicated by lower layer, construct a STATUS PDU and deliver it to lower layer; + // - else: + // - at the first transmission opportunity indicated by lower layer after t-StatusProhibit expires, construct a single + // STATUS PDU even if status reporting was triggered several times while t-StatusProhibit was running and + // deliver it to lower layer; + // + // When a STATUS PDU has been delivered to lower layer, the receiving side of an AM RLC entity shall: + // - start t-StatusProhibit. + // + // When constructing a STATUS PDU, the AM RLC entity shall: + // - for the AMD PDUs with SN such that VR(R) <= SN < VR(MR) that has not been completely received yet, in + // increasing SN of PDUs and increasing byte segment order within PDUs, starting with SN = VR(R) up to + // the point where the resulting STATUS PDU still fits to the total size of RLC PDU(s) indicated by lower layer: + // - for an AMD PDU for which no byte segments have been received yet:: + // - include in the STATUS PDU a NACK_SN which is set to the SN of the AMD PDU; + // - for a continuous sequence of byte segments of a partly received AMD PDU that have not been received yet: + // - include in the STATUS PDU a set of NACK_SN, SOstart and SOend + // - set the ACK_SN to the SN of the next not received RLC Data PDU which is not indicated as missing in the + // resulting STATUS PDU. + signed int nb_bits_to_transmit = rlc_pP->nb_bytes_requested_by_mac << 3; rlc_am_control_pdu_info_t control_pdu_info; rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; @@ -470,6 +817,7 @@ rlc_am_send_status_pdu( rlc_am_rx_list_display(rlc_pP, " DISPLAY BEFORE CONSTRUCTION OF STATUS REPORT"); #endif + if (cursor_p != NULL) { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; sn_cursor = pdu_info_cursor_p->sn; @@ -757,3 +1105,5 @@ end_push_nack: rlc_pP->stat_tx_control_bytes += pdu_size; } +#endif + diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c index 3bbc2e87ac..fa214cd5a9 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c @@ -70,6 +70,8 @@ rlc_am_check_timer_reordering( PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP,rlc_pP)); #endif + AssertFatal (rlc_pP->vr_x != RLC_SN_UNDEFINED, "RLC AM TReordering Expiry vrX not defined LcId=%d\n", rlc_pP->channel_id); + rlc_pP->t_reordering.running = 0; rlc_pP->t_reordering.timed_out = 1; rlc_pP->stat_timer_reordering_timed_out += 1; @@ -77,38 +79,54 @@ rlc_am_check_timer_reordering( rlc_am_pdu_info_t* pdu_info; mem_block_t* cursor; cursor = rlc_pP->receiver_buffer.head; + rlc_usn_t vr_ms_new = rlc_pP->vr_x; - if (cursor) { - do { - pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + AssertFatal (cursor != NULL, "RLC AM TReordering Expiry Rx PDU list empty LcId=%d\n", rlc_pP->channel_id); - // NOT VERY SURE ABOUT THAT, THINK ABOUT IT - rlc_pP->vr_ms = (pdu_info->sn + 1) & RLC_AM_SN_MASK; + while ((cursor != NULL) && (vr_ms_new != rlc_pP->vr_h)) { + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; - if (rlc_am_sn_gte_vr_x(ctxt_pP, rlc_pP, pdu_info->sn)) { - if (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received == 0) { - rlc_pP->vr_ms = pdu_info->sn; - break; - } - } - cursor = cursor->next; - } while (cursor != NULL); + // First find an element with SN greater or equal than vrX + if (RLC_AM_DIFF_SN(pdu_info->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(rlc_pP->vr_x,rlc_pP->vr_r)) { + if (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received == 0) { + // Stop at first found discontinuity + // vr_ms_new holds SN following the latest in sequence fully received PDU >= old vrX + break; + } + else { + vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); + } - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT UPDATED VR(MS) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vr_ms); + } + cursor = cursor->next; } - if (rlc_am_sn_gt_vr_ms(ctxt_pP, rlc_pP, rlc_pP->vr_h)) { + /* Update vr_ms */ + rlc_pP->vr_ms = vr_ms_new; + + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT UPDATED VR(MS) %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + rlc_pP->vr_ms); + + /* if new vrMS is lower than vrH, update vrX and restart timerReordering */ + if (rlc_pP->vr_ms != rlc_pP->vr_h) { rlc_pP->vr_x = rlc_pP->vr_h; rlc_pP->t_reordering.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_reordering.ms_duration; + + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-REORDERING] TIME-OUT, RESTARTED T-REORDERING, UPDATED VR(X) to VR(R) %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->vr_x); } - rlc_pP->status_requested = 1; + /* Trigger a STATUS report */ + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_T_REORDERING); + // Clear Delay flag if it was setup as it is useless due to Status PDU to be sent for TReordering expiry + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_TRIGGERED_DELAYED); + rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; + } } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c index b41fa1c17f..d067c5d9bb 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c @@ -70,6 +70,8 @@ rlc_am_check_timer_status_prohibit( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); //#warning TO DO rlc_am_check_timer_status_prohibit rlc_am_stop_and_reset_timer_status_prohibit(ctxt_pP, rlc_pP); + /* Clear StatusProhibit flag */ + RLC_AM_CLEAR_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); //rlc_pP->t_status_prohibit.frame_time_out = ctxt_pP->frame + rlc_pP->t_status_prohibit.time_out; } } From 66b93704e21f2859a5f7ab7692e8f4781fef5490 Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 30 Jan 2017 18:16:16 +0100 Subject: [PATCH 03/36] RLC AM fix poll criteria --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 3050d00d6b..4e5875fee5 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -150,9 +150,9 @@ config_req_rlc_am ( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p)); } } -uint32_t pollPDU_tab[PollPDU_pInfinity+1]= {4,8,16,32,64,128,256,1024}; // What is PollPDU_pInfinity??? 1024 for now +uint16_t pollPDU_tab[PollPDU_pInfinity+1]= {4,8,16,32,64,128,256,RLC_AM_POLL_PDU_INFINITE}; //PollPDU_pInfinity is chosen to 0xFFFF for now uint32_t maxRetxThreshold_tab[UL_AM_RLC__maxRetxThreshold_t32+1]= {1,2,3,4,6,8,16,32}; -uint32_t pollByte_tab[PollByte_spare1]= {25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,10000}; // What is PollByte_kBinfinity??? 10000 for now +uint32_t pollByte_tab[PollByte_spare1]= {25000,50000,75000,100000,125000,250000,375000,500000,750000,1000000,1250000,1500000,2000000,3000000,RLC_AM_POLL_BYTE_INFINITE}; // PollByte_kBinfinity is chosen to 0xFFFFFFFF for now uint32_t PollRetransmit_tab[T_PollRetransmit_spare9]= {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,300,350,400,450,500}; uint32_t am_t_Reordering_tab[T_Reordering_spare1]= {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,110,120,130,140,150,160,170,180,190,200}; uint32_t t_StatusProhibit_tab[T_StatusProhibit_spare8]= {0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,300,350,400,450,500}; From 79242aaf54e8240cd5d0f121f7f9e3f1fef2c3df Mon Sep 17 00:00:00 2001 From: fnabet Date: Fri, 3 Feb 2017 17:02:42 +0100 Subject: [PATCH 04/36] RLC AM Tx changes --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 122 +++++++++- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 61 +++-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 10 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 2 + .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 21 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 55 +++-- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h | 4 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 210 +++++++++--------- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 5 +- 9 files changed, 312 insertions(+), 178 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 23baae3714..3e88a31496 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -43,6 +43,109 @@ #include "DL-AM-RLC.h" +//----------------------------------------------------------------------------- +uint32_t +rlc_am_get_status_pdu_buffer_occupancy( + rlc_am_entity_t * const rlc_pP){ + + //Compute Max Status PDU size according to what has been received and not received in the window [vrR vrMS[ + + // minimum header size in bits to be transmitted: D/C + CPT + ACK_SN + E1 + uint32_t nb_bits_to_transmit = RLC_AM_PDU_D_C_BITS + RLC_AM_STATUS_PDU_CPT_LENGTH + RLC_AM_SN_BITS + RLC_AM_PDU_E_BITS; + mem_block_t *cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_pdu_info_t *pdu_info_cursor_p = NULL; + int waited_so = 0; + + rlc_sn_t sn_cursor = rlc_pP->vr_r; + rlc_sn_t sn_prev = rlc_pP->vr_r; + rlc_sn_t sn_end = rlc_pP->vr_ms; + boolean_t segment_loop_end = false; + + + if (sn_prev != sn_end) + { + while ((RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r)) && (cursor_p != NULL)) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + sn_cursor = pdu_info_cursor_p->sn; + + // Add holes between sn_prev and sn_cursor + while ((sn_prev != sn_cursor) && (sn_prev != sn_end)) + { + /* Add 1 NACK_SN + E1 + E2 */ + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); + sn_prev = RLC_AM_NEXT_SN(sn_prev); + } //end while (sn_prev != sn_cursor) + + /* Handle case sn_cursor is partially received */ + /* Each gap will add NACK_SN + E1 + E2 + SOStart + SOEnd */ + if ((((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received == 0) && (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(sn_end,rlc_pP->vr_r))) + { + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + /* Fill for [0 SO[ if SO not null */ + if (pdu_info_cursor_p->so) { + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; + /* Go to next segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + else { + waited_so = pdu_info_cursor_p->payload_size; + } + + /* Fill following gaps if any */ + while (!segment_loop_end) + { + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) + { + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); + + if (waited_so < pdu_info_cursor_p->so) { + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + } + else { + /* contiguous segment: only update waited_so */ + /* Assuming so and payload_size updated according to duplication removal done at reception ... */ + waited_so += pdu_info_cursor_p->payload_size; + } + + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + else + { + /* Fill last gap assuming LSF is not received */ + nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); + segment_loop_end = true; + } + } // end while (!segment_loop_end) + } // end if segments + else + { + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + } + + sn_prev = RLC_AM_NEXT_SN(sn_cursor); + } + } // end if (sn_prev != sn_end) + + // round up to the greatest byte + return ((nb_bits_to_transmit + 7) >> 3); + +} + //----------------------------------------------------------------------------- uint32_t rlc_am_get_buffer_occupancy_in_bytes ( @@ -54,26 +157,24 @@ rlc_am_get_buffer_occupancy_in_bytes ( // priority of control trafic rlc_pP->status_buffer_occupancy = 0; - if (rlc_pP->status_requested) { - if (rlc_pP->t_status_prohibit.running == 0) { + if ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK)) { + rlc_pP->status_buffer_occupancy = rlc_am_get_status_pdu_buffer_occupancy(rlc_pP); #if TRACE_RLC_AM_BO - if (((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3) > 0) { - LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3)); - } + LOG_D(RLC, PROTOCOL_CTXT_FMT RB_AM_FMT" BO : CONTROL PDU %d bytes \n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + rlc_pP->status_buffer_occupancy); #endif - rlc_pP->status_buffer_occupancy = ((15 + rlc_pP->num_nack_sn*(10+1) + rlc_pP->num_nack_so*(15+15+1) + 7) >> 3); - } } // data traffic if (rlc_pP->nb_sdu_no_segmented <= 1) { max_li_overhead = 0; } else { - max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); + /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ + uint32_t num_li = rlc_pP->nb_sdu_no_segmented - 1; + max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); } if (rlc_pP->sdu_buffer_occupancy == 0) { @@ -372,6 +473,7 @@ rlc_am_get_pdus ( } }*/ // THEN TRY TO SEND RETRANS PDU + // BUG FIX : they can be PDU to ReTx due to received NACK or 1 PDU (SN = vtS - 1) to ReTx due TPoll Expiry if Buffer Occupancy is null if (rlc_pP->first_retrans_pdu_sn >= 0) { rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index 77bf31db86..a2fc95aba5 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -72,10 +72,52 @@ # define RLC_AM_MAX_HOLES_REPORT_PER_PDU 16 /** @} */ +#define RLC_AM_POLL_PDU_INFINITE 0xFFFF +#define RLC_AM_POLL_BYTE_INFINITE 0xFFFFFFFF + +/* MACRO DEFINITIONS */ + +#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) +#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1)) + +#define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1)) +#define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1)) + +#define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO)) +#define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO)) + +#define RLC_SET_BIT(x,offset) ((x) |= (1 << (offset))) +#define RLC_GET_BIT(x,offset) (((x) & (1 << (offset))) >> (offset)) +#define RLC_CLEAR_BIT(x,offset) ((x) &= ~(1 << (offset))) + +#define RLC_SET_EVENT(x,event) ((x) |= (event)) +#define RLC_GET_EVENT(x,event) ((x) & (event)) +#define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event))) + /* Common to Data and Status PDU */ -#define RLC_AM_SN_BITS 10 -#define RLC_AM_PDU_D_C_BITS 1 -#define RLC_AM_PDU_E_BITS 1 +#define RLC_AM_SN_BITS 10 +#define RLC_AM_PDU_D_C_BITS 1 +#define RLC_AM_PDU_E_BITS 1 +#define RLC_AM_PDU_FI_BITS 2 +#define RLC_AM_PDU_POLL_BITS 1 +#define RLC_AM_PDU_RF_BITS 1 + + +#define EURL_AM_PDU_LSF_BITS 1 + + +/* AM Data PDU */ +#define RLC_AM_PDU_E_OFFSET 2 +#define RLC_AM_PDU_FI_OFFSET (RLC_AM_PDU_E_OFFSET + RLC_AM_PDU_E_BITS) +#define RLC_AM_PDU_POLL_OFFSET (RLC_AM_PDU_FI_OFFSET + RLC_AM_PDU_FI_BITS) +#define RLC_AM_PDU_RF_OFFSET (RLC_AM_PDU_POLL_OFFSET + RLC_AM_PDU_POLL_BITS) +#define RLC_AM_PDU_D_C_OFFSET (RLC_AM_PDU_RF_OFFSET + RLC_AM_PDU_RF_BITS) + +#define RLC_AM_PDU_SET_E(px) (RLC_SET_BIT((px),RLC_AM_PDU_E_OFFSET)) +#define RLC_AM_PDU_SET_D_C(px) (RLC_SET_BIT((px),RLC_AM_PDU_D_C_OFFSET)) +#define RLC_AM_PDU_SET_RF(px) (RLC_SET_BIT((px),RLC_AM_PDU_RF_OFFSET)) +#define RLC_AM_PDU_SET_POLL(px) (RLC_SET_BIT((px),RLC_AM_PDU_POLL_OFFSET)) +#define RLC_AM_PDU_CLEAR_POLL(px) (RLC_CLEAR_BIT((px),RLC_AM_PDU_POLL_OFFSET)) /* STATUS PDU */ #define RLC_AM_STATUS_PDU_CPT_STATUS 0 @@ -89,19 +131,6 @@ #define RLC_AM_STATUS_PDU_SO_END_ALL_BYTES 0x7FFF -/* MACRO DEFINITIONS */ -#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) -#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1)) - -#define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1)) -#define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1)) - -#define RLC_AM_DIFF_SN(sn,snref) (RLC_DIFF_SN(sn,snref,RLC_AM_SN_MODULO)) -#define RLC_AM_SN_IN_WINDOW(sn,snref) (RLC_SN_IN_WINDOW(sn,snref,RLC_AM_SN_MODULO)) - -#define RLC_SET_EVENT(x,event) ((x) |= (event)) -#define RLC_GET_EVENT(x,event) ((x) & (event)) -#define RLC_CLEAR_EVENT(x,event) ((x) &= (~(event))) /* Uplink STATUS PDU trigger events */ #define RLC_AM_STATUS_NOT_TRIGGERED 0 diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 581c4969e0..45d0a5d489 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -69,17 +69,15 @@ typedef struct rlc_am_entity_s { pthread_mutex_t lock_input_sdus; rlc_am_tx_sdu_management_t *input_sdus; /*!< \brief Input SDU buffer (for SDUs coming from upper layers). */ signed int nb_sdu; /*!< \brief Total number of valid rlc_am_tx_sdu_management_t in input_sdus[]. */ - signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. */ + signed int nb_sdu_no_segmented; /*!< \brief Total number of SDUs not segmented and partially segmented. nb_sdu_no_segmented = next_sdu_index - current_sdu_index */ signed int next_sdu_index; /*!< \brief Next SDU index in input_sdus array where for a new incoming SDU. */ - signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented. */ + signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented which is not segmented or partially segmented. */ rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer; /*!< \brief Retransmission buffer. */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ signed int retrans_num_bytes; /*!< \brief Number of bytes in the retransmission buffer. */ signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */ - unsigned int num_nack_so; /*!< \brief Number of segment offsets asked to be retransmitted by peer RLC entity. */ - unsigned int num_nack_sn; /*!< \brief Number of segment asked to be retransmitted by peer RLC entity. */ boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ //--------------------------------------------------------------------- @@ -137,7 +135,7 @@ typedef struct rlc_am_entity_s { //----------------------------- uint16_t max_retx_threshold; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to limit the number of retransmissions of an AMD PDU. */ uint16_t poll_pdu; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollPDU PDUs. */ - uint16_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */ + uint32_t poll_byte; /*!< \brief This parameter is used by the transmitting side of each AM RLC entity to trigger a poll for every pollByte bytes. */ //--------------------------------------------------------------------- // STATISTICS @@ -176,7 +174,7 @@ typedef struct rlc_am_entity_s { //--------------------------------------------------------------------- // OUTPUTS //--------------------------------------------------------------------- - sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of bytes requested by lower layer for next transmission. */ + sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of remaining bytes available for transmission of any RLC PDU indicated by lower layer */ list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */ list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */ rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index 0f0b0e75e1..4122fd0e66 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -56,6 +56,8 @@ void rlc_am_free_in_sdu( rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; } + // TODO : this loop is useless as UL SDUs are transmitted and acknowledged in sequence + // even with PDCP UL SDU discard functionality while ((rlcP->current_sdu_index != rlcP->next_sdu_index) && (rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 7fb801b33d..a52c9bee33 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -55,7 +55,6 @@ void rlc_am_nack_pdu ( int sdu_index; if (mb_p != NULL) { - rlc_pP->num_nack_sn += 1; assert(so_startP <= so_endP); //----------------------------------------- @@ -69,10 +68,6 @@ void rlc_am_nack_pdu ( rlc_am_clear_holes(ctxt_pP, rlc_pP, snP); } - if (!((so_startP == 0) && (so_endP == 0x7FFF))) { - rlc_pP->num_nack_so += 1; - } - rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP); if (rlc_pP->first_retrans_pdu_sn < 0) { @@ -283,7 +278,7 @@ mem_block_t* rlc_am_retransmit_get_copy ( pdu_mngt->flags.retransmit = 0; - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size,false); return mb_copy; } else { return NULL; @@ -745,7 +740,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( return NULL; } - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size,false); return mb_sub_segment_p; } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n", @@ -843,10 +838,12 @@ void rlc_am_retransmit_any_pdu( // no need for update rlc_pP->nb_bytes_requested_by_mac pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size); - pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; - rlc_pP->c_pdu_without_poll = 0; - rlc_pP->c_byte_without_poll = 0; + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size,false); + //BugFix: polling is checked and done in function above ! + //pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; + //BugFix : pdu_without_poll and byte_without_poll are reset only if a Poll is transmitted + //rlc_pP->c_pdu_without_poll = 0; + //rlc_pP->c_byte_without_poll = 0; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_pP->stat_tx_data_pdu += 1; @@ -877,7 +874,7 @@ void rlc_am_retransmit_any_pdu( rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF); pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size,false); pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index 893588d65e..af4f67f303 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -39,7 +39,8 @@ void rlc_am_pdu_polling ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP, rlc_am_pdu_sn_10_t *const pdu_pP, - const int16_t payload_sizeP) + const int16_t payload_sizeP, + boolean_t is_new_pdu) { // 5.2.2 Polling // An AM RLC entity can poll its peer AM RLC entity in order to trigger STATUS reporting at the peer AM RLC entity. @@ -68,41 +69,50 @@ void rlc_am_pdu_polling ( // - start t-PollRetransmit; // - else: // - restart t-PollRetransmit; - rlc_pP->c_pdu_without_poll += 1; - rlc_pP->c_byte_without_poll += payload_sizeP; + + if (is_new_pdu) { + if (rlc_pP->poll_pdu != RLC_AM_POLL_PDU_INFINITE) { + rlc_pP->c_pdu_without_poll += 1; + } + + if (rlc_pP->poll_byte != RLC_AM_POLL_BYTE_INFINITE) { + rlc_pP->c_byte_without_poll += payload_sizeP; + } + } if ( - (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) || - (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) || + ((is_new_pdu) && ((rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) || + (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte))) || ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) || (rlc_pP->vt_s == rlc_pP->vt_ms) || - (rlc_pP->force_poll == TRUE) + (rlc_pP->force_poll == true) ) { - rlc_pP->force_poll = FALSE; + rlc_pP->force_poll = false; - if (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu) { + if ((is_new_pdu) && (rlc_pP->c_pdu_without_poll >= rlc_pP->poll_pdu)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM PDU THRESHOLD %d HAS BEEN REACHED\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->poll_pdu); - } else - if (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte) { + } + if ((is_new_pdu) && (rlc_pP->c_byte_without_poll >= rlc_pP->poll_byte)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX NUM BYTES THRESHOLD %d HAS BEEN REACHED\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->poll_byte); - } else + } if ((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE TX BUFFERS ARE EMPTY\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - } else + } if (rlc_pP->vt_s == rlc_pP->vt_ms) { LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[POLL] SET POLL BECAUSE OF WINDOW STALLING\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } - pdu_pP->b1 = pdu_pP->b1 | 0x20; + RLC_AM_PDU_SET_POLL(pdu_pP->b1); rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; + // vt_s shall have been updated before in case of new transmission rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; //optimisation if (!rlc_pP->t_poll_retransmit.running) { rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); @@ -110,7 +120,8 @@ void rlc_am_pdu_polling ( //optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out; //optimisation } } else { - pdu_pP->b1 = pdu_pP->b1 & 0xDF; + // Not sure this is necessary + RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1); } } //----------------------------------------------------------------------------- @@ -178,7 +189,9 @@ void rlc_am_segment_10 ( if (rlc_pP->nb_sdu_no_segmented <= 1) { max_li_overhead = 0; } else { - max_li_overhead = (((rlc_pP->nb_sdu_no_segmented - 1) * 3) / 2) + ((rlc_pP->nb_sdu_no_segmented - 1) % 2); + /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ + test_num_li = rlc_pP->nb_sdu_no_segmented - 1; + max_li_overhead = test_num_li + (test_num_li >> 1) + (test_num_li & 1); } LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] max_li_overhead %d\n", @@ -485,11 +498,11 @@ void rlc_am_segment_10 ( fi = fi + 1; } - pdu_p->b1 = pdu_p->b1 | (fi << 3); + pdu_p->b1 = pdu_p->b1 | (fi << RLC_AM_PDU_FI_OFFSET); // set fist e bit if (fill_num_li > 0) { - pdu_p->b1 = pdu_p->b1 | 0x04; + RLC_AM_PDU_SET_E(pdu_p->b1); } LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] SEND PDU SN %04d SIZE %d BYTES PAYLOAD SIZE %d BYTES\n", @@ -501,8 +514,9 @@ void rlc_am_segment_10 ( rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_data_bytes += (data_pdu_size - pdu_remaining_size); - //pdu_p->sn = rlc_pP->vt_s; - pdu_p->b1 = pdu_p->b1 | 0x80; // DATA/CONTROL field is DATA PDU + // set DATA/CONTROL field is DATA PDU(1) + RLC_AM_PDU_SET_D_C(pdu_p->b1); + // set sn = rlc_pP->vt_s; pdu_p->b1 = pdu_p->b1 | (rlc_pP->vt_s >> 8); pdu_p->b2 = rlc_pP->vt_s & 0xFF; rlc_pP->vt_s = (rlc_pP->vt_s+1) & RLC_AM_SN_MASK; @@ -511,13 +525,14 @@ void rlc_am_segment_10 ( pdu_tb_req_p->tb_size = data_pdu_size - pdu_remaining_size; //#warning "why 3000: changed to RLC_SDU_MAX_SIZE " assert(pdu_tb_req_p->tb_size < RLC_SDU_MAX_SIZE ); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt_p->payload_size,true); //list_add_tail_eurecom (pdu_mem_p, &rlc_pP->segmentation_pdu_list); pdu_mngt_p->mem_block = pdu_mem_p; pdu_mngt_p->first_byte = (unsigned char*)pdu_p; pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size; pdu_mngt_p->retx_count = -1; + pdu_mngt_p->flags.transmitted = 1; rlc_pP->retrans_num_pdus += 1; rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h index 6b67758b80..b52b3e5aaa 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.h @@ -51,14 +51,14 @@ # endif # endif -/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP) +/*! \fn void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu) * \brief Set or not the poll bit in the PDU header depending on RLC AM protocol variables. * \param[in] ctxt_pP Running context. * \param[in] rlcP RLC AM protocol instance pointer. * \param[in] pduP Pointer on the header of the PDU in order to be able to set the poll bit if necessary. * \param[in] payload_sizeP Size of the payload of the PDU. */ -protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP);) +protected_rlc_am_segment(void rlc_am_pdu_polling (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, rlc_am_pdu_sn_10_t *pduP, int16_t payload_sizeP,boolean_t is_new_pdu);) /*! \fn void rlc_am_segment_10 (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlcP) * \brief Segment a PDU with 10 bits sequence number, based on segmentation information given by MAC (size to transmit). diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 4cc987d301..6495c722df 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -309,8 +309,6 @@ rlc_am_receive_process_control_pdu( assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU); if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) { - rlc_pP->num_nack_so = 0; - rlc_pP->num_nack_sn = 0; if (rlc_pP->control_pdu_info.num_nack == 0) { while (sn_cursor != ack_sn) { @@ -462,7 +460,6 @@ rlc_am_send_status_pdu( mem_block_t *tb_p = NULL; sdu_size_t pdu_size = 0; boolean_t status_report_completed = false; - boolean_t lsf_received = false; boolean_t segment_loop_end = false; memset(&control_pdu_info, 0, sizeof(rlc_am_control_pdu_info_t)); @@ -479,30 +476,20 @@ rlc_am_send_status_pdu( control_pdu_info.ack_sn = rlc_pP->vr_ms; status_report_completed = true; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d ALL ACK WITH ACK_SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + rlc_pP->vr_ms); +#endif } - else if (cursor_p != NULL) { + else if ((cursor_p != NULL) && ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)) <= nb_bits_to_transmit)) { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; sn_cursor = pdu_info_cursor_p->sn; - // Not very clear why this is needed - // commenting -#if 0 - while (!(RLC_AM_SN_IN_WINDOW(sn_cursor, rlc_pP->vr_r))) { - cursor_p = cursor_p->next; - previous_sn_cursor = sn_cursor; - - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - sn_cursor = pdu_info_cursor_p->sn; -#if TRACE_RLC_AM_STATUS_CREATION - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d FIND VR(R) <= SN sn_cursor %04d -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - __LINE__, - previous_sn_cursor, - sn_cursor); -#endif - } -#endif + /* Set E1 bit for the presence of first NACK_SN/E1/E2 */ + control_pdu_info.e1 = 1; // 12 bits = size of NACK_SN field + E1, E2 bits // 42 bits = size of NACK_SN field + SO_START, SO_END fields, E1, E2 bits @@ -512,20 +499,17 @@ rlc_am_send_status_pdu( pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; sn_cursor = pdu_info_cursor_p->sn; all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received; - // E1 bit is set at the end /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */ while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) { if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) { /* Fill NACK_SN infos */ - if (control_pdu_info.num_nack) { - /* Set E1 of previous NACK_SN */ - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; - } control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 0; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; control_pdu_info.num_nack += 1; nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); #if TRACE_RLC_AM_STATUS_CREATION @@ -541,45 +525,52 @@ rlc_am_send_status_pdu( /* latest value of sn_nack shall be used as ACK_SN */ control_pdu_info.ack_sn = sn_nack; status_report_completed = true; +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d NOT ENOUGH TBS STOP WITH ACK_SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_nack); +#endif break; } } /* Now process all Segments of sn_cursor if PDU not fully received */ - if ((!status_report_completed) && (all_segments_received == 0) && (sn_nack != rlc_pP->vr_ms)) { + if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) { AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id); /* First ensure there is enough TBS for at least 1 SOStart/SOEnd, else break */ if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { - /* Set E1 of previous NACK_SN */ - if (control_pdu_info.num_nack) { - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; - } /* Init loop flags */ - lsf_received = false; - segment_loop_end = false; + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); /* Init first SO Start according to first segment */ if (pdu_info_cursor_p->so) { - waited_so = 0; /* Fill the first SO */ control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = 0; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; control_pdu_info.num_nack += 1; nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); #if TRACE_RLC_AM_STATUS_CREATION LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), __LINE__, - previous_sn_cursor, - waited_so, - 0x7FFF); + sn_cursor, + 0, + pdu_info_cursor_p->so - 1); #endif waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; /* Go to next segment */ cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } } else { waited_so = pdu_info_cursor_p->payload_size; @@ -587,79 +578,73 @@ rlc_am_send_status_pdu( /* Find the first discontinuity and then fill SOStart/SOEnd */ while (!segment_loop_end) { - if (cursor_p != NULL) { + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) { - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + /* PDU segment is for the same SN*/ + /* Check lsf */ + segment_loop_end = (pdu_info_cursor_p->lsf == 1); - if (pdu_info_cursor_p->sn == sn_cursor) { - /* PDU segment is for the same SN*/ - if (waited_so < pdu_info_cursor_p->so) { - /* SO is greater than previous received portion : gap identified to fill */ - if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { - /* Set E1 of previous NACK_SN */ - if (control_pdu_info.num_nack) { - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; - } + if (waited_so < pdu_info_cursor_p->so) { + /* SO is greater than previous received portion : gap identified to fill */ + if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { + control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so; + control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; + control_pdu_info.num_nack += 1; + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_cursor, + waited_so, + pdu_info_cursor_p->so); +#endif + } + else { + /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ + control_pdu_info.ack_sn = sn_cursor; + status_report_completed = true; + segment_loop_end = true; + break; + } + } + else { + /* contiguous segment: only update waited_so */ + /* Assuming so and payload_size updated according to duplication removal done at reception ... */ + waited_so += pdu_info_cursor_p->payload_size; + } - control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; - control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; - control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so; - control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; - control_pdu_info.num_nack += 1; - nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); - } - else { - /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ - control_pdu_info.ack_sn = sn_cursor; - status_report_completed = true; - segment_loop_end = true; - break; - } + /* Go to next received PDU or PDU Segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } - } - else { - /* Assuming so and payload_size updated according to duplication removal done at reception ... */ - waited_so += pdu_info_cursor_p->payload_size; - } - - } //end if (pdu_info_cursor_p->sn == sn_cursor) - else if (!lsf_received) { - /* We just switched to next SN, fill last gap if not end received */ - if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { - /* Set E1 of previously received NACK */ - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; - control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; - control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; - control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; - control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; - control_pdu_info.num_nack += 1; - nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); - } - else { - /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ - control_pdu_info.ack_sn = sn_cursor; - status_report_completed = true; - } - - segment_loop_end = true; - continue; //in order not to go to next cursor - } // end if (!lsf_received) - - /* Go to next received PDU or PDU Segment */ - cursor_p = cursor_p->next; - - } //end if (cursor_p != NULL) - else if (!lsf_received) { - /* Previous PDU segment was the last one and had lsf indication : fill the latest gap */ + } //end if (cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor) + else { + /* Previous PDU segment was the last one and did not have lsf indication : fill the latest gap */ if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { - /* Set E1 of previously received NACK */ - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 1; control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = RLC_AM_STATUS_PDU_SO_END_ALL_BYTES; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; + /* Set E1 for next NACK_SN. The last one will be cleared */ + control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; control_pdu_info.num_nack += 1; nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); +#if TRACE_RLC_AM_STATUS_CREATION + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING LAST NACK %04d SO START %05d SO END %05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + sn_cursor, + waited_so, + RLC_AM_STATUS_PDU_SO_END_ALL_BYTES); +#endif } else { /* Not enough resources to set a SOStart/SEnd, then set ACK_SN to current NACK_SN and stop Status PDU build */ @@ -677,16 +662,23 @@ rlc_am_send_status_pdu( control_pdu_info.ack_sn = sn_nack; status_report_completed = true; } - } - - /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ - if ((sn_nack != rlc_pP->vr_ms) && (all_segments_received)) { - sn_nack = RLC_AM_NEXT_SN(sn_nack); + } // end while on all PDU segments of sn_cursor + else { + /* Go to next received PDU or PDU segment if sn_cursor is fully received */ cursor_p = cursor_p->next; } + /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ + if (sn_nack != rlc_pP->vr_ms) { + sn_nack = RLC_AM_NEXT_SN(sn_cursor); + } - } + + } // End main while NACK_SN + + /* Clear E1 of last nack_sn entry */ + AssertFatal (control_pdu_info.num_nack, "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id); + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0; /* Set ACK_SN unless it was set before */ if (!status_report_completed){ @@ -694,12 +686,8 @@ rlc_am_send_status_pdu( control_pdu_info.ack_sn = sn_nack; } - if (control_pdu_info.num_nack) { - control_pdu_info.e1 = 1; - } - - } else { + /* reception buffer empty or not enough TBS for filling at least 1 NACK_SN + E1 + E2 */ control_pdu_info.ack_sn = rlc_pP->vr_r; #if TRACE_RLC_AM_STATUS_CREATION LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING ACK %04d = VR(R)\n", diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index 4892090716..5ca98c88be 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -88,9 +88,12 @@ typedef struct rlc_am_tx_sdu_management { * \brief Structure containing PDU variables related to its retransmission. */ typedef struct pdu_management_flags { + uint8_t transmitted:1; /*!< \brief Boolean telling that this PDU is not empty and has been at least transmitted once. */ uint8_t ack:1; /*!< \brief Boolean telling that this PDU has been acknowledged. */ + uint8_t nack:1; /*!< \brief Boolean telling that this PDU has been acknowledged negatively. */ uint8_t retransmit:1; /*!< \brief Boolean telling a retransmission is scheduled for this PDU. */ - uint8_t dummy:6; /*!< \brief Free bits. */ + uint8_t max_retransmit:1; /*!< \brief Boolean telling max retransmission has been hit for this PDU. */ + uint8_t dummy:3; /*!< \brief Free bits. */ } pdu_management_flags_t; From ab2c1fcc8e6144feb81072348b15bc633aea26ba Mon Sep 17 00:00:00 2001 From: gabrielC Date: Mon, 6 Feb 2017 14:55:50 +0100 Subject: [PATCH 05/36] fix TStatus Prohibit 0ms --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 1 - openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 3e88a31496..6a6daeab01 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -445,7 +445,6 @@ rlc_am_get_pdus ( RLC_AM_CLEAR_ALL_STATUS(rlc_pP->status_requested); rlc_pP->status_buffer_occupancy = 0; rlc_am_start_timer_status_prohibit(ctxt_pP, rlc_pP); - RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); return; } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c index d067c5d9bb..65ea056120 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_status_prohibit.c @@ -112,6 +112,7 @@ rlc_am_start_timer_status_prohibit( rlc_pP->t_status_prohibit.running = 1; rlc_pP->t_status_prohibit.ms_time_out = rlc_pP->t_status_prohibit.ms_duration + PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); rlc_pP->t_status_prohibit.ms_start = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); + RLC_AM_SET_STATUS(rlc_pP->status_requested,RLC_AM_STATUS_PROHIBIT); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T-STATUS-PROHIBIT] STARTED (TIME-OUT = %u ms)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->t_status_prohibit.ms_time_out); From 39bdc2bce8c78231acc0917e6d773414004efb72 Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 6 Feb 2017 16:29:01 +0100 Subject: [PATCH 06/36] fix Tx Status PDU --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 6495c722df..f75b481dbb 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -511,7 +511,7 @@ rlc_am_send_status_pdu( /* Set E1 for next NACK_SN. The last one will be cleared */ control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; control_pdu_info.num_nack += 1; - nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); + nb_bits_transmitted += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1)); #if TRACE_RLC_AM_STATUS_CREATION LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEND-STATUS] LINE %d PREPARE SENDING NACK %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), From d3af6f1f3664c3561d6c6a869b1f269442e6cba1 Mon Sep 17 00:00:00 2001 From: fnabet Date: Tue, 7 Feb 2017 10:47:47 +0100 Subject: [PATCH 07/36] Renaming or removing some Tx RLC AM fields --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 35 ++-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 3 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 20 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 134 ++++++------- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 7 +- .../RLC/AM_v9.3.0/rlc_am_segments_holes.c | 182 +++++++++--------- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 4 +- 7 files changed, 192 insertions(+), 193 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 6a6daeab01..4d16a368fe 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -481,7 +481,7 @@ rlc_am_get_pdus ( (rlc_pP->first_retrans_pdu_sn >= 0) && (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s)) { - tx_data_pdu_management = &rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn]; + tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn]; if ((tx_data_pdu_management->header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) && (tx_data_pdu_management->retx_count >= 0) && (tx_data_pdu_management->nack_so_start == 0) && (tx_data_pdu_management->nack_so_stop == 0x7FFF)) { @@ -500,7 +500,7 @@ rlc_am_get_pdus ( list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer); rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - tx_data_pdu_management->header_and_payload_size; - tx_data_pdu_management->retx_count += 1; + tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next; return; } else if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac >= RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d MAC BYTES %d SIZE %d RTX COUNT %d nack_so_start %d nack_so_stop %04X(hex)\n", @@ -535,7 +535,7 @@ rlc_am_get_pdus ( // update first_retrans_pdu_sn while ((rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s) && - (!(rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn].flags.retransmit))) { + (!(rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].flags.retransmit))) { rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn+1) & RLC_AM_SN_MASK; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn SN %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -706,22 +706,23 @@ rlc_am_mac_status_indication ( // force BO to be > 0 rlc_sn_t sn = (rlc->vt_s - 1) & RLC_AM_SN_MASK; rlc_sn_t sn_end = (rlc->vt_a - 1) & RLC_AM_SN_MASK; - int found_pdu = 0; - rlc_sn_t found_pdu_sn = 0; // avoid warning - (void)found_pdu_sn; /* avoid gcc warning "set but not used" */ - + /* Look for the first retransmittable PDU starting from vtS - 1 */ while (sn != sn_end) { - if (rlc->pdu_retrans_buffer[sn].mem_block != NULL) { - if (!found_pdu) { - found_pdu = 1; - found_pdu_sn = sn; - } - status_resp.buffer_occupancy_in_bytes = rlc->pdu_retrans_buffer[sn].header_and_payload_size; - status_resp.buffer_occupancy_in_pdus = rlc->nb_sdu; - status_resp.head_sdu_remaining_size_to_send = status_resp.buffer_occupancy_in_bytes; - // TODO head_sdu_is_segmented - break; + AssertFatal (rlc->tx_data_pdu_buffer[sn].mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", + sn, rlc->vt_a,rlc->vt_s,rlc->channel_id); + if ((rlc->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) { + rlc->retrans_num_bytes_to_retransmit = rlc->tx_data_pdu_buffer[sn].header_and_payload_size; + rlc->tx_data_pdu_buffer[sn].flags.retransmit = 1; + status_resp.buffer_occupancy_in_bytes = rlc->tx_data_pdu_buffer[sn].header_and_payload_size; + status_resp.buffer_occupancy_in_pdus = rlc->nb_sdu; + status_resp.head_sdu_remaining_size_to_send = status_resp.buffer_occupancy_in_bytes; + // TODO head_sdu_is_segmented + break; + } + else + { + sn = RLC_AM_PREV_SN(sn); } } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 45d0a5d489..87150f115c 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -74,9 +74,8 @@ typedef struct rlc_am_entity_s { signed int current_sdu_index; /*!< \brief Current SDU index in input_sdus array to be segmented which is not segmented or partially segmented. */ - rlc_am_tx_data_pdu_management_t *pdu_retrans_buffer; /*!< \brief Retransmission buffer. */ + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer; /*!< \brief Transmission PDU data buffer. Used also for retransmissions */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ - signed int retrans_num_bytes; /*!< \brief Number of bytes in the retransmission buffer. */ signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */ boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index d08d010468..b93f331676 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -51,16 +51,16 @@ rlc_am_init( pthread_mutex_init(&rlc_pP->lock_input_sdus, NULL); rlc_pP->input_sdus = calloc(1, RLC_AM_SDU_CONTROL_BUFFER_SIZE*sizeof(rlc_am_tx_sdu_management_t)); //#warning "cast the rlc retrans buffer to uint32" - // rlc_pP->pdu_retrans_buffer = calloc(1, (uint16_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof(rlc_am_tx_data_pdu_management_t))); - rlc_pP->pdu_retrans_buffer = calloc(1, (uint32_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof( + // rlc_pP->tx_data_pdu_buffer = calloc(1, (uint16_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof(rlc_am_tx_data_pdu_management_t))); + rlc_pP->tx_data_pdu_buffer = calloc(1, (uint32_t)((unsigned int)RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE*(unsigned int)sizeof( rlc_am_tx_data_pdu_management_t))); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] input_sdus[] = %p element size=%zu\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->input_sdus, sizeof(rlc_am_tx_sdu_management_t)); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] pdu_retrans_buffer[] = %p element size=%zu\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[AM INIT] tx_data_pdu_buffer[] = %p element size=%zu\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer, + rlc_pP->tx_data_pdu_buffer, sizeof(rlc_am_tx_data_pdu_management_t)); // TX state variables @@ -175,16 +175,16 @@ rlc_am_cleanup( pthread_mutex_destroy(&rlc_pP->lock_input_sdus); - if (rlc_pP->pdu_retrans_buffer != NULL) { + if (rlc_pP->tx_data_pdu_buffer != NULL) { for (i=0; i < RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE; i++) { - if (rlc_pP->pdu_retrans_buffer[i].mem_block != NULL) { - free_mem_block(rlc_pP->pdu_retrans_buffer[i].mem_block, __func__); - rlc_pP->pdu_retrans_buffer[i].mem_block = NULL; + if (rlc_pP->tx_data_pdu_buffer[i].mem_block != NULL) { + free_mem_block(rlc_pP->tx_data_pdu_buffer[i].mem_block, __func__); + rlc_pP->tx_data_pdu_buffer[i].mem_block = NULL; } } - free(rlc_pP->pdu_retrans_buffer); - rlc_pP->pdu_retrans_buffer = NULL; + free(rlc_pP->tx_data_pdu_buffer); + rlc_pP->tx_data_pdu_buffer = NULL; } memset(rlc_pP, 0, sizeof(rlc_am_entity_t)); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index a52c9bee33..4db9893f8a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -50,7 +50,7 @@ void rlc_am_nack_pdu ( // - indicate to upper layers that max retransmission has been reached. - mem_block_t* mb_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; int pdu_sdu_index; int sdu_index; @@ -63,8 +63,8 @@ void rlc_am_nack_pdu ( // increasing order among calls refering to only one status PDU // and among time //----------------------------------------- - if (rlc_pP->pdu_retrans_buffer[snP].last_nack_time != ctxt_pP->frame) { - rlc_pP->pdu_retrans_buffer[snP].last_nack_time = ctxt_pP->frame; + if (rlc_pP->tx_data_pdu_buffer[snP].last_nack_time != ctxt_pP->frame) { + rlc_pP->tx_data_pdu_buffer[snP].last_nack_time = ctxt_pP->frame; rlc_am_clear_holes(ctxt_pP, rlc_pP, snP); } @@ -79,21 +79,22 @@ void rlc_am_nack_pdu ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] NACK PDU SN %04d previous retx_count %d 1ST_RETRANS_PDU %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].retx_count, + rlc_pP->tx_data_pdu_buffer[snP].retx_count, rlc_pP->first_retrans_pdu_sn); - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 1; + rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 1; - if (rlc_pP->pdu_retrans_buffer[snP].retx_count == -1) { - rlc_pP->pdu_retrans_buffer[snP].retx_count = 0; - rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; - } else { - rlc_pP->pdu_retrans_buffer[snP].retx_count += 1; + /* TODO : before incrementing retx_count_next, this must be a new occurrence of retransmission */ + if (rlc_pP->tx_data_pdu_buffer[snP].retx_count == rlc_pP->tx_data_pdu_buffer[snP].retx_count_next){ + rlc_pP->tx_data_pdu_buffer[snP].retx_count_next ++; + rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size; } - if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= rlc_pP->max_retx_threshold) { - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->pdu_retrans_buffer[snP].sdus_index[pdu_sdu_index]; + /* TODO: Move this part in UL SCH processing */ +#if 0 + if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= rlc_pP->max_retx_threshold) { + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; assert(pdu_sdu_index < RLC_AM_MAX_SDU_IN_PDU); assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; @@ -117,6 +118,7 @@ void rlc_am_nack_pdu ( } } } +#endif } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU SN %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -130,29 +132,27 @@ void rlc_am_ack_pdu ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; int pdu_sdu_index; int sdu_index; - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0; + rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; - if ((rlc_pP->pdu_retrans_buffer[snP].flags.ack == 0) && (mb_p != NULL)) { + if ((rlc_pP->tx_data_pdu_buffer[snP].flags.ack == 0) && (mb_p != NULL)) { //if (mb_pP != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL; + rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] ACK PDU SN %05d previous retx_count %d \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].retx_count); - rlc_pP->retrans_num_pdus -= 1; - rlc_pP->retrans_num_bytes -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; + rlc_pP->tx_data_pdu_buffer[snP].retx_count); - if (rlc_pP->pdu_retrans_buffer[snP].retx_count >= 0) { - rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size; + if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= 0) { + rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size; } - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->pdu_retrans_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->pdu_retrans_buffer[snP].sdus_index[pdu_sdu_index]; + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; assert(sdu_index >= 0); assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; @@ -182,19 +182,19 @@ void rlc_am_ack_pdu ( // This state variable holds the value of the SN of the next AMD PDU for which a positive acknowledgment is to be // received in-sequence, and it serves as the lower edge of the transmitting window. It is initially set to 0, and is updated // whenever the AM RLC entity receives a positive acknowledgment for an AMD PDU with SN = VT(A). - rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; + rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; if (snP == rlc_pP->vt_a) { - //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; + //rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; do { - memset(&rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); + memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; } rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); + } while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; @@ -209,7 +209,7 @@ void rlc_am_ack_pdu ( do { rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn + 1) & RLC_AM_SN_MASK; - if (rlc_pP->pdu_retrans_buffer[rlc_pP->first_retrans_pdu_sn].retx_count >= 0) { + if (rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].retx_count >= 0) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->first_retrans_pdu_sn); @@ -231,21 +231,21 @@ void rlc_am_ack_pdu ( if (mb_p != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL; + rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL; } - if (rlc_pP->pdu_retrans_buffer[snP].flags.ack > 0) { + if (rlc_pP->tx_data_pdu_buffer[snP].flags.ack > 0) { if (snP == rlc_pP->vt_a) { - //rlc_pP->pdu_retrans_buffer[snP].flags.ack = 1; + //rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; do { - memset(&rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); + memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; } rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->pdu_retrans_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); + } while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n", @@ -263,11 +263,11 @@ mem_block_t* rlc_am_retransmit_get_copy ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_original_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; if (mb_original_p != NULL) { - rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->pdu_retrans_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); mem_block_t* mb_copy = get_free_mem_block(size, __func__); @@ -335,7 +335,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // - set the header of the new AMD PDU segment in accordance with the description in sub clause 6.; // - set the P field according to sub clause 5.2.2. - mem_block_t* mb_original_p = rlc_pP->pdu_retrans_buffer[snP].mem_block; + mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; if (mb_original_p != NULL) { mem_block_t* mb_sub_segment_p = get_free_mem_block(*sizeP + sizeof(struct mac_tb_req), __func__); @@ -348,10 +348,10 @@ mem_block_t* rlc_am_retransmit_get_subsegment( ((struct mac_tb_req*)(mb_sub_segment_p->data))->data_ptr = (uint8_t*)&(mb_sub_segment_p->data[sizeof(struct mac_tb_req)]); - if (rlc_am_get_data_pdu_infos(ctxt_pP, rlc_pP, pdu_original_p, rlc_pP->pdu_retrans_buffer[snP].header_and_payload_size, &pdu_info) >= 0) { + if (rlc_am_get_data_pdu_infos(ctxt_pP, rlc_pP, pdu_original_p, rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size, &pdu_info) >= 0) { int li_index = 0; - int start_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_start; - int stop_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + int start_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start; + int stop_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] ORIGINAL PDU SN %04d:\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -361,8 +361,8 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // all 15 bits set to 1 (indicate that the missing portion of the AMD PDU includes all bytes // to the last byte of the AMD PDU) if (stop_offset == 0x7FFF) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].payload_size - 1; - stop_offset = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1; + stop_offset = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] UPDATED RETRANS PDU SN %04d nack_so_stop FROM 0x7FFF to %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, @@ -622,7 +622,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); test_pdu_copy_size = max_copy_payload_size; - if ((stop_offset == (start_offset + max_copy_payload_size - 1)) && (stop_offset == rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) { + if ((stop_offset == (start_offset + max_copy_payload_size - 1)) && (stop_offset == rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1)) { not_test_fi = (not_test_fi & 0x2) | (not_fi_original & 0x1); // set b0 idendical to the b0 of the non segmented PDU } else { not_test_fi = not_test_fi & 0x2; // clear b0 because no SDU ending in this PDU @@ -630,7 +630,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( } //--------------------------------------------------------------- - /*if (stop_offset == (rlc_pP->pdu_retrans_buffer[snP].payload_size - 1)) { + /*if (stop_offset == (rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1)) { test_fi = (test_fi & 0x02) | (fi_original & 0x01); }*/ //--------------------------------------------------------------- @@ -687,16 +687,16 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // copy payload to retransmit //--------------------------------------------------------------- memcpy(fill_payload_p, - &rlc_pP->pdu_retrans_buffer[snP].payload[start_offset], + &rlc_pP->tx_data_pdu_buffer[snP].payload[start_offset], test_pdu_copy_size); ((struct mac_tb_req*)(mb_sub_segment_p->data))->tb_size = (tb_size_t)(((uint64_t)fill_payload_p)+ test_pdu_copy_size) - ((uint64_t)(&pdu_sub_segment_p->b1)); // set LSF - if ((test_pdu_copy_size + start_offset) == rlc_pP->pdu_retrans_buffer[snP].payload_size) { + if ((test_pdu_copy_size + start_offset) == rlc_pP->tx_data_pdu_buffer[snP].payload_size) { pdu_sub_segment_p->data[0] = pdu_sub_segment_p->data[0] | 0x80; - rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 0; + rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d SO %d %d BYTES PAYLOAD %d BYTES LSF!\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -723,15 +723,15 @@ mem_block_t* rlc_am_retransmit_get_subsegment( // update nack_so_start //--------------------------------------------------------------- rlc_am_remove_hole(ctxt_pP, rlc_pP, snP, start_offset, test_pdu_copy_size+start_offset - 1); - //rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].nack_so_start + test_pdu_copy_size; + //rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start + test_pdu_copy_size; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d NOW nack_so_start %d nack_so_stop %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); - /*if (rlc_pP->pdu_retrans_buffer[snP].nack_so_start == rlc_pP->pdu_retrans_buffer[snP].nack_so_stop) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); + /*if (rlc_pP->tx_data_pdu_buffer[snP].nack_so_start == rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; }*/ } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] COULD NOT GET INFO FOR DATA PDU SN %04d -> RETURN NULL\n", @@ -773,25 +773,25 @@ void rlc_am_tx_buffer_display ( } while (rlc_pP->vt_s != sn) { - if (rlc_pP->pdu_retrans_buffer[sn].mem_block) { + if (rlc_pP->tx_data_pdu_buffer[sn].mem_block) { if ((loop % 1) == 0) { LOG_D(RLC, "\nTX SN:\t"); } - if (rlc_pP->pdu_retrans_buffer[sn].flags.retransmit) { - LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size, - rlc_pP->pdu_retrans_buffer[sn].retx_count); + if (rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit) { + LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size, rlc_pP->tx_data_pdu_buffer[sn].payload_size, + rlc_pP->tx_data_pdu_buffer[sn].retx_count); } else { - LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size, rlc_pP->pdu_retrans_buffer[sn].payload_size, - rlc_pP->pdu_retrans_buffer[sn].retx_count); + LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size, rlc_pP->tx_data_pdu_buffer[sn].payload_size, + rlc_pP->tx_data_pdu_buffer[sn].retx_count); } - if (rlc_pP->pdu_retrans_buffer[sn].num_holes == 0) { - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].nack_so_start, rlc_pP->pdu_retrans_buffer[sn].nack_so_stop); + if (rlc_pP->tx_data_pdu_buffer[sn].num_holes == 0) { + LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->tx_data_pdu_buffer[sn].nack_so_start, rlc_pP->tx_data_pdu_buffer[sn].nack_so_stop); } else { - for (i=0; ipdu_retrans_buffer[sn].num_holes; i++) { + for (i=0; itx_data_pdu_buffer[sn].num_holes; i++) { assert(i < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->pdu_retrans_buffer[sn].hole_so_start[i], rlc_pP->pdu_retrans_buffer[sn].hole_so_stop[i]); + LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->tx_data_pdu_buffer[sn].hole_so_start[i], rlc_pP->tx_data_pdu_buffer[sn].hole_so_stop[i]); } } @@ -819,13 +819,13 @@ void rlc_am_retransmit_any_pdu( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); while (sn != sn_end) { - if (rlc_pP->pdu_retrans_buffer[sn].mem_block != NULL) { + if (rlc_pP->tx_data_pdu_buffer[sn].mem_block != NULL) { if (!found_pdu) { found_pdu = 1; found_pdu_sn = sn; } - if (rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) { + if (rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[FORCE-TRAFFIC] RE-SEND DATA PDU SN %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), sn); @@ -838,7 +838,7 @@ void rlc_am_retransmit_any_pdu( // no need for update rlc_pP->nb_bytes_requested_by_mac pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[sn].header_and_payload_size,false); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size,false); //BugFix: polling is checked and done in function above ! //pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; //BugFix : pdu_without_poll and byte_without_poll are reset only if a Poll is transmitted @@ -874,7 +874,7 @@ void rlc_am_retransmit_any_pdu( rlc_am_nack_pdu (ctxt_pP, rlc_pP, found_pdu_sn, 0, 0x7FFF); pdu_p = rlc_am_retransmit_get_subsegment(ctxt_pP, rlc_pP, found_pdu_sn, &rlc_pP->nb_bytes_requested_by_mac); pdu_sn_10_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->pdu_retrans_buffer[found_pdu_sn].header_and_payload_size,false); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sn_10_p, rlc_pP->tx_data_pdu_buffer[found_pdu_sn].header_and_payload_size,false); pdu_sn_10_p->b1 = pdu_sn_10_p->b1 | 0x20; rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index af4f67f303..824154b311 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -223,7 +223,7 @@ void rlc_am_segment_10 ( pdu_remaining_size = data_pdu_size - RLC_AM_HEADER_MIN_SIZE; pdu_p = (rlc_am_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); - pdu_mngt_p = &rlc_pP->pdu_retrans_buffer[rlc_pP->vt_s % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + pdu_mngt_p = &rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_s % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; memset(pdu_mngt_p, 0, sizeof (rlc_am_tx_data_pdu_management_t)); memset (pdu_mem_p->data, 0, sizeof (rlc_am_pdu_sn_10_t)+sizeof(struct mac_tb_req)); @@ -531,11 +531,10 @@ void rlc_am_segment_10 ( pdu_mngt_p->mem_block = pdu_mem_p; pdu_mngt_p->first_byte = (unsigned char*)pdu_p; pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size; - pdu_mngt_p->retx_count = -1; + pdu_mngt_p->retx_count = 0; + pdu_mngt_p->retx_count_next = 0; pdu_mngt_p->flags.transmitted = 1; - rlc_pP->retrans_num_pdus += 1; - rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size; pdu_p = NULL; pdu_mem_p = NULL; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c index 37e9b13508..b1eabdd1ca 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c @@ -32,7 +32,7 @@ void rlc_am_clear_holes ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - rlc_pP->pdu_retrans_buffer[snP].num_holes = 0; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; } //----------------------------------------------------------------------------- void rlc_am_shift_down_holes ( @@ -43,12 +43,12 @@ void rlc_am_shift_down_holes ( { int i; - for (i=indexP; i < rlc_pP->pdu_retrans_buffer[snP].num_holes - 1; i++) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i+1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i+1]; + for (i=indexP; i < rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1; i++) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i+1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i+1]; } - rlc_pP->pdu_retrans_buffer[snP].num_holes = rlc_pP->pdu_retrans_buffer[snP].num_holes - 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1; } //----------------------------------------------------------------------------- void rlc_am_shift_up_holes ( @@ -60,13 +60,13 @@ void rlc_am_shift_up_holes ( // shift include indexP int i; - for (i=rlc_pP->pdu_retrans_buffer[snP].num_holes; i > indexP; i--) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i-1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i-1]; + for (i=rlc_pP->tx_data_pdu_buffer[snP].num_holes; i > indexP; i--) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i-1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i-1]; } - rlc_pP->pdu_retrans_buffer[snP].num_holes = rlc_pP->pdu_retrans_buffer[snP].num_holes + 1; - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + rlc_pP->tx_data_pdu_buffer[snP].num_holes = rlc_pP->tx_data_pdu_buffer[snP].num_holes + 1; + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); } //----------------------------------------------------------------------------- void rlc_am_remove_hole ( @@ -79,81 +79,81 @@ void rlc_am_remove_hole ( int i; #if TRACE_RLC_AM_HOLE LOG_D(RLC, - PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d so_startP %05d so_stopP %05d rlc_pP->pdu_retrans_buffer[snP].nack_so_start %05d rlc_pP->pdu_retrans_buffer[snP].nack_so_stop %05d\n", + PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d so_startP %05d so_stopP %05d rlc_pP->tx_data_pdu_buffer[snP].nack_so_start %05d rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, so_startP, so_stopP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); #endif assert(so_startP <= so_stopP); - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - assert(so_startP == rlc_pP->pdu_retrans_buffer[snP].nack_so_start); - assert(so_stopP <= rlc_pP->pdu_retrans_buffer[snP].nack_so_stop); + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + assert(so_startP == rlc_pP->tx_data_pdu_buffer[snP].nack_so_start); + assert(so_stopP <= rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop); #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d MODIFIED nack_so_start %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, so_stopP+1); #endif - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_stopP+1; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_stopP+1; - if (rlc_pP->pdu_retrans_buffer[snP].nack_so_start >= rlc_pP->pdu_retrans_buffer[snP].nack_so_stop) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].nack_so_start >= rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } } else { // normally should be removed in increasing order... - for (i = 0; i < rlc_pP->pdu_retrans_buffer[snP].num_holes; i++) { - if (so_startP <= rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i]) { - if (so_stopP >= rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { + for (i = 0; i < rlc_pP->tx_data_pdu_buffer[snP].num_holes; i++) { + if (so_startP <= rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i]) { + if (so_stopP >= rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { rlc_am_shift_down_holes(ctxt_pP, rlc_pP, snP, i); i = i - 1; } else { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = so_stopP; - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } else { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[rlc_pP->pdu_retrans_buffer[snP].num_holes - 1]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1]; } #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d NOW nack_so_start %05d nack_so_stop %05d num holes %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop, + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif return; } - } else if (so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i]) { - if (so_startP <= rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { - if (so_stopP < rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]) { + } else if (so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i]) { + if (so_startP <= rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { + if (so_stopP < rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]) { // BAD CASE: 1 HOLE IS SPLITTED IN 2 HOLES rlc_am_shift_up_holes(ctxt_pP, rlc_pP, snP, i+1); - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i+1] = so_startP+1; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i+1] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = so_startP - 1; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i+1] = so_startP+1; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i+1] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = so_startP - 1; } else { - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = so_startP; } } } } - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = 0x7FFF; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = 0x7FFF; } else { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[rlc_pP->pdu_retrans_buffer[snP].num_holes - 1]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[rlc_pP->tx_data_pdu_buffer[snP].num_holes - 1]; } } @@ -161,11 +161,11 @@ void rlc_am_remove_hole ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] REMOVE HOLE SN %04d NOW nack_so_start %05d nack_so_stop %05d num holes %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->pdu_retrans_buffer[snP].nack_so_start, - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start, + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop, + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); } //----------------------------------------------------------------------------- void rlc_am_get_next_hole ( @@ -175,9 +175,9 @@ void rlc_am_get_next_hole ( sdu_size_t* const so_startP, sdu_size_t* const so_stopP) { - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - *so_startP = rlc_pP->pdu_retrans_buffer[snP].nack_so_start; - *so_stopP = rlc_pP->pdu_retrans_buffer[snP].nack_so_stop; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + *so_startP = rlc_pP->tx_data_pdu_buffer[snP].nack_so_start; + *so_stopP = rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] rlc_am_get_next_hole(SN %04d) %05d->%05d (NUM HOLES == 0)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -186,15 +186,15 @@ void rlc_am_get_next_hole ( *so_stopP); #endif } else { - *so_startP = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0]; - *so_stopP = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[0]; + *so_startP = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0]; + *so_stopP = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[0]; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] rlc_am_get_next_hole(SN %04d) %05d->%05d (NUM HOLES == %d)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, *so_startP, *so_stopP, - rlc_pP->pdu_retrans_buffer[snP].num_holes); + rlc_pP->tx_data_pdu_buffer[snP].num_holes); #endif } } @@ -214,33 +214,33 @@ void rlc_am_add_hole ( // if global NACK - if ((so_startP == 0) && ((so_stopP == 0x7FFF) || (so_stopP == rlc_pP->pdu_retrans_buffer[snP].payload_size - 1))) { - rlc_pP->pdu_retrans_buffer[snP].num_holes = 0; - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + if ((so_startP == 0) && ((so_stopP == 0x7FFF) || (so_stopP == rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1))) { + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] SN %04d GLOBAL NACK 0->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); return; } if (so_stopP == 0x7FFF) { - so_stopP = rlc_pP->pdu_retrans_buffer[snP].payload_size - 1; + so_stopP = rlc_pP->tx_data_pdu_buffer[snP].payload_size - 1; } // first hole - if (rlc_pP->pdu_retrans_buffer[snP].num_holes == 0) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[0] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop [0] = so_stopP; + if (rlc_pP->tx_data_pdu_buffer[snP].num_holes == 0) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[0] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop [0] = so_stopP; - rlc_pP->pdu_retrans_buffer[snP].num_holes = 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 1; - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] FIRST HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -248,44 +248,44 @@ void rlc_am_add_hole ( so_startP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); return; } hole_index = 0; - while (hole_index < rlc_pP->pdu_retrans_buffer[snP].num_holes) { - if (so_stopP < rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index]) { - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + while (hole_index < rlc_pP->tx_data_pdu_buffer[snP].num_holes) { + if (so_stopP < rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index]) { + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); if (hole_index > 0) { - assert(so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index-1]); + assert(so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index-1]); } - for (i=rlc_pP->pdu_retrans_buffer[snP].num_holes; i >= hole_index; i--) { - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_start[i-1]; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i] = rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[i-1]; + for (i=rlc_pP->tx_data_pdu_buffer[snP].num_holes; i >= hole_index; i--) { + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[i-1]; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i] = rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[i-1]; } - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index] = so_stopP; // update nack "window" vars nack_so_start, nack_so_stop if (hole_index == 0) { - rlc_pP->pdu_retrans_buffer[snP].nack_so_start = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_start = so_startP; } - rlc_pP->pdu_retrans_buffer[snP].num_holes += 1; + rlc_pP->tx_data_pdu_buffer[snP].num_holes += 1; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] INSERT %d th HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer[snP].num_holes, + rlc_pP->tx_data_pdu_buffer[snP].num_holes, snP, so_startP, so_stopP); #endif - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); return; } @@ -293,17 +293,17 @@ void rlc_am_add_hole ( } // if here insert to the "tail" - if (so_startP > rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index - 1]) { - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - rlc_pP->pdu_retrans_buffer[snP].hole_so_start[hole_index] = so_startP; - rlc_pP->pdu_retrans_buffer[snP].hole_so_stop[hole_index] = so_stopP; - rlc_pP->pdu_retrans_buffer[snP].num_holes += 1; + if (so_startP > rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index - 1]) { + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + rlc_pP->tx_data_pdu_buffer[snP].hole_so_start[hole_index] = so_startP; + rlc_pP->tx_data_pdu_buffer[snP].hole_so_stop[hole_index] = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].num_holes += 1; // update nack "window" vars nack_so_start, nack_so_stop - rlc_pP->pdu_retrans_buffer[snP].nack_so_stop = so_stopP; + rlc_pP->tx_data_pdu_buffer[snP].nack_so_stop = so_stopP; #if TRACE_RLC_AM_HOLE LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] INSERT THE %d th LAST HOLE SN %04d GLOBAL NACK %05d->%05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->pdu_retrans_buffer[snP].num_holes, + rlc_pP->tx_data_pdu_buffer[snP].num_holes, snP, so_startP, so_stopP); @@ -312,6 +312,6 @@ void rlc_am_add_hole ( assert(1==2); } - assert(rlc_pP->pdu_retrans_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - assert(rlc_pP->pdu_retrans_buffer[snP].nack_so_start < rlc_pP->pdu_retrans_buffer[snP].payload_size); + assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); + assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index 5ca98c88be..e201e909c5 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -117,8 +117,8 @@ typedef struct rlc_am_tx_data_pdu_management { sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size if global NACK */ int8_t nb_sdus; /*!< \brief Number of sdu having segments in this pdu. */ - int8_t - retx_count; /*!< \brief Counts the number of retransmissions of an AMD PDU (see subclause 5.2.1). There is one RETX_COUNT counter per PDU that needs to be retransmitted. there is one VT(DAT) for each PDU and it is incremented each time the PDU is transmitted. */ + int8_t retx_count; /*!< \brief Counts the number of already occurred retransmissions of an AMD PDU (see subclause 5.2.1). */ + int8_t retx_count_next; /*!< \brief Counts the number of already occurred retransmissions plus the latest pending one. */ pdu_management_flags_t flags; /*!< \brief PDU variables related to its retransmission. */ } rlc_am_tx_data_pdu_management_t; From fbe109a66c799749ded9e8d180885ee4d2bd0a4b Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 16 Feb 2017 11:26:37 +0100 Subject: [PATCH 08/36] RLC/MAC UE interface changes for Tx and adapt to eNB --- openair2/COMMON/mac_rrc_primitives.h | 4 +- openair2/ENB_APP/flexran_agent_common.c | 6 +- openair2/LAYER2/MAC/eNB_scheduler_dlsch.c | 6 + openair2/LAYER2/MAC/eNB_scheduler_mch.c | 3 +- .../MAC/flexran_agent_scheduler_dataplane.c | 3 + .../MAC/flexran_agent_scheduler_dlsch_ue.c | 3 +- openair2/LAYER2/MAC/pre_processor.c | 2 +- openair2/LAYER2/MAC/ra_procedures.c | 3 +- openair2/LAYER2/MAC/ue_procedures.c | 331 ++++++------------ openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 52 ++- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 14 + openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 5 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 6 + openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 4 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 12 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 24 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 1 + .../AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 37 +- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c | 10 + openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h | 12 + openair2/LAYER2/RLC/rlc.h | 20 +- openair2/LAYER2/RLC/rlc_mac.c | 72 +++- 22 files changed, 322 insertions(+), 308 deletions(-) diff --git a/openair2/COMMON/mac_rrc_primitives.h b/openair2/COMMON/mac_rrc_primitives.h index dfa641ee66..c59791c1b6 100644 --- a/openair2/COMMON/mac_rrc_primitives.h +++ b/openair2/COMMON/mac_rrc_primitives.h @@ -388,9 +388,9 @@ typedef struct { struct PMCH_InfoList_r9 *pmch_InfoList #endif ); - unsigned int (*mac_rlc_data_req)(module_id_t, unsigned int, char*); + unsigned int (*mac_rlc_data_req)(module_id_t, unsigned int, const unsigned int,char*); void (*mac_rlc_data_ind)(module_id_t, logical_chan_id_t, char*, tb_size_t, num_tb_t, crc_t* ); - mac_rlc_status_resp_t (*mac_rlc_status_ind) (module_id_t enb_mod_idP, module_id_t ue_mod_idP, frame_t frameP, eNB_flag_t eNB_flagP, MBMS_flag_t MBMS_flagP, + mac_rlc_status_resp_t (*mac_rlc_status_ind) (module_id_t enb_mod_idP, module_id_t ue_mod_idP, frame_t frameP, sub_frame_t subframeP, eNB_flag_t eNB_flagP, MBMS_flag_t MBMS_flagP, logical_chan_id_t channel_idP, tb_size_t tb_sizeP); signed int (*rrc_rlc_data_req)(module_id_t, rb_id_t, mui_t, confirm_t, sdu_size_t, char *); void (*rrc_rlc_register_rrc) (void (*rrc_data_indP)(module_id_t , rb_id_t , sdu_size_t , char* ), diff --git a/openair2/ENB_APP/flexran_agent_common.c b/openair2/ENB_APP/flexran_agent_common.c index f2d00145a0..073bb8029c 100644 --- a/openair2/ENB_APP/flexran_agent_common.c +++ b/openair2/ENB_APP/flexran_agent_common.c @@ -562,14 +562,16 @@ int flexran_get_ue_wcqi (mid_t mod_id, mid_t ue_id) { int flexran_get_tx_queue_size(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); + uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id,rnti, mod_id,frame,subframe,ENB_FLAG_YES,MBMS_FLAG_NO, channel_id, 0); return rlc_status.bytes_in_buffer; } int flexran_get_hol_delay(mid_t mod_id, mid_t ue_id, logical_chan_id_t channel_id) { rnti_t rnti = flexran_get_ue_crnti(mod_id,ue_id); uint16_t frame = (uint16_t) flexran_get_current_frame(mod_id); - mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); + uint16_t subframe = (uint16_t) flexran_get_current_subframe(mod_id); + mac_rlc_status_resp_t rlc_status = mac_rlc_status_ind(mod_id, rnti, mod_id, frame, subframe, ENB_FLAG_YES, MBMS_FLAG_NO, channel_id, 0); return rlc_status.head_sdu_creation_time; } diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c index 41a136d6b1..6048bea9a8 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c @@ -821,6 +821,7 @@ schedule_ue_spec( rnti, module_idP, frameP, + subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, @@ -839,6 +840,7 @@ schedule_ue_spec( ENB_FLAG_YES, MBMS_FLAG_NO, DCCH, + TBS, //not used (char *)&dlsch_buffer[0]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), @@ -872,6 +874,7 @@ schedule_ue_spec( rnti, module_idP, frameP, + subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, @@ -890,6 +893,7 @@ schedule_ue_spec( ENB_FLAG_YES, MBMS_FLAG_NO, DCCH+1, + TBS, //not used (char *)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), @@ -932,6 +936,7 @@ schedule_ue_spec( rnti, module_idP, frameP, + subframeP, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, @@ -949,6 +954,7 @@ schedule_ue_spec( ENB_FLAG_YES, MBMS_FLAG_NO, lcid, + TBS, //not used (char*)&dlsch_buffer[sdu_length_total]); T(T_ENB_MAC_UE_DL_SDU, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP), T_INT(subframeP), T_INT(harq_pid), T_INT(lcid), T_INT(sdu_lengths[num_sdus])); diff --git a/openair2/LAYER2/MAC/eNB_scheduler_mch.c b/openair2/LAYER2/MAC/eNB_scheduler_mch.c index 1dac7af704..90d797198e 100644 --- a/openair2/LAYER2/MAC/eNB_scheduler_mch.c +++ b/openair2/LAYER2/MAC/eNB_scheduler_mch.c @@ -504,7 +504,7 @@ int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_fra module_idP,CC_id,frameP,MTCH,TBS, TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); - rlc_status = mac_rlc_status_ind(module_idP,0,frameP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH, + rlc_status = mac_rlc_status_ind(module_idP,0,frameP,subframeP,module_idP,ENB_FLAG_YES,MBMS_FLAG_YES,MTCH, TBS-header_len_mcch-header_len_msi-sdu_length_total-header_len_mtch); LOG_D(MAC,"e-MBMS log channel %u frameP %d, subframeP %d, rlc_status.bytes_in_buffer is %d\n", MTCH,frameP,subframeP, rlc_status.bytes_in_buffer); @@ -521,6 +521,7 @@ int schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP, sub_fra ENB_FLAG_YES, MBMS_FLAG_YES, MTCH, + 0, //not used (char*)&mch_buffer[sdu_length_total]); //sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,frameP, MBMS_FLAG_NO, MTCH+(MAX_NUM_RB*(NUMBER_OF_UE_MAX+1)), (char*)&mch_buffer[sdu_length_total]); LOG_I(MAC,"[eNB %d][MBMS USER-PLANE] CC_id %d Got %d bytes for MTCH %d\n",module_idP,CC_id,sdu_lengths[num_sdus],MTCH); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c index 9c8b23df07..38f39e50e1 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dataplane.c @@ -174,6 +174,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, @@ -193,6 +194,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, @@ -209,6 +211,7 @@ void flexran_apply_ue_spec_scheduling_decisions(mid_t mod_id, ENB_FLAG_YES, MBMS_FLAG_NO, lcid, + rlc_size, //not used (char *)&dlsch_buffer[sdu_length_total]); LOG_D(MAC,"[eNB %d][LCID %d] CC_id %d Got %d bytes from RLC\n",mod_id, lcid, CC_id, sdu_lengths[j]); diff --git a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c index 00027f04ce..5f1df67663 100644 --- a/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c +++ b/openair2/LAYER2/MAC/flexran_agent_scheduler_dlsch_ue.c @@ -160,7 +160,7 @@ void _store_dlsch_buffer (module_id_t Mod_id, for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); + rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; @@ -1241,6 +1241,7 @@ flexran_schedule_ue_spec_common(mid_t mod_id, rnti, mod_id, frame, + subframe, ENB_FLAG_YES, MBMS_FLAG_NO, j, diff --git a/openair2/LAYER2/MAC/pre_processor.c b/openair2/LAYER2/MAC/pre_processor.c index 6e73e353f0..74e0a43d7d 100644 --- a/openair2/LAYER2/MAC/pre_processor.c +++ b/openair2/LAYER2/MAC/pre_processor.c @@ -109,7 +109,7 @@ void store_dlsch_buffer (module_id_t Mod_id, for(i=0; i< MAX_NUM_LCID; i++) { // loop over all the logical channels - rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); + rlc_status = mac_rlc_status_ind(Mod_id,rnti, Mod_id,frameP,subframeP,ENB_FLAG_YES,MBMS_FLAG_NO,i,0 ); UE_template->dl_buffer_info[i] = rlc_status.bytes_in_buffer; //storing the dlsch buffer for each logical channel UE_template->dl_pdus_in_buffer[i] = rlc_status.pdus_in_buffer; UE_template->dl_buffer_head_sdu_creation_time[i] = rlc_status.head_sdu_creation_time ; diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c index 43bc113798..210648401f 100644 --- a/openair2/LAYER2/MAC/ra_procedures.c +++ b/openair2/LAYER2/MAC/ra_procedures.c @@ -394,7 +394,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, } else if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[DCCH]] > 0) { // This is for triggering a transmission on DCCH using PRACH (during handover, or sending SR for example) dcch_header_len = 2 + 2; /// SHORT Subheader + C-RNTI control element - rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, + rlc_status = mac_rlc_status_ind(module_idP,UE_mac_inst[module_idP].crnti, eNB_indexP,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, DCCH, 6); @@ -409,6 +409,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP,int CC_id,frame_t frameP, sdu_lengths[0] = mac_rlc_data_req(module_idP, UE_mac_inst[module_idP].crnti, eNB_indexP, frameP,ENB_FLAG_NO, MBMS_FLAG_NO, DCCH, + 6, //not used (char *)&ulsch_buff[0]); LOG_D(MAC,"[UE %d] TX Got %d bytes for DCCH\n",module_idP,sdu_lengths[0]); diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index 6d304051d4..c6d847c835 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -1265,13 +1265,13 @@ unsigned char generate_ulsch_header(uint8_t *mac_header, void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subframe, uint8_t eNB_index,uint8_t *ulsch_buffer,uint16_t buflen, uint8_t *access_mode) { - mac_rlc_status_resp_t rlc_status; uint8_t total_rlc_pdu_header_len=0, rlc_pdu_header_len_last=0 ; uint16_t buflen_remain = 0; uint8_t bsr_len=0,bsr_ce_len=0,bsr_header_len=0; uint8_t phr_header_len=0, phr_ce_len=0,phr_len=0; uint8_t lcid=0,lcid_rlc_pdu_count=0; boolean_t is_lcid_processed = FALSE; + boolean_t is_all_lcid_processed = FALSE; uint16_t sdu_lengths[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t sdu_lcids[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; uint8_t payload_offset=0,num_sdus=0; @@ -1291,6 +1291,7 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf int lcg_id_bsr_trunc = 0; int highest_priority = 16; int num_lcg_id_with_data = 0; + rlc_buffer_occupancy_t lcid_buffer_occupancy_old=0, lcid_buffer_occupancy_new=0; LOG_D(MAC,"[UE %d] MAC PROCESS UL TRANSPORT BLOCK at frame%d subframe %d TBS=%d\n", module_idP, frameP, subframe, buflen); @@ -1400,16 +1401,32 @@ void ue_get_sdu(module_id_t module_idP,int CC_id,frame_t frameP,sub_frame_t subf // check for UL bandwidth requests and add SR control element // Check for DCCH first -// TO DO: Unrool the loop to do it at least once to avoid the if num_sdu -for (lcid=DCCH; lcid < DTCH ; lcid++) { +// TO DO: Multiplex in the order defined by the logical channel prioritization +for (lcid=DCCH; (lcid < MAX_NUM_LCID) && (is_all_lcid_processed == FALSE) ; lcid++) { if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { - is_lcid_processed = FALSE; lcid_rlc_pdu_count = 0; + is_lcid_processed = FALSE; + lcid_buffer_occupancy_old = mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + subframe, + ENB_FLAG_NO, + lcid); + + lcid_buffer_occupancy_new = lcid_buffer_occupancy_old; + + AssertFatal (lcid_buffer_occupancy_new == UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid], "LCID=%d RLC has BO %d bytes but MAC has stored %d bytes\n", + lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); + + AssertFatal (lcid_buffer_occupancy_new <= UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], "LCID=%d RLC has more BO %d bytes than BSR = %d bytes\n", + lcid,lcid_buffer_occupancy_new,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + //Multiplex all available DCCH RLC PDUs considering to multiplex the last PDU each time for maximize the data //Adjust at the end of the loop - while ((!is_lcid_processed) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { + while ((!is_lcid_processed) && (lcid_buffer_occupancy_new) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { // Workaround for issue in OAI eNB or EPC which are not able to process SRB2 message multiplexed with SRB1 on the same MAC PDU if ((usim_test == 0) && (lcid == DCCH1) && (lcid_rlc_pdu_count == 0) && (num_sdus)) { @@ -1420,253 +1437,103 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) { buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - rlc_status = mac_rlc_status_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, // eNB_index - lcid, - buflen_remain); - // Workaround for BO issue in RLC AM ReTx : RLC BO can not be bigger than stored MAC BO - if (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] < rlc_status.bytes_in_buffer) { - - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d\n", - module_idP,frameP,subframe, - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count); - - // Skip multiplexing for the LCID - break; - } - - /* - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d Frame %d Subrame %d\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count,frameP,subframe); - */ - - if (rlc_status.bytes_in_buffer > 0) { + LOG_D(MAC, "[UE %d] Frame %d : UL-DXCH -> ULSCH, RLC %d has %d bytes to " + "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", + module_idP,frameP, lcid,lcid_buffer_occupancy_new,buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - LOG_D(MAC, "[UE %d] Frame %d : UL-DCCH -> ULSCH, RLC SRB%d has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); + sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + ENB_FLAG_NO, + MBMS_FLAG_NO, + lcid, + buflen_remain, + (char *)&ulsch_buff[sdu_length_total]); - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - (char *)&ulsch_buff[sdu_length_total]); + AssertFatal (buflen_remain >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", + lcid,sdu_lengths[num_sdus],buflen_remain); - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - lcid,sdu_lengths[num_sdus],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); + if (sdu_lengths[num_sdus]) + { + sdu_length_total += sdu_lengths[num_sdus]; + sdu_lcids[num_sdus] = lcid; + LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LcId%d\n",module_idP,sdu_lengths[num_sdus],lcid); + if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { + //No more remaining TBS after this PDU + //exit the function + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } + else { + rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; + //Change to 1 byte if it does not fit in the TBS, ie last PDU + if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { + rlc_pdu_header_len_last = 1; + is_lcid_processed = TRUE; + is_all_lcid_processed = TRUE; + } + } - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = lcid; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for SRB%d\n",module_idP,sdu_lengths[num_sdus],lcid); - //header_len +=2; - // update LCID remain buffer - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] -= sdu_lengths[num_sdus]; - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= sdu_lengths[num_sdus]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= sdu_lengths[num_sdus] ; - } - else { - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data transmitted=%d for LCID%d\n", - module_idP,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], - UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], - sdu_lengths[num_sdus],lcid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; - } + //Update number of SDU + num_sdus ++; - //Update the number of LCGID with data as BSR shall reflect status after BSR transmission - if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) - { - num_lcg_id_with_data --; - // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 - if ((bsr_len) && (num_lcg_id_with_data == 1)) - { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_len = bsr_ce_len + bsr_header_len; - } + //Update total MAC Header size for RLC PDUs and save last one + total_rlc_pdu_header_len += rlc_pdu_header_len_last; - } + lcid_rlc_pdu_count ++; + } + else + { + /* avoid infinite loop ... */ + is_lcid_processed = TRUE; + } - if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { - //No more remaining TBS after this PDU - //exit the function - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - else { - rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; + /* Get updated BO after multiplexing this PDU */ + lcid_buffer_occupancy_new = mac_rlc_get_buffer_occupancy_ind(module_idP, + UE_mac_inst[module_idP].crnti, + eNB_index, + frameP, + subframe, + ENB_FLAG_NO, + lcid); - //Change to 1 byte if it does not fit in the TBS, ie last PDU - if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - } - - //Update number of SDU - num_sdus ++; - - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - - } //end if (rlc_status.bytes_in_buffer > 0) - else { - // Switch to next LCID or exit the whole loop - is_lcid_processed = TRUE; - } - lcid_rlc_pdu_count ++; + is_lcid_processed = (is_lcid_processed) || (lcid_buffer_occupancy_new <= 0); } + //Update Buffer remain and BSR bytes after transmission + + AssertFatal (lcid_buffer_occupancy_new <= lcid_buffer_occupancy_old, "MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n", + lcid_buffer_occupancy_new,lcid_buffer_occupancy_old,lcid,lcid_rlc_pdu_count,frameP,subframe); + + UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new; + UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] += (lcid_buffer_occupancy_new - lcid_buffer_occupancy_old); + + //Update the number of LCGID with data as BSR shall reflect status after BSR transmission + if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) + { + num_lcg_id_with_data --; + // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 + if ((bsr_len) && (num_lcg_id_with_data == 1)) + { + bsr_ce_len = sizeof(BSR_SHORT); + bsr_len = bsr_ce_len + bsr_header_len; + } + } + + UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; } -} - - -// Now Check for DTCH first -// TO DO: do it according to Logical Channel Prioritization if at least 2 DTCH -for (lcid=DTCH; lcid < MAX_NUM_LCID ; lcid++) { -if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY) { - - is_lcid_processed = FALSE; - lcid_rlc_pdu_count = 0; - - //Multiplex all available DTCH RLC PDUs considering to multiplex the last PDU each time for maximize the data - //Adjust at the end of the loop - while ((!is_lcid_processed) && (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + MIN_MAC_HDR_RLC_SIZE <= buflen)) { - - buflen_remain = buflen - (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1); - - rlc_status = mac_rlc_status_ind(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, // eNB_index - lcid, - buflen_remain); - - // Workaround for BO issue in RLC AM ReTx : RLC BO can not be bigger than stored MAC BO - if (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] < rlc_status.bytes_in_buffer) { - - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d\n", - module_idP,frameP,subframe, - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count); - - // Skip multiplexing for the LCID - break; - } - - /* - AssertFatal ( UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= rlc_status.bytes_in_buffer, "Inconsistent BO! for LCID=%d MAC=%d RLC=%d RLC PDU nb=%d Frame %d Subrame %d\n", - lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],rlc_status.bytes_in_buffer,lcid_rlc_pdu_count,frameP,subframe); - */ - - if (rlc_status.bytes_in_buffer > 0) { - - - LOG_D(MAC, "[UE %d] Frame %d : UL-DTCH -> ULSCH, RLC LCID%d has %d bytes to " - "send (Transport Block size %d BSR size=%d PHR=%d SDU Length Total %d , mac header len %d BSR byte before Tx=%d)\n", - module_idP,frameP, lcid,UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid],buflen,bsr_len,phr_len,sdu_length_total,total_rlc_pdu_header_len,UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]]); - - - sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, - UE_mac_inst[module_idP].crnti, - eNB_index, - frameP, - ENB_FLAG_NO, - MBMS_FLAG_NO, - lcid, - (char *)&ulsch_buff[sdu_length_total]); - - AssertFatal (sdu_lengths[num_sdus] < MAX_ULSCH_PAYLOAD_BYTES, "LCID=%d RLC PDU size = %d is too big\n", - lcid,sdu_lengths[num_sdus]); - - - AssertFatal (UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] >= sdu_lengths[num_sdus], "LCID=%d RLC has segmented %d bytes but MAC has max=%d\n", - lcid,sdu_lengths[num_sdus],UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]); - - - - sdu_length_total += sdu_lengths[num_sdus]; - sdu_lcids[num_sdus] = lcid; - LOG_D(MAC,"[UE %d] TX Multiplex RLC PDU TX Got %d bytes for LCID%d\n",module_idP,sdu_lengths[num_sdus],lcid); - //header_len +=2; - // update LCID remain buffer - UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid] -= sdu_lengths[num_sdus]; - /* Update BSR : substract transmitted data */ - if (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] >= sdu_lengths[num_sdus]){ - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] -= sdu_lengths[num_sdus] ; - } - else { - LOG_I(MAC, "[UE %d] Frame %d Subframe%d: WARNING Buffer occupancy =%d for LCGID%d is lower than data transmitted=%d for LCID%d\n", - module_idP,frameP,subframe, - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]], - UE_mac_inst[module_idP].scheduling_info.LCGID[lcid], - sdu_lengths[num_sdus],lcid); - UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] = 0; - } - - //Update the number of LCGID with data as BSR shall reflect status after BSR transmission - if ((num_lcg_id_with_data > 1) && (UE_mac_inst[module_idP].scheduling_info.BSR_bytes[UE_mac_inst[module_idP].scheduling_info.LCGID[lcid]] == 0)) - { - num_lcg_id_with_data --; - // Change BSR size to BSR SHORT if num_lcg_id_with_data becomes to 1 - if ((bsr_len) && (num_lcg_id_with_data == 1)) - { - bsr_ce_len = sizeof(BSR_SHORT); - bsr_len = bsr_ce_len + bsr_header_len; - } - - } - - if (buflen == (bsr_len + phr_len + total_rlc_pdu_header_len + sdu_length_total + 1)) { - //No more remaining TBS after this PDU - //exit the function - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - else { - rlc_pdu_header_len_last = (sdu_lengths[num_sdus] > 128 ) ? 3 : 2 ; - - //Change to 1 byte if it does not fit in the TBS, ie last PDU - if (buflen <= (bsr_len + phr_len + total_rlc_pdu_header_len + rlc_pdu_header_len_last + sdu_length_total)) { - rlc_pdu_header_len_last = 1; - is_lcid_processed = TRUE; - } - } - - //Update number of SDU - num_sdus ++; - - //Update total MAC Header size for RLC PDUs and save last one - total_rlc_pdu_header_len += rlc_pdu_header_len_last; - - } //end if (rlc_status.bytes_in_buffer > 0) - else { - // Switch to next LCID or exit the whole loop - is_lcid_processed = TRUE; - } - lcid_rlc_pdu_count ++; } - UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY; - } -} - //lcgid= get_bsr_lcgid(module_idP); // Compute BSR Values and update Nb LCGID with data after multiplexing num_lcg_id_with_data = 0; @@ -2396,7 +2263,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra lcgid_buffer_remain[lcgid] += UE_mac_inst[module_idP].scheduling_info.LCID_buffer_remain[lcid]; } - rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,ENB_FLAG_NO,MBMS_FLAG_NO, + rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, 0); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 4d16a368fe..5dfaddb28d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -186,9 +186,9 @@ rlc_am_get_buffer_occupancy_in_bytes ( #if TRACE_RLC_AM_BO - if ((rlc_pP->status_buffer_occupancy + rlc_pP->retransmission_buffer_occupancy + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead) > 0) { + if ((rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead) > 0) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : STATUS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->status_buffer_occupancy); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : RETRANS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->retransmission_buffer_occupancy); + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : RETRANS BUFFER %d bytes \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->retrans_num_bytes_to_retransmit); LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : SDU BUFFER %d bytes + li_overhead %d bytes header_overhead %d bytes (nb sdu not segmented %d)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->sdu_buffer_occupancy, @@ -669,13 +669,13 @@ rlc_am_mac_status_indication ( */ if (rlc->input_sdus == NULL) return status_resp; - if (rlc->last_frame_status_indication != ctxt_pP->frame) { + if (rlc->last_absolute_subframe_status_indication != (PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP))) { rlc_am_check_timer_poll_retransmit(ctxt_pP, rlc); rlc_am_check_timer_reordering(ctxt_pP, rlc); rlc_am_check_timer_status_prohibit(ctxt_pP, rlc); } - rlc->last_frame_status_indication = ctxt_pP->frame; + rlc->last_absolute_subframe_status_indication = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP); rlc->nb_bytes_requested_by_mac = tb_sizeP; @@ -701,31 +701,14 @@ rlc_am_mac_status_indication ( } } else { - if (rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc)) { - if ((status_resp.buffer_occupancy_in_bytes == 0) && (rlc->input_sdus[rlc->current_sdu_index].mem_block == NULL) && (rlc->nb_sdu > 0)) { - // force BO to be > 0 - rlc_sn_t sn = (rlc->vt_s - 1) & RLC_AM_SN_MASK; - rlc_sn_t sn_end = (rlc->vt_a - 1) & RLC_AM_SN_MASK; - - /* Look for the first retransmittable PDU starting from vtS - 1 */ - while (sn != sn_end) { - AssertFatal (rlc->tx_data_pdu_buffer[sn].mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", - sn, rlc->vt_a,rlc->vt_s,rlc->channel_id); - if ((rlc->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) { - rlc->retrans_num_bytes_to_retransmit = rlc->tx_data_pdu_buffer[sn].header_and_payload_size; - rlc->tx_data_pdu_buffer[sn].flags.retransmit = 1; - status_resp.buffer_occupancy_in_bytes = rlc->tx_data_pdu_buffer[sn].header_and_payload_size; - status_resp.buffer_occupancy_in_pdus = rlc->nb_sdu; - status_resp.head_sdu_remaining_size_to_send = status_resp.buffer_occupancy_in_bytes; - // TODO head_sdu_is_segmented - break; - } - else - { - sn = RLC_AM_PREV_SN(sn); - } - } - } + /* Not so many possibilities ... */ + /* either buffer_occupancy_in_bytes = 0 and that's it */ + /* or we have segmented all received SDUs and buffer occupancy is then made of retransmissions and/or status pdu pending */ + /* then consider only retransmission buffer for the specific BO values used by eNB scheduler (not used up to now...) */ + if (rlc->retrans_num_bytes_to_retransmit) { + status_resp.buffer_occupancy_in_pdus = rlc->retrans_num_pdus; + status_resp.head_sdu_remaining_size_to_send = rlc->retrans_num_bytes_to_retransmit; + status_resp.head_sdu_is_segmented = 1; } } #if MESSAGE_CHART_GENERATOR_RLC_MAC @@ -770,6 +753,17 @@ rlc_am_mac_status_indication ( #endif return status_resp; } + +//----------------------------------------------------------------------------- +void +rlc_am_set_nb_bytes_requested_by_mac ( + void * const rlc_pP, + const tb_size_t tb_sizeP +) +{ + ((rlc_am_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP; +} + //----------------------------------------------------------------------------- struct mac_data_req rlc_am_mac_data_request ( diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h index 61c6a043cc..f64c13e850 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -277,6 +277,13 @@ protected_rlc_am( void rlc_am_rx (const protocol_ctxt_t* const ctxtP,void * */ public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP);) +/*! \fn void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP) +* \brief Set available TBS for RLC Tx just before am_mac_data_request. Used for UE only. +* \param[in] rlc_pP RLC AM protocol instance pointer. +* \param[in] tb_sizeP Available Tx Transport Block size in bytes. +*/ +public_rlc_am( void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP);) + /*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. @@ -293,6 +300,13 @@ public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ct */ public_rlc_am( void rlc_am_mac_data_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind data_indP);) +/*! \fn uint32_t rlc_am_get_buffer_occupancy_in_bytes (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP) +* \brief Get Tx Buffer Occupancy. +* \param[in] ctxt_pP Running context. +* \param[in] rlc_pP RLC AM protocol instance pointer. +*/ +public_rlc_am( uint32_t rlc_am_get_buffer_occupancy_in_bytes (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP);) + /*! \fn void rlc_am_data_req (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, mem_block_t *sduP) * \brief Interface with higher layers, buffer higher layer SDUS for transmission. * \param[in] ctxt_pP Running context. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 87150f115c..682a781818 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -57,7 +57,6 @@ typedef struct rlc_am_entity_s { boolean_t is_data_plane; /*!< \brief To know if the RLC belongs to a data radio bearer or a signalling radio bearer, for statistics and trace purpose. */ rlc_buffer_occupancy_t sdu_buffer_occupancy; /*!< \brief Number of bytes of unsegmented SDUs. */ - rlc_buffer_occupancy_t retransmission_buffer_occupancy; /*!< \brief Number of bytes of PDUs in retransmission buffer waiting for a ACK. */ rlc_buffer_occupancy_t status_buffer_occupancy; /*!< \brief Number of bytes of control PDUs waiting for transmission. */ rlc_am_control_pdu_info_t control_pdu_info; @@ -76,7 +75,7 @@ typedef struct rlc_am_entity_s { rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer; /*!< \brief Transmission PDU data buffer. Used also for retransmissions */ signed int retrans_num_pdus; /*!< \brief Number of PDUs in the retransmission buffer. */ - signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. */ + signed int retrans_num_bytes_to_retransmit; /*!< \brief Number of bytes in the retransmission buffer to be retransmitted. Only payload is taken into account */ boolean_t force_poll; /*!< \brief force poll due to t_poll_retransmit time-out. */ //--------------------------------------------------------------------- @@ -181,7 +180,7 @@ typedef struct rlc_am_entity_s { uint8_t status_requested; /*!< \brief Status bitmap requested by peer. */ rlc_sn_t sn_status_triggered_delayed; /*!< \brief SN of the last received poll for which Status is delayed until SN is out of Rx Window. */ - frame_t last_frame_status_indication; /*!< \brief The last frame number a MAC status indication has been received by RLC. */ + uint32_t last_absolute_subframe_status_indication; /*!< \brief The last absolute subframe number a MAC status indication has been received by RLC. */ //----------------------------- // buffer occupancy measurements sent to MAC //----------------------------- diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index 4122fd0e66..820b06c233 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -41,17 +41,23 @@ void rlc_am_free_in_sdu( const unsigned int index_in_bufferP) { if (index_in_bufferP <= RLC_AM_SDU_CONTROL_BUFFER_SIZE) { + /* BugFix: SDU shall have been already freed during initial PDU segmentation or concatenation !! */ + AssertFatal(rlcP->input_sdus[index_in_bufferP].mem_block == NULL, "RLC AM Tx SDU Conf: Data Part is not empty index=%d LcId=%d\n", + index_in_bufferP,rlcP->channel_id); + /* if (rlcP->input_sdus[index_in_bufferP].mem_block != NULL) { free_mem_block(rlcP->input_sdus[index_in_bufferP].mem_block, __func__); rlcP->input_sdus[index_in_bufferP].mem_block = NULL; rlcP->nb_sdu_no_segmented -= 1; rlcP->input_sdus[index_in_bufferP].sdu_remaining_size = 0; } + */ rlcP->nb_sdu -= 1; memset(&rlcP->input_sdus[index_in_bufferP], 0, sizeof(rlc_am_tx_sdu_management_t)); rlcP->input_sdus[index_in_bufferP].flags.transmitted_successfully = 1; + // TODO : understand why. This should not happen if (rlcP->current_sdu_index == index_in_bufferP) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index b93f331676..ce5afe7c59 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -79,7 +79,7 @@ rlc_am_init( //rlc_pP->vr_h = 0; rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; - rlc_pP->last_frame_status_indication = 123456; // any value > 1 + rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 rlc_pP->first_retrans_pdu_sn = -1; rlc_pP->initialized = TRUE; @@ -135,7 +135,7 @@ rlc_am_reestablish( rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; rlc_pP->status_requested = RLC_AM_STATUS_NOT_TRIGGERED; - rlc_pP->last_frame_status_indication = 123456; // any value > 1 + rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 rlc_pP->first_retrans_pdu_sn = -1; rlc_pP->initialized = TRUE; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 4db9893f8a..d2941b061d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -51,8 +51,8 @@ void rlc_am_nack_pdu ( mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; - int pdu_sdu_index; - int sdu_index; + //int pdu_sdu_index; + //int sdu_index; if (mb_p != NULL) { assert(so_startP <= so_endP); @@ -84,10 +84,10 @@ void rlc_am_nack_pdu ( rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 1; - /* TODO : before incrementing retx_count_next, this must be a new occurrence of retransmission */ + /* TODO : before incrementing retx_count_next, one have to check this must be a new occurrence of retransmission */ if (rlc_pP->tx_data_pdu_buffer[snP].retx_count == rlc_pP->tx_data_pdu_buffer[snP].retx_count_next){ rlc_pP->tx_data_pdu_buffer[snP].retx_count_next ++; - rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size; + rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[snP].payload_size; } /* TODO: Move this part in UL SCH processing */ @@ -148,7 +148,7 @@ void rlc_am_ack_pdu ( rlc_pP->tx_data_pdu_buffer[snP].retx_count); if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= 0) { - rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].header_and_payload_size; + rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].payload_size; } for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { @@ -845,7 +845,6 @@ void rlc_am_retransmit_any_pdu( //rlc_pP->c_pdu_without_poll = 0; //rlc_pP->c_byte_without_poll = 0; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; - rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_retransmit_pdu += 1; rlc_pP->stat_tx_data_bytes += ((struct mac_tb_req*)(pdu_p->data))->tb_size; @@ -879,7 +878,6 @@ void rlc_am_retransmit_any_pdu( rlc_pP->c_pdu_without_poll = 0; rlc_pP->c_byte_without_poll = 0; //rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; - rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); rlc_pP->stat_tx_data_pdu += 1; rlc_pP->stat_tx_retransmit_pdu += 1; rlc_pP->stat_tx_data_bytes += ((struct mac_tb_req*)(pdu_p->data))->tb_size; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index f75b481dbb..84d587d53b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -308,14 +308,12 @@ rlc_am_receive_process_control_pdu( assert(ack_sn < RLC_AM_SN_MODULO); assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU); - if (rlc_am_in_tx_window(ctxt_pP, rlc_pP, ack_sn) > 0) { - + /* Nv1495998 : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */ + /* and meaning the report is not complete due to not enough ressources to fill all SOStart/SOEnd of this NACK_SN */ + if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a)) + { if (rlc_pP->control_pdu_info.num_nack == 0) { while (sn_cursor != ack_sn) { - if (sn_cursor == rlc_pP->poll_sn) { - rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); - } - rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; } @@ -324,10 +322,6 @@ rlc_am_receive_process_control_pdu( nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; while (sn_cursor != ack_sn) { - if (sn_cursor == rlc_pP->poll_sn) { - rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); - } - if (sn_cursor != nack_sn) { rlc_am_ack_pdu(ctxt_pP, rlc_pP, @@ -357,6 +351,16 @@ rlc_am_receive_process_control_pdu( } } } + + /* Check for Stopping TpollReTx */ + if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) && + (RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) { + rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP); + rlc_pP->poll_sn = RLC_SN_UNDEFINED; + } + + /* Update vtA */ + } else { LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index e201e909c5..e2658f2c14 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -110,6 +110,7 @@ typedef struct rlc_am_tx_data_pdu_management { sdu_size_t hole_so_start [RLC_AM_MAX_HOLES_REPORT_PER_PDU]; /*!< \brief Array containing the start segment offsets for marking a hole (negative acknowledged area) in the PDU. */ sdu_size_t hole_so_stop [RLC_AM_MAX_HOLES_REPORT_PER_PDU]; /*!< \brief Array containing the stop segment offsets for marking a hole (negative acknowledged area) in the PDU. */ uint8_t num_holes; /*!< \brief Number of registereg holes in hole_so_start[], hole_so_stop[]. */ + uint8_t retx_hole_index; /*!< \brief Next index of registered holes to retransmit. */ sdu_size_t header_and_payload_size; /*!< \brief Size of the PDU in bytes, including header and payload. */ sdu_size_t payload_size; /*!< \brief Size of the PDU payload in bytes. */ rlc_sn_t sn; /*!< \brief Sequence number of the PDU. */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index aa3fdb909a..d7079bba9b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -77,10 +77,32 @@ rlc_am_check_timer_poll_retransmit( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] TIME-OUT\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + /* Check for any retransmittable PDU if Buffer Occupancy empty or window stall */ + if (((rlc_pP->sdu_buffer_occupancy == 0) && (rlc_pP->retrans_num_bytes_to_retransmit == 0)) || + (rlc_pP->vt_s == rlc_pP->vt_ms)) { + // force BO to be > 0 + rlc_sn_t sn = RLC_AM_PREV_SN(rlc_pP->vt_s); + rlc_sn_t sn_end = RLC_AM_PREV_SN(rlc_pP->vt_a); + + /* Look for the first retransmittable PDU starting from vtS - 1 */ + while (sn != sn_end) { + AssertFatal (rlc_pP->tx_data_pdu_buffer[sn].mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", + sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + if ((rlc_pP->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc_pP->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) { + rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit = 1; + rlc_pP->retrans_num_pdus += 1; + rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[sn].payload_size; + } + else + { + sn = RLC_AM_PREV_SN(sn); + } + } + } + rlc_pP->force_poll= TRUE; - //#warning TO DO rlc_am_check_timer_poll_retransmit - rlc_pP->t_poll_retransmit.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_poll_retransmit.ms_duration; + //BugFix : new ms_time_out is computed when next poll is transmitter } } } @@ -119,9 +141,9 @@ rlc_am_start_timer_poll_retransmit( rlc_am_entity_t * const rlc_pP ) { - rlc_pP->t_poll_retransmit.timed_out = 0; + /* Stop timer if it was previously running */ + rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP,rlc_pP); - if (rlc_pP->t_poll_retransmit.running == 0) { if (rlc_pP->t_poll_retransmit.ms_duration > 0) { rlc_pP->t_poll_retransmit.running = 1; rlc_pP->t_poll_retransmit.ms_time_out = PROTOCOL_CTXT_TIME_MILLI_SECONDS(ctxt_pP) + rlc_pP->t_poll_retransmit.ms_duration; @@ -138,14 +160,7 @@ rlc_am_start_timer_poll_retransmit( LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] NOT STARTED, CAUSE CONFIGURED 0 ms\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } - } else { -#if MESSAGE_CHART_GENERATOR_RLC_MAC - MSC_LOG_EVENT((ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_RLC_ENB:MSC_RLC_UE,\ - "0 "PROTOCOL_RLC_AM_MSC_FMT" t_poll_retransmit not restarted (TO %u ms)",\ - PROTOCOL_RLC_AM_MSC_ARGS(ctxt_pP,rlc_pP), rlc_pP->t_poll_retransmit.ms_time_out); -#endif - } } //----------------------------------------------------------------------------- void diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c index 51440d0bfa..de83717cb7 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -520,6 +520,16 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP return status_resp; } +//----------------------------------------------------------------------------- +void +rlc_um_set_nb_bytes_requested_by_mac ( + void * rlc_pP, + const tb_size_t tb_sizeP +) +{ + ((rlc_um_entity_t *) rlc_pP)->nb_bytes_requested_by_mac = tb_sizeP; +} + //----------------------------------------------------------------------------- struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP) diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h index 5951eaf149..fe3646b309 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -188,6 +188,13 @@ protected_rlc_um( void rlc_um_rx (const protocol_ctxt_t* const ctxt_pP, rlc_ */ public_rlc_um( struct mac_status_resp rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP, const eNB_flag_t enb_flagP);) +/*! \fn void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP) +* \brief Set available TBS size for MAC Tx. +* \param[in] rlc_pP RLC UM protocol instance pointer. +* \param[in] tb_sizeP remaining TBS in bytes. +*/ +public_rlc_um( void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP);) + /*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. @@ -205,6 +212,11 @@ public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ct */ public_rlc_um( void rlc_um_mac_data_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, struct mac_data_ind data_indP);) +/*! \fn uint32_t rlc_um_get_buffer_occupancy (rlc_um_entity_t *rlc_pP) +* \brief Gets Tx Buffer Occupancy. +* \param[in] rlc_pP RLC UM protocol instance pointer.) +*/ +public_rlc_um( uint32_t rlc_um_get_buffer_occupancy (rlc_um_entity_t *rlc_pP);) /*! \fn void rlc_um_data_req (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP, mem_block_t *sduP) * \brief Interface with higher layers, buffer higher layer SDUS for transmission. diff --git a/openair2/LAYER2/RLC/rlc.h b/openair2/LAYER2/RLC/rlc.h index 3fd5b8c3bc..9a53e37422 100644 --- a/openair2/LAYER2/RLC/rlc.h +++ b/openair2/LAYER2/RLC/rlc.h @@ -436,10 +436,11 @@ public_rlc_rrc(void rrc_rlc_register_rrc (rrc_data_ind_cb_t rrc_data_indP, rrc_d * \param [in] eNB_flagP Flag to indicate eNB (1) or UE (0) * \param [in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0) * \param [in] rb_idP Radio bearer identifier. +* \param [in] tb_sizeP Available Tx TBS in bytes. For UE only. * \param [in,out] bufferP Memory area to fill with the bytes requested by MAC. * \return A status about the processing, OK or error code. */ -public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, char*);) +public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, const tb_size_t,char*);) /*! \fn void mac_rlc_data_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, uint32_t frameP, char* bufferP, tb_size_t tb_sizeP, num_tb_t num_tbP, crc_t *crcs) * \brief Interface with MAC layer, deserialize the transport blocks sent by MAC, then map data indication to the RLC instance corresponding to the radio bearer identifier. @@ -457,18 +458,31 @@ public_rlc_mac(tbs_size_t mac_rlc_data_req (const module_id_t, co public_rlc_mac(void mac_rlc_data_ind (const module_id_t, const rnti_t, const eNB_index_t,const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, char*, tb_size_t, num_tb_t, crc_t* );) -/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, tb_size_t tb_sizeP) +/*! \fn mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t mod_idP, const rnti_t rntiP, const frame_t frameP, const sub_frame_t subframeP, const eNB_flag_t eNB_flagP, const MBMS_flag_t MBMS_flagP, logical_chan_id_t rb_idP, tb_size_t tb_sizeP) * \brief Interface with MAC layer, request and set the number of bytes scheduled for transmission by the RLC instance corresponding to the radio bearer identifier. * \param[in] mod_idP Virtualized module identifier. * \param[in] rntiP UE identifier. * \param[in] frameP Frame index. +* \param[in] subframeP SubFrame index. * \param[in] eNB_flagP Flag to indicate eNB operation (1 true, 0 false) * \param[in] MBMS_flagP Flag to indicate whether this is the MBMS service (1) or not (0) * \param[in] rb_idP Radio bearer identifier. * \param[in] tb_sizeP Size of a transport block set in bytes. * \return The maximum number of bytes that the RLC instance can send in the next transmission sequence. */ -public_rlc_mac(mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, tb_size_t );) +public_rlc_mac(mac_rlc_status_resp_t mac_rlc_status_ind (const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const MBMS_flag_t, logical_chan_id_t, tb_size_t );) + +/*! \fn rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(const module_id_t module_idP, const rnti_t rntiP, const eNB_index_t eNB_index, const frame_t frameP, const sub_frame_t subframeP,const eNB_flag_t enb_flagP, const logical_chan_id_t channel_idP) +* \brief Interface with MAC layer, UE only: request and get the number of bytes scheduled for transmission by the RLC instance corresponding to the radio bearer identifier. +* \param[in] mod_idP Virtualized module identifier. +* \param[in] rntiP UE identifier. +* \param[in] frameP Frame index. +* \param[in] subframeP SubFrame index. +* \param[in] eNB_flagP Flag to indicate eNB operation (1 true, 0 false) +* \param[in] channel_idP Logical Channel identifier. +* \return The maximum number of bytes that the RLC instance can send in the next transmission sequence. +*/ +public_rlc_mac(rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind(const module_id_t, const rnti_t, const eNB_index_t, const frame_t, const sub_frame_t, const eNB_flag_t, const logical_chan_id_t );) //----------------------------------------------------------------------------- // RLC methods //----------------------------------------------------------------------------- diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index d43a90ed6a..2eeea2e8c5 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -125,6 +125,7 @@ tbs_size_t mac_rlc_data_req( const eNB_flag_t enb_flagP, const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, + const tb_size_t tb_sizeP, char *buffer_pP) { //----------------------------------------------------------------------------- @@ -189,12 +190,14 @@ tbs_size_t mac_rlc_data_req( break; case RLC_MODE_AM: - data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am); + if (!enb_flagP) rlc_am_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.am,tb_sizeP); + data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am); ret_tb_size =mac_rlc_serialize_tb(buffer_pP, data_request.data); break; case RLC_MODE_UM: - data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um); + if (!enb_flagP) rlc_um_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.um,tb_sizeP); + data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um); ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data); break; @@ -320,6 +323,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( const rnti_t rntiP, const eNB_index_t eNB_index, const frame_t frameP, + const sub_frame_t subframeP, const eNB_flag_t enb_flagP, const MBMS_flag_t MBMS_flagP, const logical_chan_id_t channel_idP, @@ -337,7 +341,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( srb_flag_t srb_flag = (channel_idP <= 2) ? SRB_FLAG_YES : SRB_FLAG_NO; protocol_ctxt_t ctxt; - PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, 0, eNB_index); + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, subframeP, eNB_index); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_STATUS_IND,VCD_FUNCTION_IN); memset (&mac_rlc_status_resp, 0, sizeof(mac_rlc_status_resp_t)); @@ -430,3 +434,65 @@ mac_rlc_status_resp_t mac_rlc_status_ind( return mac_rlc_status_resp; } +//----------------------------------------------------------------------------- +rlc_buffer_occupancy_t mac_rlc_get_buffer_occupancy_ind( + const module_id_t module_idP, + const rnti_t rntiP, + const eNB_index_t eNB_index, + const frame_t frameP, + const sub_frame_t subframeP, + const eNB_flag_t enb_flagP, + const logical_chan_id_t channel_idP) +{ + //----------------------------------------------------------------------------- + rlc_buffer_occupancy_t mac_rlc_buffer_occupancy_resp = 0; + rlc_mode_t rlc_mode = RLC_MODE_NONE; + rlc_union_t *rlc_union_p = NULL; + hash_key_t key = HASHTABLE_NOT_A_KEY_VALUE; + hashtable_rc_t h_rc; + srb_flag_t srb_flag = (channel_idP <= 2) ? SRB_FLAG_YES : SRB_FLAG_NO; + protocol_ctxt_t ctxt; + + PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, enb_flagP, rntiP, frameP, 0, eNB_index); + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_GET_BUFFER_OCCUPANCY_IND,VCD_FUNCTION_IN); + + + /* Assumptions : for UE only */ + /* At each TTI, Buffer Occupancy is first computed in mac_rlc_status_ind called by MAC ue_scheduler() function */ + /* Then this function is called during MAC multiplexing ue_get_sdu(), and it may be call several times for the same bearer if it is in AM mode and there are several PDU types to transmit */ + AssertFatal(enb_flagP == FALSE,"RLC Tx mac_rlc_get_buffer_occupancy_ind function is not implemented for eNB LcId=%d\n", channel_idP); + + + key = RLC_COLL_KEY_LCID_VALUE(module_idP, rntiP, enb_flagP, channel_idP, srb_flag); + + + h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p); + + if (h_rc == HASH_TABLE_OK) { + rlc_mode = rlc_union_p->mode; + } else { + rlc_mode = RLC_MODE_NONE; + //LOG_W(RLC , "[%s] RLC not configured rb id %u lcid %u module %u!\n", __FUNCTION__, rb_id, channel_idP, ue_module_idP); + //LOG_D(RLC , "[%s] RLC not configured rb id %u lcid %u module %u!\n", __FUNCTION__, rb_id, channel_idP, ue_module_idP); + } + + switch (rlc_mode) { + case RLC_MODE_AM: + mac_rlc_buffer_occupancy_resp = rlc_am_get_buffer_occupancy_in_bytes(&ctxt, &rlc_union_p->rlc.am); + break; + + case RLC_MODE_UM: + mac_rlc_buffer_occupancy_resp = rlc_um_get_buffer_occupancy(&rlc_union_p->rlc.um); + break; + + default: + mac_rlc_buffer_occupancy_resp = 0 ; + } + + //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_MAC_RLC_GET_BUFFER_OCCUPANCY_IND,VCD_FUNCTION_OUT); + + return mac_rlc_buffer_occupancy_resp; +} + + From e7e48144e1e5ba14f17ca1274148fc8abaa74f95 Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 16 Feb 2017 15:03:26 +0100 Subject: [PATCH 09/36] Remove RLC header size from UE L2 buffer occupancy --- openair2/LAYER2/MAC/ue_procedures.c | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 55 +++++++++++++++----------- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h | 10 +++-- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c | 31 ++++++--------- openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h | 5 ++- openair2/LAYER2/RLC/rlc_mac.c | 6 +-- 6 files changed, 56 insertions(+), 53 deletions(-) diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c index c6d847c835..ddd7490040 100644 --- a/openair2/LAYER2/MAC/ue_procedures.c +++ b/openair2/LAYER2/MAC/ue_procedures.c @@ -2265,7 +2265,7 @@ boolean_t update_bsr(module_id_t module_idP, frame_t frameP, sub_frame_t subfra rlc_status = mac_rlc_status_ind(module_idP, UE_mac_inst[module_idP].crnti,eNB_index,frameP,subframeP,ENB_FLAG_NO,MBMS_FLAG_NO, lcid, - 0); + 0xFFFF); //TBS is not used in RLC at this step, set a special value for debug lcid_bytes_in_buffer[lcid] = rlc_status.bytes_in_buffer; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index 5dfaddb28d..ad9810cfff 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -152,9 +152,6 @@ rlc_am_get_buffer_occupancy_in_bytes ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP) { - uint32_t max_li_overhead; - uint32_t header_overhead; - // priority of control trafic rlc_pP->status_buffer_occupancy = 0; if ((rlc_pP->status_requested) && !(rlc_pP->status_requested & RLC_AM_STATUS_NO_TX_MASK)) { @@ -168,21 +165,6 @@ rlc_am_get_buffer_occupancy_in_bytes ( #endif } - // data traffic - if (rlc_pP->nb_sdu_no_segmented <= 1) { - max_li_overhead = 0; - } else { - /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ - uint32_t num_li = rlc_pP->nb_sdu_no_segmented - 1; - max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); - } - - if (rlc_pP->sdu_buffer_occupancy == 0) { - header_overhead = 0; - } else { - header_overhead = 2; - } - #if TRACE_RLC_AM_BO @@ -192,13 +174,13 @@ rlc_am_get_buffer_occupancy_in_bytes ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" BO : SDU BUFFER %d bytes + li_overhead %d bytes header_overhead %d bytes (nb sdu not segmented %d)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), rlc_pP->sdu_buffer_occupancy, - max_li_overhead, - header_overhead, + 0, + 0, rlc_pP->nb_sdu_no_segmented); } #endif - return rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy + max_li_overhead + header_overhead; + return rlc_pP->status_buffer_occupancy + rlc_pP->retrans_num_bytes_to_retransmit + rlc_pP->sdu_buffer_occupancy; } //----------------------------------------------------------------------------- void @@ -645,7 +627,8 @@ rlc_am_mac_status_indication ( const protocol_ctxt_t* const ctxt_pP, void * const rlc_pP, const uint16_t tb_sizeP, - struct mac_status_ind tx_statusP) + struct mac_status_ind tx_statusP, + const eNB_flag_t enb_flagP) { struct mac_status_resp status_resp; uint16_t sdu_size = 0; @@ -681,6 +664,26 @@ rlc_am_mac_status_indication ( status_resp.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, rlc); + // For eNB scheduler : Add Max RLC header size for new PDU + // For UE : do not add RLC header part to be compliant with BSR definition in 36.321 + if (enb_flagP == ENB_FLAG_YES) { + uint32_t max_li_overhead = 0; + uint32_t header_overhead = 0; + + if (rlc->nb_sdu_no_segmented > 1) { + /* This computation assumes there is no SDU with size greater than 2047 bytes, otherwise a new PDU must be built except for LI15 configuration from Rel12*/ + uint32_t num_li = rlc->nb_sdu_no_segmented - 1; + max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); + } + + if (rlc->sdu_buffer_occupancy > 0) { + header_overhead = 2; + } + + status_resp.buffer_occupancy_in_bytes += (header_overhead + max_li_overhead); + } + + if ((rlc->input_sdus[rlc->current_sdu_index].mem_block != NULL) && (status_resp.buffer_occupancy_in_bytes)) { //status_resp.buffer_occupancy_in_bytes += ((rlc_am_entity_t *) rlc)->tx_header_min_length_in_bytes; @@ -768,7 +771,8 @@ rlc_am_set_nb_bytes_requested_by_mac ( struct mac_data_req rlc_am_mac_data_request ( const protocol_ctxt_t* const ctxt_pP, - void * const rlc_pP + void * const rlc_pP, + const eNB_flag_t enb_flagP ) { struct mac_data_req data_req; @@ -806,7 +810,10 @@ rlc_am_mac_data_request ( data_req.data.nb_elements); } - data_req.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, l_rlc_p); + if (enb_flagP) { + // redundant in UE MAC Tx processing and not used in eNB ... + data_req.buffer_occupancy_in_bytes = rlc_am_get_buffer_occupancy_in_bytes(ctxt_pP, l_rlc_p); + } data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state; #if TRACE_RLC_AM_PDU || MESSAGE_CHART_GENERATOR diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h index f64c13e850..4619a07315 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.h @@ -267,15 +267,16 @@ private_rlc_am( void rlc_am_get_pdus (const protocol_ctxt_t* const ctxtP,v */ protected_rlc_am( void rlc_am_rx (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind);) -/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP) +/*! \fn struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP) * \brief Request the maximum number of bytes that can be served by RLC instance to MAC and fix the amount of bytes requested by MAC for next RLC transmission. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] tbs_sizeP Number of bytes requested by MAC for next transmission. * \param[in] tx_statusP Transmission status given by MAC on previous MAC transmission of the PDU. +* \param[in] enb_flagP eNB or UE flag indication. * \return The maximum number of bytes that can be served by RLC instance to MAC. */ -public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP);) +public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const protocol_ctxt_t* const ctxtP, void * const rlc_pP, uint16_t tbs_sizeP, struct mac_status_ind tx_statusP,const eNB_flag_t enb_flagP);) /*! \fn void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP) * \brief Set available TBS for RLC Tx just before am_mac_data_request. Used for UE only. @@ -284,13 +285,14 @@ public_rlc_am( struct mac_status_resp rlc_am_mac_status_indication (const pro */ public_rlc_am( void rlc_am_set_nb_bytes_requested_by_mac (void * const rlc_pP,const tb_size_t tb_sizeP);) -/*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP) +/*! \fn struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP,const eNB_flag_t enb_flagP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. +* \param[in] enb_flagP eNB or UE flag * \return A PDU of the previously requested number of bytes, and the updated maximum number of bytes that can be served by RLC instance to MAC for next RLC transmission. */ -public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP);) +public_rlc_am( struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP,const eNB_flag_t enb_flagP);) /*! \fn void rlc_am_mac_data_indication (const protocol_ctxt_t* const ctxtP,void * const rlc_pP, struct mac_data_ind data_indP) * \brief Receive PDUs from lower layer MAC. diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c index de83717cb7..e3322d9410 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.c @@ -434,7 +434,6 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP int32_t diff_time=0; rlc_um_entity_t *rlc_p = NULL; mem_block_t *mb_p = NULL; - unsigned int max_li_overhead = 0; status_resp.buffer_occupancy_in_pdus = 0; status_resp.buffer_occupancy_in_bytes = 0; @@ -454,20 +453,11 @@ rlc_um_mac_status_indication (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP if ((status_resp.buffer_occupancy_in_bytes > 0) && ((mb_p = list_get_head(&rlc_p->input_sdus)) != NULL)) { - //Fix on full Header size - if (enb_flagP == ENB_FLAG_NO) - { - // compute Length Indicator overhead to inform MAC of maximum full RLC PDU size according to stored SDUs - // For UE scheduler - // Could be useful for eNB: to be checked - if (rlc_p->input_sdus.nb_elements <= 1) { - max_li_overhead = 0; - } else { - unsigned int num_li = rlc_p->input_sdus.nb_elements - 1; - max_li_overhead = num_li + (num_li >> 1) + (num_li & 1); - } - } - status_resp.buffer_occupancy_in_bytes += (rlc_p->tx_header_min_length_in_bytes + max_li_overhead); + if (enb_flagP == ENB_FLAG_YES) { + /* For eNB: add minimum RLC UM header size for the scheduler */ + /* For UE : RLC header part is not taken into account for BSR reporting (cf 36.321) */ + status_resp.buffer_occupancy_in_bytes += rlc_p->tx_header_min_length_in_bytes; + } status_resp.buffer_occupancy_in_pdus = rlc_p->input_sdus.nb_elements; diff_time = ctxt_pP->frame - ((struct rlc_um_tx_sdu_management *)mb_p->data)->sdu_creation_time; @@ -532,7 +522,7 @@ rlc_um_set_nb_bytes_requested_by_mac ( //----------------------------------------------------------------------------- struct mac_data_req -rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP) +rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP,const eNB_flag_t enb_flagP) { struct mac_data_req data_req; int16_t tb_size_in_bytes; @@ -554,10 +544,13 @@ rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, void *rlc_pP) list_add_list (&l_rlc_p->pdus_to_mac_layer, &data_req.data); - data_req.buffer_occupancy_in_bytes = rlc_um_get_buffer_occupancy (l_rlc_p); + if (enb_flagP) { + // redundant in UE MAC Tx processing and not used in eNB scheduler ... + data_req.buffer_occupancy_in_bytes = rlc_um_get_buffer_occupancy (l_rlc_p); - if (data_req.buffer_occupancy_in_bytes > 0) { - data_req.buffer_occupancy_in_bytes += l_rlc_p->tx_header_min_length_in_bytes; + if (data_req.buffer_occupancy_in_bytes > 0) { + data_req.buffer_occupancy_in_bytes += l_rlc_p->tx_header_min_length_in_bytes; + } } data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state; diff --git a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h index fe3646b309..87cf2e2f37 100644 --- a/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h +++ b/openair2/LAYER2/RLC/UM_v9.3.0/rlc_um.h @@ -195,13 +195,14 @@ public_rlc_um( struct mac_status_resp rlc_um_mac_status_indication (const pro */ public_rlc_um( void rlc_um_set_nb_bytes_requested_by_mac (rlc_um_entity_t * const rlc_pP, const tb_size_t tb_sizeP);) -/*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP) +/*! \fn struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,const eNB_flag_t enb_flagP) * \brief Gives PDUs to lower layer MAC. * \param[in] ctxt_pP Running context. * \param[in] rlc_pP RLC UM protocol instance pointer. +* \param[in] enb_flagP eNB or UE flag. * \return A PDU of the previously requested number of bytes, and the updated maximum number of bytes that can be served by RLC instance to MAC for next RLC transmission. */ -public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP);) +public_rlc_um( struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,const eNB_flag_t enb_flagP);) /*! \fn void rlc_um_mac_data_indication (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP,struct mac_data_ind data_indP) diff --git a/openair2/LAYER2/RLC/rlc_mac.c b/openair2/LAYER2/RLC/rlc_mac.c index 2eeea2e8c5..b4061ad29f 100644 --- a/openair2/LAYER2/RLC/rlc_mac.c +++ b/openair2/LAYER2/RLC/rlc_mac.c @@ -191,13 +191,13 @@ tbs_size_t mac_rlc_data_req( case RLC_MODE_AM: if (!enb_flagP) rlc_am_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.am,tb_sizeP); - data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am); + data_request = rlc_am_mac_data_request(&ctxt, &rlc_union_p->rlc.am,enb_flagP); ret_tb_size =mac_rlc_serialize_tb(buffer_pP, data_request.data); break; case RLC_MODE_UM: if (!enb_flagP) rlc_um_set_nb_bytes_requested_by_mac(&rlc_union_p->rlc.um,tb_sizeP); - data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um); + data_request = rlc_um_mac_data_request(&ctxt, &rlc_union_p->rlc.um,enb_flagP); ret_tb_size = mac_rlc_serialize_tb(buffer_pP, data_request.data); break; @@ -401,7 +401,7 @@ mac_rlc_status_resp_t mac_rlc_status_ind( break; case RLC_MODE_AM: - status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tb_sizeP, tx_status); + status_resp = rlc_am_mac_status_indication(&ctxt, &rlc_union_p->rlc.am, tb_sizeP, tx_status,enb_flagP); mac_rlc_status_resp.bytes_in_buffer = status_resp.buffer_occupancy_in_bytes; mac_rlc_status_resp.head_sdu_creation_time = status_resp.head_sdu_creation_time; mac_rlc_status_resp.head_sdu_remaining_size_to_send = status_resp.head_sdu_remaining_size_to_send; From b0d468c0f7518774a5ed3b5078342a95289d8883 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 22 Feb 2017 11:40:55 +0100 Subject: [PATCH 10/36] RLC AM: add retransmission and Rx status pdu --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 141 +--- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 26 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h | 1 - openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 38 + openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h | 8 + openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 2 - .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 718 ++++++++++++++---- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h | 24 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 9 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 109 ++- .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 3 +- .../AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 4 + 12 files changed, 759 insertions(+), 324 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index ad9810cfff..df8682f726 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -389,7 +389,7 @@ rlc_am_get_pdus ( rlc_am_entity_t * const rlc_pP ) { - int display_flag = 0; + //int display_flag = 0; // 5.1.3.1 Transmit operations // 5.1.3.1.1 // General @@ -436,123 +436,21 @@ rlc_am_get_pdus ( rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED)); } - /*while ((rlc_pP->nb_bytes_requested_by_mac > 0) && (stay_on_this_list)) { - mem_block_t* pdu = list_get_head(&rlc_pP->control_pdu_list); - if (pdu != NULL { - if ( ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size <= rlc_pP->nb_bytes_requested_by_mac) { - pdu = list_remove_head(&rlc_pP->control_pdu_list); - #if TRACE_RLC_AM_TX - msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] SEND CONTROL PDU\n", ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, ctxt_pP->frame); - #endif - list_add_tail_eurecom (pdu, &rlc_pP->pdus_to_mac_layer); - rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - ((rlc_am_tx_control_pdu_management_t*)(pdu->data))->size; - } else { - stay_on_this_list = 0; - } - } else { - stay_on_this_list = 0; - } - }*/ // THEN TRY TO SEND RETRANS PDU - // BUG FIX : they can be PDU to ReTx due to received NACK or 1 PDU (SN = vtS - 1) to ReTx due TPoll Expiry if Buffer Occupancy is null - if (rlc_pP->first_retrans_pdu_sn >= 0) { - rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; + if ((rlc_pP->retrans_num_bytes_to_retransmit) && (rlc_pP->nb_bytes_requested_by_mac > 2)) { - // tx min 3 bytes because of the size of the RLC header - while ((rlc_pP->nb_bytes_requested_by_mac > 2) && - (rlc_pP->first_retrans_pdu_sn >= 0) && - (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s)) { + /* Get 1 AM data PDU or PDU segment to retransmit */ + mem_block_t* pdu_retx = rlc_am_get_pdu_to_retransmit(ctxt_pP, rlc_pP); - tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn]; + if (pdu_retx != NULL) { + list_add_tail_eurecom (pdu_retx, &rlc_pP->pdus_to_mac_layer); - if ((tx_data_pdu_management->header_and_payload_size <= rlc_pP->nb_bytes_requested_by_mac) && (tx_data_pdu_management->retx_count >= 0) - && (tx_data_pdu_management->nack_so_start == 0) && (tx_data_pdu_management->nack_so_stop == 0x7FFF)) { - mem_block_t* copy = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RE-SEND DATA PDU SN %04d %d BYTES\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - tx_data_pdu_management->header_and_payload_size); - rlc_pP->stat_tx_data_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu_by_status += 1; - rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->header_and_payload_size; - rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->header_and_payload_size; - rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->header_and_payload_size; - - list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer); - rlc_pP->nb_bytes_requested_by_mac = rlc_pP->nb_bytes_requested_by_mac - tx_data_pdu_management->header_and_payload_size; - - tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next; return; - } else if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac >= RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d MAC BYTES %d SIZE %d RTX COUNT %d nack_so_start %d nack_so_stop %04X(hex)\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - rlc_pP->nb_bytes_requested_by_mac, - tx_data_pdu_management->header_and_payload_size, - tx_data_pdu_management->retx_count, - tx_data_pdu_management->nack_so_start, - tx_data_pdu_management->nack_so_stop); - - mem_block_t* copy = rlc_am_retransmit_get_subsegment( - ctxt_pP, - rlc_pP, - rlc_pP->first_retrans_pdu_sn, - &rlc_pP->nb_bytes_requested_by_mac); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" SEND SEGMENT OF DATA PDU SN %04d (NEW SO %05d)\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn, - tx_data_pdu_management->nack_so_start); - - rlc_pP->stat_tx_data_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu += 1; - rlc_pP->stat_tx_retransmit_pdu_by_status += 1; - rlc_pP->stat_tx_data_bytes += (((struct mac_tb_req*)(copy->data))->tb_size); - rlc_pP->stat_tx_retransmit_bytes += (((struct mac_tb_req*)(copy->data))->tb_size); - rlc_pP->stat_tx_retransmit_bytes_by_status += (((struct mac_tb_req*)(copy->data))->tb_size); - list_add_tail_eurecom (copy, &rlc_pP->pdus_to_mac_layer); - } else { - break; - } - - // update first_retrans_pdu_sn - while ((rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s) && - (!(rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].flags.retransmit))) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn+1) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn SN %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - }; - - display_flag = 1; - - if (rlc_pP->first_retrans_pdu_sn == rlc_pP->vt_s) { - // no more pdu to be retransmited - rlc_pP->first_retrans_pdu_sn = -1; - display_flag = 0; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" CLEAR first_retrans_pdu_sn\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - } - - if (display_flag > 0) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" UPDATED first_retrans_pdu_sn %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - } - - return; - - /* ONLY ONE TB PER TTI - if ((tx_data_pdu_management->retx_count >= 0) && (rlc_pP->nb_bytes_requested_by_mac < RLC_AM_MIN_SEGMENT_SIZE_REQUEST)) { - #if TRACE_RLC_AM_TX - msg ("[FRAME %5u][%s][RLC_AM][MOD %u/%u][RB %u] BREAK LOOP ON RETRANSMISSION BECAUSE ONLY %d BYTES ALLOWED TO TRANSMIT BY MAC\n",ctxt_pP->frame, ((rlc_am_entity_t *) rlc_pP)->module_id,((rlc_am_entity_t *) rlc_pP)->rb_id, rlc_pP->nb_bytes_requested_by_mac); - #endif - break; - }*/ } } - if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->vt_s != rlc_pP->vt_ms)) { + // THEN TRY TO SEND NEW DATA PDU + if ((rlc_pP->nb_bytes_requested_by_mac > 2) && (rlc_pP->sdu_buffer_occupancy) && (rlc_pP->vt_s != rlc_pP->vt_ms)) { rlc_am_segment_10(ctxt_pP, rlc_pP); list_add_list (&rlc_pP->segmentation_pdu_list, &rlc_pP->pdus_to_mac_layer); @@ -563,29 +461,6 @@ rlc_am_get_pdus ( } } - if ((rlc_pP->pdus_to_mac_layer.head == NULL) && - (rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP)) && - (rlc_pP->nb_bytes_requested_by_mac > 2)) { - rlc_am_retransmit_any_pdu(ctxt_pP, rlc_pP); - return; - } else { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" COULD NOT RETRANSMIT ANY PDU BECAUSE ", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - - if (rlc_pP->pdus_to_mac_layer.head != NULL) { - LOG_D(RLC, "THERE ARE SOME PDUS READY TO TRANSMIT "); - } - - if (!(rlc_am_is_timer_poll_retransmit_timed_out(ctxt_pP, rlc_pP))) { - LOG_D(RLC, "TIMER POLL DID NOT TIMED OUT (RUNNING = %d NUM PDUS TO RETRANS = %d NUM BYTES TO RETRANS = %d) ", rlc_pP->t_poll_retransmit.running, - rlc_pP->retrans_num_pdus, rlc_pP->retrans_num_bytes_to_retransmit); - } - - if (rlc_pP->nb_bytes_requested_by_mac <= 2) { - LOG_D(RLC, "NUM BYTES REQUESTED BY MAC = %d", rlc_pP->nb_bytes_requested_by_mac); - } - LOG_D(RLC, "\n"); - } break; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index a2fc95aba5..10f310d5de 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -56,6 +56,9 @@ /** PDU minimal header size in bytes. */ # define RLC_AM_HEADER_MIN_SIZE 2 +/** PDU Segment minimal header size in bytes = PDU header + SOStart + SOEnd. */ +# define RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE 4 + /** If we want to send a segment of a PDU, then the min transport block size requested by MAC should be this amount. */ # define RLC_AM_MIN_SEGMENT_SIZE_REQUEST 8 @@ -77,8 +80,8 @@ /* MACRO DEFINITIONS */ -#define RLC_AM_NEXT_SN(sn) (((sn)+1) & ((RLC_AM_SN_MODULO)-1)) -#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & ((RLC_AM_SN_MODULO)-1)) +#define RLC_AM_NEXT_SN(sn) (((sn)+1) & (RLC_AM_SN_MASK)) +#define RLC_AM_PREV_SN(sn) (((sn)+(RLC_AM_SN_MODULO)-1) & (RLC_AM_SN_MASK)) #define RLC_DIFF_SN(sn,snref,modulus) ((sn+(modulus)-snref) & ((modulus)-1)) #define RLC_SN_IN_WINDOW(sn,snref,modulus) ((RLC_DIFF_SN(sn,snref,modulus)) < ((modulus) >> 1)) @@ -103,7 +106,8 @@ #define RLC_AM_PDU_RF_BITS 1 -#define EURL_AM_PDU_LSF_BITS 1 +#define RLC_AM_LI_BITS 11 +#define RLC_AM_LI_MASK 0x7FF /* AM Data PDU */ @@ -113,12 +117,28 @@ #define RLC_AM_PDU_RF_OFFSET (RLC_AM_PDU_POLL_OFFSET + RLC_AM_PDU_POLL_BITS) #define RLC_AM_PDU_D_C_OFFSET (RLC_AM_PDU_RF_OFFSET + RLC_AM_PDU_RF_BITS) +#define RLC_AM_PDU_GET_FI_START(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET + 1)) +#define RLC_AM_PDU_GET_FI_END(px) (RLC_GET_BIT((px),RLC_AM_PDU_FI_OFFSET)) + +#define RLC_AM_PDU_GET_LI(x,offset) (((x) >> (offset)) & RLC_AM_LI_MASK) +#define RLC_AM_PDU_SET_LI(x,li,offset) ((x) |= (((li) & RLC_AM_LI_MASK) << (offset))) + #define RLC_AM_PDU_SET_E(px) (RLC_SET_BIT((px),RLC_AM_PDU_E_OFFSET)) #define RLC_AM_PDU_SET_D_C(px) (RLC_SET_BIT((px),RLC_AM_PDU_D_C_OFFSET)) #define RLC_AM_PDU_SET_RF(px) (RLC_SET_BIT((px),RLC_AM_PDU_RF_OFFSET)) #define RLC_AM_PDU_SET_POLL(px) (RLC_SET_BIT((px),RLC_AM_PDU_POLL_OFFSET)) #define RLC_AM_PDU_CLEAR_POLL(px) (RLC_CLEAR_BIT((px),RLC_AM_PDU_POLL_OFFSET)) +#define RLC_AM_PDU_SEGMENT_SO_LENGTH 15 +#define RLC_AM_PDU_SEGMENT_SO_BYTES 2 +#define RLC_AM_PDU_SEGMENT_SO_OFFSET 0 +#define RLC_AM_PDU_LSF_OFFSET (RLC_AM_PDU_SEGMENT_SO_OFFSET + RLC_AM_PDU_SEGMENT_SO_LENGTH) + +#define RLC_AM_PDU_SET_LSF(px) (RLC_SET_BIT((px),RLC_AM_PDU_LSF_OFFSET)) + +#define RLC_AM_HEADER_LI_LENGTH(li) ((li) + ((li)>>1) + ((li)&1)) +#define RLC_AM_PDU_SEGMENT_HEADER_SIZE(numLis) (RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + RLC_AM_HEADER_LI_LENGTH(numLis)) + /* STATUS PDU */ #define RLC_AM_STATUS_PDU_CPT_STATUS 0 diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h index 682a781818..602e8e98c2 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_entity.h @@ -175,7 +175,6 @@ typedef struct rlc_am_entity_s { sdu_size_t nb_bytes_requested_by_mac; /*!< \brief Number of remaining bytes available for transmission of any RLC PDU indicated by lower layer */ list_t pdus_to_mac_layer; /*!< \brief PDUs buffered for transmission to MAC layer. */ list_t control_pdu_list; /*!< \brief Control PDUs buffered for transmission to MAC layer. */ - rlc_sn_t first_retrans_pdu_sn; /*!< \brief Lowest sequence number of PDU to be retransmitted. */ list_t segmentation_pdu_list; /*!< \brief List of "freshly" segmented PDUs. */ uint8_t status_requested; /*!< \brief Status bitmap requested by peer. */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index 820b06c233..f7ef37597a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -108,3 +108,41 @@ rlc_am_in_sdu_is_empty( return 0; } + +// called when PDU is ACKED +//----------------------------------------------------------------------------- +void +rlc_am_pdu_sdu_data_cnf( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + const rlc_sn_t snP) +{ + int pdu_sdu_index; + int sdu_index; + + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; + assert(sdu_index >= 0); + assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); + rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; + + if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) && + (rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) { + #if TEST_RLC_AM + rlc_am_v9_3_0_test_data_conf ( + rlc_pP->module_id, + rlc_pP->rb_id, + rlc_pP->input_sdus[sdu_index].mui, + RLC_SDU_CONFIRM_YES); + #else + rlc_data_conf( + ctxt_pP, + rlc_pP->rb_id, + rlc_pP->input_sdus[sdu_index].mui, + RLC_SDU_CONFIRM_YES, + rlc_pP->is_data_plane); + #endif + rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index); + } + } +} diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h index 3201dfc941..c596bc671a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.h @@ -77,5 +77,13 @@ protected_rlc_am_in_sdu(void rlc_am_free_in_sdu_data (const protocol_ctxt_t* con * \return 1 if the buffer is empty, else 0. */ protected_rlc_am_in_sdu(signed int rlc_am_in_sdu_is_empty(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP);) + +/*! \fn void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP) +* \brief Process SDU cnf of a ACKED PDU for all SDUs concatenated in this PDU. +* \param[in] ctxtP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \param[in] snP Sequence number of the PDU. +*/ +protected_rlc_am_in_sdu(void rlc_am_pdu_sdu_data_cnf(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,const rlc_sn_t snP);) /** @} */ # endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index ce5afe7c59..6a36d9b7de 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -80,7 +80,6 @@ rlc_am_init( rlc_pP->sn_status_triggered_delayed = RLC_SN_UNDEFINED; rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 - rlc_pP->first_retrans_pdu_sn = -1; rlc_pP->initialized = TRUE; } @@ -136,7 +135,6 @@ rlc_am_reestablish( rlc_pP->status_requested = RLC_AM_STATUS_NOT_TRIGGERED; rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1 - rlc_pP->first_retrans_pdu_sn = -1; rlc_pP->initialized = TRUE; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index d2941b061d..c636fc7082 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -30,12 +30,13 @@ #include "UTIL/LOG/log.h" #include "msc.h" //----------------------------------------------------------------------------- -void rlc_am_nack_pdu ( +boolean_t rlc_am_nack_pdu ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP, - const sdu_size_t so_startP, - const sdu_size_t so_endP) + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP) { // 5.2.1 Retransmission // ... @@ -51,43 +52,116 @@ void rlc_am_nack_pdu ( mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP]; //int pdu_sdu_index; //int sdu_index; + boolean_t status = TRUE; + boolean_t retx_count_increment = FALSE; + sdu_size_t pdu_data_to_retx = 0; if (mb_p != NULL) { assert(so_startP <= so_endP); - //----------------------------------------- - // allow holes in reports - // it is assumed that hole reports are done in byte offset - // increasing order among calls refering to only one status PDU - // and among time - //----------------------------------------- - if (rlc_pP->tx_data_pdu_buffer[snP].last_nack_time != ctxt_pP->frame) { - rlc_pP->tx_data_pdu_buffer[snP].last_nack_time = ctxt_pP->frame; - rlc_am_clear_holes(ctxt_pP, rlc_pP, snP); + // Handle full PDU NACK first + if ((so_startP == 0) && (so_endP == 0x7FFF)) { + if ((prev_nack_snP != snP) && (tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) { + pdu_data_to_retx = tx_data_pdu_buffer_p->payload_size; + /* Increment VtReTxNext if this is the first NACK or if some segments have already been transmitted */ + if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (tx_data_pdu_buffer_p->nack_so_start)) + { + retx_count_increment = TRUE; + } + + tx_data_pdu_buffer_p->nack_so_start = 0; + tx_data_pdu_buffer_p->num_holes = 0; + tx_data_pdu_buffer_p->retx_hole_index = 0; + tx_data_pdu_buffer_p->nack_so_stop = tx_data_pdu_buffer_p->payload_size - 1; + #if TRACE_RLC_AM_HOLE + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[HOLE] SN %04d GLOBAL NACK 0->%05d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + snP, + so_stopP); + #endif + assert(tx_data_pdu_buffer_p->nack_so_start < tx_data_pdu_buffer_p->payload_size); + } + else { + status = FALSE; + } + } + else if (tx_data_pdu_buffer_p->flags.max_retransmit == 0) { + // Handle Segment offset + if (so_endP == 0x7FFF) { + so_endP = tx_data_pdu_buffer_p->payload_size - 1; + } + + // Check consistency + if ((so_startP < so_endP) && (so_endP < tx_data_pdu_buffer_p->payload_size)) { + if (prev_nack_snP != snP) { + /* New NACK_SN with SO */ + /* check whether a new segment is to be placed in Retransmission Buffer, then increment vrReTx */ + if ((tx_data_pdu_buffer_p->flags.retransmit == 0) || (so_startP < tx_data_pdu_buffer_p->nack_so_start)) { + retx_count_increment = TRUE; + } + + tx_data_pdu_buffer_p->num_holes = 1; + tx_data_pdu_buffer_p->retx_hole_index = 0; + tx_data_pdu_buffer_p->hole_so_start[0] = so_startP; + tx_data_pdu_buffer_p->hole_so_stop[0] = so_endP; + tx_data_pdu_buffer_p->nack_so_start = so_startP; + tx_data_pdu_buffer_p->nack_so_stop = so_endP; + pdu_data_to_retx = so_endP - so_startP + 1; + + } + else if ((tx_data_pdu_buffer_p->num_holes) && (tx_data_pdu_buffer_p->num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU)) { + /* New SOStart/SOEnd for the same NACK_SN than before */ + /* check discontinuity */ + if (so_startP > tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes - 1]) { + tx_data_pdu_buffer_p->hole_so_start[tx_data_pdu_buffer_p->num_holes] = so_startP; + tx_data_pdu_buffer_p->hole_so_stop[tx_data_pdu_buffer_p->num_holes] = so_endP; + tx_data_pdu_buffer_p->nack_so_stop = so_endP; + tx_data_pdu_buffer_p->num_holes ++; + pdu_data_to_retx = so_endP - so_startP + 1; + } + else { + status = FALSE; + } + } + else { + status = FALSE; + } + } + else { + status = FALSE; + } + } + else { + status = FALSE; } - rlc_am_add_hole(ctxt_pP, rlc_pP, snP, so_startP, so_endP); - - if (rlc_pP->first_retrans_pdu_sn < 0) { - rlc_pP->first_retrans_pdu_sn = snP; - } else if (rlc_am_tx_sn1_gt_sn2(ctxt_pP, rlc_pP, rlc_pP->first_retrans_pdu_sn, snP)) { - rlc_pP->first_retrans_pdu_sn = snP; - } - - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] NACK PDU SN %04d previous retx_count %d 1ST_RETRANS_PDU %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - snP, - rlc_pP->tx_data_pdu_buffer[snP].retx_count, - rlc_pP->first_retrans_pdu_sn); - - rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 1; - - /* TODO : before incrementing retx_count_next, one have to check this must be a new occurrence of retransmission */ - if (rlc_pP->tx_data_pdu_buffer[snP].retx_count == rlc_pP->tx_data_pdu_buffer[snP].retx_count_next){ - rlc_pP->tx_data_pdu_buffer[snP].retx_count_next ++; - rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[snP].payload_size; + if (status) { + tx_data_pdu_buffer_p->flags.nack = 1; + if ((retx_count_increment) && (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next)) { + tx_data_pdu_buffer_p->retx_count_next ++; + } + if (tx_data_pdu_buffer_p->flags.retransmit == 1) { + if (prev_nack_snP != snP) { + /* if first process of this NACK_SN and data already pending for retx */ + rlc_pP->retrans_num_bytes_to_retransmit += (pdu_data_to_retx - tx_data_pdu_buffer_p->retx_payload_size); + tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx; + } + else if (tx_data_pdu_buffer_p->num_holes > 1) { + /* Segment case : SOStart and SOEnd already received for same NACK_SN */ + /* filter case where a NACK_SN is received twice with SO first time and no SO second time */ + rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx; + tx_data_pdu_buffer_p->retx_payload_size += pdu_data_to_retx; + } + } + else { + tx_data_pdu_buffer_p->flags.retransmit = 1; + rlc_pP->retrans_num_bytes_to_retransmit += pdu_data_to_retx; + tx_data_pdu_buffer_p->retx_payload_size = pdu_data_to_retx; + rlc_pP->retrans_num_pdus ++; + } } /* TODO: Move this part in UL SCH processing */ @@ -123,8 +197,10 @@ void rlc_am_nack_pdu ( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[NACK-PDU] ERROR NACK MISSING PDU SN %05d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP); - //assert(2==3); + status = FALSE; } + + return status; } //----------------------------------------------------------------------------- void rlc_am_ack_pdu ( @@ -133,8 +209,6 @@ void rlc_am_ack_pdu ( const rlc_sn_t snP) { mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; - int pdu_sdu_index; - int sdu_index; rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; @@ -147,83 +221,13 @@ void rlc_am_ack_pdu ( snP, rlc_pP->tx_data_pdu_buffer[snP].retx_count); - if (rlc_pP->tx_data_pdu_buffer[snP].retx_count >= 0) { - rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].payload_size; + if (rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size) { + rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size; + rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size = 0; + rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; + rlc_pP->retrans_num_pdus --; } - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; - assert(sdu_index >= 0); - assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); - rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; - - if ((rlc_pP->input_sdus[sdu_index].nb_pdus_ack == rlc_pP->input_sdus[sdu_index].nb_pdus) && - (rlc_pP->input_sdus[sdu_index].sdu_remaining_size == 0)) { -#if TEST_RLC_AM - rlc_am_v9_3_0_test_data_conf ( - rlc_pP->module_id, - rlc_pP->rb_id, - rlc_pP->input_sdus[sdu_index].mui, - RLC_SDU_CONFIRM_YES); -#else - rlc_data_conf( - ctxt_pP, - rlc_pP->rb_id, - rlc_pP->input_sdus[sdu_index].mui, - RLC_SDU_CONFIRM_YES, - rlc_pP->is_data_plane); -#endif - rlc_am_free_in_sdu(ctxt_pP, rlc_pP, sdu_index); - } - } - - // 7.1... - // VT(A) – Acknowledgement state variable - // This state variable holds the value of the SN of the next AMD PDU for which a positive acknowledgment is to be - // received in-sequence, and it serves as the lower edge of the transmitting window. It is initially set to 0, and is updated - // whenever the AM RLC entity receives a positive acknowledgment for an AMD PDU with SN = VT(A). - rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; - - if (snP == rlc_pP->vt_a) { - //rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; - do { - memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); - - if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } - - rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); - - - rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vt_a, - rlc_pP->vt_ms, - rlc_pP->vt_s); - } - - if (snP == rlc_pP->first_retrans_pdu_sn) { - do { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->first_retrans_pdu_sn + 1) & RLC_AM_SN_MASK; - - if (rlc_pP->tx_data_pdu_buffer[rlc_pP->first_retrans_pdu_sn].retx_count >= 0) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - break; - } - } while (rlc_pP->first_retrans_pdu_sn != rlc_pP->vt_s); - - if (rlc_pP->vt_s == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = -1; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED first_retrans_pdu_sn -> %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->first_retrans_pdu_sn); - } - } } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] WARNING ACK PDU SN %05d -> NO PDU TO ACK\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -233,29 +237,11 @@ void rlc_am_ack_pdu ( free_mem_block(mb_p, __func__); rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL; } - - if (rlc_pP->tx_data_pdu_buffer[snP].flags.ack > 0) { - if (snP == rlc_pP->vt_a) { - //rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; - do { - memset(&rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a], 0, sizeof(rlc_am_tx_data_pdu_management_t)); - - if (rlc_pP->vt_a == rlc_pP->first_retrans_pdu_sn) { - rlc_pP->first_retrans_pdu_sn = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } - - rlc_pP->vt_a = (rlc_pP->vt_a + 1) & RLC_AM_SN_MASK; - } while ((rlc_pP->tx_data_pdu_buffer[rlc_pP->vt_a].flags.ack == 1) && (rlc_pP->vt_a != rlc_pP->vt_s)); - - rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] UPDATED VT(A) %04d VT(MS) %04d VT(S) %04d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), - rlc_pP->vt_a, - rlc_pP->vt_ms, - rlc_pP->vt_s); - } - } } + rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; + rlc_pP->tx_data_pdu_buffer[snP].flags.transmitted = 0; + rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; + } //----------------------------------------------------------------------------- mem_block_t* rlc_am_retransmit_get_copy ( @@ -265,25 +251,343 @@ mem_block_t* rlc_am_retransmit_get_copy ( { mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; - if (mb_original_p != NULL) { + AssertFatal (mb_original_p != NULL, "RLC AM PDU Copy Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n", + snP,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); - rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; - int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); - mem_block_t* mb_copy = get_free_mem_block(size, __func__); - memcpy(mb_copy->data, mb_original_p->data, size); + /* We need to allocate a new buffer and copy to it because header content may change for Polling bit */ + int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); + mem_block_t* mb_copy = get_free_mem_block(size, __func__); + memcpy(mb_copy->data, mb_original_p->data, size); - rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]); - ((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p; + rlc_am_pdu_sn_10_t *pdu_p = (rlc_am_pdu_sn_10_t*) (&mb_copy->data[sizeof(struct mac_tb_req)]); + ((struct mac_tb_req*)(mb_copy->data))->data_ptr = (uint8_t*)pdu_p; - pdu_mngt->flags.retransmit = 0; - - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size,false); - return mb_copy; - } else { - return NULL; - } + return mb_copy; } + +//----------------------------------------------------------------------------- +mem_block_t* rlc_am_retransmit_get_am_segment( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t *const rlc_pP, + rlc_am_tx_data_pdu_management_t *const pdu_mngt, + sdu_size_t * const payload_sizeP /* in-out*/) +{ + int16_t sdus_segment_size[RLC_AM_MAX_SDU_IN_PDU]; + mem_block_t* mb_original_p = pdu_mngt->mem_block; + mem_block_t* mem_pdu_segment_p = NULL; + uint8_t *pdu_original_header_p = NULL; + uint8_t *pdu_segment_header_p = NULL; + sdu_size_t retx_so_start,retx_so_stop; //starting and ending SO for retransmission in this PDU + rlc_sn_t sn = pdu_mngt->sn; + uint16_t header_so_part; + boolean_t fi_start, fi_end; + uint8_t sdu_index = 0; + uint8_t sdu_segment_index = 0; + uint8_t num_LIs_pdu_segment = pdu_mngt->nb_sdus - 1; + uint8_t li_bit_offset = 4; /* toggle between 0 and 4 */ + uint8_t li_jump_offset = 1; /* toggle between 1 and 2 */ + + + AssertFatal (mb_original_p != NULL, "RLC AM PDU Segment Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + + AssertFatal (pdu_mngt->payload == mb_original_p->data + sizeof(struct mac_tb_req) + pdu_mngt->header_and_payload_size - pdu_mngt->payload_size, + "RLC AM PDU Segment Error: Inconsistent data pointers p1=%p p2=%p sn = %d total size = %d data size = %d LcId=%d !\n", + pdu_mngt->payload,mb_original_p->data + sizeof(struct mac_tb_req),pdu_mngt->header_and_payload_size,pdu_mngt->payload_size,sn,rlc_pP->channel_id); + + /* Init ReTx Hole list if not configured, ie the whole PDU has to be retransmitted */ + if (pdu_mngt->num_holes == 0) + { + AssertFatal (pdu_mngt->retx_payload_size == pdu_mngt->payload_size,"RLC AM PDU ReTx Segment: Expecting full PDU size ReTxSize=%d DataSize=%d sn=%d vtA=%d vtS=%d LcId=%d !\n", + pdu_mngt->retx_payload_size,pdu_mngt->payload_size,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + pdu_mngt->retx_hole_index = 0; + pdu_mngt->hole_so_start[0] = 0; + pdu_mngt->hole_so_stop[0] = pdu_mngt->payload_size - 1; + pdu_mngt->num_holes = 1; + } + + /* Init SO Start and SO Stop */ + retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; + + /* Init FI to the same value as original PDU */ + fi_start = (!(RLC_AM_PDU_GET_FI_START(*(pdu_mngt->first_byte)))); + fi_end = (!(RLC_AM_PDU_GET_FI_END(*(pdu_mngt->first_byte)))); + + /* Handle no LI case first */ + if (num_LIs_pdu_segment == 0) + { + /* Bound retx_so_stop to available TBS */ + if (retx_so_stop - retx_so_start + 1 + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac) + { + retx_so_stop = retx_so_start + rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE - 1; + } + + *payload_sizeP = retx_so_stop - retx_so_start + 1; + mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + sizeof(struct mac_tb_req)), __func__); + pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + + /* clear all PDU segment */ + memset(pdu_segment_header_p, 0, *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE); + /* copy data part */ + memcpy(pdu_segment_header_p + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE, pdu_mngt->payload + retx_so_start, *payload_sizeP); + + /* Set FI part to false if SO Start and SO End are different from PDU boundaries */ + if (retx_so_start) + { + fi_start = FALSE; + } + if (retx_so_stop < pdu_mngt->payload_size - 1) + { + fi_end = FALSE; + } + + /* Header content is filled at the end */ + } + else + { + /* Step 1 */ + /* Find the SDU index in the original PDU containing retx_so_start */ + sdu_size_t sdu_size = 0; + sdu_size_t data_size = 0; + sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + pdu_original_header_p = pdu_mngt->first_byte + 2; + li_bit_offset = 4; /* toggle between 0 and 4 */ + li_jump_offset = 1; /* toggle between 1 and 2 */ + + + /* Read first LI */ + sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + + while ((data_size - 1 < retx_so_start) && (sdu_index < pdu_mngt->nb_sdus)) + { + sdu_index ++; + if (sdu_index < pdu_mngt->nb_sdus) + { + sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + } + + /* Set FI Start if retx_so_start = cumulated data size */ + if (retx_so_start == data_size) + { + fi_start = TRUE; + /* jump to next SDU */ + sdu_index ++; + /* there must be at least one SDU more */ + AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", + sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); + sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + /* Set first SDU portion of the segment */ + sdus_segment_size[0] = data_size - retx_so_start; + + /* Now look for the end */ + while ((data_size - 1 < retx_so_stop) && (sdu_index < pdu_mngt->nb_sdus)) + { + sdu_index ++; + sdu_segment_index ++; + if (sdu_index < pdu_mngt->nb_sdus) + { + sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + sdus_segment_size[sdu_segment_index] = sdu_size; + } + } + + /* Set FI End if retx_so_stop = cumulated data size */ + if (retx_so_stop == data_size - 1) + { + fi_end = TRUE; + } + /* Set last SDU portion of the segment even if it will be out of LI */ + if (sdu_segment_index) + { + sdus_segment_size[sdu_segment_index] = retx_so_stop - (data_size - sdu_size) + 1; + } + else + { + sdus_segment_size[0] = retx_so_stop - retx_so_start + 1; + } + + /* Set number of LIs in the segment */ + num_LIs_pdu_segment = sdu_segment_index; + + /* Memory allocation taking into account available TBS */ + /* Compute Header Length and Data Length */ + /* Init Segment Payload data size */ + *payload_sizeP = sdus_segment_size[0]; + + /* Bound to available TBS taking into account min PDU segment header*/ + if (*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac) + { + *payload_sizeP = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + } + + sdu_segment_index = 1; + while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index))) + { + /* Add next sdu_segment_index to data part */ + if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + sdus_segment_size[sdu_segment_index] < rlc_pP->nb_bytes_requested_by_mac) + { + (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; + } + else + { + /* bound to available TBS size */ + (*payload_sizeP) += (rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index)); + sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + } + header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + sdu_segment_index ++; + } + + num_LIs_pdu_segment = sdu_segment_index - 1; + + /* Check consistency between sdus_segment_size and payload_sizeP */ + data_size = 0; + for (int i = 0; i < num_LIs_pdu_segment + 1; i++) + { + data_size += sdus_segment_size[i]; + } + + AssertFatal (data_size == *payload_sizeP, "RLC AM PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n", + data_size,*payload_sizeP,sn,rlc_pP->channel_id); + + /* Allocation */ + AssertFatal (header_segment_length + *payload_sizeP <= pdu_mngt->header_and_payload_size + 2, "RLC AM PDU Segment Error: Hdr=%d Data=%d Original Hdr+Data =%d sn=%d LcId=%d !\n", + header_segment_length,*payload_sizeP,pdu_mngt->header_and_payload_size,sn,rlc_pP->channel_id); + mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + header_segment_length + sizeof(struct mac_tb_req)), __func__); + pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + + /* clear all PDU segment */ + memset(pdu_segment_header_p, 0, *payload_sizeP + header_segment_length); + /* copy data part */ + memcpy(pdu_segment_header_p + header_segment_length, pdu_mngt->payload + retx_so_start, *payload_sizeP); + } + + /* Last step : update contexts and fill PDU Segment Header */ + if (mem_pdu_segment_p != NULL) + { + /* Update PDU Segment contexts */ + if (*payload_sizeP == pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index] - pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] + 1) + { + /* All data in the segment are transmitted : switch to next one */ + pdu_mngt->retx_hole_index ++; + if (pdu_mngt->retx_hole_index < pdu_mngt->num_holes) + { + /* Set min SOStart to the value of next hole : assumption is holes are ordered by increasing SOStart */ + pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + } + else + { + /* no more scheduled Retx: reset values */ + /* Retx size is reset in the calling function */ + pdu_mngt->num_holes = 0; + pdu_mngt->retx_hole_index = 0; + } + } + else + { + /* not all segment data could be transmitted, just update SoStart */ + pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index] += (*payload_sizeP); + pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; + } + + /* Set Fixed part of AM PDU Segment Header */ + pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + + /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + /* copy first two bytes from original: D/C + RF + FI + E+ SN*/ + *pdu_segment_header_p = *(pdu_mngt->first_byte); + *(pdu_segment_header_p + 1) = *(pdu_mngt->first_byte + 1); + + /* Set Segmentation Flag */ + RLC_AM_PDU_SET_RF(*pdu_segment_header_p); + /* clear polling */ + RLC_AM_PDU_CLEAR_POLL(*pdu_segment_header_p); + /* Change FI */ + if (!fi_start) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1)); + + } + if (!fi_end) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET)); + + } + + /* Segment Offset */ + header_so_part = retx_so_start; + + /* Last Segment Flag (LSF) */ + if (retx_so_stop == pdu_mngt->payload_size - 1) + { + RLC_AM_PDU_SET_LSF(header_so_part); + } + + /* Store SO bytes */ + * (pdu_segment_header_p + 2) = (header_so_part >> 8) & 0xFF; + * (pdu_segment_header_p + 3) = header_so_part & 0xFF; + + /* Fill LI part */ + if (num_LIs_pdu_segment) + { + uint16_t index = 0; + uint16_t temp = 0; + /* Set Extension bit in first byte */ + RLC_AM_PDU_SET_E(*pdu_segment_header_p); + + /* loop on nb of LIs */ + pdu_segment_header_p += RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + li_bit_offset = 4; /* toggle between 0 and 4 */ + li_jump_offset = 1; /* toggle between 1 and 2 */ + + while (index < num_LIs_pdu_segment) + { + /* Set E bit for next LI if present */ + if (index < num_LIs_pdu_segment - 1) + RLC_SET_BIT(temp,li_bit_offset + RLC_AM_LI_BITS); + /* Set LI */ + RLC_AM_PDU_SET_LI(temp,sdus_segment_size[index],li_bit_offset); + *pdu_segment_header_p = temp >> 8; + *(pdu_segment_header_p + 1) = temp & 0xFF; + pdu_segment_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + + temp = ((*pdu_segment_header_p) << 8) + *(pdu_segment_header_p + 1); + index ++; + } + } + + } + + return mem_pdu_segment_p; +} + +#if 0 //----------------------------------------------------------------------------- mem_block_t* rlc_am_retransmit_get_subsegment( const protocol_ctxt_t* const ctxt_pP, @@ -739,8 +1043,6 @@ mem_block_t* rlc_am_retransmit_get_subsegment( snP); return NULL; } - - rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_sub_segment_p, test_pdu_copy_size,false); return mb_sub_segment_p; } else { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] RE-SEND DATA PDU SN %04d BUT NO PDU AVAILABLE -> RETURN NULL\n", @@ -750,6 +1052,7 @@ mem_block_t* rlc_am_retransmit_get_subsegment( return NULL; } } +#endif //----------------------------------------------------------------------------- void rlc_am_tx_buffer_display ( const protocol_ctxt_t* const ctxt_pP, @@ -803,6 +1106,124 @@ void rlc_am_tx_buffer_display ( LOG_D(RLC, "\n"); } + +//----------------------------------------------------------------------------- +mem_block_t * rlc_am_get_pdu_to_retransmit( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP) +{ + rlc_sn_t sn = rlc_pP->vt_a; + rlc_sn_t sn_end = rlc_pP->vt_s; + mem_block_t* pdu_p = NULL; + rlc_am_tx_data_pdu_management_t* tx_data_pdu_management; + + AssertFatal ((rlc_pP->retrans_num_pdus > 0) && (rlc_pP->vt_a != rlc_pP->vt_s), "RLC AM ReTx start process Error: NbPDUtoRetx=%d vtA=%d vtS=%d LcId=%d !\n", + rlc_pP->retrans_num_pdus,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + do + { + tx_data_pdu_management = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + if ((tx_data_pdu_management->flags.retransmit) && (tx_data_pdu_management->flags.max_retransmit == 0)) + { + AssertFatal (tx_data_pdu_management->sn == sn, "RLC AM ReTx PDU Error: SN Error pdu_sn=%d sn=%d vtA=%d vtS=%d LcId=%d !\n", + tx_data_pdu_management->sn,sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + AssertFatal (tx_data_pdu_management->flags.transmitted == 1, "RLC AM ReTx PDU Error: State Error sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + AssertFatal (tx_data_pdu_management->retx_payload_size > 0, "RLC AM ReTx PDU Error: No Data to Retx sn=%d vtA=%d vtS=%d LcId=%d !\n", + sn,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); + + /* Either the whole RLC PDU is to be transmitted and there is enough MAC TBS or there is minimum TBS size for transmitting 1 AM PDU segment */ + if ((tx_data_pdu_management->retx_payload_size == tx_data_pdu_management->payload_size) && (rlc_pP->nb_bytes_requested_by_mac >= tx_data_pdu_management->header_and_payload_size)) + { + /* check maxretx is not hit */ + if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold) + { + pdu_p = rlc_am_retransmit_get_copy(ctxt_pP, rlc_pP, sn); + + if (pdu_p != NULL) + { + rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_management->retx_payload_size; + rlc_pP->retrans_num_pdus --; + tx_data_pdu_management->retx_payload_size = 0; + tx_data_pdu_management->flags.retransmit = 0; + + // update stats + rlc_pP->stat_tx_data_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu_by_status += 1; + rlc_pP->stat_tx_data_bytes += tx_data_pdu_management->payload_size; + rlc_pP->stat_tx_retransmit_bytes += tx_data_pdu_management->payload_size; + rlc_pP->stat_tx_retransmit_bytes_by_status += tx_data_pdu_management->payload_size; + + } + } + else + { + // TO DO : RLC Notification to RRC + ReEstablishment procedure + tx_data_pdu_management->flags.max_retransmit = 1; + } + } + else if (rlc_pP->nb_bytes_requested_by_mac >= 5) + { + /* Resegmentation case */ + /* check maxretx is not hit */ + if (tx_data_pdu_management->retx_count_next <= rlc_pP->max_retx_threshold) + { + sdu_size_t pdu_data_size = 0; + + pdu_p = rlc_am_retransmit_get_am_segment(ctxt_pP, rlc_pP, tx_data_pdu_management,&pdu_data_size); + + if (pdu_p != NULL) + { + AssertFatal ((tx_data_pdu_management->retx_payload_size >= pdu_data_size) && (rlc_pP->retrans_num_bytes_to_retransmit >= pdu_data_size), "RLC AM ReTx PDU Segment Error: DataSize=%d PDUReTxsize=%d TotalReTxsize=%d sn=%d LcId=%d !\n", + pdu_data_size,tx_data_pdu_management->retx_payload_size,rlc_pP->retrans_num_bytes_to_retransmit,sn,rlc_pP->channel_id); + + tx_data_pdu_management->retx_payload_size -= pdu_data_size; + rlc_pP->retrans_num_bytes_to_retransmit -= pdu_data_size; + if (tx_data_pdu_management->retx_payload_size == 0) + { + rlc_pP->retrans_num_pdus --; + tx_data_pdu_management->retx_payload_size = 0; + tx_data_pdu_management->flags.retransmit = 0; + } + + // update stats + rlc_pP->stat_tx_data_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu += 1; + rlc_pP->stat_tx_retransmit_pdu_by_status += 1; + rlc_pP->stat_tx_data_bytes += pdu_data_size; + rlc_pP->stat_tx_retransmit_bytes += pdu_data_size; + rlc_pP->stat_tx_retransmit_bytes_by_status += pdu_data_size; + + } + } + else + { + // TO DO : RLC Notification to RRC + ReEstablishment procedure + tx_data_pdu_management->flags.max_retransmit = 1; + } + } + + if (pdu_p != NULL) + { + /* check polling */ + rlc_am_pdu_sn_10_t* pdu_header_p = (rlc_am_pdu_sn_10_t*) (&pdu_p->data[sizeof(struct mac_tb_req)]); + rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_header_p, tx_data_pdu_management->payload_size,false); + + tx_data_pdu_management->retx_count = tx_data_pdu_management->retx_count_next; + + break; + } + + } + + sn = RLC_AM_NEXT_SN(sn); + } while((sn != sn_end) && (rlc_pP->retrans_num_pdus > 0)); + + return pdu_p; +} + +#if 0 //----------------------------------------------------------------------------- void rlc_am_retransmit_any_pdu( const protocol_ctxt_t* const ctxt_pP, @@ -891,3 +1312,4 @@ void rlc_am_retransmit_any_pdu( } } } +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h index 99570e5d7f..338bc79196 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.h @@ -50,21 +50,24 @@ # define public_rlc_am_retransmit(x) extern x # endif # endif -/*! \fn void rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, uint16_t snP, sdu_size_t so_startP, sdu_size_t so_endP) +/*! \fn boolean_t rlc_am_nack_pdu (const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *rlcP, int16_t snP, int16_t prev_nack_snP,sdu_size_t so_startP, sdu_size_t so_endP) * \brief The RLC AM PDU which have the sequence number snP is marked NACKed with segment offset fields. * \param[in] ctxtP Running context. * \param[in] rlcP RLC AM protocol instance pointer. * \param[in] snP Sequence number of the PDU that is negative acknowledged. +* \param[in] prev_nack_snP Sequence number of previous PDU that is negative acknowledged. * \param[in] so_startP Start of the segment offset of the PDU that . * \param[in] so_endP Transport blocks received from MAC layer. +* \return OK/KO * \note It may appear a new hole in the retransmission buffer depending on the segment offset informations. Depending on the state of the retransmission buffer, negative confirmation can be sent to higher layers about the drop by the RLC AM instance of a particular SDU. */ -protected_rlc_am_retransmit(void rlc_am_nack_pdu ( +protected_rlc_am_retransmit(boolean_t rlc_am_nack_pdu ( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t *const rlcP, const rlc_sn_t snP, - const sdu_size_t so_startP, - const sdu_size_t so_endP);) + const rlc_sn_t prev_nack_snP, + sdu_size_t so_startP, + sdu_size_t so_endP);) /*! \fn void rlc_am_ack_pdu (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP, rlc_sn_t snP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. @@ -90,6 +93,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_copy ( rlc_am_entity_t *const rlcP, const rlc_sn_t snP)); +#if 0 /*! \fn mem_block_t* rlc_am_retransmit_get_subsegment (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t *rlcP,rlc_sn_t snP, sdu_size_t *sizeP) * \brief The RLC AM PDU which have the sequence number snP is marked ACKed. * \param[in] ctxtP Running context. @@ -103,7 +107,18 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment ( rlc_am_entity_t *const rlcP, const rlc_sn_t snP, sdu_size_t *const sizeP)); +#endif +/*! \fn mem_block_t* rlc_am_get_pdu_to_retransmit(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP) +* \brief Find a PDU or PDU segment to retransmit. +* \param[in] ctxtP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \return A copy of the retransmitted PDU or PDU segment or NULL if TBS was not big enough +*/ +protected_rlc_am_retransmit(mem_block_t* rlc_am_get_pdu_to_retransmit( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlcP);) +#if 0 /*! \fn void rlc_am_retransmit_any_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* rlcP) * \brief Retransmit any PDU in order to unblock peer entity, if no suitable PDU is found (depending on requested MAC size) to be retransmitted, then try to retransmit a subsegment of any PDU. * \param[in] ctxtP Running context. @@ -112,6 +127,7 @@ protected_rlc_am_retransmit(mem_block_t* rlc_am_retransmit_get_subsegment ( protected_rlc_am_retransmit(void rlc_am_retransmit_any_pdu( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP);) +#endif /*! \fn void rlc_am_tx_buffer_display (const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* rlcP, char* message_pP) * \brief Display the dump of the retransmission buffer. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index 824154b311..27816ccb2c 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -113,14 +113,14 @@ void rlc_am_pdu_polling ( rlc_pP->c_byte_without_poll = 0; // vt_s shall have been updated before in case of new transmission - rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK; + rlc_pP->poll_sn = RLC_AM_PREV_SN(rlc_pP->vt_s); //optimisation if (!rlc_pP->t_poll_retransmit.running) { rlc_am_start_timer_poll_retransmit(ctxt_pP, rlc_pP); //optimisation } else { //optimisation rlc_pP->t_poll_retransmit.frame_time_out = ctxt_pP->frame + rlc_pP->t_poll_retransmit.time_out; //optimisation } } else { - // Not sure this is necessary + // Need to clear poll bit as it may be a copy(retransmission case) of the original RLC PDU which was containing a poll RLC_AM_PDU_CLEAR_POLL(pdu_pP->b1); } } @@ -533,16 +533,19 @@ void rlc_am_segment_10 ( pdu_mngt_p->header_and_payload_size = data_pdu_size - pdu_remaining_size; pdu_mngt_p->retx_count = 0; pdu_mngt_p->retx_count_next = 0; + pdu_mngt_p->flags.retransmit = 0; pdu_mngt_p->flags.transmitted = 1; + //TBC: What for resetting local pointers at the end ?? 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 - mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, (rlc_pP->vt_s-1) & RLC_AM_SN_MASK); + /* We need to copy the PDU to pass to MAC in order to keep it in the buffer for potential retransmissions */ + mem_block_t* copy = rlc_am_retransmit_get_copy (ctxt_pP, rlc_pP, RLC_AM_PREV_SN(rlc_pP->vt_s)); list_add_tail_eurecom (copy, &rlc_pP->segmentation_pdu_list); } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 84d587d53b..de23cac006 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -268,6 +268,14 @@ rlc_am_receive_process_control_pdu( { rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)*first_byte_ppP; sdu_size_t initial_pdu_size = *tb_size_in_bytes_pP; + rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn; + rlc_sn_t sn_cursor = rlc_pP->vt_a; + rlc_sn_t vt_a_new = rlc_pP->vt_a; + rlc_sn_t sn_data_cnf; + rlc_sn_t nack_sn,prev_nack_sn; + sdu_size_t data_cnf_so_stop = 0x7FFF; + unsigned int nack_index; + boolean_t status = TRUE; if (rlc_am_get_control_pdu_infos(rlc_am_pdu_sn_10_p, tb_size_in_bytes_pP, &rlc_pP->control_pdu_info) >= 0) { @@ -280,10 +288,6 @@ rlc_am_receive_process_control_pdu( rlc_pP->control_pdu_info.ack_sn); rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info); - rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn; - rlc_sn_t sn_cursor = rlc_pP->vt_a; - rlc_sn_t nack_sn; - unsigned int nack_index; // 5.2.1 Retransmission // @@ -308,50 +312,89 @@ rlc_am_receive_process_control_pdu( assert(ack_sn < RLC_AM_SN_MODULO); assert(rlc_pP->control_pdu_info.num_nack < RLC_AM_MAX_NACK_IN_STATUS_PDU); - /* Nv1495998 : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */ + /* Note : ackSn can be equal to current vtA only in case the status pdu contains a list of nack_sn with same value = vtA with SOStart/SOEnd */ /* and meaning the report is not complete due to not enough ressources to fill all SOStart/SOEnd of this NACK_SN */ if (RLC_AM_DIFF_SN(rlc_pP->vt_s,rlc_pP->vt_a) >= RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a)) { if (rlc_pP->control_pdu_info.num_nack == 0) { while (sn_cursor != ack_sn) { rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); } + + vt_a_new = ack_sn; + sn_data_cnf = RLC_AM_PREV_SN(vt_a_new); } else { nack_index = 0; nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + prev_nack_sn = 0x3FFF; - while (sn_cursor != ack_sn) { + while (sn_cursor != nack_sn) { + rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); + } + + vt_a_new = nack_sn; + + // catch DataCfn + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn]; + if (tx_data_pdu_buffer_p->retx_payload_size == tx_data_pdu_buffer_p->payload_size) { + sn_data_cnf = RLC_AM_PREV_SN(nack_sn); + } + else if (tx_data_pdu_buffer_p->nack_so_start != 0) { + sn_data_cnf = nack_sn; + data_cnf_so_stop = tx_data_pdu_buffer_p->nack_so_start - 1; + } + else { + sn_data_cnf = RLC_AM_PREV_SN(nack_sn); + } + + + while ((sn_cursor != ack_sn) && (status)) { if (sn_cursor != nack_sn) { rlc_am_ack_pdu(ctxt_pP, rlc_pP, sn_cursor); } else { - rlc_am_nack_pdu (ctxt_pP, + status = rlc_am_nack_pdu (ctxt_pP, rlc_pP, - sn_cursor, + nack_sn, + prev_nack_sn, rlc_pP->control_pdu_info.nack_list[nack_index].so_start, rlc_pP->control_pdu_info.nack_list[nack_index].so_end); nack_index = nack_index + 1; + prev_nack_sn = nack_sn; - if (nack_index == rlc_pP->control_pdu_info.num_nack) { - nack_sn = 0xFFFF; // value never reached by sn - } else { - nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + if (nack_index < rlc_pP->control_pdu_info.num_nack) { + nack_sn = rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn; + } + else if (nack_sn != ack_sn) { + /* general case*/ + nack_sn = ack_sn; + } + else { + /*specific case when the sender did not have enough TBS to fill all SOStart SOEnd for this NACK_SN */ + break; } } - - if ((nack_index < rlc_pP->control_pdu_info.num_nack) && (nack_index > 0)) { - if (rlc_pP->control_pdu_info.nack_list[nack_index].nack_sn != rlc_pP->control_pdu_info.nack_list[nack_index-1].nack_sn) { - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; - } - } else { - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; - } + sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; } } + + } else { + LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + status = FALSE; + } + } else { + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + status = FALSE; + } + + if (status) { /* Check for Stopping TpollReTx */ if ((rlc_pP->poll_sn != RLC_SN_UNDEFINED) && (RLC_AM_DIFF_SN(ack_sn,rlc_pP->vt_a) > RLC_AM_DIFF_SN(rlc_pP->poll_sn,rlc_pP->vt_a))) { @@ -359,15 +402,23 @@ rlc_am_receive_process_control_pdu( rlc_pP->poll_sn = RLC_SN_UNDEFINED; } - /* Update vtA */ + //TODO : this part does not cover all cases of Data Cnf and move it at the end of Status PDU processing + sn_cursor = rlc_pP->vt_a; - } else { - LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); - } - } else { - LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" ERROR IN DECODING CONTROL PDU\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + /* Handle all acked PDU up to and excluding sn_data_cnf */ + while (sn_cursor != sn_data_cnf) { + rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_cursor); + sn_cursor = RLC_AM_NEXT_SN(sn_cursor); + } + + // Handle last SN. TO DO : case of PDU partially ACKED with SDU to be data conf + if (data_cnf_so_stop == 0x7FFF) { + rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_data_cnf); + } + + /* Update vtA and vtMS */ + rlc_pP->vt_a = vt_a_new; + rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; } *first_byte_ppP = (uint8_t*)((uint64_t)*first_byte_ppP + initial_pdu_size - *tb_size_in_bytes_pP); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index e2658f2c14..e79dac57c0 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -113,9 +113,10 @@ typedef struct rlc_am_tx_data_pdu_management { uint8_t retx_hole_index; /*!< \brief Next index of registered holes to retransmit. */ sdu_size_t header_and_payload_size; /*!< \brief Size of the PDU in bytes, including header and payload. */ sdu_size_t payload_size; /*!< \brief Size of the PDU payload in bytes. */ + sdu_size_t retx_payload_size; /*!< \brief Size of the PDU payload to be retransmitted in bytes including all Segment portions. */ rlc_sn_t sn; /*!< \brief Sequence number of the PDU. */ sdu_size_t nack_so_start; /*!< \brief Lowest NACK start segment offset, must be set to 0 if global NACK. */ - sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size if global NACK */ + sdu_size_t nack_so_stop; /*!< \brief Highest NACK stop segment offset, must be set to data_size - 1 if global NACK */ int8_t nb_sdus; /*!< \brief Number of sdu having segments in this pdu. */ int8_t retx_count; /*!< \brief Counts the number of already occurred retransmissions of an AMD PDU (see subclause 5.2.1). */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index d7079bba9b..29b8fc0971 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -90,8 +90,12 @@ rlc_am_check_timer_poll_retransmit( sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); if ((rlc_pP->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc_pP->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) { rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit = 1; + if (rlc_pP->tx_data_pdu_buffer[sn].retx_count == rlc_pP->tx_data_pdu_buffer[sn].retx_count_next) { + rlc_pP->tx_data_pdu_buffer[sn].retx_count_next ++; + } rlc_pP->retrans_num_pdus += 1; rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[sn].payload_size; + break; } else { From 0030635237e8899486e708ccef0f3ae779e17486 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 22 Feb 2017 13:00:30 +0100 Subject: [PATCH 11/36] RLC AM Tx buffer: fix sn modulo window size access --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 4 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c | 6 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 57 ++++++++++--------- .../RLC/AM_v9.3.0/rlc_am_segments_holes.c | 2 + .../RLC/AM_v9.3.0/rlc_am_segments_holes.h | 3 +- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 6 +- .../AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 14 +++-- 7 files changed, 50 insertions(+), 42 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index f7ef37597a..b41dea42f2 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -120,8 +120,8 @@ rlc_am_pdu_sdu_data_cnf( int pdu_sdu_index; int sdu_index; - for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP].nb_sdus; pdu_sdu_index++) { - sdu_index = rlc_pP->tx_data_pdu_buffer[snP].sdus_index[pdu_sdu_index]; + for (pdu_sdu_index = 0; pdu_sdu_index < rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].nb_sdus; pdu_sdu_index++) { + sdu_index = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].sdus_index[pdu_sdu_index]; assert(sdu_index >= 0); assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE); rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c index 6a36d9b7de..129d4ffb0f 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_init.c @@ -175,9 +175,9 @@ rlc_am_cleanup( if (rlc_pP->tx_data_pdu_buffer != NULL) { for (i=0; i < RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE; i++) { - if (rlc_pP->tx_data_pdu_buffer[i].mem_block != NULL) { - free_mem_block(rlc_pP->tx_data_pdu_buffer[i].mem_block, __func__); - rlc_pP->tx_data_pdu_buffer[i].mem_block = NULL; + if (rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block != NULL) { + free_mem_block(rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block, __func__); + rlc_pP->tx_data_pdu_buffer[i % RLC_AM_WINDOW_SIZE].mem_block = NULL; } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index c636fc7082..85138afed3 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -51,8 +51,8 @@ boolean_t rlc_am_nack_pdu ( // - indicate to upper layers that max retransmission has been reached. - mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; - rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP]; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; //int pdu_sdu_index; //int sdu_index; boolean_t status = TRUE; @@ -208,23 +208,24 @@ void rlc_am_ack_pdu ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; + mem_block_t* mb_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; - rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; + tx_data_pdu_buffer->flags.retransmit = 0; - if ((rlc_pP->tx_data_pdu_buffer[snP].flags.ack == 0) && (mb_p != NULL)) { + if ((tx_data_pdu_buffer->flags.ack == 0) && (mb_p != NULL)) { //if (mb_pP != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL; + tx_data_pdu_buffer->mem_block = NULL; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[ACK-PDU] ACK PDU SN %05d previous retx_count %d \n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), snP, - rlc_pP->tx_data_pdu_buffer[snP].retx_count); + tx_data_pdu_buffer->retx_count); - if (rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size) { - rlc_pP->retrans_num_bytes_to_retransmit -= rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size; - rlc_pP->tx_data_pdu_buffer[snP].retx_payload_size = 0; - rlc_pP->tx_data_pdu_buffer[snP].num_holes = 0; + if (tx_data_pdu_buffer->retx_payload_size) { + rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_buffer->retx_payload_size; + tx_data_pdu_buffer->retx_payload_size = 0; + tx_data_pdu_buffer->num_holes = 0; rlc_pP->retrans_num_pdus --; } @@ -235,12 +236,12 @@ void rlc_am_ack_pdu ( if (mb_p != NULL) { free_mem_block(mb_p, __func__); - rlc_pP->tx_data_pdu_buffer[snP].mem_block = NULL; + tx_data_pdu_buffer->mem_block = NULL; } } - rlc_pP->tx_data_pdu_buffer[snP].flags.ack = 1; - rlc_pP->tx_data_pdu_buffer[snP].flags.transmitted = 0; - rlc_pP->tx_data_pdu_buffer[snP].flags.retransmit = 0; + tx_data_pdu_buffer->flags.ack = 1; + tx_data_pdu_buffer->flags.transmitted = 0; + tx_data_pdu_buffer->flags.retransmit = 0; } //----------------------------------------------------------------------------- @@ -249,12 +250,12 @@ mem_block_t* rlc_am_retransmit_get_copy ( rlc_am_entity_t *const rlc_pP, const rlc_sn_t snP) { - mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP].mem_block; + mem_block_t* mb_original_p = rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE].mem_block; AssertFatal (mb_original_p != NULL, "RLC AM PDU Copy Error: Empty block sn=%d vtA=%d vtS=%d LcId=%d !\n", snP,rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); - rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE]; + rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->tx_data_pdu_buffer[snP % RLC_AM_WINDOW_SIZE]; /* We need to allocate a new buffer and copy to it because header content may change for Polling bit */ int size = pdu_mngt->header_and_payload_size + sizeof(struct mac_tb_req); @@ -1061,6 +1062,7 @@ void rlc_am_tx_buffer_display ( { rlc_sn_t sn = rlc_pP->vt_a; int i, loop = 0; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p; if (message_pP) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" Retransmission buffer %s VT(A)=%04d VT(S)=%04d:", @@ -1076,25 +1078,26 @@ void rlc_am_tx_buffer_display ( } while (rlc_pP->vt_s != sn) { - if (rlc_pP->tx_data_pdu_buffer[sn].mem_block) { + tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + if (tx_data_pdu_buffer_p->mem_block) { if ((loop % 1) == 0) { LOG_D(RLC, "\nTX SN:\t"); } - if (rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit) { - LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size, rlc_pP->tx_data_pdu_buffer[sn].payload_size, - rlc_pP->tx_data_pdu_buffer[sn].retx_count); + if (tx_data_pdu_buffer_p->flags.retransmit) { + LOG_D(RLC, "%04d %d/%d Bytes (NACK RTX:%02d ",sn, tx_data_pdu_buffer_p->header_and_payload_size, tx_data_pdu_buffer_p->payload_size, + tx_data_pdu_buffer_p->retx_count); } else { - LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, rlc_pP->tx_data_pdu_buffer[sn].header_and_payload_size, rlc_pP->tx_data_pdu_buffer[sn].payload_size, - rlc_pP->tx_data_pdu_buffer[sn].retx_count); + LOG_D(RLC, "%04d %d/%d Bytes (RTX:%02d ",sn, tx_data_pdu_buffer_p->header_and_payload_size, tx_data_pdu_buffer_p->payload_size, + tx_data_pdu_buffer_p->retx_count); } - if (rlc_pP->tx_data_pdu_buffer[sn].num_holes == 0) { - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->tx_data_pdu_buffer[sn].nack_so_start, rlc_pP->tx_data_pdu_buffer[sn].nack_so_stop); + if (tx_data_pdu_buffer_p->num_holes == 0) { + LOG_D(RLC, "SO:%04d->%04d)\t", tx_data_pdu_buffer_p->nack_so_start, tx_data_pdu_buffer_p->nack_so_stop); } else { - for (i=0; itx_data_pdu_buffer[sn].num_holes; i++) { + for (i=0; inum_holes; i++) { assert(i < RLC_AM_MAX_HOLES_REPORT_PER_PDU); - LOG_D(RLC, "SO:%04d->%04d)\t", rlc_pP->tx_data_pdu_buffer[sn].hole_so_start[i], rlc_pP->tx_data_pdu_buffer[sn].hole_so_stop[i]); + LOG_D(RLC, "SO:%04d->%04d)\t", tx_data_pdu_buffer_p->hole_so_start[i], tx_data_pdu_buffer_p->hole_so_stop[i]); } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c index b1eabdd1ca..46a656e65a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.c @@ -19,6 +19,7 @@ * contact@openairinterface.org */ +#if 0 #define RLC_AM_MODULE 1 #define RLC_AM_SEGMENT_HOLES_C 1 //----------------------------------------------------------------------------- @@ -315,3 +316,4 @@ void rlc_am_add_hole ( assert(rlc_pP->tx_data_pdu_buffer[snP].num_holes < RLC_AM_MAX_HOLES_REPORT_PER_PDU); assert(rlc_pP->tx_data_pdu_buffer[snP].nack_so_start < rlc_pP->tx_data_pdu_buffer[snP].payload_size); } +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h index 902bc59306..68200c0f99 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segments_holes.h @@ -32,7 +32,7 @@ * @ingroup _rlc_am_internal_segment_impl_ * @{ */ - +#if 0 #ifndef __RLC_AM_SEGMENT_HOLES_H__ # define __RLC_AM_SEGMENT_HOLES_H__ //----------------------------------------------------------------------------- @@ -108,3 +108,4 @@ protected_rlc_am_segments_holes(void rlc_am_add_hole ( sdu_size_t so_stopP);) /** @} */ #endif +#endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index de23cac006..6d4fd0a2b7 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -268,7 +268,7 @@ rlc_am_receive_process_control_pdu( { rlc_am_pdu_sn_10_t *rlc_am_pdu_sn_10_p = (rlc_am_pdu_sn_10_t*)*first_byte_ppP; sdu_size_t initial_pdu_size = *tb_size_in_bytes_pP; - rlc_sn_t ack_sn = rlc_pP->control_pdu_info.ack_sn; + rlc_sn_t ack_sn = RLC_AM_NEXT_SN(rlc_pP->vt_a); rlc_sn_t sn_cursor = rlc_pP->vt_a; rlc_sn_t vt_a_new = rlc_pP->vt_a; rlc_sn_t sn_data_cnf; @@ -288,7 +288,7 @@ rlc_am_receive_process_control_pdu( rlc_pP->control_pdu_info.ack_sn); rlc_am_display_control_pdu_infos(&rlc_pP->control_pdu_info); - + ack_sn = rlc_pP->control_pdu_info.ack_sn; // 5.2.1 Retransmission // // The transmitting side of an AM RLC entity can receive a negative acknowledgement (notification of reception failure @@ -337,7 +337,7 @@ rlc_am_receive_process_control_pdu( vt_a_new = nack_sn; // catch DataCfn - rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn]; + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[nack_sn % RLC_AM_WINDOW_SIZE]; if (tx_data_pdu_buffer_p->retx_payload_size == tx_data_pdu_buffer_p->payload_size) { sn_data_cnf = RLC_AM_PREV_SN(nack_sn); } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index 29b8fc0971..7c5d55800f 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -83,18 +83,20 @@ rlc_am_check_timer_poll_retransmit( // force BO to be > 0 rlc_sn_t sn = RLC_AM_PREV_SN(rlc_pP->vt_s); rlc_sn_t sn_end = RLC_AM_PREV_SN(rlc_pP->vt_a); + rlc_am_tx_data_pdu_management_t *tx_data_pdu_buffer_p; /* Look for the first retransmittable PDU starting from vtS - 1 */ while (sn != sn_end) { - AssertFatal (rlc_pP->tx_data_pdu_buffer[sn].mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", + tx_data_pdu_buffer_p = &rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE]; + AssertFatal (tx_data_pdu_buffer_p->mem_block != NULL, "RLC AM Tpoll Retx expiry sn=%d is empty vtA=%d vtS=%d LcId=%d\n", sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); - if ((rlc_pP->tx_data_pdu_buffer[sn].flags.ack == 0) && (rlc_pP->tx_data_pdu_buffer[sn].flags.max_retransmit == 0)) { - rlc_pP->tx_data_pdu_buffer[sn].flags.retransmit = 1; - if (rlc_pP->tx_data_pdu_buffer[sn].retx_count == rlc_pP->tx_data_pdu_buffer[sn].retx_count_next) { - rlc_pP->tx_data_pdu_buffer[sn].retx_count_next ++; + if ((tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) { + tx_data_pdu_buffer_p->flags.retransmit = 1; + if (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next) { + tx_data_pdu_buffer_p->retx_count_next ++; } rlc_pP->retrans_num_pdus += 1; - rlc_pP->retrans_num_bytes_to_retransmit += rlc_pP->tx_data_pdu_buffer[sn].payload_size; + rlc_pP->retrans_num_bytes_to_retransmit += tx_data_pdu_buffer_p->payload_size; break; } else From aac9c6119d1fd4dafa07901d2b1bd9b8461af380 Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 23 Feb 2017 17:44:47 +0100 Subject: [PATCH 12/36] RLC AM fix in Retx PDU segment --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 85138afed3..1697b9cac5 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -352,6 +352,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( { /* Step 1 */ /* Find the SDU index in the original PDU containing retx_so_start */ + uint16_t temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); sdu_size_t sdu_size = 0; sdu_size_t data_size = 0; sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; @@ -361,7 +362,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* Read first LI */ - sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); pdu_original_header_p += li_jump_offset; li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; @@ -372,7 +373,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( sdu_index ++; if (sdu_index < pdu_mngt->nb_sdus) { - sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); pdu_original_header_p += li_jump_offset; li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; @@ -389,7 +391,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* there must be at least one SDU more */ AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); - sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); pdu_original_header_p += li_jump_offset; li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; @@ -405,7 +408,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( sdu_segment_index ++; if (sdu_index < pdu_mngt->nb_sdus) { - sdu_size = RLC_AM_PDU_GET_LI(*pdu_original_header_p + *(pdu_original_header_p + 1),li_bit_offset); + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); pdu_original_header_p += li_jump_offset; li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; @@ -578,7 +582,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; - temp = ((*pdu_segment_header_p) << 8) + *(pdu_segment_header_p + 1); + temp = ((*pdu_segment_header_p) << 8) | (*(pdu_segment_header_p + 1)); index ++; } } From 52006fc6ea2d0fe9fa0bd1f8166872d336ff9c23 Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 2 Mar 2017 10:37:33 +0100 Subject: [PATCH 13/36] RLC AM : Add Rx PDU Segment handling --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c | 7 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h | 5 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 8 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 643 +++++++++++++++++- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h | 19 + .../LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h | 12 + 6 files changed, 681 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c index 873e51fbfe..5a6cfef5a6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.c @@ -212,7 +212,8 @@ void rlc_am_reassemble_pdu( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t * const rlc_pP, - mem_block_t * const tb_pP) + mem_block_t * const tb_pP, + boolean_t free_rlc_pdu) { int i,j; @@ -397,5 +398,7 @@ rlc_am_reassemble_pdu( } } - free_mem_block(tb_pP, __func__); + if (free_rlc_pdu) { + free_mem_block(tb_pP, __func__); + } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h index fece9ae570..4b780ce441 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_reassembly.h @@ -72,13 +72,14 @@ private_rlc_am_reassembly( void rlc_am_reassembly (const protocol_ctxt_t* co */ private_rlc_am_reassembly( void rlc_am_send_sdu (const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP);) -/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP) +/*! \fn void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, const mem_block_t* const tb_pP,boolean_t free_rlc_pdu) * \brief Reassembly a RLC AM PDU, depending of the content of this PDU, data will be reassemblied to the current output SDU, the current will be sent to higher layers or not, after or before the reassembly, or no send of SDU will be triggered, depending on FI field in PDU header. * \param[in] ctxtP Running context. * \param[in] rlc_pP RLC AM protocol instance pointer. * \param[in] tb_pP RLC AM PDU embedded in a mem_block_t. +* \param[in] free_rlc_pdu Flag for freeing RLC AM PDU after reassembly. */ -protected_rlc_am_reassembly( void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP);) +protected_rlc_am_reassembly( void rlc_am_reassemble_pdu(const protocol_ctxt_t* const ctxtP, rlc_am_entity_t * const rlc_pP, mem_block_t* const tb_pP,boolean_t free_rlc_pdu);) /** @} */ #endif diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index f2246e45f8..94654f097a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -31,6 +31,7 @@ #include "LAYER2/MAC/extern.h" #include "UTIL/LOG/log.h" + //----------------------------------------------------------------------------- signed int rlc_am_get_data_pdu_infos( @@ -330,7 +331,8 @@ rlc_am_receive_process_data_pdu ( rlc_pP->vr_ms, rlc_pP->vr_x); - if (rlc_am_rx_list_insert_pdu(ctxt_pP, rlc_pP,tb_pP) < 0) { + pdu_status = rlc_am_rx_list_check_duplicate_insert_pdu(ctxt_pP, rlc_pP,tb_pP); + if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_size_in_bytesP; LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED, STATUS REQUESTED:\n", @@ -398,7 +400,7 @@ rlc_am_receive_process_data_pdu ( rlc_pP->vr_mr = (rlc_pP->vr_r + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; } - reassemble = true; + reassemble = rlc_am_rx_check_vr_reassemble(ctxt_pP, rlc_pP); //TODO : optimization : check whether a reassembly is needed by looking at LI, FI, SO, etc... } @@ -446,7 +448,7 @@ rlc_am_receive_process_data_pdu ( } /* 3) Check for triggering a Tx Status PDU if a poll is received or if a pending status was delayed */ - if (pdu_info_p->p) { + if ((pdu_info_p->p) && (pdu_status < RLC_AM_DATA_PDU_STATUS_BUFFER_FULL)) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] POLL BIT SET, STATUS REQUESTED:\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 8e055406a1..e08be44b54 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -31,7 +31,595 @@ #include "UTIL/LOG/log.h" +boolean_t rlc_am_rx_check_vr_reassemble( + const protocol_ctxt_t* const ctxt_pP, + const rlc_am_entity_t* const rlc_pP) +{ + mem_block_t* cursor_p = NULL; + cursor_p = rlc_pP->receiver_buffer.head; + boolean_t reassemble = FALSE; + if (cursor_p != NULL) { + + 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; + if (sn_ref != rlc_pP->vr_r) { + reassemble = TRUE; + } + + /* 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)) { + 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; + if (cursor_p != NULL) { + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + if ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r)) { + /* 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; + AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received LCID=%d\n", + 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)) { + 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; + reassemble = TRUE; + } + 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; + } + } + } + + } + return reassemble; +} + +mem_block_t * create_new_segment_from_pdu( + mem_block_t* const tb_pP, + uint16_t so_offset, /* offset from the data part of the PDU to copy */ + sdu_size_t data_length_to_copy) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_new_segment_info_p = NULL; + mem_block_t * new_segment_p = NULL; + int16_t new_li_list[RLC_AM_MAX_SDU_IN_PDU]; + int16_t header_size = 0; + uint8_t num_li = 0; + boolean_t fi_start, fi_end, lsf; + + /* Init some PDU Segment header fixed parameters */ + fi_start = !((pdu_rx_info_p->fi & 0x2) >> 1); + fi_end = !(pdu_rx_info_p->fi & 0x1); + lsf = ((pdu_rx_info_p->lsf == 1) || (pdu_rx_info_p->rf == 0)); + + /* Handle NO Li case fist */ + if (pdu_rx_info_p->num_li == 0) { + + header_size = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + + if (so_offset) { + fi_start = FALSE; + } + if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { + fi_end = FALSE; + lsf = FALSE; + } + } // end no LI in original segment + else { + + uint8_t li_index = 0; + uint16_t li_sum = 0; + num_li = pdu_rx_info_p->num_li; + + /* set LSF to false if we know that end of the original segment will not be copied */ + if (so_offset + data_length_to_copy != pdu_rx_info_p->payload_size) { + lsf = FALSE; + } + + /* catch the first LI containing so_offset */ + while ((li_index < pdu_rx_info_p->num_li) && (li_sum + pdu_rx_info_p->li_list[li_index] <= so_offset)) { + li_sum += pdu_rx_info_p->li_list[li_index]; + num_li --; + li_index ++; + } + + /* set FI start if so_offset = LI sum and at least one LI have been read */ + if ((li_index) && (so_offset == li_sum)) { + fi_start = TRUE; + } + + /* Fill LI until the end */ + if (num_li) { + sdu_size_t remaining_size = data_length_to_copy; + uint8_t j = 0; + new_li_list[0] = li_sum + pdu_rx_info_p->li_list[li_index] - so_offset; + if (data_length_to_copy <= new_li_list[0]) { + num_li = 0; + } + else { + remaining_size -= new_li_list[0]; + j++; + li_index ++; + while ((li_index < pdu_rx_info_p->num_li) && (remaining_size >= pdu_rx_info_p->li_list[li_index])) { + remaining_size -= pdu_rx_info_p->li_list[li_index]; + new_li_list[j] = pdu_rx_info_p->li_list[li_index]; + j++; + li_index ++; + } + + /* update number of LI in the segment */ + num_li = j; + /* set FI End if remaining size = 0 */ + if (remaining_size == 0) { + fi_end = TRUE; + } + } + } + + /* compute header size */ + header_size = RLC_AM_PDU_SEGMENT_HEADER_SIZE(num_li); + + } // end LIs in original segment + + /* Allocate new buffer */ + new_segment_p = get_free_mem_block(sizeof (mac_rlc_max_rx_header_size_t) + header_size + data_length_to_copy, __func__); + + /* Fill PDU Segment Infos and Header */ + if (new_segment_p != NULL) { + pdu_new_segment_info_p = &((rlc_am_rx_pdu_management_t*)(new_segment_p->data))->pdu_info; + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (new_segment_p->data); + uint8_t *pdu_segment_header_p = &(new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]); + + pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; //to be updated after if SN = vrR + + pdu_new_segment_info_p->d_c = pdu_rx_info_p->d_c; + pdu_new_segment_info_p->sn = pdu_rx_info_p->sn; + pdu_new_segment_info_p->p = pdu_rx_info_p->p; + pdu_new_segment_info_p->rf = 1; + pdu_new_segment_info_p->fi = (((fi_start ? 0: 1) << 1) | (fi_end ? 0: 1)); + pdu_new_segment_info_p->e = (num_li ? 1: 0); + pdu_new_segment_info_p->lsf = (lsf ? 1: 0); + pdu_new_segment_info_p->so = pdu_rx_info_p->so + so_offset; + pdu_new_segment_info_p->payload = pdu_segment_header_p + header_size; + pdu_new_segment_info_p->header_size = header_size; + pdu_new_segment_info_p->payload_size = data_length_to_copy; + pdu_new_segment_info_p->hidden_size = data_length_to_copy; + for (int i=0; i < num_li; i++) { + pdu_new_segment_info_p->li_list[i] = new_li_list[i]; + pdu_new_segment_info_p->hidden_size -= new_li_list[i]; + } + + /* Fill Header part in the buffer */ + /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ + /* copy first two bytes from original: D/C + RF + FI + E+ SN*/ + memset(pdu_segment_header_p, 0, header_size); + RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); + RLC_AM_PDU_SET_RF(*pdu_segment_header_p); + if (pdu_new_segment_info_p->p) { + RLC_AM_PDU_SET_POLL(*pdu_segment_header_p); + } + /* Change FI */ + if (!fi_start) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1)); + + } + if (!fi_end) + { + // Set to not starting + (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET)); + + } + /* E */ + if (pdu_new_segment_info_p->e) { + RLC_AM_PDU_SET_E(*pdu_segment_header_p); + } + /* SN */ + (*pdu_segment_header_p) |= (pdu_new_segment_info_p->sn >> 8) ; + *(pdu_segment_header_p + 1) = (pdu_new_segment_info_p->sn & 0xFF); + + pdu_segment_header_p += 2; + + /* Last Segment Flag (LSF) */ + if (lsf) + { + RLC_AM_PDU_SET_LSF(*pdu_segment_header_p); + } + /* Store SO bytes */ + * (pdu_segment_header_p ) = (pdu_new_segment_info_p->so >> 8) & 0xFF; + * (pdu_segment_header_p + 1) = pdu_new_segment_info_p->so & 0xFF; + + if (num_li) { + uint16_t index = 0; + uint16_t temp = 0; + uint8_t li_bit_offset = 4; /* toggle between 0 and 4 */ + uint8_t li_jump_offset = 1; /* toggle between 1 and 2 */ + + /* loop on nb of LIs */ + pdu_segment_header_p += 2; + + while (index < num_li) + { + /* Set E bit for next LI if present */ + if (index < num_li - 1) + RLC_SET_BIT(temp,li_bit_offset + RLC_AM_LI_BITS); + /* Set LI */ + RLC_AM_PDU_SET_LI(temp,new_li_list[index],li_bit_offset); + *pdu_segment_header_p = temp >> 8; + *(pdu_segment_header_p + 1) = temp & 0xFF; + pdu_segment_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + + temp = ((*pdu_segment_header_p) << 8) | (*(pdu_segment_header_p + 1)); + index ++; + } + } + + /* copy data part */ + /* Fill mem_block contexts */ + ((struct mac_tb_ind *) (new_segment_p->data))->first_bit = 0; + ((struct mac_tb_ind *) (new_segment_p->data))->data_ptr = (uint8_t*)&new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]; + ((struct mac_tb_ind *) (new_segment_p->data))->size = data_length_to_copy + header_size; + memcpy(pdu_new_segment_info_p->payload,pdu_rx_info_p->payload + so_offset,data_length_to_copy); + } + + return new_segment_p; +} + +rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; + rlc_am_pdu_info_t* pdu_info_previous_cursor_p = NULL; + mem_block_t* cursor_p = NULL; + mem_block_t* previous_cursor_p = NULL; + mem_block_t* next_cursor_p = NULL; + cursor_p = rlc_pP->receiver_buffer.head; + boolean_t prev_segment_found = FALSE; + boolean_t next_segment_found = FALSE; + uint16_t so_start = 0; + uint16_t so_end = 0; + 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; + + /*****************************************************/ + // 1) Find previous cursor to the PDU to insert + /*****************************************************/ + previous_cursor_p = cursor_p; + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + while (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + // Stop if Cursor SN >= Received SN + if (RLC_AM_DIFF_SN(pdu_info_cursor_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + break; + } + + previous_cursor_p = cursor_p; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + cursor_p = cursor_p->next; + } + + /*****************************************************/ + // 2) Store the received Segment + /*****************************************************/ + // First case : cursor_p is NULL or its SN is different from the received one, it means the SN is received for the first time + // Insert PDU after previous_cursor_p + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } + + // Filter out SN duplicate + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + + if (pdu_cursor_mgnt_p->all_segments_received) { + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + + // Handle the remaining case : some PDU Segments already received for the same SN + // Try to insert the PDU according to its SO and SO+datalength of stored ones + // First find the segment just before the pdu to insert + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { + if (pdu_rx_info_p->so < pdu_info_cursor_p->so) { + prev_segment_found = TRUE; + break; + } + + 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; + } + } + + /* if not previously inserted, it will be put after the last segment if it was not LSF*/ + if ((!prev_segment_found) && (pdu_info_previous_cursor_p->lsf == 0)) { + prev_segment_found = TRUE; + next_segment_found = TRUE; // no more segment after the PDU + 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); + } + else + { + // the segment is duplicate + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + + + + // Check that the Segment is not duplicate by scanning stored contiguous segments from previous_cursor_p + pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info; + if ((previous_cursor_p != NULL) && (pdu_info_previous_cursor_p->sn == pdu_rx_info_p->sn)) { + so_start = pdu_info_previous_cursor_p->so; + so_end = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1; + + cursor_p = previous_cursor_p; + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + cursor_p = cursor_p->next; + rlc_am_pdu_info_t* pdu_info_cursor_next_p = NULL; + if (cursor_p != NULL) { + pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + + while ((cursor_p != NULL) && (pdu_info_cursor_next_p->sn == pdu_rx_info_p->sn) + && (pdu_info_cursor_next_p->so == pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size)) { + so_end += pdu_info_cursor_next_p->payload_size; + pdu_info_cursor_p = pdu_info_cursor_next_p; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + + /* Now discard the PDU segment if it is within so_start so_end */ + if ((so_start <= so_start_segment) && (so_end_segment <= so_end)) { + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } + } + + + // Now found the segment which will be right after the pdu to insert + if (!next_segment_found) { + + cursor_p = previous_cursor_p->next; + 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 + 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)) { + /* 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; + } + } + } + + /* 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 + 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 - pdu_rx_info_p->so); + } + // remove duplicate at the end + if (next_cursor_p != NULL) { + 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; + } + } + + 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), + " AM RX PDU Segment Duplicate elimination error 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); + + /* Last step : Insertion */ + /* 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)) { + + 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) { + list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); + /* Free original PDU Segment */ + free_mem_block(tb_pP, __func__); + + return RLC_AM_DATA_PDU_STATUS_OK; + } + else { + return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + } + } + else + { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } +} + +rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; + mem_block_t* cursor_p = NULL; + mem_block_t* previous_cursor_p = NULL; + cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + // it is assumed this pdu is in rx window + + + /*****************************************************/ + // 1) Find previous cursor to the PDU to insert + /*****************************************************/ + previous_cursor_p = cursor_p; + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + while (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + // Stop if Cursor SN >= Received SN + if (RLC_AM_DIFF_SN(pdu_info_cursor_p->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + break; + } + + previous_cursor_p = cursor_p; + cursor_p = cursor_p->next; + } + + /*****************************************************/ + // 2) Insert PDU by removing byte duplicate if required + /*****************************************************/ + // First case : cursor_p is NULL, it means the SN is received for the first time + // Insert PDU after previous_cursor_p + if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return pdu_status; + } + + // Filter out SN duplicate + // SN of received PDU has already data stored + rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (cursor_p->data); + + if (pdu_cursor_mgnt_p->all_segments_received) { + return RLC_AM_DATA_PDU_STATUS_SN_DUPLICATE; + } + + /* check if the received PDU is equal to vrR */ + if ((pdu_rx_info_p->sn != rlc_pP->vr_r) || (pdu_info_cursor_p->so != 0)) { + /* The full received PDU can replace the allready received PDU Segments. */ + /* clean them and append this PDU */ + mem_block_t* cursor_next_p = cursor_p; + while (cursor_next_p) { + cursor_p = cursor_next_p; + cursor_next_p = cursor_next_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + if (cursor_next_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_next_p->data))->pdu_info; + if (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) { + break; + } + } + } + + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return pdu_status; + } // End SN != vrR or SO != 0 + else { + /* First update cursor until discontinuity */ + previous_cursor_p = cursor_p; + AssertFatal(pdu_info_cursor_p->rf != 0,"AM Rx PDU Error, stored SN=%d should be a PDU segment\n",pdu_info_cursor_p->sn); + AssertFatal(((rlc_am_rx_pdu_management_t *) (cursor_p->data))->all_segments_received == 0, + "AM Rx PDU Error, stored SN=%d already fully received\n",pdu_info_cursor_p->sn); + sdu_size_t next_waited_so = 0; + while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn) && (pdu_info_cursor_p->so == next_waited_so)) { + next_waited_so += pdu_info_cursor_p->payload_size; + previous_cursor_p = 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; + } + } + /* Create a new PDU segment by removing first next_waited_so bytes */ + mem_block_t* trunc_pdu = create_new_segment_from_pdu(tb_pP,next_waited_so,pdu_rx_info_p->payload_size - next_waited_so); + + if (trunc_pdu != NULL) { + ((rlc_am_rx_pdu_management_t *) (trunc_pdu->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; + /* Insert PDU Segment */ + list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer); + + /* clean previous stored segments in duplicate */ + if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { + mem_block_t* cursor_next_p = cursor_p; + while (cursor_next_p) { + cursor_p = cursor_next_p; + cursor_next_p = cursor_next_p->next; + list2_remove_element (cursor_p, &rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + if (cursor_next_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_next_p->data))->pdu_info; + if (pdu_info_cursor_p->sn != pdu_rx_info_p->sn) { + break; + } + } + } + } + + /* Free original PDU */ + free_mem_block(tb_pP, __func__); + + return pdu_status; + } + else { + return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + } + } +} + +// returns 0 if success +// returns neg value if failure +//----------------------------------------------------------------------------- +rlc_am_rx_pdu_status_t +rlc_am_rx_list_check_duplicate_insert_pdu( + const protocol_ctxt_t* const ctxt_pP, + rlc_am_entity_t* const rlc_pP, + mem_block_t* const tb_pP) +{ + rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; + mem_block_t* cursor_p = NULL; + cursor_p = rlc_pP->receiver_buffer.head; + rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; + // it is assumed this pdu is in rx window + + if (cursor_p == NULL) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[INSERT PDU] LINE %d RX PDU SN %04d (only inserted)\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + __LINE__, + pdu_rx_info_p->sn); + list2_add_head(tb_pP, &rlc_pP->receiver_buffer); + return pdu_status; + } + + + /* Init Reassembly status */ + ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; + + if (pdu_rx_info_p->rf == 0) { // Case normal PDU received + pdu_status = rlc_am_rx_list_handle_pdu(ctxt_pP,rlc_pP,tb_pP); + } + else { + pdu_status = rlc_am_rx_list_handle_pdu_segment(ctxt_pP,rlc_pP,tb_pP); + } + + return pdu_status; +} +#if 0 // returns 0 if success // returns neg value if failure //----------------------------------------------------------------------------- @@ -483,6 +1071,8 @@ rlc_am_rx_list_insert_pdu( pdu_info_p->sn); return -1; } +#endif + //----------------------------------------------------------------------------- void rlc_am_rx_check_all_byte_segments( @@ -523,8 +1113,10 @@ rlc_am_rx_check_all_byte_segments( // in case all first segments up to tb_pP are in list // the so field of the first PDU should be 0 //cursor_p = list.head; + //we start from the first stored PDU segment of this SN pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + // if the first segment does not have SO = 0 then no need to continue if (pdu_info_p->so != 0) { return; } @@ -553,13 +1145,15 @@ rlc_am_rx_check_all_byte_segments( next_waited_so = next_waited_so + pdu_info_p->payload_size; //msg("rlc_am_rx_check_all_byte_segments(%d) @6\n",sn); } else { // assumed pdu_info_p->so + pdu_info_p->payload_size > next_waited_so - next_waited_so = (next_waited_so + pdu_info_p->payload_size) - (next_waited_so - pdu_info_p->so); + //next_waited_so = (next_waited_so + pdu_info_p->payload_size) - (next_waited_so - pdu_info_p->so); //msg("rlc_am_rx_check_all_byte_segments(%d) @7\n",sn); + return; } if (pdu_info_p->lsf > 0) { //msg("rlc_am_rx_check_all_byte_segments(%d) @8\n",sn); rlc_am_rx_mark_all_segments_received(ctxt_pP, rlc_pP, first_cursor_p); + return; } } @@ -608,8 +1202,9 @@ rlc_am_rx_list_reassemble_rlc_sdus( const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlc_pP) { - mem_block_t* cursor_p = NULL; - rlc_am_rx_pdu_management_t* rlc_am_rx_old_pdu_management = NULL; + mem_block_t* cursor_p = NULL; + rlc_am_rx_pdu_management_t* rlc_am_rx_old_pdu_management = NULL; + rlc_am_pdu_info_t* pdu_info_p = NULL; cursor_p = list2_get_head(&rlc_pP->receiver_buffer); @@ -618,11 +1213,31 @@ rlc_am_rx_list_reassemble_rlc_sdus( } rlc_am_rx_pdu_management_t* rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + + /* Specific process for the first SN if all PDU segments had been reassembled but not freed */ + if ((rlc_am_rx_pdu_management_p->all_segments_received > 0) && (pdu_info_p->rf != 0)) { + rlc_sn_t sn = pdu_info_p->sn; + while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) + && ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn) { + cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); + free_mem_block(cursor_p, __func__); + cursor_p = list2_get_head(&rlc_pP->receiver_buffer); + } + + /* Reset Management pointers */ + if (cursor_p != NULL) { + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + } + else { + return; + } + } do { if (rlc_am_rx_pdu_management_p->all_segments_received > 0) { cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); - rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p); + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,TRUE); rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; cursor_p = list2_get_head(&rlc_pP->receiver_buffer); @@ -631,7 +1246,22 @@ rlc_am_rx_list_reassemble_rlc_sdus( } rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); - } else { + } + else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING) { + rlc_am_rx_pdu_management_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLED; + + cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); + rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,FALSE); + rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; + cursor_p = list2_get_head(&rlc_pP->receiver_buffer); + + if (cursor_p == NULL) { + return; + } + + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + } + else { #if RLC_STOP_ON_LOST_PDU if (list2_get_head(&rlc_pP->receiver_buffer) != cursor_p) { @@ -645,7 +1275,8 @@ rlc_am_rx_list_reassemble_rlc_sdus( } } while ((rlc_am_rx_pdu_management_p->pdu_info.sn == ((rlc_am_rx_old_pdu_management->pdu_info.sn + 1) & RLC_AM_SN_MASK)) - || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && (rlc_am_rx_pdu_management_p->all_segments_received > 0))); + || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && ( + (rlc_am_rx_pdu_management_p->all_segments_received > 0) || (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING)))); } //----------------------------------------------------------------------------- mem_block_t * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h index c75255c4fa..e6e043dd0a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.h @@ -59,6 +59,16 @@ #include "PHY/defs.h" //----------------------------------------------------------------------------- +/*! \fn rlc_am_rx_pdu_status_t rlc_am_rx_list_check_duplicate_insert_pdu(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,mem_block_t* const tb_pP) +* \brief Insert a PDU in the RX buffer after removing byte duplicate (implemented with a list). +* \param[in] ctxt_pP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \param[in] tbP A PDU embedded in a mem_block_t. +* \return Zero if the PDU could be inserted in the RX buffer, a negative value if the PDU could not be inserted. +*/ +protected_rlc_am_rx_list( rlc_am_rx_pdu_status_t rlc_am_rx_list_check_duplicate_insert_pdu(const protocol_ctxt_t* const ctxt_pP,rlc_am_entity_t* const rlc_pP,mem_block_t* const tb_pP);) + +#if 0 /*! \fn signed int rlc_am_rx_list_insert_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP , mem_block_t* const tbP) * \brief Insert a PDU in the RX buffer (implemented with a list). * \param[in] ctxt_pP Running context. @@ -67,6 +77,15 @@ * \return Zero if the PDU could be inserted in the RX buffer, a negative value if the PDU could not be inserted. */ protected_rlc_am_rx_list( signed int rlc_am_rx_list_insert_pdu(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP);) +#endif + +/*! \fn boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP) +* \brief Check if reassembly taking into account potential new vrR value +* \param[in] ctxt_pP Running context. +* \param[in] rlcP RLC AM protocol instance pointer. +* \return TRUE if reassembly must be done, FALSE else +*/ +protected_rlc_am_rx_list( boolean_t rlc_am_rx_check_vr_reassemble(const protocol_ctxt_t* const ctxt_pP,const rlc_am_entity_t* const rlc_pP);) /*! \fn void rlc_am_rx_check_all_byte_segments(const protocol_ctxt_t* const ctxt_pP, rlc_am_entity_t* const rlcP, mem_block_t* const tbP) * \brief Check if all sub-segments of a PDU are received, if yes then call rlc_am_rx_mark_all_segments_received() procedure. diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h index e79dac57c0..2b75cb21a7 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_structs.h @@ -233,12 +233,24 @@ typedef struct rlc_am_timer { * @{ */ +typedef enum rlc_am_rx_segment_reassemble_info +{ + /** No Reassembly scheduled */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO = 0, + /** Reassembly scheduled */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING = 1, + /** Reassembly done */ + RLC_AM_RX_PDU_SEGMENT_REASSEMBLED = 2 + +} rlc_am_rx_segment_reassemble_info_t; + /*! \struct rlc_am_rx_pdu_management_t * \brief Structure for storing decoded informations from the header of a AMD PDU or AMD PDU segment and information on reassembly. */ typedef struct rlc_am_rx_pdu_management { rlc_am_pdu_info_t pdu_info; /*!< \brief Field for storing decoded informations from the header of a AMD PDU or AMD PDU segment. */ uint8_t all_segments_received; /*!< \brief Is all segments of PDU SN have been received. */ + rlc_am_rx_segment_reassemble_info_t segment_reassembled; /*!< \brief if the segment for SN=vrR is reassembled but not discarded yet. */ } rlc_am_rx_pdu_management_t; /** @} */ From 684ca32e9b86700fccec7c828e3242fd557e2b4f Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 2 Mar 2017 14:51:58 +0100 Subject: [PATCH 14/36] RLC AM Add Log points --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 10 ++++++---- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 13 +++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index 94654f097a..acc047d633 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -335,8 +335,8 @@ rlc_am_receive_process_data_pdu ( if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { rlc_pP->stat_rx_data_pdu_dropped += 1; rlc_pP->stat_rx_data_bytes_dropped += tb_size_in_bytesP; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED CAUSE=%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_status,pdu_info_p->sn); #if RLC_STOP_ON_LOST_PDU AssertFatal( 0 == 1, PROTOCOL_RLC_AM_CTXT_FMT" LOST PDU DETECTED\n", @@ -443,8 +443,8 @@ rlc_am_receive_process_data_pdu ( rlc_pP->stat_rx_data_pdu_out_of_window += 1; rlc_pP->stat_rx_data_bytes_out_of_window += tb_size_in_bytesP; pdu_status = RLC_AM_DATA_PDU_STATUS_SN_OUTSIDE_WINDOW; - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, STATUS REQUESTED:\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_info_p->sn); } /* 3) Check for triggering a Tx Status PDU if a poll is received or if a pending status was delayed */ @@ -495,6 +495,8 @@ rlc_am_receive_process_data_pdu ( } else { pdu_status = RLC_AM_DATA_PDU_STATUS_HEADER_ERROR; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU DISCARDED BAD HEADER FORMAT SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_info_p->sn); } if (pdu_status != RLC_AM_DATA_PDU_STATUS_OK) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index e08be44b54..e8c63a8e40 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -320,6 +320,8 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( // First case : cursor_p is NULL or its SN is different from the received one, it means the SN is received for the first time // Insert PDU after previous_cursor_p if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] STORE FIRST PDU SEGMENT FOR SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); return RLC_AM_DATA_PDU_STATUS_OK; } @@ -389,6 +391,8 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( /* Now discard the PDU segment if it is within so_start so_end */ if ((so_start <= 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; } } @@ -444,6 +448,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( 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) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); + list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); /* Free original PDU Segment */ free_mem_block(tb_pP, __func__); @@ -528,6 +535,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( } } + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU REPLACES STORED PDU SEGMENTS SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); return pdu_status; } // End SN != vrR or SO != 0 @@ -554,6 +564,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( /* Insert PDU Segment */ list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer); + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] CREATE PDU SEGMENT FROM PDU OFFSET =%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),next_waited_so,pdu_rx_info_p->sn); + /* clean previous stored segments in duplicate */ if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { mem_block_t* cursor_next_p = cursor_p; From 709b1fd299c11e9608a190d600475ad501381e22 Mon Sep 17 00:00:00 2001 From: fnabet Date: Sat, 4 Mar 2017 13:40:13 +0100 Subject: [PATCH 15/36] RLC AM: fix TReordering expiry --- .../RLC/AM_v9.3.0/rlc_am_timer_reordering.c | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c index fa214cd5a9..a824c13d15 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c @@ -83,23 +83,22 @@ rlc_am_check_timer_reordering( AssertFatal (cursor != NULL, "RLC AM TReordering Expiry Rx PDU list empty LcId=%d\n", rlc_pP->channel_id); - while ((cursor != NULL) && (vr_ms_new != rlc_pP->vr_h)) { - pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + /* go to memblock up to vrX*/ + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + while ((cursor != NULL) && (RLC_AM_DIFF_SN(pdu_info->sn,rlc_pP->vr_r) < RLC_AM_DIFF_SN(vr_ms_new,rlc_pP->vr_r))) { + cursor = cursor->next; + if (cursor != NULL) { + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + } + } - - // First find an element with SN greater or equal than vrX - if (RLC_AM_DIFF_SN(pdu_info->sn,rlc_pP->vr_r) >= RLC_AM_DIFF_SN(rlc_pP->vr_x,rlc_pP->vr_r)) { - if (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received == 0) { - // Stop at first found discontinuity - // vr_ms_new holds SN following the latest in sequence fully received PDU >= old vrX - break; - } - else { - vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); - } - - } - cursor = cursor->next; + /* Now find a SN for which either no PDU is received or partially received */ + while ((cursor != NULL) && (pdu_info->sn == vr_ms_new) && (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received > 0)) { + cursor = cursor->next; + vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); + if (cursor != NULL) { + pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; + } } /* Update vr_ms */ From 65040130778c89b2cc0a13c0b64175416d4cf591 Mon Sep 17 00:00:00 2001 From: fnabet Date: Sat, 4 Mar 2017 15:19:58 +0100 Subject: [PATCH 16/36] RLC AM : fix update of vrMS in tReordering expiry --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c index a824c13d15..cec0dffd1d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_reordering.c @@ -93,9 +93,12 @@ rlc_am_check_timer_reordering( } /* Now find a SN for which either no PDU is received or partially received */ - while ((cursor != NULL) && (pdu_info->sn == vr_ms_new) && (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received > 0)) { + while ((cursor != NULL) && (vr_ms_new != rlc_pP->vr_h) && (pdu_info->sn == vr_ms_new) && (((rlc_am_rx_pdu_management_t*)(cursor->data))->all_segments_received > 0)) { + /* Increment vrMS if the PDU is fully received or if this is the last PDU segment */ + if ((pdu_info->rf == 0) || (pdu_info->lsf == 1)) { + vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); + } cursor = cursor->next; - vr_ms_new = RLC_AM_NEXT_SN(vr_ms_new); if (cursor != NULL) { pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info; } From dc960a60430153aa97c7e0577b696fba189be543 Mon Sep 17 00:00:00 2001 From: GabrielCouturier Date: Tue, 7 Mar 2017 16:01:35 +0100 Subject: [PATCH 17/36] RLC AM: missing SN setup in Tx Pdu Management at first Tx --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c | 1 + 1 file changed, 1 insertion(+) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c index 27816ccb2c..113ee7d048 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c @@ -535,6 +535,7 @@ void rlc_am_segment_10 ( pdu_mngt_p->retx_count_next = 0; pdu_mngt_p->flags.retransmit = 0; pdu_mngt_p->flags.transmitted = 1; + pdu_mngt_p->sn = RLC_AM_PREV_SN(rlc_pP->vt_s); //TBC: What for resetting local pointers at the end ?? From fd5932c5442e0a910a1a74839b6d9345c877efdd Mon Sep 17 00:00:00 2001 From: GabrielCouturier Date: Tue, 7 Mar 2017 16:58:39 +0100 Subject: [PATCH 18/36] RLC AM Tx: TPollRetx Expiry fix for BO --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c index 7c5d55800f..2dfa472523 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_timer_poll_retransmit.c @@ -92,11 +92,14 @@ rlc_am_check_timer_poll_retransmit( sn, rlc_pP->vt_a,rlc_pP->vt_s,rlc_pP->channel_id); if ((tx_data_pdu_buffer_p->flags.ack == 0) && (tx_data_pdu_buffer_p->flags.max_retransmit == 0)) { tx_data_pdu_buffer_p->flags.retransmit = 1; + tx_data_pdu_buffer_p->retx_payload_size = tx_data_pdu_buffer_p->payload_size; if (tx_data_pdu_buffer_p->retx_count == tx_data_pdu_buffer_p->retx_count_next) { tx_data_pdu_buffer_p->retx_count_next ++; } rlc_pP->retrans_num_pdus += 1; rlc_pP->retrans_num_bytes_to_retransmit += tx_data_pdu_buffer_p->payload_size; + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[T_POLL_RETRANSMIT] TIME-OUT PUT SN=%d in ReTx Buffer\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),tx_data_pdu_buffer_p->sn); break; } else From b5ab7267c24b39d3aa855cc0a004572826733de5 Mon Sep 17 00:00:00 2001 From: gabrielC Date: Tue, 7 Mar 2017 17:51:29 +0100 Subject: [PATCH 19/36] RLC AM fix for PDU insertion in case of gaps --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c | 10 +++++++--- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 15 ++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c index acc047d633..d2a5cc985e 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_receiver.c @@ -323,8 +323,9 @@ rlc_am_receive_process_data_pdu ( if (RLC_AM_SN_IN_WINDOW(pdu_info_p->sn, rlc_pP->vr_r)) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] VR(R) %04d VR(H) %04d VR(MR) %04d VR(MS) %04d VR(X) %04d\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%04d] VR(R) %04d VR(H) %04d VR(MR) %04d VR(MS) %04d VR(X) %04d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_info_p->sn, rlc_pP->vr_r, rlc_pP->vr_h, rlc_pP->vr_mr, @@ -433,12 +434,15 @@ rlc_am_receive_process_data_pdu ( } } - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] VR(R) %04d VR(H) %04d VR(MS) %04d VR(MR) %04d\n", + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%04d] NEW VR(R) %04d VR(H) %04d VR(MS) %04d VR(MR) %04d VR(X) %04d reassemble=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + pdu_info_p->sn, rlc_pP->vr_r, rlc_pP->vr_h, rlc_pP->vr_ms, - rlc_pP->vr_mr); + rlc_pP->vr_mr, + rlc_pP->vr_x, + reassemble); } else { rlc_pP->stat_rx_data_pdu_out_of_window += 1; rlc_pP->stat_rx_data_bytes_out_of_window += tb_size_in_bytesP; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index e8c63a8e40..f0ae6a7888 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -505,7 +505,20 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( // First case : cursor_p is NULL, it means the SN is received for the first time // Insert PDU after previous_cursor_p if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { - list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + rlc_usn_t sn_prev = ((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info.sn; + if (RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%d] PDU INSERTED AFTER PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + ((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info.sn); + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { /* SN of head of Rx PDU list is higher than received PDU SN */ + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%d] PDU INSERTED BEFORE PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + pdu_info_cursor_p->sn); + list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer); + } + return pdu_status; } From ce1ac08b19f1ba1caab64b9e941152fe73c0b9ff Mon Sep 17 00:00:00 2001 From: gabrielC Date: Tue, 7 Mar 2017 18:33:14 +0100 Subject: [PATCH 20/36] RLC AM fix for PDU Segment insertion in case of gaps --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index f0ae6a7888..69201d7066 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -320,9 +320,20 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( // First case : cursor_p is NULL or its SN is different from the received one, it means the SN is received for the first time // Insert PDU after previous_cursor_p if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] STORE FIRST PDU SEGMENT FOR SN=%d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); - list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + rlc_usn_t sn_prev = pdu_info_previous_cursor_p->sn; + if (RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d] PDU SEGMENT INSERTED AFTER PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + sn_prev); + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { /* SN of head of Rx PDU list is higher than received PDU SN */ + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d] PDU SEGMENT INSERTED BEFORE PDU SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, + pdu_info_cursor_p->sn); + list2_insert_before_element(tb_pP, cursor_p, &rlc_pP->receiver_buffer); + } + return RLC_AM_DATA_PDU_STATUS_OK; } From 7c7172ca18f67c1f86a8e1c8eaf6d532efa2c5a0 Mon Sep 17 00:00:00 2001 From: GabrielCouturier Date: Wed, 8 Mar 2017 17:16:30 +0100 Subject: [PATCH 21/36] RLC AM fix bad pointer init in ReSegmentation --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 1697b9cac5..a4805df368 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -352,13 +352,13 @@ mem_block_t* rlc_am_retransmit_get_am_segment( { /* Step 1 */ /* Find the SDU index in the original PDU containing retx_so_start */ - uint16_t temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); sdu_size_t sdu_size = 0; sdu_size_t data_size = 0; sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; pdu_original_header_p = pdu_mngt->first_byte + 2; li_bit_offset = 4; /* toggle between 0 and 4 */ li_jump_offset = 1; /* toggle between 1 and 2 */ + uint16_t temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); /* Read first LI */ From 7f60e38fee2f9f14cda568348cc5043ea656128e Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 9 Mar 2017 16:04:31 +0100 Subject: [PATCH 22/36] RCL AM: fixes on Tx resegmentation --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 223 +++++++++++------- 1 file changed, 141 insertions(+), 82 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index a4805df368..314bdc56c1 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -314,6 +314,10 @@ mem_block_t* rlc_am_retransmit_get_am_segment( retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; + AssertFatal (retx_so_start <= retx_so_stop, + "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d sn=%d LcId=%d!\n", + retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); + /* Init FI to the same value as original PDU */ fi_start = (!(RLC_AM_PDU_GET_FI_START(*(pdu_mngt->first_byte)))); fi_end = (!(RLC_AM_PDU_GET_FI_END(*(pdu_mngt->first_byte)))); @@ -328,6 +332,11 @@ mem_block_t* rlc_am_retransmit_get_am_segment( } *payload_sizeP = retx_so_stop - retx_so_start + 1; + + AssertFatal (retx_so_stop <= pdu_mngt->payload_size - 1, + "RLC AM Tx PDU Segment Data Error noLI: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d sn=%d LcId=%d !\n", + retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,sn,rlc_pP->channel_id); + mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + sizeof(struct mac_tb_req)), __func__); pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; @@ -354,6 +363,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* Find the SDU index in the original PDU containing retx_so_start */ sdu_size_t sdu_size = 0; sdu_size_t data_size = 0; + *payload_sizeP = 0; sdu_size_t header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; pdu_original_header_p = pdu_mngt->first_byte + 2; li_bit_offset = 4; /* toggle between 0 and 4 */ @@ -368,29 +378,10 @@ mem_block_t* rlc_am_retransmit_get_am_segment( li_jump_offset ^= 0x3; data_size += sdu_size; - while ((data_size - 1 < retx_so_start) && (sdu_index < pdu_mngt->nb_sdus)) + /* Loop on all original LIs */ + while ((data_size < retx_so_start + 1) && (sdu_index + 1 < pdu_mngt->nb_sdus - 1)) { sdu_index ++; - if (sdu_index < pdu_mngt->nb_sdus) - { - temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); - sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); - pdu_original_header_p += li_jump_offset; - li_bit_offset ^= 0x4; - li_jump_offset ^= 0x3; - data_size += sdu_size; - } - } - - /* Set FI Start if retx_so_start = cumulated data size */ - if (retx_so_start == data_size) - { - fi_start = TRUE; - /* jump to next SDU */ - sdu_index ++; - /* there must be at least one SDU more */ - AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", - sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); pdu_original_header_p += li_jump_offset; @@ -398,15 +389,25 @@ mem_block_t* rlc_am_retransmit_get_am_segment( li_jump_offset ^= 0x3; data_size += sdu_size; } - /* Set first SDU portion of the segment */ - sdus_segment_size[0] = data_size - retx_so_start; - /* Now look for the end */ - while ((data_size - 1 < retx_so_stop) && (sdu_index < pdu_mngt->nb_sdus)) + /* if retx_so_start is still not included then set data_size with full original PDU data size */ + /* Set fi_start to FALSE in this case */ + if ((data_size < retx_so_start + 1) && (sdu_index == pdu_mngt->nb_sdus - 1)) { + data_size = pdu_mngt->payload_size; + fi_start = FALSE; + + } + else if (retx_so_start == data_size) + { + /* Set FI Start if retx_so_start = cumulated data size */ + fi_start = TRUE; + /* jump to next SDU */ sdu_index ++; - sdu_segment_index ++; - if (sdu_index < pdu_mngt->nb_sdus) + /* there must be at least one SDU more */ + AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM Tx PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", + sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); + if (sdu_index < pdu_mngt->nb_sdus - 1) { temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); @@ -414,69 +415,132 @@ mem_block_t* rlc_am_retransmit_get_am_segment( li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; data_size += sdu_size; - sdus_segment_size[sdu_segment_index] = sdu_size; - } - } - - /* Set FI End if retx_so_stop = cumulated data size */ - if (retx_so_stop == data_size - 1) - { - fi_end = TRUE; - } - /* Set last SDU portion of the segment even if it will be out of LI */ - if (sdu_segment_index) - { - sdus_segment_size[sdu_segment_index] = retx_so_stop - (data_size - sdu_size) + 1; - } - else - { - sdus_segment_size[0] = retx_so_stop - retx_so_start + 1; - } - - /* Set number of LIs in the segment */ - num_LIs_pdu_segment = sdu_segment_index; - - /* Memory allocation taking into account available TBS */ - /* Compute Header Length and Data Length */ - /* Init Segment Payload data size */ - *payload_sizeP = sdus_segment_size[0]; - - /* Bound to available TBS taking into account min PDU segment header*/ - if (*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE > rlc_pP->nb_bytes_requested_by_mac) - { - *payload_sizeP = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; - } - - sdu_segment_index = 1; - while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index))) - { - /* Add next sdu_segment_index to data part */ - if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + sdus_segment_size[sdu_segment_index] < rlc_pP->nb_bytes_requested_by_mac) - { - (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; } else { - /* bound to available TBS size */ - (*payload_sizeP) += (rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index)); - sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + /* It was the last LI, then set data_size to full original PDU size */ + data_size = pdu_mngt->payload_size; } - header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); - sdu_segment_index ++; + } + else if (retx_so_start != 0) + { + /* in all other cases set fi_start to FALSE if it SO Start is not 0 */ + fi_start = FALSE; } - num_LIs_pdu_segment = sdu_segment_index - 1; + /* Set first SDU portion of the segment */ + sdus_segment_size[0] = data_size - retx_so_start; + + /* Check if so end is in the first SDU portion */ + if (sdus_segment_size[0] > retx_so_stop - retx_so_start + 1) + { + sdus_segment_size[0] = retx_so_stop - retx_so_start + 1; + *payload_sizeP = sdus_segment_size[0]; + num_LIs_pdu_segment = 0; + } + + /* Bound first SDU segment to available TBS if necessary */ + if (sdus_segment_size[0] + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE >= rlc_pP->nb_bytes_requested_by_mac) + { + sdus_segment_size[0] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE; + *payload_sizeP = sdus_segment_size[0]; + num_LIs_pdu_segment = 0; + } + + + /* Now look for the end if it was not set previously */ + if (*payload_sizeP == 0) + { + sdu_index ++; + sdu_segment_index ++; + while (sdu_index < pdu_mngt->nb_sdus) + { + if (sdu_index < pdu_mngt->nb_sdus - 1) + { + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + else + { + sdu_size = pdu_mngt->payload_size - data_size; + data_size = pdu_mngt->payload_size; + } + + if (data_size >= retx_so_stop + 1) + { + sdus_segment_size[sdu_segment_index] = retx_so_stop - (data_size - sdu_size) + 1; + break; + } + + sdus_segment_size[sdu_segment_index] = sdu_size; + sdu_index ++; + sdu_segment_index ++; + } + + + /* Set number of LIs in the segment */ + num_LIs_pdu_segment = sdu_segment_index; + + AssertFatal (num_LIs_pdu_segment <= pdu_mngt->nb_sdus - 1, "RLC AM Tx PDU Segment Data Error: nbLISegment=%d nbLIPDU=%d sn=%d LcId=%d !\n", + num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); + + /* Bound to available TBS taking into account min PDU segment header*/ + sdu_segment_index = 0; + while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index))) + { + /* Add next sdu_segment_index to data part */ + if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + sdus_segment_size[sdu_segment_index] <= rlc_pP->nb_bytes_requested_by_mac) + { + (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; + } + else + { + /* bound to available TBS size */ + (*payload_sizeP) += (rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index)); + sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + } + header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + sdu_segment_index ++; + } + + num_LIs_pdu_segment = sdu_segment_index - 1; + } + + + /* update retx_so_stop */ + retx_so_stop = retx_so_start + (*payload_sizeP) - 1; + + AssertFatal (retx_so_stop <= pdu_mngt->payload_size - 1, + "RLC AM Tx PDU Segment Data Error: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d numLISegment=%d sn=%d LcId=%d !\n", + retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,num_LIs_pdu_segment,sn,rlc_pP->channel_id); + + /* init FI End to FALSE if retx_so_stop is not end of PDU */ + if (retx_so_stop != pdu_mngt->payload_size - 1) + { + fi_end = FALSE; + } /* Check consistency between sdus_segment_size and payload_sizeP */ + /* And Set FI End if retx_so_stop = cumulated data size and this is not last SDU */ data_size = 0; for (int i = 0; i < num_LIs_pdu_segment + 1; i++) { data_size += sdus_segment_size[i]; + if ((retx_so_stop == data_size - 1) && (i < num_LIs_pdu_segment)) + { + fi_end = TRUE; + } } AssertFatal (data_size == *payload_sizeP, "RLC AM PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n", data_size,*payload_sizeP,sn,rlc_pP->channel_id); + + /* Allocation */ AssertFatal (header_segment_length + *payload_sizeP <= pdu_mngt->header_and_payload_size + 2, "RLC AM PDU Segment Error: Hdr=%d Data=%d Original Hdr+Data =%d sn=%d LcId=%d !\n", header_segment_length,*payload_sizeP,pdu_mngt->header_and_payload_size,sn,rlc_pP->channel_id); @@ -521,27 +585,22 @@ mem_block_t* rlc_am_retransmit_get_am_segment( pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ - /* copy first two bytes from original: D/C + RF + FI + E+ SN*/ - *pdu_segment_header_p = *(pdu_mngt->first_byte); - *(pdu_segment_header_p + 1) = *(pdu_mngt->first_byte + 1); - - /* Set Segmentation Flag */ + RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); RLC_AM_PDU_SET_RF(*pdu_segment_header_p); - /* clear polling */ - RLC_AM_PDU_CLEAR_POLL(*pdu_segment_header_p); /* Change FI */ if (!fi_start) { // Set to not starting (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET + 1)); - } if (!fi_end) { // Set to not starting (*pdu_segment_header_p) |= (1 << (RLC_AM_PDU_FI_OFFSET)); - } + /* Set SN */ + (*pdu_segment_header_p) |= ((sn >> 8) & 0x3); + (*(pdu_segment_header_p + 1)) |= (sn & 0xFF); /* Segment Offset */ header_so_part = retx_so_start; From 0ce73b4d0ec72e6ece27fc2d0f19ae672f01f20a Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 9 Mar 2017 18:08:43 +0100 Subject: [PATCH 23/36] RLC AM Rx PDU Segment fixes --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 97 +++++++++++++------ 1 file changed, 70 insertions(+), 27 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 69201d7066..cc84ef9ab5 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -298,9 +298,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( /*****************************************************/ // 1) Find previous cursor to the PDU to insert /*****************************************************/ - previous_cursor_p = cursor_p; pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - pdu_info_previous_cursor_p = pdu_info_cursor_p; while (cursor_p != NULL) { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; @@ -320,11 +318,10 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( // First case : cursor_p is NULL or its SN is different from the received one, it means the SN is received for the first time // Insert PDU after previous_cursor_p if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { - rlc_usn_t sn_prev = pdu_info_previous_cursor_p->sn; - if (RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + if (previous_cursor_p != NULL) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT SN=%d] PDU SEGMENT INSERTED AFTER PDU SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, - sn_prev); + pdu_info_previous_cursor_p->sn); list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); } else { /* SN of head of Rx PDU list is higher than received PDU SN */ @@ -337,6 +334,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( return RLC_AM_DATA_PDU_STATUS_OK; } + /* 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); @@ -362,29 +360,29 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( } /* if not previously inserted, it will be put after the last segment if it was not LSF*/ - if ((!prev_segment_found) && (pdu_info_previous_cursor_p->lsf == 0)) { - prev_segment_found = TRUE; - next_segment_found = TRUE; // no more segment after the PDU - 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); + if (!prev_segment_found) { + if (pdu_info_previous_cursor_p->lsf == 0) { + prev_segment_found = TRUE; + next_segment_found = TRUE; // no more segment after the PDU + 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); + } + else + { + // the segment is duplicate + return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; + } } - else - { - // the segment is duplicate - return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; - } - // Check that the Segment is not duplicate by scanning stored contiguous segments from previous_cursor_p - pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info; if ((previous_cursor_p != NULL) && (pdu_info_previous_cursor_p->sn == pdu_rx_info_p->sn)) { + so_start = pdu_info_previous_cursor_p->so; so_end = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1; - cursor_p = previous_cursor_p; - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - cursor_p = cursor_p->next; + pdu_info_cursor_p = pdu_info_previous_cursor_p; + cursor_p = previous_cursor_p->next; rlc_am_pdu_info_t* pdu_info_cursor_next_p = NULL; if (cursor_p != NULL) { pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; @@ -403,7 +401,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( /* Now discard the PDU segment if it is within so_start so_end */ if ((so_start <= 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); + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; } } @@ -411,8 +409,37 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( // Now found the segment which will be right after the pdu to insert if (!next_segment_found) { + /* 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)) { + if (((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) { + pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info; + so_end = pdu_info_previous_cursor_p->so + 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) && + (((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; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + } + } + } + + if (previous_cursor_p != NULL) { + cursor_p = previous_cursor_p->next; + } + else { + cursor_p = rlc_pP->receiver_buffer.head; + } - cursor_p = previous_cursor_p->next; 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; @@ -435,10 +462,13 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( /* 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 - 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 - pdu_rx_info_p->so); + 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 - pdu_rx_info_p->so); + } } + // remove duplicate at the end if (next_cursor_p != NULL) { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; @@ -448,6 +478,7 @@ 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) && (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", @@ -462,7 +493,13 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); - list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); + if (previous_cursor_p != NULL) { + list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { + list2_insert_before_element(trunc_segment, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer); + } + /* Free original PDU Segment */ free_mem_block(tb_pP, __func__); @@ -474,7 +511,13 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( } else { - list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + if (previous_cursor_p != NULL) { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { + list2_insert_before_element(tb_pP, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer); + } + return RLC_AM_DATA_PDU_STATUS_OK; } } From 0e78513b5a32bd55a441bcb06fd0cb4f07d6f897 Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 13 Mar 2017 12:27:09 +0100 Subject: [PATCH 24/36] RLC AM Tx Segment : missing data_ptr setting --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 314bdc56c1..c4a5ca9ce3 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -314,9 +314,9 @@ mem_block_t* rlc_am_retransmit_get_am_segment( retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; - AssertFatal (retx_so_start <= retx_so_stop, - "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d sn=%d LcId=%d!\n", - retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); + AssertFatal ((retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 < pdu_mngt->payload_size), + "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d OriginalPDUDataLength=%d sn=%d LcId=%d!\n", + retx_so_start,retx_so_stop,pdu_mngt->payload_size,sn,rlc_pP->channel_id); /* Init FI to the same value as original PDU */ fi_start = (!(RLC_AM_PDU_GET_FI_START(*(pdu_mngt->first_byte)))); @@ -333,12 +333,10 @@ mem_block_t* rlc_am_retransmit_get_am_segment( *payload_sizeP = retx_so_stop - retx_so_start + 1; - AssertFatal (retx_so_stop <= pdu_mngt->payload_size - 1, - "RLC AM Tx PDU Segment Data Error noLI: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d sn=%d LcId=%d !\n", - retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,sn,rlc_pP->channel_id); - mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + sizeof(struct mac_tb_req)), __func__); - pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + pdu_segment_header_p = (uint8_t *)&mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->data_ptr = pdu_segment_header_p; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->tb_size = RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE + *payload_sizeP; /* clear all PDU segment */ memset(pdu_segment_header_p, 0, *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_MIN_SIZE); @@ -545,7 +543,9 @@ mem_block_t* rlc_am_retransmit_get_am_segment( AssertFatal (header_segment_length + *payload_sizeP <= pdu_mngt->header_and_payload_size + 2, "RLC AM PDU Segment Error: Hdr=%d Data=%d Original Hdr+Data =%d sn=%d LcId=%d !\n", header_segment_length,*payload_sizeP,pdu_mngt->header_and_payload_size,sn,rlc_pP->channel_id); mem_pdu_segment_p = get_free_mem_block((*payload_sizeP + header_segment_length + sizeof(struct mac_tb_req)), __func__); - pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + pdu_segment_header_p = (uint8_t *)&mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->data_ptr = pdu_segment_header_p; + ((struct mac_tb_req*)(mem_pdu_segment_p->data))->tb_size = header_segment_length + *payload_sizeP; /* clear all PDU segment */ memset(pdu_segment_header_p, 0, *payload_sizeP + header_segment_length); @@ -581,9 +581,6 @@ mem_block_t* rlc_am_retransmit_get_am_segment( pdu_mngt->nack_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; } - /* Set Fixed part of AM PDU Segment Header */ - pdu_segment_header_p = &mem_pdu_segment_p->data[sizeof(struct mac_tb_req)]; - /* Content is supposed to be init with 0 so with FIStart=FIEnd=TRUE */ RLC_AM_PDU_SET_D_C(*pdu_segment_header_p); RLC_AM_PDU_SET_RF(*pdu_segment_header_p); @@ -645,7 +642,12 @@ mem_block_t* rlc_am_retransmit_get_am_segment( index ++; } } - + } + else + { + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RE-SEGMENT] OUT OF MEMORY PDU SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + sn); } return mem_pdu_segment_p; From 3a43c08ae306201e1a0ef2fff421c0f3942a9c8a Mon Sep 17 00:00:00 2001 From: fnabet Date: Mon, 13 Mar 2017 15:54:27 +0100 Subject: [PATCH 25/36] RLC AM fix RX Segment --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index cc84ef9ab5..310c66a44c 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -176,7 +176,7 @@ mem_block_t * create_new_segment_from_pdu( if (new_segment_p != NULL) { pdu_new_segment_info_p = &((rlc_am_rx_pdu_management_t*)(new_segment_p->data))->pdu_info; rlc_am_rx_pdu_management_t * pdu_cursor_mgnt_p = (rlc_am_rx_pdu_management_t *) (new_segment_p->data); - uint8_t *pdu_segment_header_p = &(new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]); + uint8_t *pdu_segment_header_p = (uint8_t *)&(new_segment_p->data[sizeof (mac_rlc_max_rx_header_size_t)]); pdu_cursor_mgnt_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; //to be updated after if SN = vrR From dabf833c107a0bb5349bed522a59b9f9bc1dd2dd Mon Sep 17 00:00:00 2001 From: gabrielC Date: Mon, 13 Mar 2017 19:41:24 +0100 Subject: [PATCH 26/36] RLC AM Rx Segment and Tx Status Report fixes --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 13 +++++---- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 29 ++++++++++++++----- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 17 ++++++----- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index df8682f726..f7f4de1718 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -88,17 +88,18 @@ rlc_am_get_status_pdu_buffer_occupancy( if (pdu_info_cursor_p->so) { nb_bits_to_transmit += (RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)); waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; - /* Go to next segment */ - cursor_p = cursor_p->next; - if (cursor_p != NULL) - { - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - } } else { waited_so = pdu_info_cursor_p->payload_size; } + /* Go to next segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + /* Fill following gaps if any */ while (!segment_loop_end) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 310c66a44c..bb1d172451 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -464,8 +464,8 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( // 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 - pdu_rx_info_p->so); + 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); } } @@ -512,9 +512,16 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( 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); } @@ -1330,10 +1337,19 @@ rlc_am_rx_list_reassemble_rlc_sdus( else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING) { rlc_am_rx_pdu_management_p->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLED; - cursor_p = list2_remove_head(&rlc_pP->receiver_buffer); rlc_am_reassemble_pdu(ctxt_pP, rlc_pP, cursor_p,FALSE); rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; - cursor_p = list2_get_head(&rlc_pP->receiver_buffer); + cursor_p = cursor_p->next; + + if (cursor_p == NULL) { + return; + } + + rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); + } + else if (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) { + rlc_am_rx_old_pdu_management = rlc_am_rx_pdu_management_p; + cursor_p = cursor_p->next; if (cursor_p == NULL) { return; @@ -1354,9 +1370,8 @@ rlc_am_rx_list_reassemble_rlc_sdus( return; } - } while ((rlc_am_rx_pdu_management_p->pdu_info.sn == ((rlc_am_rx_old_pdu_management->pdu_info.sn + 1) & RLC_AM_SN_MASK)) - || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && ( - (rlc_am_rx_pdu_management_p->all_segments_received > 0) || (rlc_am_rx_pdu_management_p->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING)))); + } while (((rlc_am_rx_pdu_management_p->pdu_info.sn == ((rlc_am_rx_old_pdu_management->pdu_info.sn + 1) & RLC_AM_SN_MASK)) && (rlc_am_rx_old_pdu_management->all_segments_received > 0)) + || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && (rlc_am_rx_pdu_management_p->segment_reassembled != RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO))); } //----------------------------------------------------------------------------- mem_block_t * diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 6d4fd0a2b7..dfa62f0351 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -620,17 +620,18 @@ rlc_am_send_status_pdu( pdu_info_cursor_p->so - 1); #endif waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size; - /* Go to next segment */ - cursor_p = cursor_p->next; - if (cursor_p != NULL) - { - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - } } else { waited_so = pdu_info_cursor_p->payload_size; } + /* Go to next segment */ + cursor_p = cursor_p->next; + if (cursor_p != NULL) + { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + } + /* Find the first discontinuity and then fill SOStart/SOEnd */ while (!segment_loop_end) { if ((cursor_p != NULL) && (pdu_info_cursor_p->sn == sn_cursor)) { @@ -644,7 +645,7 @@ rlc_am_send_status_pdu( if ((nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) + (RLC_AM_STATUS_PDU_SO_LENGTH << 1)) <= nb_bits_to_transmit) { control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_cursor; control_pdu_info.nack_list[control_pdu_info.num_nack].so_start = waited_so; - control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so; + control_pdu_info.nack_list[control_pdu_info.num_nack].so_end = pdu_info_cursor_p->so - 1; control_pdu_info.nack_list[control_pdu_info.num_nack].e2 = 1; /* Set E1 for next NACK_SN. The last one will be cleared */ control_pdu_info.nack_list[control_pdu_info.num_nack].e1 = 1; @@ -732,7 +733,7 @@ rlc_am_send_status_pdu( } // End main while NACK_SN /* Clear E1 of last nack_sn entry */ - AssertFatal (control_pdu_info.num_nack, "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id); + AssertFatal ((control_pdu_info.num_nack) || (all_segments_received == 0), "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id); control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0; /* Set ACK_SN unless it was set before */ From cf9727c4be5f69815357758a315a6af2839db08f Mon Sep 17 00:00:00 2001 From: GabrielCouturier Date: Mon, 13 Mar 2017 19:44:52 +0100 Subject: [PATCH 27/36] RLC AM fix bad assert for resegmentation --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index c4a5ca9ce3..d61dd8b6ab 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -314,7 +314,14 @@ mem_block_t* rlc_am_retransmit_get_am_segment( retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; - AssertFatal ((retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 < pdu_mngt->payload_size), + /* + if (!(retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 <= pdu_mngt->payload_size)) + { + AssertFatal(0); + } + */ + + AssertFatal ((retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 <= pdu_mngt->payload_size), "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d OriginalPDUDataLength=%d sn=%d LcId=%d!\n", retx_so_start,retx_so_stop,pdu_mngt->payload_size,sn,rlc_pP->channel_id); From c1da605f6d56e5193b2639ff56678efb745c5f71 Mon Sep 17 00:00:00 2001 From: fnabet Date: Tue, 14 Mar 2017 10:10:36 +0100 Subject: [PATCH 28/36] RLC AM code cleaning --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 7 ----- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 26 +++++++++---------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index d61dd8b6ab..27aa0b6ddf 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -314,13 +314,6 @@ mem_block_t* rlc_am_retransmit_get_am_segment( retx_so_start = pdu_mngt->hole_so_start[pdu_mngt->retx_hole_index]; retx_so_stop = pdu_mngt->hole_so_stop[pdu_mngt->retx_hole_index]; - /* - if (!(retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 <= pdu_mngt->payload_size)) - { - AssertFatal(0); - } - */ - AssertFatal ((retx_so_start <= retx_so_stop) && (retx_so_stop - retx_so_start + 1 <= pdu_mngt->payload_size), "RLC AM Tx PDU Segment Data SO Error: retx_so_start=%d retx_so_stop=%d OriginalPDUDataLength=%d sn=%d LcId=%d!\n", retx_so_start,retx_so_stop,pdu_mngt->payload_size,sn,rlc_pP->channel_id); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index bb1d172451..fd84cd5e35 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -284,10 +284,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; rlc_am_pdu_info_t* pdu_info_previous_cursor_p = NULL; - mem_block_t* cursor_p = NULL; + mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; mem_block_t* previous_cursor_p = NULL; mem_block_t* next_cursor_p = NULL; - cursor_p = rlc_pP->receiver_buffer.head; boolean_t prev_segment_found = FALSE; boolean_t next_segment_found = FALSE; uint16_t so_start = 0; @@ -298,8 +297,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( /*****************************************************/ // 1) Find previous cursor to the PDU to insert /*****************************************************/ - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - while (cursor_p != NULL) { + AssertFatal(cursor_p != NULL,"AM Rx PDU Error, received buffer empty LcID=%d\n",rlc_pP->channel_id); + + do { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; // Stop if Cursor SN >= Received SN @@ -310,7 +310,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( previous_cursor_p = cursor_p; pdu_info_previous_cursor_p = pdu_info_cursor_p; cursor_p = cursor_p->next; - } + } while (cursor_p != NULL); /*****************************************************/ // 2) Store the received Segment @@ -536,9 +536,8 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( { rlc_am_pdu_info_t* pdu_rx_info_p = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info; rlc_am_pdu_info_t* pdu_info_cursor_p = NULL; - mem_block_t* cursor_p = NULL; + mem_block_t* cursor_p = rlc_pP->receiver_buffer.head; mem_block_t* previous_cursor_p = NULL; - cursor_p = rlc_pP->receiver_buffer.head; rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; // it is assumed this pdu is in rx window @@ -546,9 +545,9 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( /*****************************************************/ // 1) Find previous cursor to the PDU to insert /*****************************************************/ - previous_cursor_p = cursor_p; - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - while (cursor_p != NULL) { + AssertFatal(cursor_p != NULL,"AM Rx PDU Error, received buffer empty LcID=%d\n",rlc_pP->channel_id); + + do { pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; // Stop if Cursor SN >= Received SN @@ -558,16 +557,15 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( previous_cursor_p = cursor_p; cursor_p = cursor_p->next; - } + } while (cursor_p != NULL); /*****************************************************/ // 2) Insert PDU by removing byte duplicate if required /*****************************************************/ - // First case : cursor_p is NULL, it means the SN is received for the first time + // First case : cursor_p is NULL or SN are different, it means the SN is received for the first time // Insert PDU after previous_cursor_p if ((cursor_p == NULL) || (pdu_info_cursor_p->sn != pdu_rx_info_p->sn)) { - rlc_usn_t sn_prev = ((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info.sn; - if (RLC_AM_DIFF_SN(sn_prev,rlc_pP->vr_r) < RLC_AM_DIFF_SN(pdu_rx_info_p->sn,rlc_pP->vr_r)) { + if (previous_cursor_p != NULL) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SN=%d] PDU INSERTED AFTER PDU SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn, ((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info.sn); From bf71c6f01e0a6f926445d464f3cd13d0d60d4b2c Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 15 Mar 2017 10:10:32 +0100 Subject: [PATCH 29/36] RLC AM Tx Segment: fix --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 27aa0b6ddf..b88d321494 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -430,7 +430,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( sdus_segment_size[0] = data_size - retx_so_start; /* Check if so end is in the first SDU portion */ - if (sdus_segment_size[0] > retx_so_stop - retx_so_start + 1) + if (sdus_segment_size[0] >= retx_so_stop - retx_so_start + 1) { sdus_segment_size[0] = retx_so_stop - retx_so_start + 1; *payload_sizeP = sdus_segment_size[0]; @@ -451,7 +451,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( { sdu_index ++; sdu_segment_index ++; - while (sdu_index < pdu_mngt->nb_sdus) + while ((sdu_index < pdu_mngt->nb_sdus) && (data_size < retx_so_stop + 1)) { if (sdu_index < pdu_mngt->nb_sdus - 1) { @@ -468,20 +468,19 @@ mem_block_t* rlc_am_retransmit_get_am_segment( data_size = pdu_mngt->payload_size; } - if (data_size >= retx_so_stop + 1) - { - sdus_segment_size[sdu_segment_index] = retx_so_stop - (data_size - sdu_size) + 1; - break; - } - sdus_segment_size[sdu_segment_index] = sdu_size; sdu_index ++; sdu_segment_index ++; } + if (data_size > retx_so_stop + 1) + { + sdus_segment_size[sdu_segment_index - 1] = retx_so_stop - (data_size - sdu_size) + 1; + } + /* Set number of LIs in the segment */ - num_LIs_pdu_segment = sdu_segment_index; + num_LIs_pdu_segment = sdu_segment_index - 1; AssertFatal (num_LIs_pdu_segment <= pdu_mngt->nb_sdus - 1, "RLC AM Tx PDU Segment Data Error: nbLISegment=%d nbLIPDU=%d sn=%d LcId=%d !\n", num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); @@ -527,6 +526,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( data_size = 0; for (int i = 0; i < num_LIs_pdu_segment + 1; i++) { + AssertFatal (sdus_segment_size[i] > 0, "RLC AM Tx PDU Segment Data Error: EMpty LI index=%d numLISegment=%d numLIPDU=%d PDULength=%d SOStart=%d SOStop=%d sn=%d LcId=%d !\n", + i,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,pdu_mngt->payload_size,retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); data_size += sdus_segment_size[i]; if ((retx_so_stop == data_size - 1) && (i < num_LIs_pdu_segment)) { @@ -534,7 +535,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( } } - AssertFatal (data_size == *payload_sizeP, "RLC AM PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n", + AssertFatal (data_size == *payload_sizeP, "RLC AM Tx PDU Segment Data Error: SduSum=%d Data=%d sn=%d LcId=%d !\n", data_size,*payload_sizeP,sn,rlc_pP->channel_id); From 18f628848c764fff2a36928806622f0ed169a7ec Mon Sep 17 00:00:00 2001 From: GabrielCouturier Date: Wed, 15 Mar 2017 16:54:01 +0100 Subject: [PATCH 30/36] RLC AM Fix on ReTx --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 3 + .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 57 ++++++++++--------- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 7 ++- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index f7f4de1718..c399fb8447 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -1236,6 +1236,8 @@ rlc_am_data_req ( l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].flags.no_new_sdu_segmented_in_last_pdu = 0; //l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].li_index_for_discard = -1; l_rlc_p->next_sdu_index = (l_rlc_p->next_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; + if (l_rlc_p->channel_id <3) + { LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p), data_size, @@ -1244,6 +1246,7 @@ rlc_am_data_req ( l_rlc_p->next_sdu_index, conf, mui); + } } else { #if MESSAGE_CHART_GENERATOR mui = ((struct rlc_am_data_req*) (sdu_pP->data))->mui; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index b88d321494..4cef19253a 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -375,33 +375,33 @@ mem_block_t* rlc_am_retransmit_get_am_segment( li_bit_offset ^= 0x4; li_jump_offset ^= 0x3; data_size += sdu_size; + sdu_index = 1; /* Loop on all original LIs */ - while ((data_size < retx_so_start + 1) && (sdu_index + 1 < pdu_mngt->nb_sdus - 1)) + while ((data_size < retx_so_start + 1) && (sdu_index < pdu_mngt->nb_sdus)) { + if (sdu_index < pdu_mngt->nb_sdus - 1) + { + temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); + sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); + pdu_original_header_p += li_jump_offset; + li_bit_offset ^= 0x4; + li_jump_offset ^= 0x3; + data_size += sdu_size; + } + else + { + /* if retx_so_start is still not included then set data_size with full original PDU data size */ + /* Set fi_start to FALSE in this case */ + data_size = pdu_mngt->payload_size; + } sdu_index ++; - temp_read = ((*pdu_original_header_p) << 8) | (*(pdu_original_header_p + 1)); - sdu_size = RLC_AM_PDU_GET_LI(temp_read,li_bit_offset); - pdu_original_header_p += li_jump_offset; - li_bit_offset ^= 0x4; - li_jump_offset ^= 0x3; - data_size += sdu_size; } - /* if retx_so_start is still not included then set data_size with full original PDU data size */ - /* Set fi_start to FALSE in this case */ - if ((data_size < retx_so_start + 1) && (sdu_index == pdu_mngt->nb_sdus - 1)) - { - data_size = pdu_mngt->payload_size; - fi_start = FALSE; - - } - else if (retx_so_start == data_size) + if (retx_so_start == data_size) { /* Set FI Start if retx_so_start = cumulated data size */ fi_start = TRUE; - /* jump to next SDU */ - sdu_index ++; /* there must be at least one SDU more */ AssertFatal (sdu_index < pdu_mngt->nb_sdus, "RLC AM Tx PDU Segment Error: sdu_index=%d nb_sdus=%d sn=%d LcId=%d !\n", sdu_index,pdu_mngt->nb_sdus,sn,rlc_pP->channel_id); @@ -419,6 +419,8 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* It was the last LI, then set data_size to full original PDU size */ data_size = pdu_mngt->payload_size; } + /* Go to next SDU */ + sdu_index ++; } else if (retx_so_start != 0) { @@ -449,7 +451,6 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* Now look for the end if it was not set previously */ if (*payload_sizeP == 0) { - sdu_index ++; sdu_segment_index ++; while ((sdu_index < pdu_mngt->nb_sdus) && (data_size < retx_so_stop + 1)) { @@ -489,16 +490,19 @@ mem_block_t* rlc_am_retransmit_get_am_segment( sdu_segment_index = 0; while ((sdu_segment_index < num_LIs_pdu_segment + 1) && (rlc_pP->nb_bytes_requested_by_mac > *payload_sizeP + RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index))) { + AssertFatal (sdus_segment_size[sdu_segment_index] > 0, "RLC AM Tx PDU Segment Data Error: EMpty LI index=%d numLISegment=%d numLIPDU=%d PDULength=%d SOStart=%d SOStop=%d sn=%d LcId=%d !\n", + sdu_segment_index,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,pdu_mngt->payload_size,retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); + /* Add next sdu_segment_index to data part */ - if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + sdus_segment_size[sdu_segment_index] <= rlc_pP->nb_bytes_requested_by_mac) + if (RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) + (*payload_sizeP) + sdus_segment_size[sdu_segment_index] <= rlc_pP->nb_bytes_requested_by_mac) { (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; } else { /* bound to available TBS size */ - (*payload_sizeP) += (rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index)); - sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); + sdus_segment_size[sdu_segment_index] = rlc_pP->nb_bytes_requested_by_mac - RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index) - (*payload_sizeP); + (*payload_sizeP) += sdus_segment_size[sdu_segment_index]; } header_segment_length = RLC_AM_PDU_SEGMENT_HEADER_SIZE(sdu_segment_index); sdu_segment_index ++; @@ -511,9 +515,9 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* update retx_so_stop */ retx_so_stop = retx_so_start + (*payload_sizeP) - 1; - AssertFatal (retx_so_stop <= pdu_mngt->payload_size - 1, - "RLC AM Tx PDU Segment Data Error: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d numLISegment=%d sn=%d LcId=%d !\n", - retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,num_LIs_pdu_segment,sn,rlc_pP->channel_id); + AssertFatal ((retx_so_stop <= pdu_mngt->payload_size - 1) && (retx_so_stop - retx_so_start + 1 < pdu_mngt->payload_size), + "RLC AM Tx PDU Segment Data Error: retx_so_stop=%d OriginalPDUDataLength=%d SOStart=%d SegmentLength=%d numLISegment=%d numLIPDU=%d sn=%d LcId=%d !\n", + retx_so_stop,pdu_mngt->payload_size,retx_so_start,*payload_sizeP,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,sn,rlc_pP->channel_id); /* init FI End to FALSE if retx_so_stop is not end of PDU */ if (retx_so_stop != pdu_mngt->payload_size - 1) @@ -526,8 +530,6 @@ mem_block_t* rlc_am_retransmit_get_am_segment( data_size = 0; for (int i = 0; i < num_LIs_pdu_segment + 1; i++) { - AssertFatal (sdus_segment_size[i] > 0, "RLC AM Tx PDU Segment Data Error: EMpty LI index=%d numLISegment=%d numLIPDU=%d PDULength=%d SOStart=%d SOStop=%d sn=%d LcId=%d !\n", - i,num_LIs_pdu_segment,pdu_mngt->nb_sdus - 1,pdu_mngt->payload_size,retx_so_start,retx_so_stop,sn,rlc_pP->channel_id); data_size += sdus_segment_size[i]; if ((retx_so_stop == data_size - 1) && (i < num_LIs_pdu_segment)) { @@ -573,6 +575,7 @@ mem_block_t* rlc_am_retransmit_get_am_segment( /* Retx size is reset in the calling function */ pdu_mngt->num_holes = 0; pdu_mngt->retx_hole_index = 0; + pdu_mngt->nack_so_start = 0; } } else diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index dfa62f0351..50ed5dca56 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -384,8 +384,8 @@ rlc_am_receive_process_control_pdu( } else { - LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN OUT OF WINDOW\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); + LOG_N(RLC, PROTOCOL_RLC_AM_CTXT_FMT" WARNING CONTROL PDU ACK SN %d OUT OF WINDOW vtA=%d vtS=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),ack_sn,rlc_pP->vt_a,rlc_pP->vt_s); status = FALSE; } } else { @@ -416,6 +416,9 @@ rlc_am_receive_process_control_pdu( rlc_am_pdu_sdu_data_cnf(ctxt_pP,rlc_pP,sn_data_cnf); } + LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RECEIVE STATUS PDU ACK_SN=%d NewvtA=%d OldvtA=%d SnDataCnf=%d DataCnfSOStop=%d vtS=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),ack_sn,vt_a_new,rlc_pP->vt_a,sn_data_cnf,data_cnf_so_stop,rlc_pP->vt_s); + /* Update vtA and vtMS */ rlc_pP->vt_a = vt_a_new; rlc_pP->vt_ms = (rlc_pP->vt_a + RLC_AM_WINDOW_SIZE) & RLC_AM_SN_MASK; From 40fa3e076cd50b403f5034063890ac07b1053547 Mon Sep 17 00:00:00 2001 From: gabrielC Date: Wed, 15 Mar 2017 16:58:54 +0100 Subject: [PATCH 31/36] RLC AM Rx fixes --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 12 +++++++++--- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c | 8 ++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index fd84cd5e35..c66b826fd6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -490,7 +490,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( 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) { - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); if (previous_cursor_p != NULL) { @@ -610,7 +610,13 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU REPLACES STORED PDU SEGMENTS SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),pdu_rx_info_p->sn); - list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + if (previous_cursor_p != NULL) { + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + } + else { + list2_insert_before_element(tb_pP, cursor_next_p, &rlc_pP->receiver_buffer); + } + return pdu_status; } // End SN != vrR or SO != 0 else { @@ -636,7 +642,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( /* Insert PDU Segment */ list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer); - LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] CREATE PDU SEGMENT FROM PDU OFFSET =%d SN=%d\n", + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] CREATE PDU SEGMENT FROM PDU OFFSET =%d SN=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),next_waited_so,pdu_rx_info_p->sn); /* clean previous stored segments in duplicate */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 50ed5dca56..0d01d0b1ce 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -736,8 +736,12 @@ rlc_am_send_status_pdu( } // End main while NACK_SN /* Clear E1 of last nack_sn entry */ - AssertFatal ((control_pdu_info.num_nack) || (all_segments_received == 0), "RLC AM Tx Status PDU Data Error no NACK_SN LcId=%d\n",rlc_pP->channel_id); - control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0; + AssertFatal ((control_pdu_info.num_nack) || (all_segments_received == 0), "RLC AM Tx Status PDU Data Error no NACK_SN vrR=%d vrMS=%d lastSN_NACK=%d Completed=%d NbBytesAvailable=%d LcId=%d\n", + rlc_pP->vr_r,rlc_pP->vr_ms,sn_nack,status_report_completed,(nb_bits_to_transmit >> 3),rlc_pP->channel_id); + if (control_pdu_info.num_nack) { + control_pdu_info.nack_list[control_pdu_info.num_nack - 1].e1 = 0; + } + /* Set ACK_SN unless it was set before */ if (!status_report_completed){ From 01530385f1b8a2080af5cd9d9555d990c4bb0013 Mon Sep 17 00:00:00 2001 From: fnabet Date: Wed, 15 Mar 2017 18:56:53 +0100 Subject: [PATCH 32/36] RLC AM fix Tx Status Report --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 7 +++++-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 5 +++-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index c399fb8447..7d193bcd01 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -134,8 +134,11 @@ rlc_am_get_status_pdu_buffer_occupancy( } // end if segments else { - /* Go to next received PDU or PDU Segment */ - cursor_p = cursor_p->next; + /* Go to next received PDU or PDU segment with different SN */ + do + { + cursor_p = cursor_p->next; + } while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn_cursor)); } sn_prev = RLC_AM_NEXT_SN(sn_cursor); diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index c66b826fd6..048466a1a9 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -638,7 +638,6 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( mem_block_t* trunc_pdu = create_new_segment_from_pdu(tb_pP,next_waited_so,pdu_rx_info_p->payload_size - next_waited_so); if (trunc_pdu != NULL) { - ((rlc_am_rx_pdu_management_t *) (trunc_pdu->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_PENDING; /* Insert PDU Segment */ list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer); @@ -1317,7 +1316,9 @@ rlc_am_rx_list_reassemble_rlc_sdus( } /* 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)); } else { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 0d01d0b1ce..3a00946160 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -723,8 +723,10 @@ rlc_am_send_status_pdu( } } // end while on all PDU segments of sn_cursor else { - /* Go to next received PDU or PDU segment if sn_cursor is fully received */ - cursor_p = cursor_p->next; + /* Go to next received PDU or PDU segment with different SN */ + do { + cursor_p = cursor_p->next; + } while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn_cursor)); } /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ From 353334f69b963d3911afa0c68941c94c48899599 Mon Sep 17 00:00:00 2001 From: fnabet Date: Thu, 16 Mar 2017 16:45:44 +0100 Subject: [PATCH 33/36] RLC AM Rx PDU Segment changes --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 445 +++++++++++------- 1 file changed, 278 insertions(+), 167 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 048466a1a9..62e67b044b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -35,34 +35,72 @@ boolean_t rlc_am_rx_check_vr_reassemble( const protocol_ctxt_t* const ctxt_pP, const rlc_am_entity_t* const rlc_pP) { - mem_block_t* cursor_p = NULL; - cursor_p = rlc_pP->receiver_buffer.head; + mem_block_t* 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; if (cursor_p != NULL) { 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; + if (sn_ref != rlc_pP->vr_r) { + /* Case vrR has advanced from head : most likely case */ + reassemble = TRUE; - } - - /* 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)) { - 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; + /* 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; + } + } } - cursor_p = cursor_p->next; - if (cursor_p != NULL) { - pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - } - } - if ((cursor_p != NULL) && (pdu_info_p->sn == rlc_pP->vr_r)) { + /* 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)) { + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + 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)) { + 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 */ - 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; - AssertFatal(pdu_cursor_mgnt_p->all_segments_received == 0,"AM Rx Check Reassembly vr=%d should be partly received LCID=%d\n", + + 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 SNHead=vr=%d should be partly received LCID=%d\n", 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)) { 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( pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; } } - } - + } /*end sn_ref == rlc_pP->vr_r */ } return reassemble; } @@ -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* previous_cursor_p = NULL; mem_block_t* next_cursor_p = NULL; - boolean_t prev_segment_found = FALSE; - boolean_t next_segment_found = FALSE; - uint16_t so_start = 0; + uint16_t so_start_min = 0; uint16_t so_end = 0; 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; @@ -334,120 +369,73 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( return RLC_AM_DATA_PDU_STATUS_OK; } + /********************************************/ /* 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); + // Filter out SN duplicate if (pdu_cursor_mgnt_p->all_segments_received) { return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; } - // Handle the remaining case : some PDU Segments already received for the same SN - // Try to insert the PDU according to its SO and SO+datalength of stored ones - // First find the segment just before the pdu to insert - while ((cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { - if (pdu_rx_info_p->so < pdu_info_cursor_p->so) { - prev_segment_found = TRUE; - break; - } + // Try to Handle the most likely cases first + if (pdu_info_cursor_p->so == 0) { + /* 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; - cursor_p = cursor_p->next; - if (cursor_p != NULL) { - 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*/ - if (!prev_segment_found) { - if (pdu_info_previous_cursor_p->lsf == 0) { - prev_segment_found = TRUE; - next_segment_found = TRUE; // no more segment after the PDU - 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); - } - else - { - // the segment is duplicate - return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; - } - } - - - // Check that the Segment is not duplicate by scanning stored contiguous segments from previous_cursor_p - if ((previous_cursor_p != NULL) && (pdu_info_previous_cursor_p->sn == pdu_rx_info_p->sn)) { - - so_start = pdu_info_previous_cursor_p->so; - so_end = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - 1; - - pdu_info_cursor_p = pdu_info_previous_cursor_p; - cursor_p = previous_cursor_p->next; - rlc_am_pdu_info_t* pdu_info_cursor_next_p = NULL; - if (cursor_p != NULL) { - pdu_info_cursor_next_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - } - - while ((cursor_p != NULL) && (pdu_info_cursor_next_p->sn == pdu_rx_info_p->sn) - && (pdu_info_cursor_next_p->so == pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size)) { - so_end += pdu_info_cursor_next_p->payload_size; - pdu_info_cursor_p = pdu_info_cursor_next_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_next_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 so_end */ - if ((so_start <= so_start_segment) && (so_end_segment <= so_end)) { + // 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; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + so_end += pdu_info_cursor_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + 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; } - } - - - // Now found the segment which will be right after the pdu to insert - if (!next_segment_found) { - /* 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)) { - if (((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->segment_reassembled == RLC_AM_RX_PDU_SEGMENT_REASSEMBLED) { - pdu_info_previous_cursor_p = &((rlc_am_rx_pdu_management_t*)(previous_cursor_p->data))->pdu_info; - so_end = pdu_info_previous_cursor_p->so + 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) && - (((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; - cursor_p = cursor_p->next; - if (cursor_p != NULL) { - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; - } - } - } - } - - if (previous_cursor_p != NULL) { - cursor_p = previous_cursor_p->next; - } - else { - cursor_p = rlc_pP->receiver_buffer.head; - } + // Discard potential embedded segments in the received PDU segment + // The first one is discontigous 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 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 */ cursor_p = next_cursor_p; next_cursor_p = next_cursor_p->next; @@ -458,75 +446,196 @@ 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; } } - } + 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)) { + //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); } - } - // remove duplicate at the end - if (next_cursor_p != NULL) { - pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + // 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; - 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; + 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; + } } - } + 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), + " 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); - 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), - " AM RX PDU Segment Duplicate elimination error 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); - - /* Last step : Insertion */ - /* 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)) { - - 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) { - LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", - PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); - - if (previous_cursor_p != NULL) { - list2_insert_after_element(trunc_segment, previous_cursor_p, &rlc_pP->receiver_buffer); - } - else { - list2_insert_before_element(trunc_segment, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer); - } - - /* Free original PDU Segment */ - free_mem_block(tb_pP, __func__); + } // end pdu_info_cursor_p->so == 0 + else { + // Handle most likely case : PDU Segment without duplicate is inserted before first stored PDU segment + if (so_end_segment < pdu_info_cursor_p->so) { + 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; } - else { - return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + + // Handle duplicate case + if (so_start_segment < pdu_info_cursor_p->so) { + // First Case : only duplicate at the end + // 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) && + (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) { + 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; + } + } + + AssertFatal((so_start_segment <= so_end_segment) && + (so_end_segment <= pdu_rx_info_p->so + pdu_rx_info_p->payload_size - 1), + " AM RX PDU Segment Duplicate elimination at the end error FirstSO!=0 SOStart=%d OldSOEnd=%d newSOEnd =%d SN=%d\n", + 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); + } - } - else - { + 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); + + list2_insert_after_element(tb_pP, previous_cursor_p, &rlc_pP->receiver_buffer); + return RLC_AM_DATA_PDU_STATUS_OK; + } + + // Now look for contiguous segments to check whether the received segment is not fully duplicate + 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; + pdu_info_previous_cursor_p = pdu_info_cursor_p; + so_end += pdu_info_cursor_p->payload_size; + cursor_p = cursor_p->next; + if (cursor_p != NULL) { + 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; + } + + //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 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) && + (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) { + 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; + } + } + + 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), + " 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); + } + + } // end pdu_info_cursor_p->so != 0 + + + /* 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); + if (trunc_segment != NULL) { + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU SEGMENT] CREATE SEGMENT FROM SEGMENT OFFSET=%d DATA LENGTH=%d SN=%d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),so_start_segment - pdu_rx_info_p->so,so_end_segment - so_start_segment + 1,pdu_rx_info_p->sn); + 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); + list2_insert_after_element(trunc_segment, 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); + list2_insert_before_element(trunc_segment, rlc_pP->receiver_buffer.head, &rlc_pP->receiver_buffer); } + /* Free original PDU Segment */ + free_mem_block(tb_pP, __func__); + return RLC_AM_DATA_PDU_STATUS_OK; } + else { + return RLC_AM_DATA_PDU_STATUS_BUFFER_FULL; + } + } rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu( @@ -1316,10 +1425,12 @@ rlc_am_rx_list_reassemble_rlc_sdus( } /* Reset Management pointers */ - 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))) { + if (cursor_p != NULL) { 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 { return; From 3c7c61a46c58f11fc79112c291efbd021010490c Mon Sep 17 00:00:00 2001 From: hbilel Date: Tue, 28 Mar 2017 18:08:00 +0200 Subject: [PATCH 34/36] RLC AM fix specific reassembly issue --- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 37 +++++++++++++++++-- openair2/UTIL/LISTS/list2.c | 2 + 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 62e67b044b..7b0d74c5d9 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -796,6 +796,9 @@ rlc_am_rx_list_check_duplicate_insert_pdu( rlc_am_rx_pdu_status_t pdu_status = RLC_AM_DATA_PDU_STATUS_OK; // it is assumed this pdu is in rx window + /* Init Reassembly status */ + ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; + if (cursor_p == NULL) { LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[INSERT PDU] LINE %d RX PDU SN %04d (only inserted)\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), @@ -806,9 +809,6 @@ rlc_am_rx_list_check_duplicate_insert_pdu( } - /* Init Reassembly status */ - ((rlc_am_rx_pdu_management_t*)(tb_pP->data))->segment_reassembled = RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO; - if (pdu_rx_info_p->rf == 0) { // Case normal PDU received pdu_status = rlc_am_rx_list_handle_pdu(ctxt_pP,rlc_pP,tb_pP); } @@ -1396,6 +1396,7 @@ rlc_am_rx_mark_all_segments_received( } } //----------------------------------------------------------------------------- +//#define RLC_AM_DEBUG_REASSEMBLY void rlc_am_rx_list_reassemble_rlc_sdus( const protocol_ctxt_t* const ctxt_pP, @@ -1413,6 +1414,9 @@ rlc_am_rx_list_reassemble_rlc_sdus( rlc_am_rx_pdu_management_t* rlc_am_rx_pdu_management_p = ((rlc_am_rx_pdu_management_t*)(cursor_p->data)); pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; +#ifdef RLC_AM_DEBUG_REASSEMBLY + rlc_usn_t sn_reass_start = pdu_info_p->sn; +#endif /* Specific process for the first SN if all PDU segments had been reassembled but not freed */ if ((rlc_am_rx_pdu_management_p->all_segments_received > 0) && (pdu_info_p->rf != 0)) { @@ -1445,6 +1449,10 @@ rlc_am_rx_list_reassemble_rlc_sdus( cursor_p = list2_get_head(&rlc_pP->receiver_buffer); if (cursor_p == NULL) { +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif return; } @@ -1458,6 +1466,10 @@ rlc_am_rx_list_reassemble_rlc_sdus( cursor_p = cursor_p->next; if (cursor_p == NULL) { +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, Last is Segment, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif return; } @@ -1482,12 +1494,29 @@ rlc_am_rx_list_reassemble_rlc_sdus( PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP)); } +#endif +#ifdef RLC_AM_DEBUG_REASSEMBLY + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to ALL, vrR=%d vrMS=%d\n", + sn_reass_start,rlc_pP->vr_r,rlc_pP->vr_ms); #endif return; } - } while (((rlc_am_rx_pdu_management_p->pdu_info.sn == ((rlc_am_rx_old_pdu_management->pdu_info.sn + 1) & RLC_AM_SN_MASK)) && (rlc_am_rx_old_pdu_management->all_segments_received > 0)) + } while (((RLC_AM_DIFF_SN(rlc_am_rx_pdu_management_p->pdu_info.sn,rlc_am_rx_old_pdu_management->pdu_info.sn) < 2) && (rlc_am_rx_old_pdu_management->all_segments_received > 0)) || ((rlc_am_rx_pdu_management_p->pdu_info.sn == rlc_am_rx_old_pdu_management->pdu_info.sn) && (rlc_am_rx_pdu_management_p->segment_reassembled != RLC_AM_RX_PDU_SEGMENT_REASSEMBLE_NO))); + +#ifdef RLC_AM_DEBUG_REASSEMBLY + mem_block_t* cursor_head_p = list2_get_head(&rlc_pP->receiver_buffer); + if (cursor_head_p == NULL) { + return; + } + + rlc_am_pdu_info_t* pdu_info_head_p = &((rlc_am_rx_pdu_management_t*)(cursor_head_p->data))->pdu_info; + + LOG_D(RLC, "RLC AM REASSEMBLY from sn=%d to sn=%d, next_sn=%d head sn=%d vrR=%d vrMS=%d\n", + sn_reass_start,rlc_am_rx_old_pdu_management->pdu_info.sn,rlc_am_rx_pdu_management_p->pdu_info.sn,pdu_info_head_p->sn,rlc_pP->vr_r,rlc_pP->vr_ms); +#endif + } //----------------------------------------------------------------------------- mem_block_t * diff --git a/openair2/UTIL/LISTS/list2.c b/openair2/UTIL/LISTS/list2.c index abd9d2aacc..8daa19bfa4 100644 --- a/openair2/UTIL/LISTS/list2.c +++ b/openair2/UTIL/LISTS/list2.c @@ -233,6 +233,8 @@ list2_add_head (mem_block_t * elementP, list2_t * listP) // almost one element if (head == NULL) { + elementP->previous = NULL; + elementP->next = NULL; listP->head = elementP; listP->tail = elementP; } else { From bb4131b33d532356365e0dae7225002cd6b56671 Mon Sep 17 00:00:00 2001 From: hbilel Date: Tue, 28 Mar 2017 19:59:52 +0200 Subject: [PATCH 35/36] RLC AM add fixes --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 8 ++++++++ openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 4 ++-- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c | 5 ++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index 4cef19253a..fc31d6e8b6 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -1233,6 +1233,10 @@ mem_block_t * rlc_am_get_pdu_to_retransmit( { // TO DO : RLC Notification to RRC + ReEstablishment procedure tx_data_pdu_management->flags.max_retransmit = 1; + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RLC AM MAX RETX=%d] SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + tx_data_pdu_management->retx_count_next, + sn); } } else if (rlc_pP->nb_bytes_requested_by_mac >= 5) @@ -1273,6 +1277,10 @@ mem_block_t * rlc_am_get_pdu_to_retransmit( { // TO DO : RLC Notification to RRC + ReEstablishment procedure tx_data_pdu_management->flags.max_retransmit = 1; + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[RLC AM MAX RETX=%d] SN %04d\n", + PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP), + tx_data_pdu_management->retx_count_next, + sn); } } diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 7b0d74c5d9..33b86f7948 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -261,7 +261,7 @@ mem_block_t * create_new_segment_from_pdu( RLC_AM_PDU_SET_E(*pdu_segment_header_p); } /* SN */ - (*pdu_segment_header_p) |= (pdu_new_segment_info_p->sn >> 8) ; + (*pdu_segment_header_p) |= ((pdu_new_segment_info_p->sn >> 8) & 0x3); *(pdu_segment_header_p + 1) = (pdu_new_segment_info_p->sn & 0xFF); pdu_segment_header_p += 2; @@ -272,7 +272,7 @@ mem_block_t * create_new_segment_from_pdu( RLC_AM_PDU_SET_LSF(*pdu_segment_header_p); } /* Store SO bytes */ - * (pdu_segment_header_p ) = (pdu_new_segment_info_p->so >> 8) & 0xFF; + * (pdu_segment_header_p ) |= ((pdu_new_segment_info_p->so >> 8) & 0x7F); * (pdu_segment_header_p + 1) = pdu_new_segment_info_p->so & 0xFF; if (num_li) { diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index 3a00946160..b1f53586cb 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -378,7 +378,10 @@ rlc_am_receive_process_control_pdu( break; } } - sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; + if (prev_nack_sn != nack_sn) { + /* do not increment sn_cursor in case of several informations for the same nack_sn */ + sn_cursor = (sn_cursor + 1) & RLC_AM_SN_MASK; + } } } From 49006696ac4ef2af66de0b7fe2b6033b06c5ca51 Mon Sep 17 00:00:00 2001 From: hbilel Date: Wed, 29 Mar 2017 15:59:16 +0200 Subject: [PATCH 36/36] RLC AM add various fixes --- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c | 12 +++++++---- .../LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h | 2 +- openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c | 5 ++--- .../LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c | 2 +- .../LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c | 20 ++++++++++++++++++- .../RLC/AM_v9.3.0/rlc_am_status_report.c | 13 +++++++++--- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c index eda90edf9a..03fabf47b3 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am.c @@ -1253,14 +1253,16 @@ rlc_am_data_req ( l_rlc_p->next_sdu_index = (l_rlc_p->next_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; if (l_rlc_p->channel_id <3) { - LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d\n", + LOG_I(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ size %d Bytes, NB SDU %d current_sdu_index=%d next_sdu_index=%d conf %d mui %d vtA %d vtS %d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p), data_size, l_rlc_p->nb_sdu, l_rlc_p->current_sdu_index, l_rlc_p->next_sdu_index, conf, - mui); + mui, + l_rlc_p->vt_a, + l_rlc_p->vt_s); } } else { #if MESSAGE_CHART_GENERATOR @@ -1278,12 +1280,14 @@ rlc_am_data_req ( data_size, mui); #endif - LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ BUFFER FULL, NB SDU %d current_sdu_index=%d next_sdu_index=%d size_input_sdus_buffer=%d\n", + LOG_W(RLC, PROTOCOL_RLC_AM_CTXT_FMT" RLC_AM_DATA_REQ BUFFER FULL, NB SDU %d current_sdu_index=%d next_sdu_index=%d size_input_sdus_buffer=%d vtA=%d vtS=%d\n", PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,l_rlc_p), l_rlc_p->nb_sdu, l_rlc_p->current_sdu_index, l_rlc_p->next_sdu_index, - RLC_AM_SDU_CONTROL_BUFFER_SIZE); + RLC_AM_SDU_CONTROL_BUFFER_SIZE, + l_rlc_p->vt_a, + l_rlc_p->vt_s); LOG_W(RLC, " input_sdus[].mem_block=%p next input_sdus[].flags.segmented=%d\n", l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].mem_block, l_rlc_p->input_sdus[l_rlc_p->next_sdu_index].flags.segmented); l_rlc_p->stat_tx_pdcp_sdu_discarded += 1; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h index 10f310d5de..69429b84b8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_constants.h @@ -48,7 +48,7 @@ # define RLC_AM_SDU_DATA_BUFFER_SIZE 64*1024 /** Max number of incoming SDUs from upper layer that can be buffered in a RLC AM protocol instance. */ -# define RLC_AM_SDU_CONTROL_BUFFER_SIZE 128 +# define RLC_AM_SDU_CONTROL_BUFFER_SIZE 1024 /** Size of the retransmission buffer (number of PDUs). */ # define RLC_AM_PDU_RETRANSMISSION_BUFFER_SIZE RLC_AM_WINDOW_SIZE diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c index b41dea42f2..4b5c173d4b 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_in_sdu.c @@ -57,13 +57,12 @@ void rlc_am_free_in_sdu( memset(&rlcP->input_sdus[index_in_bufferP], 0, sizeof(rlc_am_tx_sdu_management_t)); rlcP->input_sdus[index_in_bufferP].flags.transmitted_successfully = 1; - // TODO : understand why. This should not happen + // case when either one SDU needs to be removed from segmentation or SDU buffer is full if (rlcP->current_sdu_index == index_in_bufferP) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; } - // TODO : this loop is useless as UL SDUs are transmitted and acknowledged in sequence - // even with PDCP UL SDU discard functionality + // wrapping and reset current_sdu_index to next_sdu_index when all transmitted SDUs have been acknowledged while ((rlcP->current_sdu_index != rlcP->next_sdu_index) && (rlcP->input_sdus[rlcP->current_sdu_index].flags.transmitted_successfully == 1)) { rlcP->current_sdu_index = (rlcP->current_sdu_index + 1) % RLC_AM_SDU_CONTROL_BUFFER_SIZE; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c index fc31d6e8b6..f80a46695d 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c @@ -95,7 +95,7 @@ boolean_t rlc_am_nack_pdu ( } // Check consistency - if ((so_startP < so_endP) && (so_endP < tx_data_pdu_buffer_p->payload_size)) { + if ((so_startP <= so_endP) && (so_endP < tx_data_pdu_buffer_p->payload_size)) { if (prev_nack_snP != snP) { /* New NACK_SN with SO */ /* check whether a new segment is to be placed in Retransmission Buffer, then increment vrReTx */ diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c index 33b86f7948..cad1a776a8 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c @@ -222,6 +222,7 @@ mem_block_t * create_new_segment_from_pdu( pdu_new_segment_info_p->p = pdu_rx_info_p->p; pdu_new_segment_info_p->rf = 1; pdu_new_segment_info_p->fi = (((fi_start ? 0: 1) << 1) | (fi_end ? 0: 1)); + pdu_new_segment_info_p->num_li = num_li; pdu_new_segment_info_p->e = (num_li ? 1: 0); pdu_new_segment_info_p->lsf = (lsf ? 1: 0); pdu_new_segment_info_p->so = pdu_rx_info_p->so + so_offset; @@ -380,6 +381,23 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( return RLC_AM_DATA_PDU_STATUS_AM_SEGMENT_DUPLICATE; } + // Try to catch a segment duplicate + next_cursor_p = cursor_p; + while ((next_cursor_p != NULL) && (pdu_info_cursor_p->sn == pdu_rx_info_p->sn)) { + if ((so_start_segment >= pdu_info_cursor_p->so) && (so_end_segment <= pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size - 1)) { + 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; + } + next_cursor_p = next_cursor_p->next; + if (next_cursor_p != NULL) { + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info; + } + } + + // Reset pdu_info_cursor_p because of the loop before + pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info; + // Try to Handle the most likely cases first if (pdu_info_cursor_p->so == 0) { @@ -425,7 +443,7 @@ rlc_am_rx_pdu_status_t rlc_am_rx_list_handle_pdu_segment( } /* 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)) { + if ((so_start_min <= so_start_segment) && (so_end_segment <= so_end - 1)) { 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; diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c index b1f53586cb..d33dc78e91 100644 --- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c +++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_status_report.c @@ -562,7 +562,7 @@ rlc_am_send_status_pdu( all_segments_received = ((rlc_am_rx_pdu_management_t*)(cursor_p->data))->all_segments_received; /* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */ - while ((sn_nack != sn_cursor) && (sn_nack != rlc_pP->vr_ms)) { + while ((sn_nack != sn_cursor) && (RLC_AM_DIFF_SN(sn_nack,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r))) { if (nb_bits_transmitted + RLC_AM_SN_BITS + (RLC_AM_PDU_E_BITS << 1) <= nb_bits_to_transmit) { /* Fill NACK_SN infos */ control_pdu_info.nack_list[control_pdu_info.num_nack].nack_sn = sn_nack; @@ -596,6 +596,10 @@ rlc_am_send_status_pdu( } } + if (sn_nack == rlc_pP->vr_ms) { + break; + } + /* Now process all Segments of sn_cursor if PDU not fully received */ if ((!status_report_completed) && (all_segments_received == 0) && (sn_cursor != rlc_pP->vr_ms)) { AssertFatal (sn_nack == sn_cursor, "RLC AM Tx Status PDU Data sn_nack=%d and sn_cursor=%d should be equal LcId=%d\n",sn_nack,sn_cursor, rlc_pP->channel_id); @@ -732,10 +736,13 @@ rlc_am_send_status_pdu( } while ((cursor_p != NULL) && (((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info.sn == sn_cursor)); } - /* Increment sn_nack except if sn_nack = vrMS and if current SN was not fully received */ - if (sn_nack != rlc_pP->vr_ms) { + /* Increment sn_nack except if sn_cursor = vrMS and if current SN was not fully received */ + if (RLC_AM_DIFF_SN(sn_cursor,rlc_pP->vr_r) < RLC_AM_DIFF_SN(rlc_pP->vr_ms,rlc_pP->vr_r)) { sn_nack = RLC_AM_NEXT_SN(sn_cursor); } + else { + sn_nack = rlc_pP->vr_ms; + } } // End main while NACK_SN