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; } }