Commit a0325027 authored by Cedric Roux's avatar Cedric Roux

Merge remote-tracking branch 'origin/bugfix-189-rlc-am-fixes' into develop_integration_w13

parents 2437d0fb 49006696
......@@ -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* ),
......
......@@ -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;
}
......
......@@ -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]));
......
......@@ -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);
......
......@@ -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]);
......
......@@ -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,
......
......@@ -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 ;
......
......@@ -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]);
......
......@@ -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,37 +1437,10 @@ 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-DCCH -> ULSCH, RLC SRB%d has %d bytes to "
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,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]]);
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]]);
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP,
......@@ -1460,51 +1450,26 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) {
ENB_FLAG_NO,
MBMS_FLAG_NO,
lcid,
buflen_remain,
(char *)&ulsch_buff[sdu_length_total]);
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]);
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);
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 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 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;
}
}
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 ;
......@@ -1513,6 +1478,7 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) {
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;
}
}
......@@ -1522,102 +1488,33 @@ for (lcid=DCCH; lcid < DTCH ; lcid++) {
//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;
else
{
/* avoid infinite loop ... */
is_lcid_processed = TRUE;
}
}
// 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,
/* 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,
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) {
lcid);
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;
is_lcid_processed = (is_lcid_processed) || (lcid_buffer_occupancy_new <= 0);
}
/*
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]]);
//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);
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;
}
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))
......@@ -1629,44 +1526,14 @@ if (UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] == LCID_NOT_EMPTY)
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;
UE_mac_inst[module_idP].scheduling_info.LCID_status[lcid] = LCID_EMPTY;
}
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,9 +2263,9 @@ 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);
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;
......
......@@ -43,61 +43,148 @@
#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;
}
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)
{
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 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);
}
} // 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 (
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) {
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));
}
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);
}
if (rlc_pP->sdu_buffer_occupancy == 0) {
header_overhead = 0;
} else {
header_overhead = 2;
}
#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,
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
......@@ -150,9 +237,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
#if defined(Rel14)
uint32_t PollRetransmit_tab[T_PollRetransmit_spare5]= {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,800,1000,2000,4000};
uint32_t am_t_Reordering_tab[32]= {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,1600};
......@@ -318,7 +405,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
......@@ -335,7 +422,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;
......@@ -346,140 +434,39 @@ 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) {
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);
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);
}
}
/*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
if (rlc_pP->first_retrans_pdu_sn >= 0) {
rlc_am_tx_data_pdu_management_t* tx_data_pdu_management;
// 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)) {
tx_data_pdu_management = &rlc_pP->pdu_retrans_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)) {
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",
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->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 += 1;
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;
rlc_pP->nb_bytes_requested_by_mac,rlc_pP->t_status_prohibit.ms_time_out,(rlc_pP->status_requested & RLC_AM_STATUS_TRIGGERED_DELAYED));
}
// 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->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;
// THEN TRY TO SEND RETRANS PDU
if ((rlc_pP->retrans_num_bytes_to_retransmit) && (rlc_pP->nb_bytes_requested_by_mac > 2)) {
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));
}
/* 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);
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);
}
if (pdu_retx != NULL) {
list_add_tail_eurecom (pdu_retx, &rlc_pP->pdus_to_mac_layer);
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);
......@@ -490,29 +477,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;
......@@ -554,7 +518,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;
......@@ -578,18 +543,38 @@ 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;
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;
......@@ -610,30 +595,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;
int found_pdu = 0;
rlc_sn_t found_pdu_sn = 0; // avoid warning
(void)found_pdu_sn; /* avoid gcc warning "set but not used" */
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;
}
}
}
/* 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
......@@ -678,11 +647,23 @@ 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 (
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;
......@@ -720,7 +701,10 @@ rlc_am_mac_data_request (
data_req.data.nb_elements);
}
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
......@@ -1267,14 +1251,19 @@ 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;
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",
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 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
mui = ((struct rlc_am_data_req*) (sdu_pP->data))->mui;
......@@ -1291,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;
......
......@@ -267,23 +267,32 @@ 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 struct mac_data_req rlc_am_mac_data_request (const protocol_ctxt_t* const ctxtP,void * const rlc_pP)
/*! \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,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.
......@@ -293,6 +302,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.
......
......@@ -48,14 +48,17 @@
# 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_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
/** 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
......@@ -69,6 +72,99 @@
# 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
#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_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))
#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_PDU_FI_BITS 2
#define RLC_AM_PDU_POLL_BITS 1
#define RLC_AM_PDU_RF_BITS 1
#define RLC_AM_LI_BITS 11
#define RLC_AM_LI_MASK 0x7FF
/* 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_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
#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
/* 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 */
#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))
#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
......@@ -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;
......@@ -69,17 +68,14 @@ 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. */
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. */
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. */
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. */
//---------------------------------------------------------------------
......@@ -137,7 +133,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,14 +172,14 @@ 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. */
list_t segmentation_pdu_list; /*!< \brief List of "freshly" segmented PDUs. */
boolean_t status_requested; /*!< \brief Status requested by peer. */
frame_t last_frame_status_indication; /*!< \brief The last frame number a MAC status indication has been received by RLC. */
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. */
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
//-----------------------------
......
......@@ -41,21 +41,28 @@ 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;
// 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;
}
// 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;
......@@ -100,3 +107,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 % 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;
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);
}
}
}
......@@ -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
......@@ -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
......@@ -74,12 +74,12 @@ 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;
rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1
rlc_pP->initialized = TRUE;
}
......@@ -128,12 +128,13 @@ 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;
rlc_pP->last_absolute_subframe_status_indication = 0xFFFFFFFF; // any value > 1
rlc_pP->initialized = TRUE;
......@@ -172,16 +173,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 % 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;
}
}
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));
......
......@@ -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(
}
}
if (free_rlc_pdu) {
free_mem_block(tb_pP, __func__);
}
}
......@@ -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
......@@ -31,6 +31,7 @@
#include "LAYER2/MAC/extern.h"
#include "UTIL/LOG/log.h"
//-----------------------------------------------------------------------------
signed int
rlc_am_get_data_pdu_infos(
......@@ -47,7 +48,8 @@ rlc_am_get_data_pdu_infos(
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 +119,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 +177,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,34 +314,30 @@ 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",
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,
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;
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;
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",
......@@ -394,12 +382,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,39 +401,114 @@ 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 = 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...
}
//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;
}
}
}
}
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;
free_mem_block (tb_pP, __func__);
LOG_D(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[PROCESS RX PDU] PDU OUT OF RX WINDOW, DISCARDED, STATUS REQUESTED:\n",
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, 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 */
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));
rlc_pP->status_requested = 1;
/* 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 {
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) {
/* 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);
}
}
......@@ -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
// ...
......@@ -50,55 +51,124 @@ 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;
int pdu_sdu_index;
int sdu_index;
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;
boolean_t retx_count_increment = FALSE;
sdu_size_t pdu_data_to_retx = 0;
if (mb_p != NULL) {
rlc_pP->num_nack_sn += 1;
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->pdu_retrans_buffer[snP].last_nack_time != ctxt_pP->frame) {
rlc_pP->pdu_retrans_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;
}
if (!((so_startP == 0) && (so_endP == 0x7FFF))) {
rlc_pP->num_nack_so += 1;
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;
}
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;
// 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;
}
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->first_retrans_pdu_sn);
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;
rlc_pP->pdu_retrans_buffer[snP].flags.retransmit = 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;
}
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;
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 ++;
}
}
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;
......@@ -122,12 +192,15 @@ 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),
snP);
//assert(2==3);
status = FALSE;
}
return status;
}
//-----------------------------------------------------------------------------
void rlc_am_ack_pdu (
......@@ -135,160 +208,456 @@ 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;
int pdu_sdu_index;
int sdu_index;
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->pdu_retrans_buffer[snP].flags.retransmit = 0;
tx_data_pdu_buffer->flags.retransmit = 0;
if ((rlc_pP->pdu_retrans_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->pdu_retrans_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->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;
tx_data_pdu_buffer->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 (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 --;
}
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];
assert(sdu_index >= 0);
assert(sdu_index < RLC_AM_SDU_CONTROL_BUFFER_SIZE);
rlc_pP->input_sdus[sdu_index].nb_pdus_ack += 1;
} 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),
snP);
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);
if (mb_p != NULL) {
free_mem_block(mb_p, __func__);
tx_data_pdu_buffer->mem_block = NULL;
}
}
tx_data_pdu_buffer->flags.ack = 1;
tx_data_pdu_buffer->flags.transmitted = 0;
tx_data_pdu_buffer->flags.retransmit = 0;
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_copy (
const protocol_ctxt_t* const ctxt_pP,
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 % 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_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);
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;
// 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->pdu_retrans_buffer[snP].flags.ack = 1;
return mb_copy;
}
if (snP == rlc_pP->vt_a) {
//rlc_pP->pdu_retrans_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));
//-----------------------------------------------------------------------------
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;
}
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;
/* 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];
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))));
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;
}
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));
*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 = (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;
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);
/* 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;
}
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;
/* 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;
*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 */
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 */
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;
sdu_index = 1;
/* Loop on all original LIs */
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 ++;
}
if (rlc_pP->pdu_retrans_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;
if (retx_so_start == data_size)
{
/* Set FI Start if retx_so_start = cumulated data size */
fi_start = TRUE;
/* 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);
pdu_original_header_p += li_jump_offset;
li_bit_offset ^= 0x4;
li_jump_offset ^= 0x3;
data_size += sdu_size;
}
else
{
/* 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)
{
/* in all other cases set fi_start to FALSE if it SO Start is not 0 */
fi_start = FALSE;
}
} 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);
/* 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;
}
} 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),
snP);
if (mb_p != NULL) {
free_mem_block(mb_p, __func__);
rlc_pP->pdu_retrans_buffer[snP].mem_block = NULL;
/* Now look for the end if it was not set previously */
if (*payload_sizeP == 0)
{
sdu_segment_index ++;
while ((sdu_index < pdu_mngt->nb_sdus) && (data_size < retx_so_stop + 1))
{
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;
}
sdus_segment_size[sdu_segment_index] = sdu_size;
sdu_index ++;
sdu_segment_index ++;
}
if (rlc_pP->pdu_retrans_buffer[snP].flags.ack > 0) {
if (snP == rlc_pP->vt_a) {
//rlc_pP->pdu_retrans_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));
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;
if (data_size > retx_so_stop + 1)
{
sdus_segment_size[sdu_segment_index - 1] = retx_so_stop - (data_size - sdu_size) + 1;
}
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));
/* Set number of LIs in the segment */
num_LIs_pdu_segment = sdu_segment_index - 1;
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);
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)))
{
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) + (*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 */
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 ++;
}
}
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_copy (
const protocol_ctxt_t* const ctxt_pP,
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;
if (mb_original_p != NULL) {
num_LIs_pdu_segment = sdu_segment_index - 1;
}
rlc_am_tx_data_pdu_management_t *pdu_mngt = &rlc_pP->pdu_retrans_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);
/* update retx_so_stop */
retx_so_stop = retx_so_start + (*payload_sizeP) - 1;
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;
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);
pdu_mngt->flags.retransmit = 0;
/* 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;
}
rlc_am_pdu_polling(ctxt_pP, rlc_pP, pdu_p, pdu_mngt->payload_size);
return mb_copy;
} else {
return NULL;
/* 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 Tx 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 = (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);
/* 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;
pdu_mngt->nack_so_start = 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];
}
/* 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);
/* 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;
/* 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 ++;
}
}
}
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;
}
#if 0
//-----------------------------------------------------------------------------
mem_block_t* rlc_am_retransmit_get_subsegment(
const protocol_ctxt_t* const ctxt_pP,
......@@ -340,7 +709,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__);
......@@ -353,10 +722,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),
......@@ -366,8 +735,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,
......@@ -627,7 +996,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
......@@ -635,7 +1004,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);
}*/
//---------------------------------------------------------------
......@@ -692,16 +1061,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),
......@@ -728,15 +1097,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",
......@@ -744,8 +1113,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);
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",
......@@ -755,6 +1122,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,
......@@ -763,6 +1131,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:",
......@@ -778,25 +1147,26 @@ void rlc_am_tx_buffer_display (
}
while (rlc_pP->vt_s != sn) {
if (rlc_pP->pdu_retrans_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->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 (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->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, 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->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 (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; i<rlc_pP->pdu_retrans_buffer[sn].num_holes; i++) {
for (i=0; i<tx_data_pdu_buffer_p->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", tx_data_pdu_buffer_p->hole_so_start[i], tx_data_pdu_buffer_p->hole_so_stop[i]);
}
}
......@@ -808,6 +1178,132 @@ 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;
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)
{
/* 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;
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);
}
}
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,
......@@ -824,13 +1320,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);
......@@ -843,12 +1339,13 @@ 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->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
//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;
......@@ -877,12 +1374,11 @@ 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->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;
//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;
......@@ -896,3 +1392,4 @@ void rlc_am_retransmit_any_pdu(
}
}
}
#endif
......@@ -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.
......
......@@ -31,7 +31,812 @@
#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 = 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;
/* 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;
}
}
}
/* 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 */
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) {
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;
}
}
} /*end sn_ref == rlc_pP->vr_r */
}
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 = (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
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->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;
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) & 0x3);
*(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) & 0x7F);
* (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 = rlc_pP->receiver_buffer.head;
mem_block_t* previous_cursor_p = NULL;
mem_block_t* next_cursor_p = NULL;
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;
/*****************************************************/
// 1) Find previous cursor to the PDU to insert
/*****************************************************/
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
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;
} while (cursor_p != NULL);
/*****************************************************/
// 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)) {
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,
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 */
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;
}
/********************************************/
/* Now handle case cursor->sn = received SN */
/********************************************/
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;
}
// 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) {
/* 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;
}
// 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 - 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;
}
// Discard potential embedded segments in the received PDU segment
// The first one is discontigous
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;
//Remove duplicate at the begining
if (so_start_segment < pdu_info_previous_cursor_p->so) {
so_start_segment = pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size;
}
else if (so_start_segment < pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size){
so_start_segment += (pdu_info_previous_cursor_p->so + pdu_info_previous_cursor_p->payload_size - so_start_segment);
}
// Now remove duplicate at the end, only valid if cursor_p SN has the same received SN
if (cursor_p != NULL) {
pdu_info_cursor_p = &((rlc_am_rx_pdu_management_t*)(next_cursor_p->data))->pdu_info;
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
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;
}
// 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 {
// 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) {
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__);
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(
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 = rlc_pP->receiver_buffer.head;
mem_block_t* previous_cursor_p = NULL;
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
/*****************************************************/
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
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;
} while (cursor_p != NULL);
/*****************************************************/
// 2) Insert PDU by removing byte duplicate if required
/*****************************************************/
// 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)) {
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);
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;
}
// 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;
}
}
}
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);
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 {
/* 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) {
/* Insert PDU Segment */
list2_insert_after_element(trunc_pdu, previous_cursor_p, &rlc_pP->receiver_buffer);
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 */
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
/* 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),
__LINE__,
pdu_rx_info_p->sn);
list2_add_head(tb_pP, &rlc_pP->receiver_buffer);
return pdu_status;
}
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
//-----------------------------------------------------------------------------
......@@ -49,6 +854,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) {
......@@ -479,6 +1288,8 @@ rlc_am_rx_list_insert_pdu(
pdu_info_p->sn);
return -1;
}
#endif
//-----------------------------------------------------------------------------
void
rlc_am_rx_check_all_byte_segments(
......@@ -519,8 +1330,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;
}
......@@ -549,13 +1362,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;
}
}
......@@ -599,6 +1414,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,
......@@ -606,6 +1422,7 @@ rlc_am_rx_list_reassemble_rlc_sdus(
{
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);
......@@ -614,20 +1431,79 @@ 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)) {
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));
/* 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;
}
}
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);
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;
}
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;
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 = 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;
}
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;
}
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) {
......@@ -637,11 +1513,28 @@ rlc_am_rx_list_reassemble_rlc_sdus(
}
#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_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;
}
} 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_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 *
......
......@@ -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.
......
......@@ -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,49 +69,59 @@ void rlc_am_pdu_polling (
// - start t-PollRetransmit;
// - else:
// - restart t-PollRetransmit;
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;
rlc_pP->poll_sn = (rlc_pP->vt_s -1) & RLC_AM_SN_MASK;
// vt_s shall have been updated before in case of new transmission
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 {
pdu_pP->b1 = pdu_pP->b1 & 0xDF;
// 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);
}
}
//-----------------------------------------------------------------------------
......@@ -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",
......@@ -210,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));
......@@ -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,24 +525,28 @@ 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->retx_count = 0;
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);
rlc_pP->retrans_num_pdus += 1;
rlc_pP->retrans_num_bytes += pdu_mngt_p->header_and_payload_size;
//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);
}
......
......@@ -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).
......
......@@ -19,6 +19,7 @@
* contact@openairinterface.org
*/
#if 0
#define RLC_AM_MODULE 1
#define RLC_AM_SEGMENT_HOLES_C 1
//-----------------------------------------------------------------------------
......@@ -32,7 +33,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 +44,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 +61,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 +80,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 +162,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 +176,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 +187,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 +215,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 +249,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 +294,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 +313,7 @@ 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);
}
#endif
......@@ -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
......@@ -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_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;
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,11 +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);
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;
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
......@@ -308,64 +312,119 @@ 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) {
rlc_pP->num_nack_so = 0;
rlc_pP->num_nack_sn = 0;
/* 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) {
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;
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) {
if (sn_cursor == rlc_pP->poll_sn) {
rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
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 % 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);
}
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 {
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;
}
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 {
/*specific case when the sender did not have enough TBS to fill all SOStart SOEnd for this NACK_SN */
break;
}
} else {
}
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;
}
}
}
} 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 {
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))) {
rlc_am_stop_and_reset_timer_poll_retransmit(ctxt_pP, rlc_pP);
rlc_pP->poll_sn = RLC_SN_UNDEFINED;
}
//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;
/* 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);
}
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;
}
*first_byte_ppP = (uint8_t*)((uint64_t)*first_byte_ppP + initial_pdu_size - *tb_size_in_bytes_pP);
......@@ -449,6 +508,357 @@ 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 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;
#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) && ((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;
/* 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
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;
/* First fill NACK_SN with each missing PDU between current sn_nack and sn_cursor */
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;
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_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),
__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;
#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;
}
}
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);
/* 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) {
/* Init loop flags */
/* 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) {
/* 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__,
sn_cursor,
0,
pdu_info_cursor_p->so - 1);
#endif
waited_so = pdu_info_cursor_p->so + pdu_info_cursor_p->payload_size;
}
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)) {
/* PDU segment is for the same SN*/
/* Check lsf */
segment_loop_end = (pdu_info_cursor_p->lsf == 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 - 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__,
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;
}
/* 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;
}
} //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) {
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 */
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;
}
} // end while on all PDU segments of sn_cursor
else {
/* 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_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
/* 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 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){
control_pdu_info.ack_sn = sn_nack;
}
} 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",
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,11 +880,12 @@ 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;
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;
......@@ -757,3 +1168,5 @@ end_push_nack:
rlc_pP->stat_tx_control_bytes += pdu_size;
}
#endif
......@@ -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;
......@@ -107,15 +110,17 @@ 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. */
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 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;
......@@ -228,14 +233,48 @@ 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;
/** @} */
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
......
......@@ -77,10 +77,41 @@ 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);
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) {
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 ((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
{
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 +150,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 +169,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
......
......@@ -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,56 @@ 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;
// NOT VERY SURE ABOUT THAT, THINK ABOUT IT
rlc_pP->vr_ms = (pdu_info->sn + 1) & RLC_AM_SN_MASK;
AssertFatal (cursor != NULL, "RLC AM TReordering Expiry Rx PDU list empty LcId=%d\n", rlc_pP->channel_id);
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;
/* 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;
}
}
/* Now find a SN for which either no PDU is received or partially received */
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;
} while (cursor != NULL);
if (cursor != NULL) {
pdu_info = &((rlc_am_rx_pdu_management_t*)(cursor->data))->pdu_info;
}
}
/* 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 (rlc_am_sn_gt_vr_ms(ctxt_pP, rlc_pP, rlc_pP->vr_h)) {
/* 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;
}
}
}
......
......@@ -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;
}
}
......@@ -110,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);
......
......@@ -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);
}
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_bytes += (rlc_p->tx_header_min_length_in_bytes + max_li_overhead);
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;
......@@ -520,9 +510,19 @@ 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)
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;
......@@ -544,11 +544,14 @@ 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);
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;
}
}
data_req.rlc_info.rlc_protocol_state = l_rlc_p->protocol_state;
......
......@@ -188,13 +188,21 @@ 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 struct mac_data_req rlc_um_mac_data_request (const protocol_ctxt_t* const ctxt_pP, rlc_um_entity_t * const rlc_pP)
/*! \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,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)
......@@ -205,6 +213,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.
......
......@@ -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
//-----------------------------------------------------------------------------
......
......@@ -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
//----------------------------------------------------------
......
......@@ -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,enb_flagP);
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,enb_flagP);
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));
......@@ -397,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;
......@@ -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;
}
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment