Merge branch 'develop'
This commit is contained in:
@@ -73,7 +73,9 @@
|
||||
#ifdef UESIM_EXPANSION
|
||||
#define MAX_MOBILES_PER_ENB 256
|
||||
#define MAX_MOBILES_PER_ENB_NB_IoT 256
|
||||
#define MAX_MOBILES_PER_GNB 256
|
||||
#define MAX_eNB 2
|
||||
#define MAX_gNB 2
|
||||
#else
|
||||
#ifdef LARGE_SCALE
|
||||
#define MAX_MOBILES_PER_ENB 128
|
||||
|
||||
@@ -76,3 +76,6 @@ MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, NasDlDataInd
|
||||
|
||||
// eNB: realtime -> RRC messages
|
||||
MESSAGE_DEF(RRC_SUBFRAME_PROCESS, MESSAGE_PRIORITY_MED, RrcSubframeProcess, rrc_subframe_process)
|
||||
|
||||
// eNB: RLC -> RRC messages
|
||||
MESSAGE_DEF(RLC_SDU_INDICATION, MESSAGE_PRIORITY_MED, RlcSduIndication, rlc_sdu_indication)
|
||||
|
||||
@@ -87,6 +87,8 @@
|
||||
|
||||
#define RRC_SUBFRAME_PROCESS(mSGpTR) (mSGpTR)->ittiMsg.rrc_subframe_process
|
||||
|
||||
#define RLC_SDU_INDICATION(mSGpTR) (mSGpTR)->ittiMsg.rlc_sdu_indication
|
||||
|
||||
//-------------------------------------------------------------------------------------------//
|
||||
typedef struct RrcStateInd_s {
|
||||
Rrc_State_t state;
|
||||
@@ -429,4 +431,12 @@ typedef struct rrc_subframe_process_s {
|
||||
int CC_id;
|
||||
} RrcSubframeProcess;
|
||||
|
||||
// eNB: RLC -> RRC messages
|
||||
typedef struct rlc_sdu_indication_s {
|
||||
int rnti;
|
||||
int is_successful;
|
||||
int srb_id;
|
||||
int message_id;
|
||||
} RlcSduIndication;
|
||||
|
||||
#endif /* RRC_MESSAGES_TYPES_H_ */
|
||||
|
||||
@@ -290,7 +290,7 @@ Protocol__FlexUlCqiReport * copy_ul_cqi_report(Protocol__FlexUlCqiReport * origi
|
||||
full_ul_report->has_sfn_sn = original->has_sfn_sn;
|
||||
full_ul_report->n_cqi_meas = original->n_cqi_meas;
|
||||
|
||||
Protocol__FlexUlCqi **ul_report;
|
||||
Protocol__FlexUlCqi **ul_report=NULL;
|
||||
ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas);
|
||||
if(ul_report == NULL)
|
||||
goto error;
|
||||
@@ -348,7 +348,7 @@ Protocol__FlexDlCqiReport * copy_dl_cqi_report(Protocol__FlexDlCqiReport * origi
|
||||
dl_report->has_sfn_sn = original->has_sfn_sn;
|
||||
dl_report->n_csi_report = original->n_csi_report;
|
||||
|
||||
Protocol__FlexDlCsi **csi_reports;
|
||||
Protocol__FlexDlCsi **csi_reports=NULL;
|
||||
csi_reports = malloc(sizeof(Protocol__FlexDlCsi *) * dl_report->n_csi_report);
|
||||
if (csi_reports == NULL)
|
||||
goto error;
|
||||
@@ -383,7 +383,7 @@ Protocol__FlexPagingBufferReport * copy_paging_buffer_report(Protocol__FlexPagin
|
||||
protocol__flex_paging_buffer_report__init(copy);
|
||||
copy->n_paging_info = original->n_paging_info;
|
||||
|
||||
Protocol__FlexPagingInfo **p_info;
|
||||
Protocol__FlexPagingInfo **p_info=NULL;
|
||||
p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * copy->n_paging_info);
|
||||
if (p_info == NULL)
|
||||
goto error;
|
||||
|
||||
@@ -128,18 +128,18 @@
|
||||
#define GNB_CONFIG_STRING_RARESPONSEWINDOW "ra_ResponseWindow"
|
||||
#define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSBPR "ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR"
|
||||
#define GNB_CONFIG_STRING_SSBPERRACHOCCASIONANDCBPREAMBLESPERSSB "ssb_perRACH_OccasionAndCB_PreamblesPerSSB"
|
||||
#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER "ra_ContentionResolutionTimer"
|
||||
#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB "rsrp_ThresholdSSB"
|
||||
#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR "prach_RootSequenceIndex_PR"
|
||||
#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX "prach_RootSequenceIndex"
|
||||
#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING "msg1_SubcarrierSpacing"
|
||||
#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG "restrictedSetConfig"
|
||||
#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST "puschTimeDomainAllocationList"
|
||||
#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE "msg3_DeltaPreamble"
|
||||
#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT "p0_NominalWithGrant"
|
||||
#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING "pucchGroupHopping"
|
||||
#define GNB_CONFIG_STRING_HOPPINGID "hoppingId"
|
||||
#define GNB_CONFIG_STRING_P0NOMINAL "p0_nominal"
|
||||
#define GNB_CONFIG_STRING_RACONTENTIONRESOLUTIONTIMER "ra_ContentionResolutionTimer"
|
||||
#define GNB_CONFIG_STRING_RSRPTHRESHOLDSSB "rsrp_ThresholdSSB"
|
||||
#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEXPR "prach_RootSequenceIndex_PR"
|
||||
#define GNB_CONFIG_STRING_PRACHROOTSEQUENCEINDEX "prach_RootSequenceIndex"
|
||||
#define GNB_CONFIG_STRING_MSG1SUBCARRIERSPACING "msg1_SubcarrierSpacing"
|
||||
#define GNB_CONFIG_STRING_RESTRICTEDSETCONFIG "restrictedSetConfig"
|
||||
#define GNB_CONFIG_STRING_PUSCHTIMEDOMAINALLOCATIONLIST "puschTimeDomainAllocationList"
|
||||
#define GNB_CONFIG_STRING_MSG3DELTAPREABMLE "msg3_DeltaPreamble"
|
||||
#define GNB_CONFIG_STRING_P0NOMINALWITHGRANT "p0_NominalWithGrant"
|
||||
#define GNB_CONFIG_STRING_PUCCHGROUPHOPPING "pucchGroupHopping"
|
||||
#define GNB_CONFIG_STRING_HOPPINGID "hoppingId"
|
||||
#define GNB_CONFIG_STRING_P0NOMINAL "p0_nominal"
|
||||
#define GNB_CONFIG_STRING_INITIALULBWPK2_0 "initialULBWPk2_0"
|
||||
#define GNB_CONFIG_STRING_INITIALULBWPMAPPINGTYPE_0 "initialULBWPmappingType_0"
|
||||
#define GNB_CONFIG_STRING_INITIALULBWPSTARTSYMBOLANDLENGTH_0 "initialULBWPstartSymbolAndLength_0"
|
||||
|
||||
@@ -978,8 +978,6 @@ void NRRCConfig(void) {
|
||||
paramlist_def_t RUParamList = {CONFIG_STRING_RU_LIST,NULL,0};
|
||||
paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
|
||||
|
||||
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
|
||||
|
||||
/* get global parameters, defined outside any section in the config file */
|
||||
|
||||
LOG_I(GNB_APP, "Getting GNBSParams\n");
|
||||
|
||||
@@ -2240,7 +2240,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
|
||||
uint8_t first_ue_total[MAX_NUM_CCs][20];
|
||||
uint8_t first_ue_id[MAX_NUM_CCs][20];
|
||||
uint8_t ul_inactivity_num[MAX_NUM_CCs];
|
||||
uint8_t ul_inactivity_id[MAX_NUM_CCs][20];
|
||||
uint8_t ul_inactivity_id[MAX_NUM_CCs][20]={0};
|
||||
// LTE_DL_FRAME_PARMS *frame_parms;
|
||||
uint8_t ulsch_ue_max_num[MAX_NUM_CCs];
|
||||
uint16_t saved_ulsch_dci[MAX_NUM_CCs];
|
||||
|
||||
@@ -714,7 +714,7 @@ schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9;
|
||||
|
||||
rlc_status =
|
||||
mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP,
|
||||
mac_rlc_status_ind(module_idP, 0xfffd, frameP, subframeP,
|
||||
module_idP, ENB_FLAG_YES, MBMS_FLAG_YES,
|
||||
cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
//MTCH,
|
||||
@@ -771,7 +771,7 @@ schedule_MBMS_NFAPI(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0xfffd, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
TBS - header_len_mcch - header_len_msi - sdu_length_total - header_len_mtch,
|
||||
(char *)
|
||||
&mch_buffer[sdu_length_total]
|
||||
@@ -1553,7 +1553,7 @@ schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
mbms_rab_id = cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9;
|
||||
|
||||
rlc_status =
|
||||
mac_rlc_status_ind(module_idP, 0/*0xfffd*/, frameP, subframeP,
|
||||
mac_rlc_status_ind(module_idP, 0xfffd, frameP, subframeP,
|
||||
module_idP, ENB_FLAG_YES, MBMS_FLAG_YES,
|
||||
cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
//MTCH,
|
||||
@@ -1576,7 +1576,7 @@ schedule_MBMS(module_id_t module_idP, uint8_t CC_id, frame_t frameP,
|
||||
TBS - header_len_mcch - header_len_msi -
|
||||
sdu_length_total - header_len_mtch, header_len_mtch, rlc_status.bytes_in_buffer);
|
||||
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
sdu_lengths[num_sdus] = mac_rlc_data_req(module_idP, 0xfffd, module_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_YES,cc->mbms_SessionList[0]->list.array[0]->logicalChannelIdentity_r9,
|
||||
TBS - header_len_mcch - header_len_msi - sdu_length_total - header_len_mtch,
|
||||
(char *)
|
||||
&mch_buffer[sdu_length_total]
|
||||
|
||||
@@ -180,7 +180,7 @@ rx_sdu(const module_id_t enb_mod_idP,
|
||||
UE_template_ptr->scheduled_ul_bytes = 0;
|
||||
}
|
||||
} else { // sduP == NULL => error
|
||||
LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x\n",
|
||||
LOG_W(MAC, "[eNB %d][PUSCH %d] CC_id %d %d.%d ULSCH in error in round %d, ul_cqi %d, UE_id %d, RNTI %x (len %d)\n",
|
||||
enb_mod_idP,
|
||||
harq_pid,
|
||||
CC_idP,
|
||||
@@ -189,7 +189,8 @@ rx_sdu(const module_id_t enb_mod_idP,
|
||||
UE_scheduling_control->round_UL[CC_idP][harq_pid],
|
||||
ul_cqi,
|
||||
UE_id,
|
||||
current_rnti);
|
||||
current_rnti,
|
||||
sdu_lenP);
|
||||
|
||||
if (ul_cqi > 200) { // too high energy pattern
|
||||
UE_scheduling_control->pusch_snr[CC_idP] = ul_cqi;
|
||||
|
||||
@@ -1972,6 +1972,10 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
subframe, ENB_FLAG_NO,
|
||||
lcid);
|
||||
lcid_buffer_occupancy_new = lcid_buffer_occupancy_old;
|
||||
#if 0
|
||||
/* TODO: those assert crash the L2 simulator with the new RLC.
|
||||
* Are they necessary?
|
||||
*/
|
||||
AssertFatal(lcid_buffer_occupancy_new ==
|
||||
UE_mac_inst[module_idP].
|
||||
scheduling_info.LCID_buffer_remain[lcid],
|
||||
@@ -1990,6 +1994,7 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
scheduling_info.BSR_bytes[UE_mac_inst[module_idP].
|
||||
scheduling_info.LCGID
|
||||
[lcid]]);
|
||||
#endif
|
||||
|
||||
//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
|
||||
@@ -2085,18 +2090,10 @@ ue_get_sdu(module_id_t module_idP, int CC_id, frame_t frameP,
|
||||
}
|
||||
|
||||
//Update Buffer remain and BSR bytes after transmission
|
||||
AssertFatal(lcid_buffer_occupancy_new <=
|
||||
lcid_buffer_occupancy_old,
|
||||
"MAC UE Tx error : Buffer Occupancy After Tx=%d greater than before=%d BO! for LCID=%d RLC PDU nb=%d Frame %d Subrame %d\n",
|
||||
lcid_buffer_occupancy_new,
|
||||
lcid_buffer_occupancy_old, lcid,
|
||||
lcid_rlc_pdu_count, frameP, subframe);
|
||||
UE_mac_inst[module_idP].scheduling_info.
|
||||
LCID_buffer_remain[lcid] = lcid_buffer_occupancy_new;
|
||||
UE_mac_inst[module_idP].
|
||||
scheduling_info.BSR_bytes[UE_mac_inst[module_idP].
|
||||
scheduling_info.LCGID[lcid]] +=
|
||||
(lcid_buffer_occupancy_new - lcid_buffer_occupancy_old);
|
||||
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);
|
||||
if (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.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)
|
||||
|
||||
@@ -166,6 +166,11 @@ void nr_extract_dci_info(NR_UE_MAC_INST_t *mac,
|
||||
nr_dci_pdu_rel15_t *nr_pdci_info_extracted);
|
||||
|
||||
|
||||
uint8_t
|
||||
nr_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) ;
|
||||
|
||||
int set_tdd_config_nr_ue(fapi_nr_config_request_t *cfg, int mu,
|
||||
int nrofDownlinkSlots, int nrofDownlinkSymbols,
|
||||
int nrofUplinkSlots, int nrofUplinkSymbols);
|
||||
|
||||
@@ -467,7 +467,6 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
|
||||
uint32_t number_of_search_space_per_slot=UINT_MAX;
|
||||
uint32_t first_symbol_index=UINT_MAX;
|
||||
uint32_t search_space_duration; // element of search space
|
||||
uint32_t coreset_duration; // element of coreset
|
||||
// 38.213 table 10.1-1
|
||||
|
||||
/// MUX PATTERN 1
|
||||
@@ -603,8 +602,8 @@ int8_t nr_ue_decode_mib(module_id_t module_id,
|
||||
}
|
||||
|
||||
AssertFatal(number_of_search_space_per_slot!=UINT_MAX,"");
|
||||
coreset_duration = num_symbols * number_of_search_space_per_slot;
|
||||
/*
|
||||
uint32_t coreset_duration = num_symbols * number_of_search_space_per_slot;
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[0] = table_38213_10_1_1_c2[0];
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[1] = table_38213_10_1_1_c2[1];
|
||||
mac->type0_pdcch_dci_config.number_of_candidates[2] = table_38213_10_1_1_c2[2]; // CCE aggregation level = 4
|
||||
|
||||
@@ -51,7 +51,6 @@ extern RAN_CONTEXT_t RC;
|
||||
extern void mac_top_init_gNB(void);
|
||||
extern uint8_t nfapi_mode;
|
||||
|
||||
|
||||
void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigCommon_t *scc) {
|
||||
|
||||
nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[Mod_idP]->config[0];
|
||||
@@ -283,7 +282,6 @@ void config_common(int Mod_idP, int pdsch_AntennaPorts, NR_ServingCellConfigComm
|
||||
else LOG_I(PHY,"TDD has been properly configurated\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// PDCCH-ConfigCommon
|
||||
cfg->pdcch_config.controlResourceSetZero.value = scc->downlinkConfigCommon->initialDownlinkBWP->pdcch_ConfigCommon->choice.setup->controlResourceSetZero;
|
||||
|
||||
@@ -61,6 +61,8 @@
|
||||
|
||||
uint16_t nr_pdcch_order_table[6] = { 31, 31, 511, 2047, 2047, 8191 };
|
||||
|
||||
uint8_t nr_slots_per_frame[5] = {10, 20, 40, 80, 160};
|
||||
|
||||
void clear_nr_nfapi_information(gNB_MAC_INST * gNB,
|
||||
int CC_idP,
|
||||
frame_t frameP,
|
||||
@@ -299,6 +301,67 @@ void copy_nr_ulreq(module_id_t module_idP, frame_t frameP, sub_frame_t slotP)
|
||||
}
|
||||
*/
|
||||
|
||||
void nr_schedule_pucch(int Mod_idP,
|
||||
int UE_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP) {
|
||||
|
||||
uint16_t O_uci;
|
||||
uint16_t O_ack;
|
||||
uint8_t SR_flag = 0; // no SR in PUCCH implemented for now
|
||||
NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
AssertFatal(UE_list->active[UE_id] >=0,"Cannot find UE_id %d is not active\n",UE_id);
|
||||
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
|
||||
int bwp_id=1;
|
||||
NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[Mod_idP]->UL_tti_req[0];
|
||||
|
||||
NR_sched_pucch *curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
NR_sched_pucch *temp_pucch;
|
||||
int release_pucch = 0;
|
||||
|
||||
if (curr_pucch != NULL) {
|
||||
if ((frameP == curr_pucch->frame) && (slotP == curr_pucch->ul_slot)) {
|
||||
UL_tti_req->SFN = frameP;
|
||||
UL_tti_req->Slot = slotP;
|
||||
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUCCH_PDU_TYPE;
|
||||
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pucch_pdu_t);
|
||||
nfapi_nr_pucch_pdu_t *pucch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pucch_pdu;
|
||||
memset(pucch_pdu,0,sizeof(nfapi_nr_pucch_pdu_t));
|
||||
UL_tti_req->n_pdus+=1;
|
||||
O_ack = curr_pucch->dai_c;
|
||||
O_uci = O_ack; // for now we are just sending acknacks in pucch
|
||||
|
||||
nr_configure_pucch(pucch_pdu,
|
||||
scc,
|
||||
ubwp,
|
||||
curr_pucch->resource_indicator,
|
||||
O_uci,
|
||||
O_ack,
|
||||
SR_flag);
|
||||
|
||||
release_pucch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (release_pucch) {
|
||||
temp_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch->next_sched_pucch;
|
||||
free(temp_pucch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot){
|
||||
|
||||
if((bitmap>>slot)&0x01)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
frame_t frame_rxP,
|
||||
sub_frame_t slot_rxP,
|
||||
@@ -314,6 +377,7 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
NR_UE_list_t *UE_list = &gNB->UE_list;
|
||||
UE_sched_ctrl_t *ue_sched_ctl = &UE_list->UE_sched_ctrl[UE_id];
|
||||
NR_COMMON_channels_t *cc = gNB->common_channels;
|
||||
NR_sched_pucch *pucch_sched = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
|
||||
|
||||
start_meas(&RC.nrmac[module_idP]->eNB_scheduler);
|
||||
VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER,VCD_FUNCTION_IN);
|
||||
@@ -327,27 +391,27 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
// Check if there are downlink symbols in the slot,
|
||||
if (is_nr_DL_slot(cc->ServingCellConfigCommon,slot_txP)) {
|
||||
|
||||
memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
//mbsfn_status[CC_id] = 0;
|
||||
memset(RC.nrmac[module_idP]->cce_list[1][0],0,MAX_NUM_CCE*sizeof(int));
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
//mbsfn_status[CC_id] = 0;
|
||||
|
||||
// clear vrb_maps
|
||||
memset(cc[CC_id].vrb_map, 0, 100);
|
||||
memset(cc[CC_id].vrb_map_UL, 0, 100);
|
||||
// clear vrb_maps
|
||||
memset(cc[CC_id].vrb_map, 0, 100);
|
||||
memset(cc[CC_id].vrb_map_UL, 0, 100);
|
||||
|
||||
clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP);
|
||||
}
|
||||
clear_nr_nfapi_information(RC.nrmac[module_idP], CC_id, frame_txP, slot_txP);
|
||||
}
|
||||
|
||||
// refresh UE list based on UEs dropped by PHY in previous subframe
|
||||
/*
|
||||
for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
|
||||
if (UE_list->active[i]) {
|
||||
// refresh UE list based on UEs dropped by PHY in previous subframe
|
||||
/*
|
||||
for (i = 0; i < MAX_MOBILES_PER_GNB; i++) {
|
||||
if (UE_list->active[i]) {
|
||||
|
||||
nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];
|
||||
nfapi_nr_config_request_t *cfg = &RC.nrmac[module_idP]->config[CC_id];
|
||||
|
||||
|
||||
rnti = 0;//UE_RNTI(module_idP, i);
|
||||
CC_id = 0;//UE_PCCID(module_idP, i);
|
||||
rnti = 0;//UE_RNTI(module_idP, i);
|
||||
CC_id = 0;//UE_PCCID(module_idP, i);
|
||||
|
||||
} //END if (UE_list->active[i])
|
||||
} //END for (i = 0; i < MAX_MOBILES_PER_GNB; i++)
|
||||
@@ -374,16 +438,16 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
|
||||
|
||||
// Phytest scheduling
|
||||
if (get_softmodem_params()->phy_test && slot_txP==1){
|
||||
nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP,NULL);
|
||||
// resetting ta flag
|
||||
nr_schedule_uss_dlsch_phytest(module_idP, frame_txP, slot_txP, pucch_sched, NULL);
|
||||
// resetting ta flag
|
||||
gNB->ta_len = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
// Allocate CCEs for good after scheduling is done
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
|
||||
allocate_CCEs(module_idP, CC_id, subframeP, 0);
|
||||
*/
|
||||
/*
|
||||
// Allocate CCEs for good after scheduling is done
|
||||
for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++)
|
||||
allocate_CCEs(module_idP, CC_id, subframeP, 0);
|
||||
*/
|
||||
|
||||
} //is_nr_DL_slot
|
||||
|
||||
|
||||
@@ -249,9 +249,14 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int configure_fapi_dl_pdu(int Mod_idP,
|
||||
int *CCEIndex,
|
||||
nfapi_nr_dl_tti_request_body_t *dl_req,
|
||||
NR_sched_pucch *pucch_sched,
|
||||
uint8_t *mcsIndex,
|
||||
uint16_t *rbSize,
|
||||
uint16_t *rbStart) {
|
||||
@@ -260,13 +265,12 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
gNB_MAC_INST *nr_mac = RC.nrmac[Mod_idP];
|
||||
NR_COMMON_channels_t *cc = nr_mac->common_channels;
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
|
||||
|
||||
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdcch_pdu;
|
||||
nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdsch_pdu;
|
||||
int TBS, bwp_id = 1, UE_id = 0;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
|
||||
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
|
||||
AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
|
||||
"downlinkBWP_ToAddModList has %d BWP!\n",
|
||||
@@ -351,10 +355,10 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
dci_pdu_rel15[0].ndi = 1;
|
||||
dci_pdu_rel15[0].rv = 0;
|
||||
dci_pdu_rel15[0].harq_pid = 0;
|
||||
dci_pdu_rel15[0].dai = 2;
|
||||
dci_pdu_rel15[0].dai = (pucch_sched->dai_c-1)&3;
|
||||
dci_pdu_rel15[0].tpc = 2;
|
||||
dci_pdu_rel15[0].pucch_resource_indicator = 7;
|
||||
dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = 7;
|
||||
dci_pdu_rel15[0].pucch_resource_indicator = pucch_sched->resource_indicator;
|
||||
dci_pdu_rel15[0].pdsch_to_harq_feedback_timing_indicator = pucch_sched->timing_indicator;
|
||||
|
||||
LOG_D(MAC, "[gNB scheduler phytest] DCI type 1 payload: freq_alloc %d (%d,%d,%d), time_alloc %d, vrb to prb %d, mcs %d tb_scaling %d ndi %d rv %d\n",
|
||||
dci_pdu_rel15[0].frequency_domain_assignment,
|
||||
@@ -413,7 +417,6 @@ int configure_fapi_dl_pdu(int Mod_idP,
|
||||
pdsch_pdu_rel15->NrOfCodewords,
|
||||
pdsch_pdu_rel15->mcsIndex[0],
|
||||
TBS);
|
||||
|
||||
return TBS; //Return TBS in bytes
|
||||
}
|
||||
|
||||
@@ -491,6 +494,7 @@ void configure_fapi_dl_Tx(module_id_t Mod_idP,
|
||||
void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
NR_sched_pucch *pucch_sched,
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *dlsch_config){
|
||||
|
||||
LOG_D(MAC, "In nr_schedule_uss_dlsch_phytest \n");
|
||||
@@ -537,7 +541,8 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
|
||||
TBS_bytes = configure_fapi_dl_pdu(module_idP,
|
||||
CCEIndices,
|
||||
dl_req,
|
||||
dl_req,
|
||||
pucch_sched,
|
||||
dlsch_config!=NULL ? dlsch_config->mcsIndex : NULL,
|
||||
dlsch_config!=NULL ? &dlsch_config->rbSize : NULL,
|
||||
dlsch_config!=NULL ? &dlsch_config->rbStart : NULL);
|
||||
@@ -598,13 +603,11 @@ void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} //if (IS_SOFTMODEM_NOS1)
|
||||
else {
|
||||
|
||||
//When the --NOS1 option is not enabled, DLSCH transmissions with random data
|
||||
//occur every time that the current function is called (dlsch phytest mode)
|
||||
|
||||
LOG_D(MAC,"Configuring DL_TX in %d.%d\n", frameP, slotP);
|
||||
|
||||
// fill dlsch_buffer with random data
|
||||
@@ -718,12 +721,12 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
|
||||
UL_tti_req->SFN = frameP;
|
||||
UL_tti_req->Slot = slotP;
|
||||
UL_tti_req->n_pdus = 1;
|
||||
UL_tti_req->pdus_list[0].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
|
||||
UL_tti_req->pdus_list[0].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
|
||||
nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[0].pusch_pdu;
|
||||
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PUSCH_PDU_TYPE;
|
||||
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
|
||||
nfapi_nr_pusch_pdu_t *pusch_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].pusch_pdu;
|
||||
memset(pusch_pdu,0,sizeof(nfapi_nr_pusch_pdu_t));
|
||||
|
||||
UL_tti_req->n_pdus+=1;
|
||||
|
||||
LOG_D(MAC, "Scheduling UE specific PUSCH\n");
|
||||
//UL_tti_req = &nr_mac->UL_tti_req[CC_id];
|
||||
/*
|
||||
@@ -846,7 +849,6 @@ void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
1, // ue-specific,
|
||||
scc,
|
||||
bwp);
|
||||
|
||||
|
||||
dci_pdu_rel15_t dci_pdu_rel15[MAX_DCI_CORESET];
|
||||
|
||||
|
||||
@@ -507,7 +507,7 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
|
||||
AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList!=NULL,"searchPsacesToAddModList is null\n");
|
||||
AssertFatal(bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count>0,
|
||||
"searchPsacesToAddModList is empty\n");
|
||||
NR_SearchSpace_t *ss;
|
||||
NR_SearchSpace_t *ss=NULL;
|
||||
int found=0;
|
||||
int target_ss = NR_SearchSpace__searchSpaceType_PR_common;
|
||||
if (ss_type == 1) {
|
||||
@@ -545,12 +545,196 @@ void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
|
||||
}
|
||||
|
||||
|
||||
// This function configures pucch pdu fapi structure
|
||||
void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_Uplink_t *bwp,
|
||||
uint8_t pucch_resource,
|
||||
uint16_t O_uci,
|
||||
uint16_t O_ack,
|
||||
uint8_t SR_flag) {
|
||||
|
||||
NR_PUCCH_Config_t *pucch_Config;
|
||||
NR_PUCCH_Resource_t *pucchres;
|
||||
NR_PUCCH_ResourceSet_t *pucchresset;
|
||||
NR_PUCCH_FormatConfig_t *pucchfmt;
|
||||
NR_PUCCH_ResourceId_t *resource_id = NULL;
|
||||
|
||||
long *id0 = NULL;
|
||||
int n_list, n_set;
|
||||
uint16_t N2,N3;
|
||||
int res_found = 0;
|
||||
|
||||
pucch_pdu->bit_len_harq = O_ack;
|
||||
|
||||
if (bwp) { // This is not the InitialBWP
|
||||
|
||||
NR_PUSCH_Config_t *pusch_Config = bwp->bwp_Dedicated->pusch_Config->choice.setup;
|
||||
long *pusch_id = pusch_Config->dataScramblingIdentityPUSCH;
|
||||
|
||||
if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA != NULL)
|
||||
id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup->transformPrecodingDisabled->scramblingID0;
|
||||
if (pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB != NULL)
|
||||
id0 = pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup->transformPrecodingDisabled->scramblingID0;
|
||||
|
||||
// hop flags and hopping id are valid for any BWP
|
||||
switch (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping){
|
||||
case 0 :
|
||||
// if neither, both disabled
|
||||
pucch_pdu->group_hop_flag = 0;
|
||||
pucch_pdu->sequence_hop_flag = 0;
|
||||
break;
|
||||
case 1 :
|
||||
// if enable, group enabled
|
||||
pucch_pdu->group_hop_flag = 1;
|
||||
pucch_pdu->sequence_hop_flag = 0;
|
||||
break;
|
||||
case 2 :
|
||||
// if disable, sequence disabled
|
||||
pucch_pdu->group_hop_flag = 0;
|
||||
pucch_pdu->sequence_hop_flag = 1;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(1==0,"Group hopping flag %ld undefined (0,1,2) \n", bwp->bwp_Common->pucch_ConfigCommon->choice.setup->pucch_GroupHopping);
|
||||
}
|
||||
|
||||
if (bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId != NULL)
|
||||
pucch_pdu->hopping_id = *bwp->bwp_Common->pucch_ConfigCommon->choice.setup->hoppingId;
|
||||
else
|
||||
pucch_pdu->hopping_id = *scc->physCellId;
|
||||
|
||||
pucch_pdu->bwp_size = NRRIV2BW(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
|
||||
pucch_pdu->bwp_start = NRRIV2PRBOFFSET(bwp->bwp_Common->genericParameters.locationAndBandwidth,275);
|
||||
pucch_pdu->subcarrier_spacing = bwp->bwp_Common->genericParameters.subcarrierSpacing;
|
||||
pucch_pdu->cyclic_prefix = (bwp->bwp_Common->genericParameters.cyclicPrefix==NULL) ? 0 : *bwp->bwp_Common->genericParameters.cyclicPrefix;
|
||||
|
||||
pucch_Config = bwp->bwp_Dedicated->pucch_Config->choice.setup;
|
||||
|
||||
AssertFatal(pucch_Config->resourceSetToAddModList!=NULL,
|
||||
"PUCCH resourceSetToAddModList is null\n");
|
||||
|
||||
n_set = pucch_Config->resourceSetToAddModList->list.count;
|
||||
AssertFatal(n_set>0,"PUCCH resourceSetToAddModList is empty\n");
|
||||
|
||||
N2 = 2;
|
||||
// procedure to select pucch resource id from resource sets according to
|
||||
// number of uci bits and pucch resource indicator pucch_resource
|
||||
// ( see table 9.2.3.2 in 38.213)
|
||||
for (int i=0; i<n_set; i++) {
|
||||
pucchresset = pucch_Config->resourceSetToAddModList->list.array[i];
|
||||
n_list = pucchresset->resourceList.list.count;
|
||||
if (pucchresset->pucch_ResourceSetId == 0 && O_uci<3) {
|
||||
if (pucch_resource < n_list)
|
||||
resource_id = pucchresset->resourceList.list.array[pucch_resource];
|
||||
else
|
||||
AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
|
||||
}
|
||||
else {
|
||||
N3 = pucchresset->maxPayloadMinus1!= NULL ? *pucchresset->maxPayloadMinus1 : 1706;
|
||||
if (N2<O_uci && N3>O_uci) {
|
||||
if (pucch_resource < n_list)
|
||||
resource_id = pucchresset->resourceList.list.array[pucch_resource];
|
||||
else
|
||||
AssertFatal(1==0,"Couldn't fine pucch resource indicator %d in PUCCH resource set %d for %d UCI bits",pucch_resource,i,O_uci);
|
||||
}
|
||||
else N2 = N3;
|
||||
}
|
||||
}
|
||||
|
||||
AssertFatal(resource_id!=NULL,"Couldn-t find any matching PUCCH resource in the PUCCH resource sets");
|
||||
|
||||
AssertFatal(pucch_Config->resourceToAddModList!=NULL,
|
||||
"PUCCH resourceToAddModList is null\n");
|
||||
|
||||
n_list = pucch_Config->resourceToAddModList->list.count;
|
||||
AssertFatal(n_list>0,"PUCCH resourceToAddModList is empty\n");
|
||||
|
||||
// going through the list of PUCCH resources to find the one indexed by resource_id
|
||||
for (int i=0; i<n_list; i++) {
|
||||
pucchres = pucch_Config->resourceToAddModList->list.array[i];
|
||||
if (pucchres->pucch_ResourceId == *resource_id) {
|
||||
res_found = 1;
|
||||
pucch_pdu->prb_start = pucchres->startingPRB;
|
||||
// FIXME why there is only one frequency hopping flag
|
||||
// what about inter slot frequency hopping?
|
||||
pucch_pdu->freq_hop_flag = pucchres->intraSlotFrequencyHopping!= NULL ? 1 : 0;
|
||||
pucch_pdu->second_hop_prb = pucchres->secondHopPRB!= NULL ? *pucchres->secondHopPRB : 0;
|
||||
switch(pucchres->format.present) {
|
||||
case NR_PUCCH_Resource__format_PR_format0 :
|
||||
pucch_pdu->format_type = 0;
|
||||
pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format0->initialCyclicShift;
|
||||
pucch_pdu->nr_of_symbols = pucchres->format.choice.format0->nrofSymbols;
|
||||
pucch_pdu->start_symbol_index = pucchres->format.choice.format0->startingSymbolIndex;
|
||||
pucch_pdu->sr_flag = SR_flag;
|
||||
break;
|
||||
case NR_PUCCH_Resource__format_PR_format1 :
|
||||
pucch_pdu->format_type = 1;
|
||||
pucch_pdu->initial_cyclic_shift = pucchres->format.choice.format1->initialCyclicShift;
|
||||
pucch_pdu->nr_of_symbols = pucchres->format.choice.format1->nrofSymbols;
|
||||
pucch_pdu->start_symbol_index = pucchres->format.choice.format1->startingSymbolIndex;
|
||||
pucch_pdu->time_domain_occ_idx = pucchres->format.choice.format1->timeDomainOCC;
|
||||
pucch_pdu->sr_flag = SR_flag;
|
||||
break;
|
||||
case NR_PUCCH_Resource__format_PR_format2 :
|
||||
pucch_pdu->format_type = 2;
|
||||
pucch_pdu->nr_of_symbols = pucchres->format.choice.format2->nrofSymbols;
|
||||
pucch_pdu->start_symbol_index = pucchres->format.choice.format2->startingSymbolIndex;
|
||||
pucch_pdu->prb_size = pucchres->format.choice.format2->nrofPRBs;
|
||||
pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
|
||||
pucch_pdu->dmrs_scrambling_id = id0!= NULL ? *id0 : *scc->physCellId;
|
||||
break;
|
||||
case NR_PUCCH_Resource__format_PR_format3 :
|
||||
pucch_pdu->format_type = 3;
|
||||
pucch_pdu->nr_of_symbols = pucchres->format.choice.format3->nrofSymbols;
|
||||
pucch_pdu->start_symbol_index = pucchres->format.choice.format3->startingSymbolIndex;
|
||||
pucch_pdu->prb_size = pucchres->format.choice.format3->nrofPRBs;
|
||||
pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
|
||||
if (pucch_Config->format3 == NULL) {
|
||||
pucch_pdu->pi_2bpsk = 0;
|
||||
pucch_pdu->add_dmrs_flag = 0;
|
||||
}
|
||||
else {
|
||||
pucchfmt = pucch_Config->format3->choice.setup;
|
||||
pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0;
|
||||
pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case NR_PUCCH_Resource__format_PR_format4 :
|
||||
pucch_pdu->format_type = 4;
|
||||
pucch_pdu->nr_of_symbols = pucchres->format.choice.format4->nrofSymbols;
|
||||
pucch_pdu->start_symbol_index = pucchres->format.choice.format4->startingSymbolIndex;
|
||||
pucch_pdu->pre_dft_occ_len = pucchres->format.choice.format4->occ_Length;
|
||||
pucch_pdu->pre_dft_occ_idx = pucchres->format.choice.format4->occ_Index;
|
||||
pucch_pdu->data_scrambling_id = pusch_id!= NULL ? *pusch_id : *scc->physCellId;
|
||||
if (pucch_Config->format3 == NULL) {
|
||||
pucch_pdu->pi_2bpsk = 0;
|
||||
pucch_pdu->add_dmrs_flag = 0;
|
||||
}
|
||||
else {
|
||||
pucchfmt = pucch_Config->format3->choice.setup;
|
||||
pucch_pdu->pi_2bpsk = pucchfmt->pi2BPSK!= NULL ? 1 : 0;
|
||||
pucch_pdu->add_dmrs_flag = pucchfmt->additionalDMRS!= NULL ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
AssertFatal(1==0,"Undefined PUCCH format \n");
|
||||
}
|
||||
}
|
||||
}
|
||||
AssertFatal(res_found==1,"No PUCCH resource found corresponding to id %ld\n",*resource_id);
|
||||
}
|
||||
else { // this is for InitialBWP
|
||||
AssertFatal(1==0,"Fill in InitialBWP PUCCH configuration\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats,
|
||||
int *rnti_types
|
||||
) {
|
||||
int *rnti_types) {
|
||||
|
||||
uint16_t N_RB = pdcch_pdu_rel15->BWPSize;
|
||||
uint8_t fsize=0, pos=0;
|
||||
@@ -1003,6 +1187,171 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void get_pdsch_to_harq_feedback(int Mod_idP,
|
||||
int UE_id,
|
||||
NR_SearchSpace__searchSpaceType_PR ss_type,
|
||||
uint8_t *pdsch_to_harq_feedback) {
|
||||
|
||||
int bwp_id=1;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = UE_list->secondaryCellGroup[UE_id];
|
||||
NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[bwp_id-1];
|
||||
|
||||
NR_SearchSpace_t *ss;
|
||||
|
||||
// common search type uses DCI format 1_0
|
||||
if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) {
|
||||
for (int i=0; i<8; i++)
|
||||
pdsch_to_harq_feedback[i] = i+1;
|
||||
}
|
||||
else {
|
||||
// searching for a ue specific search space
|
||||
int found=0;
|
||||
|
||||
for (int i=0;i<bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;i++) {
|
||||
ss=bwp->bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.array[i];
|
||||
AssertFatal(ss->controlResourceSetId != NULL,"ss->controlResourceSetId is null\n");
|
||||
AssertFatal(ss->searchSpaceType != NULL,"ss->searchSpaceType is null\n");
|
||||
if (ss->searchSpaceType->present == ss_type) {
|
||||
found=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AssertFatal(found==1,"Couldn't find a ue specific searchspace\n");
|
||||
if (ss->searchSpaceType->choice.ue_Specific->dci_Formats == NR_SearchSpace__searchSpaceType__ue_Specific__dci_Formats_formats0_0_And_1_0) {
|
||||
for (int i=0; i<8; i++)
|
||||
pdsch_to_harq_feedback[i] = i+1;
|
||||
}
|
||||
else {
|
||||
if(ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK != NULL)
|
||||
pdsch_to_harq_feedback = (uint8_t *)ubwp->bwp_Dedicated->pucch_Config->choice.setup->dl_DataToUL_ACK;
|
||||
else
|
||||
AssertFatal(found==1,"There is no allocated dl_DataToUL_ACK for pdsch to harq feedback\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// function to update pucch scheduling parameters in UE list when a USS DL is scheduled
|
||||
void nr_update_pucch_scheduling(int Mod_idP,
|
||||
int UE_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
int slots_per_tdd,
|
||||
NR_sched_pucch *sched_pucch) {
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = RC.nrmac[Mod_idP]->common_channels->ServingCellConfigCommon;
|
||||
NR_UE_list_t *UE_list = &RC.nrmac[Mod_idP]->UE_list;
|
||||
int first_ul_slot_tdd,k;
|
||||
NR_sched_pucch *curr_pucch;
|
||||
uint8_t pdsch_to_harq_feedback[8];
|
||||
int found = 0;
|
||||
int i = 0;
|
||||
int nr_ulmix_slots = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSlots;
|
||||
if (scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofUplinkSymbols!=0)
|
||||
nr_ulmix_slots++;
|
||||
|
||||
// this is hardcoded for now as ue specific
|
||||
NR_SearchSpace__searchSpaceType_PR ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
|
||||
get_pdsch_to_harq_feedback(Mod_idP,UE_id,ss_type,pdsch_to_harq_feedback);
|
||||
|
||||
// if the list of pucch to be scheduled is empty
|
||||
if (UE_list->UE_sched_ctrl[UE_id].sched_pucch == NULL) {
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->next_sched_pucch = NULL;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
if ( nr_ulmix_slots > 0 ) {
|
||||
// first pucch occasion in first UL or MIXED slot
|
||||
first_ul_slot_tdd = scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots;
|
||||
for (k=0; k<nr_ulmix_slots; k++) { // for each possible UL or mixed slot
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values
|
||||
if (pdsch_to_harq_feedback[i]==(first_ul_slot_tdd+k)-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) break;
|
||||
}
|
||||
if (found == 1) {
|
||||
// computing slot in which pucch is scheduled
|
||||
sched_pucch->ul_slot = first_ul_slot_tdd + k + (slotP - (slotP % slots_per_tdd));
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"No Uplink slot available in accordance to allowed timing indicator\n");
|
||||
}
|
||||
else
|
||||
AssertFatal(1==0,"No Uplink Slots in this Frame\n");
|
||||
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
|
||||
}
|
||||
else { // to be tested
|
||||
curr_pucch = UE_list->UE_sched_ctrl[UE_id].sched_pucch;
|
||||
if (curr_pucch->dai_c<MAX_ACK_BITS) { // we are scheduling at most MAX_UCI_BITS harq-ack in the same pucch
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values for current pucch
|
||||
if (pdsch_to_harq_feedback[i]==(curr_pucch->ul_slot % slots_per_tdd)-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) { // scheduling this harq-ack in current pucch
|
||||
sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1 + sched_pucch->dai_c;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
}
|
||||
if (curr_pucch->dai_c==MAX_ACK_BITS || found == 0) { // if current pucch is full or no timing indicator allowed
|
||||
// look for pucch occasions in other UL of mixed slots
|
||||
for (k=scc->tdd_UL_DL_ConfigurationCommon->pattern1.nrofDownlinkSlots; k<slots_per_tdd; k++) { // for each possible UL or mixed slot
|
||||
if (k!=(curr_pucch->ul_slot % slots_per_tdd)) { // skip current scheduled slot (already checked)
|
||||
i = 0;
|
||||
while (i<8 && found == 0) { // look if timing indicator is among allowed values
|
||||
if (pdsch_to_harq_feedback[i]==k-(slotP % slots_per_tdd))
|
||||
found = 1;
|
||||
if (found == 0) i++;
|
||||
}
|
||||
if (found == 1) {
|
||||
if (k<(curr_pucch->ul_slot % slots_per_tdd)) { // we need to add a pucch occasion before current pucch
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd));
|
||||
sched_pucch->next_sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
UE_list->UE_sched_ctrl[UE_id].sched_pucch = sched_pucch;
|
||||
}
|
||||
else {
|
||||
while (curr_pucch->next_sched_pucch != NULL && k!=(curr_pucch->ul_slot % slots_per_tdd))
|
||||
curr_pucch = curr_pucch->next_sched_pucch;
|
||||
if (curr_pucch == NULL) { // creating a new item in the list
|
||||
sched_pucch->frame = frameP;
|
||||
sched_pucch->next_sched_pucch = NULL;
|
||||
sched_pucch->dai_c = 1;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
sched_pucch->resource_indicator = 0; // in phytest with only 1 UE we are using just the 1st resource
|
||||
sched_pucch->ul_slot = k + (slotP - (slotP % slots_per_tdd));
|
||||
curr_pucch->next_sched_pucch = (NR_sched_pucch*) malloc(sizeof(NR_sched_pucch));
|
||||
curr_pucch->next_sched_pucch = sched_pucch;
|
||||
}
|
||||
else {
|
||||
if (curr_pucch->dai_c==MAX_ACK_BITS)
|
||||
found = 0; // if pucch at index k is already full we have to find a new one in a following occasion
|
||||
else { // scheduling this harq-ack in current pucch
|
||||
sched_pucch = curr_pucch;
|
||||
sched_pucch->dai_c = 1 + sched_pucch->dai_c;
|
||||
sched_pucch->timing_indicator = pdsch_to_harq_feedback[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*void fill_nfapi_coresets_and_searchspaces(NR_CellGroupConfig_t *cg,
|
||||
nfapi_nr_coreset_t *coreset,
|
||||
nfapi_nr_search_space_t *search_space) {
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "PHY/defs_gNB.h"
|
||||
#include "NR_TAG-Id.h"
|
||||
|
||||
#define MAX_ACK_BITS 2 //only format 0 is available for now
|
||||
|
||||
void set_cset_offset(uint16_t);
|
||||
|
||||
void mac_top_init_gNB(void);
|
||||
@@ -83,6 +85,7 @@ void nr_schedule_css_dlsch_phytest(module_id_t module_idP,
|
||||
int configure_fapi_dl_pdu(int Mod_id,
|
||||
int *CCEIndeces,
|
||||
nfapi_nr_dl_tti_request_body_t *dl_req,
|
||||
NR_sched_pucch *pucch_sched,
|
||||
uint8_t *mcsIndex,
|
||||
uint16_t *rbSize,
|
||||
uint16_t *rbStart);
|
||||
@@ -100,11 +103,24 @@ void configure_fapi_dl_Tx(module_id_t Mod_idP,
|
||||
void nr_schedule_uss_dlsch_phytest(module_id_t module_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
NR_sched_pucch *pucch_sched,
|
||||
nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdsch_config);
|
||||
|
||||
void nr_schedule_uss_ulsch_phytest(int Mod_idP,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP);
|
||||
|
||||
void nr_update_pucch_scheduling(int Mod_idP,
|
||||
int UE_id,
|
||||
frame_t frameP,
|
||||
sub_frame_t slotP,
|
||||
int slots_per_tdd,
|
||||
NR_sched_pucch *sched_pucch);
|
||||
|
||||
void get_pdsch_to_harq_feedback(int Mod_idP,
|
||||
int UE_id,
|
||||
NR_SearchSpace__searchSpaceType_PR ss_type,
|
||||
uint8_t *pdsch_to_harq_feedback);
|
||||
|
||||
void nr_configure_css_dci_initial(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
|
||||
nr_scs_e scs_common,
|
||||
@@ -124,7 +140,13 @@ int nr_is_dci_opportunity(nfapi_nr_search_space_t search_space,
|
||||
uint16_t slot,
|
||||
nfapi_nr_config_request_scf_t cfg);
|
||||
*/
|
||||
|
||||
void nr_configure_pucch(nfapi_nr_pucch_pdu_t* pucch_pdu,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_Uplink_t *bwp,
|
||||
uint8_t pucch_resource,
|
||||
uint16_t O_uci,
|
||||
uint16_t O_ack,
|
||||
uint8_t SR_flag);
|
||||
void nr_configure_pdcch(nfapi_nr_dl_tti_pdcch_pdu_rel15_t* pdcch_pdu,
|
||||
int ss_type,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
@@ -134,7 +156,6 @@ void fill_dci_pdu_rel15(nfapi_nr_dl_tti_pdcch_pdu_rel15_t *pdcch_pdu_rel15,
|
||||
dci_pdu_rel15_t *dci_pdu_rel15,
|
||||
int *dci_formats,
|
||||
int *rnti_types);
|
||||
|
||||
int get_spf(nfapi_nr_config_request_scf_t *cfg);
|
||||
|
||||
int to_absslot(nfapi_nr_config_request_scf_t *cfg,int frame,int slot);
|
||||
|
||||
@@ -102,9 +102,20 @@ typedef struct {
|
||||
uint8_t num_sf_allocation_pattern;
|
||||
} NR_COMMON_channels_t;
|
||||
|
||||
/*! \brief scheduling control information set through an API (not used)*/
|
||||
typedef struct NR_sched_pucch {
|
||||
int frame;
|
||||
int ul_slot;
|
||||
uint8_t dai_c;
|
||||
uint8_t timing_indicator;
|
||||
uint8_t resource_indicator;
|
||||
struct NR_sched_pucch *next_sched_pucch;
|
||||
} NR_sched_pucch;
|
||||
|
||||
/*! \brief scheduling control information set through an API */
|
||||
typedef struct {
|
||||
int dummy;
|
||||
uint64_t dlsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains dlsch
|
||||
uint64_t ulsch_in_slot_bitmap; // static bitmap signaling which slot in a tdd period contains ulsch
|
||||
NR_sched_pucch *sched_pucch;
|
||||
} NR_UE_sched_ctrl_t;
|
||||
|
||||
/*! \brief UE list used by eNB to order UEs/CC for scheduling*/
|
||||
@@ -112,7 +123,7 @@ typedef struct {
|
||||
|
||||
DLSCH_PDU DLSCH_pdu[4][MAX_MOBILES_PER_GNB];
|
||||
/// scheduling control info
|
||||
UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
|
||||
NR_UE_sched_ctrl_t UE_sched_ctrl[MAX_MOBILES_PER_GNB];
|
||||
int next[MAX_MOBILES_PER_GNB];
|
||||
int head;
|
||||
int next_ul[MAX_MOBILES_PER_GNB];
|
||||
@@ -124,7 +135,7 @@ typedef struct {
|
||||
NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB];
|
||||
} NR_UE_list_t;
|
||||
|
||||
/*! \brief top level eNB MAC structure */
|
||||
/*! \brief top level gNB MAC structure */
|
||||
typedef struct gNB_MAC_INST_s {
|
||||
/// Ethernet parameters for northbound midhaul interface
|
||||
eth_params_t eth_params_n;
|
||||
@@ -191,64 +202,62 @@ typedef struct gNB_MAC_INST_s {
|
||||
} gNB_MAC_INST;
|
||||
|
||||
typedef struct {
|
||||
|
||||
|
||||
uint8_t format_indicator; //1 bit
|
||||
uint16_t frequency_domain_assignment; //up to 16 bits
|
||||
uint8_t time_domain_assignment; // 4 bits
|
||||
uint8_t frequency_hopping_flag; //1 bit
|
||||
|
||||
uint8_t ra_preamble_index; //6 bits
|
||||
uint8_t ss_pbch_index; //6 bits
|
||||
uint8_t prach_mask_index; //4 bits
|
||||
|
||||
uint8_t vrb_to_prb_mapping; //0 or 1 bit
|
||||
uint8_t mcs; //5 bits
|
||||
uint8_t ndi; //1 bit
|
||||
uint8_t rv; //2 bits
|
||||
uint8_t harq_pid; //4 bits
|
||||
uint8_t dai; //0, 2 or 4 bits
|
||||
uint8_t dai1; //1 or 2 bits
|
||||
uint8_t dai2; //0 or 2 bits
|
||||
uint8_t tpc; //2 bits
|
||||
uint8_t pucch_resource_indicator; //3 bits
|
||||
uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits
|
||||
|
||||
uint8_t short_messages_indicator; //2 bits
|
||||
uint8_t short_messages; //8 bits
|
||||
uint8_t tb_scaling; //2 bits
|
||||
|
||||
uint8_t carrier_indicator; //0 or 3 bits
|
||||
uint8_t bwp_indicator; //0, 1 or 2 bits
|
||||
uint8_t prb_bundling_size_indicator; //0 or 1 bits
|
||||
uint8_t rate_matching_indicator; //0, 1 or 2 bits
|
||||
uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits
|
||||
uint8_t transmission_configuration_indication; //0 or 3 bits
|
||||
uint8_t srs_request; //2 bits
|
||||
uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
|
||||
uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit
|
||||
uint8_t dmrs_sequence_initialization; //0 or 1 bit
|
||||
|
||||
uint8_t srs_resource_indicator;
|
||||
uint8_t precoding_information;
|
||||
uint8_t csi_request;
|
||||
uint8_t ptrs_dmrs_association;
|
||||
uint8_t beta_offset_indicator; //0 or 2 bits
|
||||
|
||||
uint8_t slot_format_indicator_count;
|
||||
uint8_t *slot_format_indicators;
|
||||
|
||||
uint8_t pre_emption_indication_count;
|
||||
uint16_t *pre_emption_indications; //14 bit
|
||||
|
||||
uint8_t block_number_count;
|
||||
uint8_t *block_numbers;
|
||||
|
||||
uint8_t ul_sul_indicator; //0 or 1 bit
|
||||
uint8_t antenna_ports;
|
||||
|
||||
uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
|
||||
uint16_t padding;
|
||||
uint8_t format_indicator; //1 bit
|
||||
uint16_t frequency_domain_assignment; //up to 16 bits
|
||||
uint8_t time_domain_assignment; // 4 bits
|
||||
uint8_t frequency_hopping_flag; //1 bit
|
||||
|
||||
uint8_t ra_preamble_index; //6 bits
|
||||
uint8_t ss_pbch_index; //6 bits
|
||||
uint8_t prach_mask_index; //4 bits
|
||||
|
||||
uint8_t vrb_to_prb_mapping; //0 or 1 bit
|
||||
uint8_t mcs; //5 bits
|
||||
uint8_t ndi; //1 bit
|
||||
uint8_t rv; //2 bits
|
||||
uint8_t harq_pid; //4 bits
|
||||
uint8_t dai; //0, 2 or 4 bits
|
||||
uint8_t dai1; //1 or 2 bits
|
||||
uint8_t dai2; //0 or 2 bits
|
||||
uint8_t tpc; //2 bits
|
||||
uint8_t pucch_resource_indicator; //3 bits
|
||||
uint8_t pdsch_to_harq_feedback_timing_indicator; //0, 1, 2 or 3 bits
|
||||
|
||||
uint8_t short_messages_indicator; //2 bits
|
||||
uint8_t short_messages; //8 bits
|
||||
uint8_t tb_scaling; //2 bits
|
||||
|
||||
uint8_t carrier_indicator; //0 or 3 bits
|
||||
uint8_t bwp_indicator; //0, 1 or 2 bits
|
||||
uint8_t prb_bundling_size_indicator; //0 or 1 bits
|
||||
uint8_t rate_matching_indicator; //0, 1 or 2 bits
|
||||
uint8_t zp_csi_rs_trigger; //0, 1 or 2 bits
|
||||
uint8_t transmission_configuration_indication; //0 or 3 bits
|
||||
uint8_t srs_request; //2 bits
|
||||
uint8_t cbgti; //CBG Transmission Information: 0, 2, 4, 6 or 8 bits
|
||||
uint8_t cbgfi; //CBG Flushing Out Information: 0 or 1 bit
|
||||
uint8_t dmrs_sequence_initialization; //0 or 1 bit
|
||||
|
||||
uint8_t srs_resource_indicator;
|
||||
uint8_t precoding_information;
|
||||
uint8_t csi_request;
|
||||
uint8_t ptrs_dmrs_association;
|
||||
uint8_t beta_offset_indicator; //0 or 2 bits
|
||||
|
||||
uint8_t slot_format_indicator_count;
|
||||
uint8_t *slot_format_indicators;
|
||||
|
||||
uint8_t pre_emption_indication_count;
|
||||
uint16_t *pre_emption_indications; //14 bit
|
||||
|
||||
uint8_t block_number_count;
|
||||
uint8_t *block_numbers;
|
||||
|
||||
uint8_t ul_sul_indicator; //0 or 1 bit
|
||||
uint8_t antenna_ports;
|
||||
|
||||
uint16_t reserved; //1_0/C-RNTI:10 bits, 1_0/P-RNTI: 6 bits, 1_0/SI-&RA-RNTI: 16 bits
|
||||
uint16_t padding;
|
||||
|
||||
} dci_pdu_rel15_t;
|
||||
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent.h
|
||||
* \brief top level enb agent receive thread and itti task
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file proto_agent.h
|
||||
* \brief top level protocol agent
|
||||
|
||||
@@ -1,32 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "proto_agent_async.h"
|
||||
#include "proto_agent_defs.h"
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_async.h
|
||||
* \brief channel implementation for async interface
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file proto_agent_common.c
|
||||
* \brief common primitives for all agents
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_common.h
|
||||
* \brief common message primitves and utilities
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_defs.h
|
||||
* \brief enb agent common definitions
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2014 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_handler.c
|
||||
* \brief enb agent tx and rx message handler
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_net_comm.c
|
||||
* \brief enb agent network interface abstraction
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
/*******************************************************************************
|
||||
OpenAirInterface
|
||||
Copyright(c) 1999 - 2016 Eurecom
|
||||
|
||||
OpenAirInterface is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
OpenAirInterface is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenAirInterface.The full GNU General Public License is
|
||||
included in this distribution in the file called "COPYING". If not,
|
||||
see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Contact Information
|
||||
OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
|
||||
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
|
||||
|
||||
*******************************************************************************/
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file enb_agent_net_comm.h
|
||||
* \brief enb agent network interface abstraction
|
||||
|
||||
@@ -137,7 +137,7 @@ void (*rlc_rrc_data_ind)(
|
||||
const protocol_ctxt_t *const ctxtP,
|
||||
const rb_id_t rb_idP,
|
||||
const sdu_size_t sdu_sizeP,
|
||||
const uint8_t *const sduP);
|
||||
const uint8_t *const sduP) __attribute__ ((aligned(32)));
|
||||
|
||||
void (*rlc_rrc_data_conf)(
|
||||
const protocol_ctxt_t *const ctxtP,
|
||||
@@ -250,7 +250,7 @@ logical_chan_id_t rlc_mbms_rbid2lcid_eNB[MAX_eNB][NB_RB_MBMS_MAX];
|
||||
(((hash_key_t)(sESSION_ID)) << 37) | \
|
||||
(((hash_key_t)(0x0000000000000001)) << 63))
|
||||
|
||||
hash_table_t *rlc_coll_p;
|
||||
hash_table_t *rlc_coll_p __attribute__ ((aligned(32)));
|
||||
|
||||
/*! \fn tbs_size_t mac_rlc_serialize_tb (char* bufferP, list_t transport_blocksP)
|
||||
* \brief Serialize a list of transport blocks coming from RLC in order to be processed by MAC.
|
||||
|
||||
@@ -107,7 +107,6 @@ tbs_size_t mac_rlc_data_req(
|
||||
int ret;
|
||||
nr_rlc_ue_t *ue;
|
||||
nr_rlc_entity_t *rb;
|
||||
int is_enb;
|
||||
int maxsize;
|
||||
|
||||
nr_rlc_manager_lock(nr_rlc_ue_manager);
|
||||
@@ -121,8 +120,6 @@ tbs_size_t mac_rlc_data_req(
|
||||
|
||||
if (rb != NULL) {
|
||||
rb->set_time(rb, nr_rlc_current_time);
|
||||
/* UE does not seem to use saved_status_ind_tb_size */
|
||||
is_enb = nr_rlc_manager_get_enb_flag(nr_rlc_ue_manager);
|
||||
maxsize = tb_sizeP;
|
||||
ret = rb->generate_pdu(rb, buffer_pP, maxsize);
|
||||
} else {
|
||||
|
||||
@@ -28,10 +28,6 @@ typedef void nr_rlc_ue_manager_t;
|
||||
|
||||
typedef struct nr_rlc_ue_t {
|
||||
int rnti;
|
||||
/* due to openair calling status_ind/data_req, we need to keep this.
|
||||
* To be considered 'hackish'.
|
||||
*/
|
||||
int saved_status_ind_tb_size[2+5];
|
||||
nr_rlc_entity_t *srb[2];
|
||||
nr_rlc_entity_t *drb[5];
|
||||
} nr_rlc_ue_t;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
RLC AM
|
||||
======
|
||||
|
||||
- 36.322 5.4 Re-establishment procedure
|
||||
when possible, reassemble RLC SDUs from any byte segments of AMD PDUs
|
||||
with SN < VR(MR) in the receiving side, remove RLC headers when doing
|
||||
so and deliver all reassembled RLC SDUs to upper layer in ascending order
|
||||
of the RLC SN, if not delivered before;
|
||||
|
||||
- 36.322 5.2.3 Status reporting
|
||||
delay triggering the STATUS report until x < VR(MS) or x >= VR(MR)
|
||||
|
||||
- 36.322 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception
|
||||
buffer
|
||||
[...] and in-sequence byte segments of the AMD PDU with SN = VR(R) [...]
|
||||
|
||||
- use SOstart/SOend in NACK reporting, do not NACK full PDU if
|
||||
parts of it have been received
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc.h"
|
||||
|
||||
int decode_t_reordering(int v)
|
||||
{
|
||||
static int 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
|
||||
};
|
||||
|
||||
if (v < 0 || v > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_t_status_prohibit(int v)
|
||||
{
|
||||
static int tab[62] = {
|
||||
0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90,
|
||||
95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150, 155, 160, 165,
|
||||
170, 175, 180, 185, 190, 195, 200, 205, 210, 215, 220, 225, 230, 235, 240,
|
||||
245, 250, 300, 350, 400, 450, 500, 800, 1000, 1200, 1600, 2000, 2400
|
||||
};
|
||||
|
||||
if (v < 0 || v > 61) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_t_poll_retransmit(int v)
|
||||
{
|
||||
static int tab[59] = {
|
||||
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
|
||||
};
|
||||
|
||||
if (v < 0 || v > 58) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_poll_pdu(int v)
|
||||
{
|
||||
static int tab[8] = {
|
||||
4, 8, 16, 32, 64, 128, 256, -1 /* -1 means infinity */
|
||||
};
|
||||
|
||||
if (v < 0 || v > 7) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_poll_byte(int v)
|
||||
{
|
||||
static int tab[15] = {
|
||||
25, 50, 75, 100, 125, 250, 375, 500, 750, 1000, 1250, 1500, 2000, 3000,
|
||||
-1 /* -1 means infinity */
|
||||
};
|
||||
|
||||
if (v < 0 || v > 14) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (tab[v] == -1) return -1;
|
||||
return tab[v] * 1024;
|
||||
}
|
||||
|
||||
int decode_max_retx_threshold(int v)
|
||||
{
|
||||
static int tab[8] = {
|
||||
1, 2, 3, 4, 6, 8, 16, 32
|
||||
};
|
||||
|
||||
if (v < 0 || v > 7) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
|
||||
int decode_sn_field_length(int v)
|
||||
{
|
||||
static int tab[2] = {
|
||||
5, 10
|
||||
};
|
||||
|
||||
if (v < 0 || v > 1) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return tab[v];
|
||||
}
|
||||
@@ -19,3 +19,15 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _ASN1_UTILS_H_
|
||||
#define _ASN1_UTILS_H_
|
||||
|
||||
int decode_t_reordering(int v);
|
||||
int decode_t_status_prohibit(int v);
|
||||
int decode_t_poll_retransmit(int v);
|
||||
int decode_poll_pdu(int v);
|
||||
int decode_poll_byte(int v);
|
||||
int decode_max_retx_threshold(int v);
|
||||
int decode_sn_field_length(int v);
|
||||
|
||||
#endif /* _ASN1_UTILS_H_ */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_entity.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rlc_entity_am.h"
|
||||
#include "rlc_entity_um.h"
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
rlc_entity_t *new_rlc_entity_am(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id),
|
||||
void *sdu_successful_delivery_data,
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity),
|
||||
void *max_retx_reached_data,
|
||||
int t_reordering,
|
||||
int t_status_prohibit,
|
||||
int t_poll_retransmit,
|
||||
int poll_pdu,
|
||||
int poll_byte,
|
||||
int max_retx_threshold)
|
||||
{
|
||||
rlc_entity_am_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_entity_am_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret->common.recv_pdu = rlc_entity_am_recv_pdu;
|
||||
ret->common.buffer_status = rlc_entity_am_buffer_status;
|
||||
ret->common.generate_pdu = rlc_entity_am_generate_pdu;
|
||||
|
||||
ret->common.recv_sdu = rlc_entity_am_recv_sdu;
|
||||
|
||||
ret->common.set_time = rlc_entity_am_set_time;
|
||||
|
||||
ret->common.discard_sdu = rlc_entity_am_discard_sdu;
|
||||
|
||||
ret->common.reestablishment = rlc_entity_am_reestablishment;
|
||||
|
||||
ret->common.delete = rlc_entity_am_delete;
|
||||
|
||||
ret->common.deliver_sdu = deliver_sdu;
|
||||
ret->common.deliver_sdu_data = deliver_sdu_data;
|
||||
|
||||
ret->common.sdu_successful_delivery = sdu_successful_delivery;
|
||||
ret->common.sdu_successful_delivery_data = sdu_successful_delivery_data;
|
||||
|
||||
ret->common.max_retx_reached = max_retx_reached;
|
||||
ret->common.max_retx_reached_data = max_retx_reached_data;
|
||||
|
||||
ret->rx_maxsize = rx_maxsize;
|
||||
ret->tx_maxsize = tx_maxsize;
|
||||
ret->t_reordering = t_reordering;
|
||||
ret->t_status_prohibit = t_status_prohibit;
|
||||
ret->t_poll_retransmit = t_poll_retransmit;
|
||||
ret->poll_pdu = poll_pdu;
|
||||
ret->poll_byte = poll_byte;
|
||||
ret->max_retx_threshold = max_retx_threshold;
|
||||
|
||||
return (rlc_entity_t *)ret;
|
||||
}
|
||||
|
||||
rlc_entity_t *new_rlc_entity_um(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
int t_reordering,
|
||||
int sn_field_length)
|
||||
{
|
||||
rlc_entity_um_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_entity_um_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret->common.recv_pdu = rlc_entity_um_recv_pdu;
|
||||
ret->common.buffer_status = rlc_entity_um_buffer_status;
|
||||
ret->common.generate_pdu = rlc_entity_um_generate_pdu;
|
||||
|
||||
ret->common.recv_sdu = rlc_entity_um_recv_sdu;
|
||||
|
||||
ret->common.set_time = rlc_entity_um_set_time;
|
||||
|
||||
ret->common.discard_sdu = rlc_entity_um_discard_sdu;
|
||||
|
||||
ret->common.reestablishment = rlc_entity_um_reestablishment;
|
||||
|
||||
ret->common.delete = rlc_entity_um_delete;
|
||||
|
||||
ret->common.deliver_sdu = deliver_sdu;
|
||||
ret->common.deliver_sdu_data = deliver_sdu_data;
|
||||
|
||||
ret->sn_field_length = sn_field_length;
|
||||
ret->rx_maxsize = rx_maxsize;
|
||||
ret->tx_maxsize = tx_maxsize;
|
||||
ret->t_reordering = t_reordering;
|
||||
|
||||
if (sn_field_length == 5)
|
||||
ret->sn_modulus = 32;
|
||||
else if (sn_field_length == 10)
|
||||
ret->sn_modulus = 1024;
|
||||
else {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->window_size = ret->sn_modulus / 2;
|
||||
|
||||
return (rlc_entity_t *)ret;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_H_
|
||||
#define _RLC_ENTITY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SDU_MAX 16000 /* maximum PDCP SDU size is 8188, let's take more */
|
||||
|
||||
typedef struct {
|
||||
int status_size;
|
||||
int tx_size;
|
||||
int retx_size;
|
||||
} rlc_entity_buffer_status_t;
|
||||
|
||||
typedef struct rlc_entity_t {
|
||||
/* functions provided by the RLC module */
|
||||
void (*recv_pdu)(struct rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t (*buffer_status)(
|
||||
struct rlc_entity_t *entity, int maxsize);
|
||||
int (*generate_pdu)(struct rlc_entity_t *entity, char *buffer, int size);
|
||||
|
||||
void (*recv_sdu)(struct rlc_entity_t *entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
|
||||
void (*set_time)(struct rlc_entity_t *entity, uint64_t now);
|
||||
|
||||
void (*discard_sdu)(struct rlc_entity_t *entity, int sdu_id);
|
||||
|
||||
void (*reestablishment)(struct rlc_entity_t *entity);
|
||||
|
||||
void (*delete)(struct rlc_entity_t *entity);
|
||||
|
||||
/* callbacks provided to the RLC module */
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size);
|
||||
void *deliver_sdu_data;
|
||||
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id);
|
||||
void *sdu_successful_delivery_data;
|
||||
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity);
|
||||
void *max_retx_reached_data;
|
||||
} rlc_entity_t;
|
||||
|
||||
rlc_entity_t *new_rlc_entity_am(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
void (*sdu_successful_delivery)(void *sdu_successful_delivery_data,
|
||||
struct rlc_entity_t *entity,
|
||||
int sdu_id),
|
||||
void *sdu_successful_delivery_data,
|
||||
void (*max_retx_reached)(void *max_retx_reached_data,
|
||||
struct rlc_entity_t *entity),
|
||||
void *max_retx_reached_data,
|
||||
int t_reordering,
|
||||
int t_status_prohibit,
|
||||
int t_poll_retransmit,
|
||||
int poll_pdu,
|
||||
int poll_byte,
|
||||
int max_retx_threshold);
|
||||
|
||||
rlc_entity_t *new_rlc_entity_um(
|
||||
int rx_maxsize,
|
||||
int tx_maxsize,
|
||||
void (*deliver_sdu)(void *deliver_sdu_data, struct rlc_entity_t *entity,
|
||||
char *buf, int size),
|
||||
void *deliver_sdu_data,
|
||||
int t_reordering,
|
||||
int sn_field_length);
|
||||
|
||||
#endif /* _RLC_ENTITY_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_AM_H_
|
||||
#define _RLC_ENTITY_AM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rlc_entity.h"
|
||||
#include "rlc_pdu.h"
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
/*
|
||||
* Here comes some documentation to understand the reassembly
|
||||
* logic in the code and the fields in the structure rlc_am_reassemble_t.
|
||||
*
|
||||
* Inside RLC, we deal with SDUs, PDUs and PDU segments.
|
||||
* SDUs are packets coming from upper layer.
|
||||
* A PDU is made of a header and a payload.
|
||||
* In the payload there are SDUs.
|
||||
* First SDU and last SDU in a PDU may be incomplete.
|
||||
* PDU segments exist in case of retransmissions when the MAC
|
||||
* layer asks for less data than previously, in which case
|
||||
* only part of the previous PDU is sent.
|
||||
*
|
||||
* This is PDU data (just bytes):
|
||||
* ---------------------------------------------------------
|
||||
* | PDU data |
|
||||
* ---------------------------------------------------------
|
||||
* It contains SDUs, like:
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
* SDU 1 may be only the end of an SDU from which previous bytes were
|
||||
* transmitted in previous PDUs.
|
||||
* SDU n may be only the start of an SDU, that is more bytes from
|
||||
* this SDU may be sent in successive PDUs.
|
||||
*
|
||||
* At front of the PDU data, we have a header:
|
||||
* --------------- ---------------------------------------------------------
|
||||
* | PDU header | | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* --------------- ---------------------------------------------------------
|
||||
* PDU header describes PDU data (most notably lengths).
|
||||
*
|
||||
* A PDU segment is a part of a PDU. For example, from this PDU data:
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1 | SDU 2 | [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
* We can extract the following PDU segment (data part only):
|
||||
* ----------------------
|
||||
* | PDU segment data |
|
||||
* ----------------------
|
||||
* This PDU segment would contain the end of SDU 2 above and some SDUs up to,
|
||||
* let's say SDU x (x is 5 below).
|
||||
*
|
||||
* In front of a transmitted PDU segment, we have a header,
|
||||
* containing the important variable 'so' (segment offset) that gives
|
||||
* the index of the first byte of the segment in the original PDU.
|
||||
* -------------- ----------------------
|
||||
* | seg. header| | PDU segment data |
|
||||
* -------------- ----------------------
|
||||
*
|
||||
* Let's now explain the data structure rlc_am_reassemble_t.
|
||||
*
|
||||
* In the structure rlc_am_reassemble_t, the fields fi, e, sn and so
|
||||
* are coming from the PDU segment header and the semantics is the
|
||||
* one of the RLC specs.
|
||||
*
|
||||
* The currently processed PDU segment is stored in 'start'.
|
||||
* We have 'start->s->data_offset' and 'start->s->size'.
|
||||
* start->s->data_offset is the index of the start of the data in the
|
||||
* PDU segment. That is if the header is of length 3 bytes
|
||||
* then start->s->data_offset is 3.
|
||||
* start->s->size is the total length of the PDU segment,
|
||||
* including header.
|
||||
* The size of actual data bytes in the PDU segment is thus
|
||||
* start->s->size - start->s->data_offset.
|
||||
*
|
||||
* The field sdu_len is the length of the current SDU being
|
||||
* processed.
|
||||
*
|
||||
* The field sdu_offset is the starting point of the
|
||||
* current SDU being processed (starting from beginning
|
||||
* of PDU segment, including header).
|
||||
*
|
||||
* The field data_pos is the current read pointer. 0 points to
|
||||
* the beginning of the PDU segment (including header).
|
||||
*
|
||||
* The field pdu_byte points to the current byte in the original
|
||||
* PDU (not the PDU segment). It starts at 0 when we start
|
||||
* processing a new PDU (when a new 'sn' is seen) and always
|
||||
* increases after each byte processed. This is tha variable
|
||||
* that is used to know if the next PDU segment will be used
|
||||
* or not and if yes, starting from which data byte (see
|
||||
* function rlc_am_reassemble_next_segment).
|
||||
*
|
||||
* 'so' is important and points to the byte in the original PDU
|
||||
* that is the first byte of the PDU segment.
|
||||
*
|
||||
* For example, let's take this PDU segment data from above:
|
||||
* ----------------------
|
||||
* | PDU segment data |
|
||||
* ----------------------
|
||||
* Let's say it is decomposed as:
|
||||
* ----------------------
|
||||
* |222|33|4444|55555555|
|
||||
* ----------------------
|
||||
* It contains SDUs 2, 3, 4, and 5.
|
||||
* SDU 2 is 3 bytes, SDU 3 is 2 bytes, SDU 4 is 4 bytes, SDU 5 is 8 bytes.
|
||||
*
|
||||
* Let's suppose that the original PDU starts with:
|
||||
* ----------------
|
||||
* |1111111|222222|
|
||||
* ----------------
|
||||
*
|
||||
* (In this example, in the PDU segment, SDU 2 is not full,
|
||||
* we only have its end.)
|
||||
*
|
||||
* Then 'so' is 13 (SDU 1 is 7 bytes, head of SDU 2 is 6 bytes).
|
||||
*
|
||||
* Let's continue with our PDU segment data.
|
||||
* Let's say we are current processing SDU 4.
|
||||
* Let's say the read pointer (variable 'data_pos') is there:
|
||||
* ----------------------
|
||||
* |222|33|4444|55555555|
|
||||
* ----------------------
|
||||
* ^
|
||||
* read pointer (data_pos)
|
||||
*
|
||||
* Then:
|
||||
* - sdu_len is 4
|
||||
* - sdu_offset is 5 + [PDU segment header length]
|
||||
* (it points to the beginning of SDU 4, starting
|
||||
* from the head of the PDU segment, that is
|
||||
* 3 bytes for SDU 2, 2 bytes for SDU 3, and the
|
||||
* PDU segment header length)
|
||||
* - start->s->data_offset is [PDU segment header length]
|
||||
* - pdu_byte is 20
|
||||
* (13 bytes from beginning of original PDU,
|
||||
* 3 bytes for SDU 2, 2 bytes for SDU 3, then 2 bytes for SDU 4)
|
||||
* - data_pos = read pointer = 7 + [PDU segment header length]
|
||||
*
|
||||
* To finish this description, in the code, a PDU is simply
|
||||
* seen as a PDU segment with 'so' = 0 (and is_last == 1 (lsf in the specs),
|
||||
* but this variable is not used by the reassembly logic).
|
||||
*
|
||||
* And for [PDU segment header length] we use start->s->data_offset.
|
||||
*
|
||||
* To recap, here is an illustration of the various variables
|
||||
* and what starting point they use. In the figures, the start
|
||||
* of the variable name is aligned to the byte it refers to.
|
||||
* + is used to show the starting point.
|
||||
*
|
||||
* Let's put the PDU segment back into the original PDU.
|
||||
* And let's show the values for when the read pointer
|
||||
* is on the second byte of SDU 4 (as above).
|
||||
*
|
||||
* +++++++++++++++ so
|
||||
* +++++++++++++++++++++++ pdu_byte
|
||||
* ---------------------------------------------------------
|
||||
* | SDU 1| SDU 2..222|33|4444|55555555| [...] | SDU n |
|
||||
* ---------------------------------------------------------
|
||||
*
|
||||
* And now the PDU segment with header.
|
||||
*
|
||||
*
|
||||
* ++++ sdu_len
|
||||
* ++++++++++++++++++++++ sdu_offset
|
||||
* +++++++++++++++++++++++ data_pos
|
||||
* +++++++++++++++ start->s->data_offset
|
||||
* +++++++++++++++++++++++++++++++++++++ start->s->size
|
||||
* -------------- ----------------------
|
||||
* | seg. header| |222|33|4444|55555555|
|
||||
* -------------- ----------------------
|
||||
*
|
||||
* We see three case for the starting point:
|
||||
* - start of original PDU (without any header)
|
||||
* - start of header of current PDU segment
|
||||
* - start of current SDU (for sdu_len)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
rlc_rx_pdu_segment_t *start; /* start of list */
|
||||
rlc_rx_pdu_segment_t *end; /* end of list (last element) */
|
||||
int pos; /* byte to get from current buffer */
|
||||
char sdu[SDU_MAX]; /* sdu is reassembled here */
|
||||
int sdu_pos; /* next byte to put in sdu */
|
||||
|
||||
/* decoder of current PDU */
|
||||
rlc_pdu_decoder_t dec;
|
||||
int fi;
|
||||
int e;
|
||||
int sn;
|
||||
int so;
|
||||
int sdu_len;
|
||||
int sdu_offset;
|
||||
int data_pos;
|
||||
int pdu_byte;
|
||||
} rlc_am_reassemble_t;
|
||||
|
||||
typedef struct {
|
||||
rlc_entity_t common;
|
||||
|
||||
/* configuration */
|
||||
int t_reordering;
|
||||
int t_status_prohibit;
|
||||
int t_poll_retransmit;
|
||||
int poll_pdu; /* -1 means infinity */
|
||||
int poll_byte; /* -1 means infinity */
|
||||
int max_retx_threshold;
|
||||
|
||||
/* runtime rx */
|
||||
int vr_r;
|
||||
int vr_x;
|
||||
int vr_ms;
|
||||
int vr_h;
|
||||
|
||||
int status_triggered;
|
||||
|
||||
/* runtime tx */
|
||||
int vt_a;
|
||||
int vt_s;
|
||||
int poll_sn;
|
||||
int pdu_without_poll;
|
||||
int byte_without_poll;
|
||||
int force_poll;
|
||||
|
||||
/* set to the latest know time by the user of the module. Unit: ms */
|
||||
uint64_t t_current;
|
||||
|
||||
/* timers (stores the TTI of activation, 0 means not active) */
|
||||
uint64_t t_reordering_start;
|
||||
uint64_t t_status_prohibit_start;
|
||||
uint64_t t_poll_retransmit_start;
|
||||
|
||||
/* rx management */
|
||||
rlc_rx_pdu_segment_t *rx_list;
|
||||
int rx_size;
|
||||
int rx_maxsize;
|
||||
|
||||
/* reassembly management */
|
||||
rlc_am_reassemble_t reassemble;
|
||||
|
||||
/* tx management */
|
||||
rlc_sdu_t *tx_list;
|
||||
rlc_sdu_t *tx_end;
|
||||
int tx_size;
|
||||
int tx_maxsize;
|
||||
|
||||
rlc_tx_pdu_segment_t *wait_list;
|
||||
rlc_tx_pdu_segment_t *retransmit_list;
|
||||
|
||||
rlc_tx_pdu_segment_t *ack_list;
|
||||
} rlc_entity_am_t;
|
||||
|
||||
void rlc_entity_am_recv_sdu(rlc_entity_t *entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
void rlc_entity_am_recv_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t rlc_entity_am_buffer_status(
|
||||
rlc_entity_t *entity, int maxsize);
|
||||
int rlc_entity_am_generate_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
void rlc_entity_am_set_time(rlc_entity_t *entity, uint64_t now);
|
||||
void rlc_entity_am_discard_sdu(rlc_entity_t *entity, int sdu_id);
|
||||
void rlc_entity_am_reestablishment(rlc_entity_t *entity);
|
||||
void rlc_entity_am_delete(rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_ENTITY_AM_H_ */
|
||||
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_entity_um.h"
|
||||
#include "rlc_pdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
/*************************************************************************/
|
||||
/* PDU RX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
static int modulus_rx(rlc_entity_um_t *entity, int a)
|
||||
{
|
||||
/* as per 36.322 7.1, modulus base is vr(uh)-window_size and modulus is
|
||||
* 2^sn_field_length (which is 'sn_modulus' in rlc_entity_um_t)
|
||||
*/
|
||||
int r = a - (entity->vr_uh - entity->window_size);
|
||||
if (r < 0) r += entity->sn_modulus;
|
||||
return r % entity->sn_modulus;
|
||||
}
|
||||
|
||||
static int sn_compare_rx(void *_entity, int a, int b)
|
||||
{
|
||||
rlc_entity_um_t *entity = _entity;
|
||||
return modulus_rx(entity, a) - modulus_rx(entity, b);
|
||||
}
|
||||
|
||||
static int sn_in_recv_window(void *_entity, int sn)
|
||||
{
|
||||
rlc_entity_um_t *entity = _entity;
|
||||
int mod_sn = modulus_rx(entity, sn);
|
||||
/* we simplify (VR(UH) - UM_Window_Size) <= SN < VR(UH), base is
|
||||
* (VR(UH) - UM_Window_Size) and VR(UH) = base + window_size
|
||||
*/
|
||||
return mod_sn < entity->window_size;
|
||||
}
|
||||
|
||||
/* return 1 if a PDU with SN == 'sn' is in the rx list, 0 otherwise */
|
||||
static int rlc_um_pdu_received(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur = entity->rx_list;
|
||||
while (cur != NULL) {
|
||||
if (cur->sn == sn)
|
||||
return 1;
|
||||
cur = cur->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int less_than_vr_ur(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return sn_compare_rx(entity, sn, entity->vr_ur) < 0;
|
||||
}
|
||||
|
||||
static int outside_of_reordering_window(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return !sn_in_recv_window(entity, sn);
|
||||
}
|
||||
|
||||
static int less_than_vr_uh(rlc_entity_um_t *entity, int sn)
|
||||
{
|
||||
return sn_compare_rx(entity, sn, entity->vr_uh) < 0;
|
||||
}
|
||||
|
||||
static void rlc_um_reassemble_pdu(rlc_entity_um_t *entity,
|
||||
rlc_rx_pdu_segment_t *pdu)
|
||||
{
|
||||
rlc_um_reassemble_t *r = &entity->reassemble;
|
||||
|
||||
int fi;
|
||||
int e;
|
||||
int sn;
|
||||
int data_pos;
|
||||
int sdu_len;
|
||||
int sdu_offset;
|
||||
|
||||
sdu_offset = pdu->data_offset;
|
||||
|
||||
rlc_pdu_decoder_init(&r->dec, pdu->data, pdu->size);
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_decoder_get_bits(&r->dec, 3);
|
||||
|
||||
fi = rlc_pdu_decoder_get_bits(&r->dec, 2);
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sn = rlc_pdu_decoder_get_bits(&r->dec, entity->sn_field_length);
|
||||
|
||||
if (e) {
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11);
|
||||
} else
|
||||
sdu_len = pdu->size - sdu_offset;
|
||||
|
||||
/* discard current SDU being reassembled if bad SN or bad FI */
|
||||
if (sn != (r->sn + 1) % entity->sn_modulus ||
|
||||
!(fi & 0x02)) {
|
||||
if (r->sdu_pos)
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard partially reassembled SDU\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
r->sdu_pos = 0;
|
||||
}
|
||||
|
||||
/* if the head of the SDU is missing, still process the PDU
|
||||
* but remember to discard the reassembled SDU later on (the
|
||||
* head has not been received).
|
||||
* The head is missing if sdu_pos == 0 and fi says the PDU does not
|
||||
* start an SDU.
|
||||
*/
|
||||
if (r->sdu_pos == 0 && (fi & 0x02))
|
||||
r->sdu_head_missing = 1;
|
||||
|
||||
r->sn = sn;
|
||||
data_pos = pdu->data_offset;
|
||||
|
||||
while (1) {
|
||||
if (r->sdu_pos >= SDU_MAX) {
|
||||
/* TODO: proper error handling (discard PDUs with current sn from
|
||||
* reassembly queue? something else?)
|
||||
*/
|
||||
LOG_E(RLC, "%s:%d:%s: bad RLC PDU\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
r->sdu[r->sdu_pos] = pdu->data[data_pos];
|
||||
r->sdu_pos++;
|
||||
data_pos++;
|
||||
if (data_pos == sdu_offset + sdu_len) {
|
||||
/* all bytes of SDU are consumed, check if SDU is fully there.
|
||||
* It is if the data pointer is not at the end of the PDU segment
|
||||
* or if 'fi' & 1 == 0
|
||||
*/
|
||||
if (data_pos != pdu->size || (fi & 1) == 0) {
|
||||
/* time to discard the SDU if we didn't receive the head */
|
||||
if (r->sdu_head_missing) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard SDU, head not received\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
r->sdu_head_missing = 0;
|
||||
} else {
|
||||
/* SDU is full - deliver to higher layer */
|
||||
entity->common.deliver_sdu(entity->common.deliver_sdu_data,
|
||||
(rlc_entity_t *)entity,
|
||||
r->sdu, r->sdu_pos);
|
||||
}
|
||||
r->sdu_pos = 0;
|
||||
}
|
||||
/* done with PDU? */
|
||||
if (data_pos == pdu->size)
|
||||
break;
|
||||
/* not at the end of PDU, process next SDU */
|
||||
sdu_offset += sdu_len;
|
||||
if (e) {
|
||||
e = rlc_pdu_decoder_get_bits(&r->dec, 1);
|
||||
sdu_len = rlc_pdu_decoder_get_bits(&r->dec, 11);
|
||||
} else
|
||||
sdu_len = pdu->size - sdu_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rlc_um_reassemble(rlc_entity_um_t *entity,
|
||||
int (*check_sn)(rlc_entity_um_t *entity, int sn))
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur;
|
||||
|
||||
/* process all PDUs from head of rx list until all is processed or
|
||||
* the SN is not valid anymore with respect to 'check_sn'
|
||||
*/
|
||||
while (entity->rx_list != NULL && check_sn(entity, entity->rx_list->sn)) {
|
||||
cur = entity->rx_list;
|
||||
rlc_um_reassemble_pdu(entity, cur);
|
||||
entity->rx_size -= cur->size;
|
||||
entity->rx_list = cur->next;
|
||||
rlc_rx_free_pdu_segment(cur);
|
||||
}
|
||||
}
|
||||
|
||||
static void rlc_um_reception_actions(rlc_entity_um_t *entity,
|
||||
rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
if (!sn_in_recv_window(entity, pdu_segment->sn)) {
|
||||
entity->vr_uh = (pdu_segment->sn + 1) % entity->sn_modulus;
|
||||
rlc_um_reassemble(entity, outside_of_reordering_window);
|
||||
if (!sn_in_recv_window(entity, entity->vr_ur))
|
||||
entity->vr_ur = (entity->vr_uh - entity->window_size
|
||||
+ entity->sn_modulus) % entity->sn_modulus;
|
||||
}
|
||||
|
||||
if (rlc_um_pdu_received(entity, entity->vr_ur)) {
|
||||
do {
|
||||
entity->vr_ur = (entity->vr_ur + 1) % entity->sn_modulus;
|
||||
} while (rlc_um_pdu_received(entity, entity->vr_ur));
|
||||
rlc_um_reassemble(entity, less_than_vr_ur);
|
||||
}
|
||||
|
||||
if (entity->t_reordering_start) {
|
||||
if (sn_compare_rx(entity, entity->vr_ux, entity->vr_ur) <= 0 ||
|
||||
(!sn_in_recv_window(entity, entity->vr_ux) &&
|
||||
entity->vr_ux != entity->vr_uh))
|
||||
entity->t_reordering_start = 0;
|
||||
}
|
||||
|
||||
if (entity->t_reordering_start == 0) {
|
||||
if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) {
|
||||
entity->t_reordering_start = entity->t_current;
|
||||
entity->vr_ux = entity->vr_uh;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_entity_um_recv_pdu(rlc_entity_t *_entity, char *buffer, int size)
|
||||
{
|
||||
#define R(d) do { if (rlc_pdu_decoder_in_error(&d)) goto err; } while (0)
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_pdu_decoder_t decoder;
|
||||
rlc_pdu_decoder_t data_decoder;
|
||||
|
||||
int e;
|
||||
int sn;
|
||||
|
||||
int data_e;
|
||||
int data_li;
|
||||
|
||||
int packet_count;
|
||||
int data_size;
|
||||
int data_start;
|
||||
int indicated_data_size;
|
||||
|
||||
rlc_rx_pdu_segment_t *pdu_segment;
|
||||
|
||||
rlc_pdu_decoder_init(&decoder, buffer, size);
|
||||
|
||||
if (entity->sn_field_length == 10) {
|
||||
rlc_pdu_decoder_get_bits(&decoder, 3); R(decoder); /* R1 */
|
||||
}
|
||||
|
||||
rlc_pdu_decoder_get_bits(&decoder, 2); R(decoder); /* FI */
|
||||
e = rlc_pdu_decoder_get_bits(&decoder, 1); R(decoder);
|
||||
sn = rlc_pdu_decoder_get_bits(&decoder, entity->sn_field_length); R(decoder);
|
||||
|
||||
/* dicard PDU if rx buffer is full */
|
||||
if (entity->rx_size + size > entity->rx_maxsize) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, RX buffer full\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* discard according to 36.322 5.1.2.2.2 */
|
||||
if ((sn_compare_rx(entity, entity->vr_ur, sn) < 0 &&
|
||||
sn_compare_rx(entity, sn, entity->vr_uh) < 0 &&
|
||||
rlc_um_pdu_received(entity, sn)) ||
|
||||
(sn_compare_rx(entity, entity->vr_uh - entity->window_size, sn) <= 0 &&
|
||||
sn_compare_rx(entity, sn, entity->vr_ur) < 0)) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU (sn %d vr(ur) %d vr(uh) %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
sn, entity->vr_ur, entity->vr_uh);
|
||||
return;
|
||||
}
|
||||
|
||||
packet_count = 1;
|
||||
|
||||
/* go to start of data */
|
||||
indicated_data_size = 0;
|
||||
data_decoder = decoder;
|
||||
data_e = e;
|
||||
while (data_e) {
|
||||
data_e = rlc_pdu_decoder_get_bits(&data_decoder, 1); R(data_decoder);
|
||||
data_li = rlc_pdu_decoder_get_bits(&data_decoder, 11); R(data_decoder);
|
||||
if (data_li == 0) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, li == 0\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
indicated_data_size += data_li;
|
||||
packet_count++;
|
||||
}
|
||||
rlc_pdu_decoder_align(&data_decoder);
|
||||
|
||||
data_start = data_decoder.byte;
|
||||
data_size = size - data_start;
|
||||
|
||||
if (data_size <= 0) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, wrong data size (sum of LI %d data size %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
indicated_data_size, data_size);
|
||||
return;
|
||||
}
|
||||
if (indicated_data_size >= data_size) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: discard PDU, bad LIs (sum of LI %d data size %d)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
indicated_data_size, data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
/* put in pdu reception list */
|
||||
entity->rx_size += size;
|
||||
pdu_segment = rlc_rx_new_pdu_segment(sn, 0, size, 1, buffer, data_start);
|
||||
entity->rx_list = rlc_rx_pdu_segment_list_add(sn_compare_rx, entity,
|
||||
entity->rx_list, pdu_segment);
|
||||
|
||||
/* do reception actions (36.322 5.1.2.2.3) */
|
||||
rlc_um_reception_actions(entity, pdu_segment);
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
LOG_D(RLC, "%s:%d:%s: error decoding PDU, discarding\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
#undef R
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* TX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int sdu_count;
|
||||
int data_size;
|
||||
int header_size;
|
||||
int last_sdu_is_full;
|
||||
int first_sdu_length;
|
||||
} tx_pdu_size_t;
|
||||
|
||||
static int header_size(int sn_field_length, int sdu_count)
|
||||
{
|
||||
int bits = 8 + 8 * (sn_field_length == 10) + 12 * (sdu_count - 1);
|
||||
/* padding if we have to */
|
||||
return (bits + 7) / 8;
|
||||
}
|
||||
|
||||
static tx_pdu_size_t tx_pdu_size(rlc_entity_um_t *entity, int maxsize)
|
||||
{
|
||||
tx_pdu_size_t ret;
|
||||
int sdu_count;
|
||||
int sdu_size;
|
||||
int pdu_data_size;
|
||||
rlc_sdu_t *sdu;
|
||||
|
||||
ret.sdu_count = 0;
|
||||
ret.data_size = 0;
|
||||
ret.header_size = 0;
|
||||
ret.last_sdu_is_full = 1;
|
||||
ret.first_sdu_length = 0;
|
||||
|
||||
/* TX PDU - let's make the biggest PDU we can with the SDUs we have */
|
||||
sdu_count = 0;
|
||||
pdu_data_size = 0;
|
||||
sdu = entity->tx_list;
|
||||
while (sdu != NULL) {
|
||||
int new_header_size = header_size(entity->sn_field_length, sdu_count+1);
|
||||
/* if we cannot put new header + at least 1 byte of data then over */
|
||||
if (new_header_size + pdu_data_size >= maxsize)
|
||||
break;
|
||||
sdu_count++;
|
||||
/* only include the bytes of this SDU not included in PDUs already */
|
||||
sdu_size = sdu->size - sdu->next_byte;
|
||||
/* don't feed more than 'maxsize' bytes */
|
||||
if (new_header_size + pdu_data_size + sdu_size > maxsize) {
|
||||
sdu_size = maxsize - new_header_size - pdu_data_size;
|
||||
ret.last_sdu_is_full = 0;
|
||||
}
|
||||
if (sdu_count == 1)
|
||||
ret.first_sdu_length = sdu_size;
|
||||
pdu_data_size += sdu_size;
|
||||
/* if we put more than 2^11-1 bytes then the LI field cannot be used,
|
||||
* so this is the last SDU we can put
|
||||
*/
|
||||
if (sdu_size > 2047)
|
||||
break;
|
||||
sdu = sdu->next;
|
||||
}
|
||||
|
||||
if (sdu_count) {
|
||||
ret.sdu_count = sdu_count;
|
||||
ret.data_size = pdu_data_size;
|
||||
ret.header_size = header_size(entity->sn_field_length, sdu_count);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rlc_entity_buffer_status_t rlc_entity_um_buffer_status(
|
||||
rlc_entity_t *_entity, int maxsize)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_entity_buffer_status_t ret;
|
||||
tx_pdu_size_t tx_size;
|
||||
|
||||
ret.status_size = 0;
|
||||
|
||||
/* todo: if an SDU has size >2047 in the tx list then processing
|
||||
* stops and computed size will not be accurate. Change the computation
|
||||
* to be more accurate (if needed).
|
||||
*/
|
||||
tx_size = tx_pdu_size(entity, maxsize);
|
||||
ret.tx_size = tx_size.data_size + tx_size.header_size;
|
||||
|
||||
ret.retx_size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
tx_pdu_size_t pdu_size;
|
||||
rlc_sdu_t *sdu;
|
||||
int i;
|
||||
int cursize;
|
||||
int first_sdu_full;
|
||||
int last_sdu_full;
|
||||
rlc_pdu_encoder_t encoder;
|
||||
int fi;
|
||||
int e;
|
||||
int li;
|
||||
char *out;
|
||||
int outpos;
|
||||
int first_sdu_start_byte;
|
||||
int sdu_start_byte;
|
||||
|
||||
pdu_size = tx_pdu_size(entity, size);
|
||||
if (pdu_size.sdu_count == 0)
|
||||
return 0;
|
||||
|
||||
sdu = entity->tx_list;
|
||||
|
||||
first_sdu_start_byte = sdu->next_byte;
|
||||
|
||||
/* reserve SDU bytes */
|
||||
cursize = 0;
|
||||
for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
int sdu_size = sdu->size - sdu->next_byte;
|
||||
if (cursize + sdu_size > pdu_size.data_size)
|
||||
sdu_size = pdu_size.data_size - cursize;
|
||||
sdu->next_byte += sdu_size;
|
||||
cursize += sdu_size;
|
||||
}
|
||||
|
||||
first_sdu_full = first_sdu_start_byte == 0;
|
||||
last_sdu_full = pdu_size.last_sdu_is_full;
|
||||
|
||||
/* generate header */
|
||||
rlc_pdu_encoder_init(&encoder, buffer, size);
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_encoder_put_bits(&encoder, 0, 3); /* R1 */
|
||||
|
||||
fi = 0;
|
||||
if (!first_sdu_full)
|
||||
fi |= 0x02;
|
||||
if (!last_sdu_full)
|
||||
fi |= 0x01;
|
||||
rlc_pdu_encoder_put_bits(&encoder, fi, 2); /* FI */
|
||||
|
||||
/* see the AM code to understand the logic for Es and LIs */
|
||||
if (pdu_size.sdu_count >= 2)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
|
||||
if (entity->sn_field_length == 10)
|
||||
rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 10); /* SN */
|
||||
else
|
||||
rlc_pdu_encoder_put_bits(&encoder, entity->vt_us, 5); /* SN */
|
||||
|
||||
/* put LIs */
|
||||
sdu = entity->tx_list;
|
||||
/* first SDU */
|
||||
li = pdu_size.first_sdu_length;
|
||||
/* put E+LI only if at least 2 SDUs */
|
||||
if (pdu_size.sdu_count >= 2) {
|
||||
/* E is 1 if at least 3 SDUs */
|
||||
if (pdu_size.sdu_count >= 3)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */
|
||||
}
|
||||
/* next SDUs, but not the last (no LI for the last) */
|
||||
sdu = sdu->next;
|
||||
for (i = 2; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
if (i != pdu_size.sdu_count - 1)
|
||||
e = 1;
|
||||
else
|
||||
e = 0;
|
||||
li = sdu->size;
|
||||
rlc_pdu_encoder_put_bits(&encoder, e, 1); /* E */
|
||||
rlc_pdu_encoder_put_bits(&encoder, li, 11); /* LI */
|
||||
}
|
||||
|
||||
rlc_pdu_encoder_align(&encoder);
|
||||
|
||||
/* generate data */
|
||||
out = buffer + pdu_size.header_size;
|
||||
sdu = entity->tx_list;
|
||||
sdu_start_byte = first_sdu_start_byte;
|
||||
outpos = 0;
|
||||
for (i = 0; i < pdu_size.sdu_count; i++, sdu = sdu->next) {
|
||||
li = sdu->size - sdu_start_byte;
|
||||
if (outpos + li >= pdu_size.data_size)
|
||||
li = pdu_size.data_size - outpos;
|
||||
memcpy(out+outpos, sdu->data + sdu_start_byte, li);
|
||||
outpos += li;
|
||||
sdu_start_byte = 0;
|
||||
}
|
||||
|
||||
/* cleanup sdu list */
|
||||
while (entity->tx_list != NULL &&
|
||||
entity->tx_list->size == entity->tx_list->next_byte) {
|
||||
rlc_sdu_t *c = entity->tx_list;
|
||||
/* release SDU bytes */
|
||||
entity->tx_size -= c->size;
|
||||
entity->tx_list = c->next;
|
||||
rlc_free_sdu(c);
|
||||
}
|
||||
if (entity->tx_list == NULL)
|
||||
entity->tx_end = NULL;
|
||||
|
||||
/* update VT(US) */
|
||||
entity->vt_us = (entity->vt_us + 1) % entity->sn_modulus;
|
||||
|
||||
return pdu_size.header_size + pdu_size.data_size;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* SDU RX functions */
|
||||
/*************************************************************************/
|
||||
|
||||
void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size,
|
||||
int sdu_id)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_sdu_t *sdu;
|
||||
|
||||
if (size > SDU_MAX) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal: SDU size too big (%d bytes)\n",
|
||||
__FILE__, __LINE__, __FUNCTION__, size);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (entity->tx_size + size > entity->tx_maxsize) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: SDU rejected, SDU buffer full\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
entity->tx_size += size;
|
||||
|
||||
sdu = rlc_new_sdu(buffer, size, sdu_id);
|
||||
rlc_sdu_list_add(&entity->tx_list, &entity->tx_end, sdu);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* time/timers */
|
||||
/*************************************************************************/
|
||||
|
||||
static void check_t_reordering(rlc_entity_um_t *entity)
|
||||
{
|
||||
int sn;
|
||||
|
||||
/* is t_reordering running and if yes has it expired? */
|
||||
if (entity->t_reordering_start == 0 ||
|
||||
entity->t_current <= entity->t_reordering_start + entity->t_reordering)
|
||||
return;
|
||||
|
||||
/* stop timer */
|
||||
entity->t_reordering_start = 0;
|
||||
|
||||
LOG_D(RLC, "%s:%d:%s: t_reordering expired\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
|
||||
/* update VR(UR) to first SN >= VR(UX) of PDU not received
|
||||
*/
|
||||
sn = entity->vr_ux;
|
||||
while (rlc_um_pdu_received(entity, sn))
|
||||
sn = (sn + 1) % entity->sn_modulus;
|
||||
entity->vr_ur = sn;
|
||||
|
||||
rlc_um_reassemble(entity, less_than_vr_ur);
|
||||
|
||||
if (sn_compare_rx(entity, entity->vr_uh, entity->vr_ur) > 0) {
|
||||
entity->t_reordering_start = entity->t_current;
|
||||
entity->vr_ux = entity->vr_uh;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_entity_um_set_time(rlc_entity_t *_entity, uint64_t now)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
|
||||
entity->t_current = now;
|
||||
|
||||
check_t_reordering(entity);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* discard/re-establishment/delete */
|
||||
/*************************************************************************/
|
||||
|
||||
void rlc_entity_um_discard_sdu(rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
/* implements 36.322 5.3 */
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
rlc_sdu_t head;
|
||||
rlc_sdu_t *cur;
|
||||
rlc_sdu_t *prev;
|
||||
|
||||
head.next = entity->tx_list;
|
||||
cur = entity->tx_list;
|
||||
prev = &head;
|
||||
|
||||
while (cur != NULL && cur->upper_layer_id != sdu_id) {
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
/* if sdu_id not found or some bytes have already been 'PDU-ized'
|
||||
* then do nothing
|
||||
*/
|
||||
if (cur == NULL || cur->next_byte != 0)
|
||||
return;
|
||||
|
||||
/* remove SDU from tx_list */
|
||||
prev->next = cur->next;
|
||||
entity->tx_list = head.next;
|
||||
if (entity->tx_end == cur) {
|
||||
if (prev != &head)
|
||||
entity->tx_end = prev;
|
||||
else
|
||||
entity->tx_end = NULL;
|
||||
}
|
||||
|
||||
rlc_free_sdu(cur);
|
||||
}
|
||||
|
||||
static void clear_entity(rlc_entity_um_t *entity)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *cur_rx;
|
||||
rlc_sdu_t *cur_tx;
|
||||
|
||||
entity->vr_ur = 0;
|
||||
entity->vr_ux = 0;
|
||||
entity->vr_uh = 0;
|
||||
|
||||
entity->vt_us = 0;
|
||||
|
||||
entity->t_current = 0;
|
||||
|
||||
entity->t_reordering_start = 0;
|
||||
|
||||
cur_rx = entity->rx_list;
|
||||
while (cur_rx != NULL) {
|
||||
rlc_rx_pdu_segment_t *p = cur_rx;
|
||||
cur_rx = cur_rx->next;
|
||||
rlc_rx_free_pdu_segment(p);
|
||||
}
|
||||
entity->rx_list = NULL;
|
||||
entity->rx_size = 0;
|
||||
|
||||
memset(&entity->reassemble, 0, sizeof(rlc_um_reassemble_t));
|
||||
|
||||
cur_tx = entity->tx_list;
|
||||
while (cur_tx != NULL) {
|
||||
rlc_sdu_t *p = cur_tx;
|
||||
cur_tx = cur_tx->next;
|
||||
rlc_free_sdu(p);
|
||||
}
|
||||
entity->tx_list = NULL;
|
||||
entity->tx_end = NULL;
|
||||
entity->tx_size = 0;
|
||||
}
|
||||
|
||||
void rlc_entity_um_reestablishment(rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
|
||||
rlc_um_reassemble(entity, less_than_vr_uh);
|
||||
|
||||
clear_entity(entity);
|
||||
}
|
||||
|
||||
void rlc_entity_um_delete(rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
clear_entity(entity);
|
||||
free(entity);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_ENTITY_UM_H_
|
||||
#define _RLC_ENTITY_UM_H_
|
||||
|
||||
#include "rlc_entity.h"
|
||||
#include "rlc_pdu.h"
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
typedef struct {
|
||||
char sdu[SDU_MAX]; /* sdu is reassembled here */
|
||||
int sdu_pos; /* next byte to put in sdu */
|
||||
|
||||
/* decoder of current PDU */
|
||||
rlc_pdu_decoder_t dec;
|
||||
int sn;
|
||||
|
||||
int sdu_head_missing;
|
||||
} rlc_um_reassemble_t;
|
||||
|
||||
typedef struct {
|
||||
rlc_entity_t common;
|
||||
|
||||
/* configuration */
|
||||
int t_reordering;
|
||||
int sn_field_length;
|
||||
|
||||
int sn_modulus; /* 1024 for sn_field_length == 10, 32 for 5 */
|
||||
int window_size; /* 512 for sn_field_length == 10, 16 for 5 */
|
||||
|
||||
/* runtime rx */
|
||||
int vr_ur;
|
||||
int vr_ux;
|
||||
int vr_uh;
|
||||
|
||||
/* runtime tx */
|
||||
int vt_us;
|
||||
|
||||
/* set to the latest know time by the user of the module. Unit: ms */
|
||||
uint64_t t_current;
|
||||
|
||||
/* timers (stores the TTI of activation, 0 means not active) */
|
||||
uint64_t t_reordering_start;
|
||||
|
||||
/* rx management */
|
||||
rlc_rx_pdu_segment_t *rx_list;
|
||||
int rx_size;
|
||||
int rx_maxsize;
|
||||
|
||||
/* reassembly management */
|
||||
rlc_um_reassemble_t reassemble;
|
||||
|
||||
/* tx management */
|
||||
rlc_sdu_t *tx_list;
|
||||
rlc_sdu_t *tx_end;
|
||||
int tx_size;
|
||||
int tx_maxsize;
|
||||
} rlc_entity_um_t;
|
||||
|
||||
void rlc_entity_um_recv_sdu(rlc_entity_t *_entity, char *buffer, int size,
|
||||
int sdu_id);
|
||||
void rlc_entity_um_recv_pdu(rlc_entity_t *entity, char *buffer, int size);
|
||||
rlc_entity_buffer_status_t rlc_entity_um_buffer_status(
|
||||
rlc_entity_t *entity, int maxsize);
|
||||
int rlc_entity_um_generate_pdu(rlc_entity_t *_entity, char *buffer, int size);
|
||||
void rlc_entity_um_set_time(rlc_entity_t *entity, uint64_t now);
|
||||
void rlc_entity_um_discard_sdu(rlc_entity_t *entity, int sdu_id);
|
||||
void rlc_entity_um_reestablishment(rlc_entity_t *entity);
|
||||
void rlc_entity_um_delete(rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_ENTITY_UM_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_pdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
/**************************************************************************/
|
||||
/* RX PDU segment and segment list */
|
||||
/**************************************************************************/
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size,
|
||||
int is_last, char *data, int data_offset)
|
||||
{
|
||||
rlc_rx_pdu_segment_t *ret = malloc(sizeof(rlc_rx_pdu_segment_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->sn = sn;
|
||||
ret->so = so;
|
||||
ret->size = size;
|
||||
ret->is_last = is_last;
|
||||
ret->next = NULL;
|
||||
|
||||
ret->data = malloc(size);
|
||||
if (ret->data == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
memcpy(ret->data, data, size);
|
||||
|
||||
ret->data_offset = data_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
free(pdu_segment->data);
|
||||
free(pdu_segment);
|
||||
}
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
rlc_rx_pdu_segment_t head;
|
||||
rlc_rx_pdu_segment_t *cur;
|
||||
rlc_rx_pdu_segment_t *prev;
|
||||
|
||||
head.next = list;
|
||||
cur = list;
|
||||
prev = &head;
|
||||
|
||||
/* order is by 'sn', if 'sn' is the same then order is by 'so' */
|
||||
while (cur != NULL) {
|
||||
/* check if 'pdu_segment' is before 'cur' in the list */
|
||||
if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 ||
|
||||
(cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) {
|
||||
break;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
prev->next = pdu_segment;
|
||||
pdu_segment->next = cur;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* TX PDU management */
|
||||
/**************************************************************************/
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void)
|
||||
{
|
||||
rlc_tx_pdu_segment_t *ret = calloc(1, sizeof(rlc_tx_pdu_segment_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
ret->retx_count = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu)
|
||||
{
|
||||
free(pdu);
|
||||
}
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list,
|
||||
rlc_tx_pdu_segment_t *pdu)
|
||||
{
|
||||
rlc_tx_pdu_segment_t head;
|
||||
rlc_tx_pdu_segment_t *cur;
|
||||
|
||||
head.next = list;
|
||||
|
||||
cur = &head;
|
||||
while (cur->next != NULL) {
|
||||
cur = cur->next;
|
||||
}
|
||||
cur->next = pdu;
|
||||
|
||||
return head.next;
|
||||
}
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment)
|
||||
{
|
||||
rlc_tx_pdu_segment_t head;
|
||||
rlc_tx_pdu_segment_t *cur;
|
||||
rlc_tx_pdu_segment_t *prev;
|
||||
|
||||
head.next = list;
|
||||
cur = list;
|
||||
prev = &head;
|
||||
|
||||
/* order is by 'sn', if 'sn' is the same then order is by 'so' */
|
||||
while (cur != NULL) {
|
||||
/* check if 'pdu_segment' is before 'cur' in the list */
|
||||
if (sn_compare(sn_compare_data, cur->sn, pdu_segment->sn) > 0 ||
|
||||
(cur->sn == pdu_segment->sn && cur->so > pdu_segment->so)) {
|
||||
break;
|
||||
}
|
||||
prev = cur;
|
||||
cur = cur->next;
|
||||
}
|
||||
prev->next = pdu_segment;
|
||||
pdu_segment->next = cur;
|
||||
return head.next;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU decoder */
|
||||
/**************************************************************************/
|
||||
|
||||
void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size)
|
||||
{
|
||||
decoder->error = 0;
|
||||
decoder->byte = 0;
|
||||
decoder->bit = 0;
|
||||
decoder->buffer = buffer;
|
||||
decoder->size = size;
|
||||
}
|
||||
|
||||
static int get_bit(rlc_pdu_decoder_t *decoder)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (decoder->byte >= decoder->size) {
|
||||
decoder->error = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = (decoder->buffer[decoder->byte] >> (7 - decoder->bit)) & 1;
|
||||
|
||||
decoder->bit++;
|
||||
if (decoder->bit == 8) {
|
||||
decoder->bit = 0;
|
||||
decoder->byte++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (count > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret <<= 1;
|
||||
ret |= get_bit(decoder);
|
||||
if (decoder->error) return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder)
|
||||
{
|
||||
if (decoder->bit) {
|
||||
decoder->bit = 0;
|
||||
decoder->byte++;
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU encoder */
|
||||
/**************************************************************************/
|
||||
|
||||
void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size)
|
||||
{
|
||||
encoder->byte = 0;
|
||||
encoder->bit = 0;
|
||||
encoder->buffer = buffer;
|
||||
encoder->size = size;
|
||||
}
|
||||
|
||||
static void put_bit(rlc_pdu_encoder_t *encoder, int bit)
|
||||
{
|
||||
if (encoder->byte == encoder->size) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, buffer full\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
encoder->buffer[encoder->byte] <<= 1;
|
||||
if (bit)
|
||||
encoder->buffer[encoder->byte] |= 1;
|
||||
|
||||
encoder->bit++;
|
||||
if (encoder->bit == 8) {
|
||||
encoder->bit = 0;
|
||||
encoder->byte++;
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count)
|
||||
{
|
||||
int i;
|
||||
int x;
|
||||
|
||||
if (count > 31) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
x = 1 << (count - 1);
|
||||
for (i = 0; i < count; i++, x >>= 1)
|
||||
put_bit(encoder, value & x);
|
||||
}
|
||||
|
||||
void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder)
|
||||
{
|
||||
while (encoder->bit)
|
||||
put_bit(encoder, 0);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_PDU_H_
|
||||
#define _RLC_PDU_H_
|
||||
|
||||
/**************************************************************************/
|
||||
/* RX PDU segment and segment list */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct rlc_rx_pdu_segment_t {
|
||||
int sn;
|
||||
int so;
|
||||
int size;
|
||||
int is_last;
|
||||
char *data;
|
||||
int data_offset;
|
||||
struct rlc_rx_pdu_segment_t *next;
|
||||
} rlc_rx_pdu_segment_t;
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_new_pdu_segment(int sn, int so, int size,
|
||||
int is_last, char *data, int data_offset);
|
||||
|
||||
void rlc_rx_free_pdu_segment(rlc_rx_pdu_segment_t *pdu_segment);
|
||||
|
||||
rlc_rx_pdu_segment_t *rlc_rx_pdu_segment_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_rx_pdu_segment_t *list, rlc_rx_pdu_segment_t *pdu_segment);
|
||||
|
||||
/**************************************************************************/
|
||||
/* TX PDU management */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct rlc_tx_pdu_segment_t {
|
||||
int sn;
|
||||
void *start_sdu; /* real type is rlc_sdu_t * */
|
||||
int sdu_start_byte; /* starting byte in 'start_sdu' */
|
||||
int so; /* starting byte of the segment in full PDU */
|
||||
int data_size; /* number of data bytes (exclude header) */
|
||||
int is_segment;
|
||||
int is_last;
|
||||
int retx_count;
|
||||
struct rlc_tx_pdu_segment_t *next;
|
||||
} rlc_tx_pdu_segment_t;
|
||||
|
||||
rlc_tx_pdu_segment_t *rlc_tx_new_pdu(void);
|
||||
void rlc_tx_free_pdu(rlc_tx_pdu_segment_t *pdu);
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_append(rlc_tx_pdu_segment_t *list,
|
||||
rlc_tx_pdu_segment_t *pdu);
|
||||
rlc_tx_pdu_segment_t *rlc_tx_pdu_list_add(
|
||||
int (*sn_compare)(void *, int, int), void *sn_compare_data,
|
||||
rlc_tx_pdu_segment_t *list, rlc_tx_pdu_segment_t *pdu_segment);
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU decoder */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int error;
|
||||
int byte; /* next byte to decode */
|
||||
int bit; /* next bit in next byte to decode */
|
||||
char *buffer;
|
||||
int size;
|
||||
} rlc_pdu_decoder_t;
|
||||
|
||||
void rlc_pdu_decoder_init(rlc_pdu_decoder_t *decoder, char *buffer, int size);
|
||||
|
||||
#define rlc_pdu_decoder_in_error(d) ((d)->error == 1)
|
||||
|
||||
int rlc_pdu_decoder_get_bits(rlc_pdu_decoder_t *decoder, int count);
|
||||
|
||||
void rlc_pdu_decoder_align(rlc_pdu_decoder_t *decoder);
|
||||
|
||||
/**************************************************************************/
|
||||
/* PDU encoder */
|
||||
/**************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
int byte; /* next byte to encode */
|
||||
int bit; /* next bit in next byte to encode */
|
||||
char *buffer;
|
||||
int size;
|
||||
} rlc_pdu_encoder_t;
|
||||
|
||||
void rlc_pdu_encoder_init(rlc_pdu_encoder_t *encoder, char *buffer, int size);
|
||||
|
||||
void rlc_pdu_encoder_put_bits(rlc_pdu_encoder_t *encoder, int value, int count);
|
||||
|
||||
void rlc_pdu_encoder_align(rlc_pdu_encoder_t *encoder);
|
||||
|
||||
#endif /* _RLC_PDU_H_ */
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_sdu.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id)
|
||||
{
|
||||
rlc_sdu_t *ret = calloc(1, sizeof(rlc_sdu_t));
|
||||
if (ret == NULL)
|
||||
goto oom;
|
||||
|
||||
ret->upper_layer_id = upper_layer_id;
|
||||
|
||||
ret->data = malloc(size);
|
||||
if (ret->data == NULL)
|
||||
goto oom;
|
||||
|
||||
memcpy(ret->data, buffer, size);
|
||||
|
||||
ret->size = size;
|
||||
|
||||
return ret;
|
||||
|
||||
oom:
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void rlc_free_sdu(rlc_sdu_t *sdu)
|
||||
{
|
||||
free(sdu->data);
|
||||
free(sdu);
|
||||
}
|
||||
|
||||
void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu)
|
||||
{
|
||||
if (*list == NULL) {
|
||||
*list = sdu;
|
||||
*end = sdu;
|
||||
return;
|
||||
}
|
||||
|
||||
(*end)->next = sdu;
|
||||
*end = sdu;
|
||||
}
|
||||
@@ -19,20 +19,21 @@
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/***************************************************************************
|
||||
mem_pool.h - description
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
#ifndef _RLC_SDU_H_
|
||||
#define _RLC_SDU_H_
|
||||
|
||||
typedef struct rlc_sdu_t {
|
||||
int upper_layer_id;
|
||||
char *data;
|
||||
int size;
|
||||
/* next_byte indicates the starting byte to use to construct a new PDU */
|
||||
int next_byte;
|
||||
int acked_bytes;
|
||||
struct rlc_sdu_t *next;
|
||||
} rlc_sdu_t;
|
||||
|
||||
***************************************************************************/
|
||||
#ifndef __MEM_POOL_H__
|
||||
# define __MEM_POOL_H__
|
||||
rlc_sdu_t *rlc_new_sdu(char *buffer, int size, int upper_layer_id);
|
||||
void rlc_free_sdu(rlc_sdu_t *sdu);
|
||||
void rlc_sdu_list_add(rlc_sdu_t **list, rlc_sdu_t **end, rlc_sdu_t *sdu);
|
||||
|
||||
# include "list.h"
|
||||
# include "mem_block.h"
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* _RLC_SDU_H_ */
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "rlc_ue_manager.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "LOG/log.h"
|
||||
|
||||
typedef struct {
|
||||
pthread_mutex_t lock;
|
||||
rlc_ue_t **ue_list;
|
||||
int ue_count;
|
||||
int enb_flag;
|
||||
} rlc_ue_manager_internal_t;
|
||||
|
||||
rlc_ue_manager_t *new_rlc_ue_manager(int enb_flag)
|
||||
{
|
||||
rlc_ue_manager_internal_t *ret;
|
||||
|
||||
ret = calloc(1, sizeof(rlc_ue_manager_internal_t));
|
||||
if (ret == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pthread_mutex_init(&ret->lock, NULL)) abort();
|
||||
ret->enb_flag = enb_flag;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rlc_manager_get_enb_flag(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
return m->enb_flag;
|
||||
}
|
||||
|
||||
void rlc_manager_lock(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
if (pthread_mutex_lock(&m->lock)) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void rlc_manager_unlock(rlc_ue_manager_t *_m)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
if (pthread_mutex_unlock(&m->lock)) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *_m, int rnti)
|
||||
{
|
||||
/* TODO: optimze */
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m->ue_count; i++)
|
||||
if (m->ue_list[i]->rnti == rnti)
|
||||
return m->ue_list[i];
|
||||
|
||||
LOG_D(RLC, "%s:%d:%s: new UE %d\n", __FILE__, __LINE__, __FUNCTION__, rnti);
|
||||
|
||||
m->ue_count++;
|
||||
m->ue_list = realloc(m->ue_list, sizeof(rlc_ue_t *) * m->ue_count);
|
||||
if (m->ue_list == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
m->ue_list[m->ue_count-1] = calloc(1, sizeof(rlc_ue_t));
|
||||
if (m->ue_list[m->ue_count-1] == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: out of memory\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
m->ue_list[m->ue_count-1]->rnti = rnti;
|
||||
|
||||
return m->ue_list[m->ue_count-1];
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_manager_remove_ue(rlc_ue_manager_t *_m, int rnti)
|
||||
{
|
||||
rlc_ue_manager_internal_t *m = _m;
|
||||
rlc_ue_t *ue;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < m->ue_count; i++)
|
||||
if (m->ue_list[i]->rnti == rnti)
|
||||
break;
|
||||
|
||||
if (i == m->ue_count) {
|
||||
LOG_D(RLC, "%s:%d:%s: warning: ue %d not found\n",
|
||||
__FILE__, __LINE__, __FUNCTION__,
|
||||
rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
ue = m->ue_list[i];
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
if (ue->srb[j] != NULL)
|
||||
ue->srb[j]->delete(ue->srb[j]);
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
if (ue->drb[j] != NULL)
|
||||
ue->drb[j]->delete(ue->drb[j]);
|
||||
|
||||
free(ue);
|
||||
|
||||
m->ue_count--;
|
||||
if (m->ue_count == 0) {
|
||||
free(m->ue_list);
|
||||
m->ue_list = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(&m->ue_list[i], &m->ue_list[i+1],
|
||||
(m->ue_count - i) * sizeof(rlc_ue_t *));
|
||||
m->ue_list = realloc(m->ue_list, m->ue_count * sizeof(rlc_ue_t *));
|
||||
if (m->ue_list == NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity)
|
||||
{
|
||||
if (srb_id < 1 || srb_id > 2) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, bad srb id\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
srb_id--;
|
||||
|
||||
if (ue->srb[srb_id] != NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, srb already present\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ue->srb[srb_id] = entity;
|
||||
}
|
||||
|
||||
/* must be called with lock acquired */
|
||||
void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity)
|
||||
{
|
||||
if (drb_id < 1 || drb_id > 5) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
drb_id--;
|
||||
|
||||
if (ue->drb[drb_id] != NULL) {
|
||||
LOG_E(RLC, "%s:%d:%s: fatal, drb already present\n",
|
||||
__FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ue->drb[drb_id] = entity;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RLC_UE_MANAGER_H_
|
||||
#define _RLC_UE_MANAGER_H_
|
||||
|
||||
#include "rlc_entity.h"
|
||||
|
||||
typedef void rlc_ue_manager_t;
|
||||
|
||||
typedef struct rlc_ue_t {
|
||||
int rnti;
|
||||
int module_id; /* necesarry for the L2 simulator - not clean, to revise */
|
||||
rlc_entity_t *srb[2];
|
||||
rlc_entity_t *drb[5];
|
||||
} rlc_ue_t;
|
||||
|
||||
/***********************************************************************/
|
||||
/* manager functions */
|
||||
/***********************************************************************/
|
||||
|
||||
rlc_ue_manager_t *new_rlc_ue_manager(int enb_flag);
|
||||
|
||||
int rlc_manager_get_enb_flag(rlc_ue_manager_t *m);
|
||||
|
||||
void rlc_manager_lock(rlc_ue_manager_t *m);
|
||||
void rlc_manager_unlock(rlc_ue_manager_t *m);
|
||||
|
||||
rlc_ue_t *rlc_manager_get_ue(rlc_ue_manager_t *m, int rnti);
|
||||
void rlc_manager_remove_ue(rlc_ue_manager_t *m, int rnti);
|
||||
|
||||
/***********************************************************************/
|
||||
/* ue functions */
|
||||
/***********************************************************************/
|
||||
|
||||
void rlc_ue_add_srb_rlc_entity(rlc_ue_t *ue, int srb_id, rlc_entity_t *entity);
|
||||
void rlc_ue_add_drb_rlc_entity(rlc_ue_t *ue, int drb_id, rlc_entity_t *entity);
|
||||
|
||||
#endif /* _RLC_UE_MANAGER_H_ */
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef _LOG_H_
|
||||
#define _LOG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG_E(x, ...) printf(__VA_ARGS__)
|
||||
#define LOG_D(x, ...) printf(__VA_ARGS__)
|
||||
#define LOG_W(x, ...) printf(__VA_ARGS__)
|
||||
|
||||
#endif /* _LOG_H_ */
|
||||
@@ -0,0 +1,32 @@
|
||||
CC=gcc
|
||||
CFLAGS=-Wall -g --coverage -I.
|
||||
|
||||
LIB=rlc_entity.o rlc_entity_am.o rlc_entity_um.o rlc_pdu.o rlc_sdu.o
|
||||
|
||||
tests:
|
||||
@./run_tests.sh
|
||||
|
||||
all: clean_run $(TEST).run
|
||||
|
||||
%.run: $(TEST).bin
|
||||
#valgrind ./$(TEST).bin > $(TEST).run_pre 2> $(TEST).valgrind
|
||||
./$(TEST).bin > $(TEST).run_pre
|
||||
grep ^TEST $(TEST).run_pre > $(TEST).run
|
||||
gunzip -c $(TEST).txt.gz > $(TEST).txt
|
||||
diff -q $(TEST).txt $(TEST).run
|
||||
|
||||
$(TEST).bin: $(TEST).o $(LIB)
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
%.o: ../%.c
|
||||
$(CC) $(CFLAGS) -I.. -c -o $@ $<
|
||||
|
||||
$(TEST).o: test.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $< -DTEST='"$(TEST).h"'
|
||||
|
||||
clean_run:
|
||||
rm -f $(TEST).run $(TEST).bin $(TEST).o
|
||||
|
||||
clean:
|
||||
rm -f *.o *.bin *.run *.run_pre *.gcov *.gcda *.gcno test*.txt a.out \
|
||||
*.valgrind
|
||||
@@ -0,0 +1,38 @@
|
||||
To run tests, simply type: make
|
||||
|
||||
Each test is made of:
|
||||
testXX.h definition of the test
|
||||
testXX.txt.gz compressed expected output of the test
|
||||
|
||||
At runtime, we generate:
|
||||
testXX.run actual output of the test
|
||||
|
||||
test.c is the test driving program.
|
||||
|
||||
Only the output lines of the test program starting with "TEST" are
|
||||
stored into testXX.txt and testXX.run.
|
||||
|
||||
A test is considered a success if testXX.txt and testXX.run are equal.
|
||||
|
||||
Only failed tests are reported.
|
||||
|
||||
How to define a new test?
|
||||
|
||||
1 - get the ID
|
||||
|
||||
Look in the file run_tests.sh, the variable test_count gives you
|
||||
the number of existing tests. The ID of your test has to be
|
||||
test_count + 1.
|
||||
|
||||
2 - create files
|
||||
|
||||
Create the file test<ID>.h containing the test, then generate test<ID>.run
|
||||
by running 'make all TEST=test<ID>' and copy test<ID>.run to test<ID>.txt.
|
||||
Then compress this file (gzip -9 test<ID>.txt). Be sure that the output
|
||||
is correct, of course.
|
||||
|
||||
For the file names, replace <ID> by the actual number of the test.
|
||||
For example, if your test ID is 47, then name the files test47.h and
|
||||
test47.txt. And run 'make all TEST=test47' to generate test47.run.
|
||||
|
||||
The available instructions for a test are described at the top of test.c.
|
||||
@@ -0,0 +1,29 @@
|
||||
/* gcc -Wall make_pdu.c -I.. ../rlc_pdu.c */
|
||||
|
||||
#include "rlc_pdu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
char out[100];
|
||||
rlc_pdu_encoder_t e;
|
||||
int i;
|
||||
|
||||
rlc_pdu_encoder_init(&e, out, 100);
|
||||
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
rlc_pdu_encoder_put_bits(&e, 0, 1); // e2
|
||||
|
||||
rlc_pdu_encoder_align(&e);
|
||||
|
||||
for (i = 0; i < e.byte; i++) printf(" %2.2x", (unsigned char)e.buffer[i]);
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
test_count=45
|
||||
|
||||
for i in `seq $test_count`
|
||||
do
|
||||
make all TEST=test$i >/dev/null 2>/dev/null
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
echo TEST $i FAILURE
|
||||
fi
|
||||
done
|
||||
@@ -0,0 +1,433 @@
|
||||
#include "../rlc_entity.h"
|
||||
#include "../rlc_entity_am.h"
|
||||
#include "../rlc_entity_um.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* ENB_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit>
|
||||
* <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold>
|
||||
* create the eNB RLC AM entity with given parameters
|
||||
*
|
||||
* UE_AM <rx_maxsize> <tx_maxsize> <t_reordering> <t_status_prohibit>
|
||||
* <t_poll_retransmit> <poll_pdu> <poll_byte> <max_retx_threshold>
|
||||
* create the UE RLC AM entity with given parameters
|
||||
*
|
||||
* ENB_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length>
|
||||
* create the eNB RLC UM entity with given parameters
|
||||
*
|
||||
* UE_UM <rx_maxsize> <tx_maxsize> <t_reordering> <sn_field_length>
|
||||
* create the UE RLC UM entity with given parameters
|
||||
*
|
||||
* TIME <time>
|
||||
* following actions to be performed at time <time>
|
||||
* <time> starts at 1
|
||||
* You must end your test definition with a line 'TIME, -1'.
|
||||
*
|
||||
* ENB_SDU <id> <size>
|
||||
* send an SDU to eNB with id <i> and size <size>
|
||||
* the SDU is [00 01 ... ff 01 ...]
|
||||
* (ie. start byte is 00 then we increment for each byte, loop if needed)
|
||||
*
|
||||
* UE_SDU <id> <size>
|
||||
* same as ENB_SDU but the SDU is sent to the UE
|
||||
*
|
||||
* ENB_PDU <size> <'size' bytes>
|
||||
* send a custom PDU from eNB to UE (eNB does not see this PDU at all)
|
||||
*
|
||||
* UE_PDU <size> <'size' bytes>
|
||||
* send a custom PDU from UE to eNB (UE does not see this PDU at all)
|
||||
*
|
||||
* ENB_PDU_SIZE <size>
|
||||
* set 'enb_pdu_size'
|
||||
*
|
||||
* UE_PDU_SIZE <size>
|
||||
* set 'ue_pdu_size'
|
||||
*
|
||||
* ENB_RECV_FAILS <fails>
|
||||
* set the 'enb_recv_fails' flag to <fails>
|
||||
* (1: recv will fail, 0: recv will succeed)
|
||||
*
|
||||
* UE_RECV_FAILS <fails>
|
||||
* same as ENB_RECV_FAILS but for 'ue_recv_fails'
|
||||
*
|
||||
* MUST_FAIL
|
||||
* to be used as first command after the first TIME to indicate
|
||||
* that the test must fail (ie. exit with non zero, crash not allowed)
|
||||
*
|
||||
* ENB_BUFFER_STATUS
|
||||
* call buffer_status for eNB and print result
|
||||
*
|
||||
* UE_BUFFER_STATUS
|
||||
* call buffer_status for UE and print result
|
||||
*
|
||||
* ENB_DISCARD_SDU <sdu ID>
|
||||
* discards given SDU
|
||||
*
|
||||
* UE_DISCARD_SDU <sdu ID>
|
||||
* discards given SDU
|
||||
*
|
||||
* RE_ESTABLISH
|
||||
* re-establish both eNB and UE
|
||||
*/
|
||||
|
||||
enum action {
|
||||
ENB_AM, UE_AM,
|
||||
ENB_UM, UE_UM,
|
||||
TIME, ENB_SDU, UE_SDU, ENB_PDU, UE_PDU,
|
||||
ENB_PDU_SIZE, UE_PDU_SIZE,
|
||||
ENB_RECV_FAILS, UE_RECV_FAILS,
|
||||
MUST_FAIL,
|
||||
ENB_BUFFER_STATUS, UE_BUFFER_STATUS,
|
||||
ENB_DISCARD_SDU, UE_DISCARD_SDU,
|
||||
RE_ESTABLISH
|
||||
};
|
||||
|
||||
int test[] = {
|
||||
/* TEST is defined at compilation time */
|
||||
#include TEST
|
||||
};
|
||||
|
||||
void deliver_sdu_enb_am(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void deliver_sdu_enb_um(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void successful_delivery_enb(void *successful_delivery_data,
|
||||
rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": SDU %d was successfully delivered.\n",
|
||||
entity->t_current, sdu_id);
|
||||
}
|
||||
|
||||
void max_retx_reached_enb(void *max_retx_reached_data, rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: ENB: %"PRIu64": max RETX reached! radio link failure!\n",
|
||||
entity->t_current);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void deliver_sdu_ue_am(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void deliver_sdu_ue_um(void *deliver_sdu_data, struct rlc_entity_t *_entity,
|
||||
char *buf, int size)
|
||||
{
|
||||
rlc_entity_um_t *entity = (rlc_entity_um_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": deliver SDU size %d [",
|
||||
entity->t_current, size);
|
||||
for (int i = 0; i < size; i++) printf(" %2.2x", (unsigned char)buf[i]);
|
||||
printf("]\n");
|
||||
}
|
||||
|
||||
void successful_delivery_ue(void *successful_delivery_data,
|
||||
rlc_entity_t *_entity, int sdu_id)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64": SDU %d was successfully delivered.\n",
|
||||
entity->t_current, sdu_id);
|
||||
}
|
||||
|
||||
void max_retx_reached_ue(void *max_retx_reached_data, rlc_entity_t *_entity)
|
||||
{
|
||||
rlc_entity_am_t *entity = (rlc_entity_am_t *)_entity;
|
||||
printf("TEST: UE: %"PRIu64", max RETX reached! radio link failure!\n",
|
||||
entity->t_current);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int test_main(void)
|
||||
{
|
||||
rlc_entity_t *enb = NULL;
|
||||
rlc_entity_t *ue = NULL;
|
||||
int i;
|
||||
int k;
|
||||
char *sdu;
|
||||
char *pdu;
|
||||
rlc_entity_buffer_status_t buffer_status;
|
||||
int enb_do_buffer_status = 0;
|
||||
int ue_do_buffer_status = 0;
|
||||
int size;
|
||||
int pos;
|
||||
int next_byte_enb = 0;
|
||||
int next_byte_ue = 0;
|
||||
int enb_recv_fails = 0;
|
||||
int ue_recv_fails = 0;
|
||||
int enb_pdu_size = 1000;
|
||||
int ue_pdu_size = 1000;
|
||||
|
||||
sdu = malloc(16001);
|
||||
pdu = malloc(3000);
|
||||
if (sdu == NULL || pdu == NULL) {
|
||||
printf("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 0; i < 16001; i++)
|
||||
sdu[i] = i & 255;
|
||||
|
||||
pos = 0;
|
||||
if (test[pos] != TIME) {
|
||||
printf("%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i = 1; i < 1000; i++) {
|
||||
if (i == test[pos+1]) {
|
||||
pos += 2;
|
||||
while (test[pos] != TIME)
|
||||
switch (test[pos]) {
|
||||
default: printf("fatal: unknown action\n"); exit(1);
|
||||
case ENB_AM:
|
||||
enb = new_rlc_entity_am(test[pos+1], test[pos+2],
|
||||
deliver_sdu_enb_am, NULL,
|
||||
successful_delivery_enb, NULL,
|
||||
max_retx_reached_enb, NULL,
|
||||
test[pos+3], test[pos+4], test[pos+5],
|
||||
test[pos+6], test[pos+7], test[pos+8]);
|
||||
pos += 9;
|
||||
break;
|
||||
case UE_AM:
|
||||
ue = new_rlc_entity_am(test[pos+1], test[pos+2],
|
||||
deliver_sdu_ue_am, NULL,
|
||||
successful_delivery_ue, NULL,
|
||||
max_retx_reached_ue, NULL,
|
||||
test[pos+3], test[pos+4], test[pos+5],
|
||||
test[pos+6], test[pos+7], test[pos+8]);
|
||||
pos += 9;
|
||||
break;
|
||||
case ENB_UM:
|
||||
enb = new_rlc_entity_um(test[pos+1], test[pos+2],
|
||||
deliver_sdu_enb_um, NULL,
|
||||
test[pos+3], test[pos+4]);
|
||||
pos += 5;
|
||||
break;
|
||||
case UE_UM:
|
||||
ue = new_rlc_entity_um(test[pos+1], test[pos+2],
|
||||
deliver_sdu_ue_um, NULL,
|
||||
test[pos+3], test[pos+4]);
|
||||
pos += 5;
|
||||
break;
|
||||
case ENB_SDU:
|
||||
for (k = 0; k < test[pos+2]; k++, next_byte_enb++)
|
||||
sdu[k] = next_byte_enb;
|
||||
printf("TEST: ENB: %d: recv_sdu (id %d): size %d: [",
|
||||
i, test[pos+1], test[pos+2]);
|
||||
for (k = 0; k < test[pos+2]; k++)
|
||||
printf(" %2.2x", (unsigned char)sdu[k]);
|
||||
printf("]\n");
|
||||
enb->recv_sdu(enb, sdu, test[pos+2], test[pos+1]);
|
||||
pos += 3;
|
||||
break;
|
||||
case UE_SDU:
|
||||
for (k = 0; k < test[pos+2]; k++, next_byte_ue++)
|
||||
sdu[k] = next_byte_ue;
|
||||
printf("TEST: UE: %d: recv_sdu (id %d): size %d: [",
|
||||
i, test[pos+1], test[pos+2]);
|
||||
for (k = 0; k < test[pos+2]; k++)
|
||||
printf(" %2.2x", (unsigned char)sdu[k]);
|
||||
printf("]\n");
|
||||
ue->recv_sdu(ue, sdu, test[pos+2], test[pos+1]);
|
||||
pos += 3;
|
||||
break;
|
||||
case ENB_PDU:
|
||||
for (k = 0; k < test[pos+1]; k++)
|
||||
pdu[k] = test[pos+2+k];
|
||||
printf("TEST: ENB: %d: custom PDU: size %d: [", i, test[pos+1]);
|
||||
for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!ue_recv_fails)
|
||||
ue->recv_pdu(ue, pdu, test[pos+1]);
|
||||
pos += 2 + test[pos+1];
|
||||
break;
|
||||
case UE_PDU:
|
||||
for (k = 0; k < test[pos+1]; k++)
|
||||
pdu[k] = test[pos+2+k];
|
||||
printf("TEST: UE: %d: custom PDU: size %d: [", i, test[pos+1]);
|
||||
for (k = 0; k < test[pos+1]; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!enb_recv_fails)
|
||||
enb->recv_pdu(enb, pdu, test[pos+1]);
|
||||
pos += 2 + test[pos+1];
|
||||
break;
|
||||
case ENB_PDU_SIZE:
|
||||
enb_pdu_size = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_PDU_SIZE:
|
||||
ue_pdu_size = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case ENB_RECV_FAILS:
|
||||
enb_recv_fails = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_RECV_FAILS:
|
||||
ue_recv_fails = test[pos+1];
|
||||
pos += 2;
|
||||
break;
|
||||
case MUST_FAIL:
|
||||
/* do nothing, only used by caller */
|
||||
pos++;
|
||||
break;
|
||||
case ENB_BUFFER_STATUS:
|
||||
enb_do_buffer_status = 1;
|
||||
pos++;
|
||||
break;
|
||||
case UE_BUFFER_STATUS:
|
||||
ue_do_buffer_status = 1;
|
||||
pos++;
|
||||
break;
|
||||
case ENB_DISCARD_SDU:
|
||||
printf("TEST: ENB: %d: discard SDU %d\n", i, test[pos+1]);
|
||||
enb->discard_sdu(enb, test[pos+1]);
|
||||
pos += 2;
|
||||
break;
|
||||
case UE_DISCARD_SDU:
|
||||
printf("TEST: UE: %d: discard SDU %d\n", i, test[pos+1]);
|
||||
ue->discard_sdu(ue, test[pos+1]);
|
||||
pos += 2;
|
||||
break;
|
||||
case RE_ESTABLISH:
|
||||
printf("TEST: %d: re-establish eNB and UE\n", i);
|
||||
enb->reestablishment(enb);
|
||||
ue->reestablishment(ue);
|
||||
pos++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enb->set_time(enb, i);
|
||||
ue->set_time(ue, i);
|
||||
|
||||
if (enb_do_buffer_status) {
|
||||
enb_do_buffer_status = 0;
|
||||
buffer_status = enb->buffer_status(enb, enb_pdu_size);
|
||||
printf("TEST: ENB: %d: buffer_status: status_size %d tx_size %d retx_size %d\n",
|
||||
i,
|
||||
buffer_status.status_size,
|
||||
buffer_status.tx_size,
|
||||
buffer_status.retx_size);
|
||||
}
|
||||
|
||||
size = enb->generate_pdu(enb, pdu, enb_pdu_size);
|
||||
if (size) {
|
||||
printf("TEST: ENB: %d: generate_pdu: size %d: [", i, size);
|
||||
for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!ue_recv_fails)
|
||||
ue->recv_pdu(ue, pdu, size);
|
||||
}
|
||||
|
||||
if (ue_do_buffer_status) {
|
||||
ue_do_buffer_status = 0;
|
||||
buffer_status = ue->buffer_status(ue, ue_pdu_size);
|
||||
printf("TEST: UE: %d: buffer_status: status_size %d tx_size %d retx_size %d\n",
|
||||
i,
|
||||
buffer_status.status_size,
|
||||
buffer_status.tx_size,
|
||||
buffer_status.retx_size);
|
||||
}
|
||||
|
||||
size = ue->generate_pdu(ue, pdu, ue_pdu_size);
|
||||
if (size) {
|
||||
printf("TEST: UE: %d: generate_pdu: size %d: [", i, size);
|
||||
for (k = 0; k < size; k++) printf(" %2.2x", (unsigned char)pdu[k]);
|
||||
printf("]\n");
|
||||
if (!enb_recv_fails)
|
||||
enb->recv_pdu(enb, pdu, size);
|
||||
}
|
||||
}
|
||||
|
||||
enb->delete(enb);
|
||||
ue->delete(ue);
|
||||
|
||||
free(sdu);
|
||||
free(pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("options:\n");
|
||||
printf(" -no-fork\n");
|
||||
printf(" don't fork (to ease debugging with gdb)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int n, char **v)
|
||||
{
|
||||
int must_fail = 0;
|
||||
int son;
|
||||
int status;
|
||||
int i;
|
||||
int no_fork = 0;
|
||||
|
||||
for (i = 1; i < n; i++) {
|
||||
if (!strcmp(v[i], "-no-fork")) { no_fork = 1; continue; }
|
||||
usage();
|
||||
}
|
||||
|
||||
if (test[2] == MUST_FAIL)
|
||||
must_fail = 1;
|
||||
|
||||
if (no_fork) return test_main();
|
||||
|
||||
son = fork();
|
||||
if (son == -1) {
|
||||
perror("fork");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (son == 0)
|
||||
return test_main();
|
||||
|
||||
if (wait(&status) == -1) {
|
||||
perror("wait");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* child must quit properly */
|
||||
if (!WIFEXITED(status))
|
||||
return 1;
|
||||
|
||||
/* child must fail if expected to */
|
||||
if (must_fail && WEXITSTATUS(status) == 0)
|
||||
return 1;
|
||||
|
||||
/* child must not fail if not expected to */
|
||||
if (!must_fail && WEXITSTATUS(status))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* basic am test:
|
||||
* at time 1, eNB receives an SDU of 10 bytes
|
||||
* at time 10, UE receives an SDU of 5 bytes
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 10,
|
||||
UE_SDU, 0, 5,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* rlc am test resegmentation of PDU segment with several SDUs
|
||||
* eNB sends 3 SDUs [1..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 100,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* rlc am test function rlc_am_reassemble_next_segment
|
||||
* in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset)
|
||||
* + r->sdu_len
|
||||
* when case 'if (r->e)' is false
|
||||
* eNB sends 3 SDUs [1..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then UE reception on
|
||||
* then custom PDUs, first a small part of head of original PDU
|
||||
* then a bigger part, covering the first part
|
||||
* so that the beginning of this part triggers the 'while'
|
||||
* then eNB reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 95,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 99,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_PDU, 14, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
TIME, 100,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, 134,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* rlc am test function rlc_am_reassemble_next_segment
|
||||
* in r->pdu_byte >= r->so + (r->sdu_offset - r->start->data_offset)
|
||||
* + r->sdu_len
|
||||
* when case 'if (r->e)' is true
|
||||
* eNB sends 4 SDUs [1..5] [6..10] [11.20] [21..30], not received
|
||||
* eNB retx with smaller PDUs, not received
|
||||
* eNB retx with still smaller PDUs, not received
|
||||
* then UE reception on
|
||||
* then custom PDUs, first a small part of head of original PDU
|
||||
* then a bigger part, covering the first part
|
||||
* so that the beginning of this part triggers the 'while'
|
||||
* then eNB reception on, all passes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 5,
|
||||
ENB_SDU, 1, 5,
|
||||
ENB_SDU, 2, 10,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, 2,
|
||||
ENB_PDU_SIZE, 25,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 15,
|
||||
TIME, 99,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_PDU, 15, 0xec, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||
ENB_PDU, 25, 0xec, 0x00, 0x00, 0x00, 0x80, 0x50, 0x05, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
|
||||
TIME, 100,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* rlc am test function process_received_ack with something in
|
||||
* the retransmit_list to put in the ack_list
|
||||
* eNB sends 4 PDUs, not received
|
||||
* eNB retransmits 4th PDU, received, ACKed with NACKs for PDU 1, 2, 3
|
||||
* UE receives custom PDU for 1, 2, 3, 4 (they are not sent by eNB)
|
||||
* (4 resent to have the P bit set)
|
||||
* UE sends ACK for all, eNB puts from retransmit_list to ack_list
|
||||
*
|
||||
* Maybe not very realistic (custom PDUs).
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_PDU_SIZE, 12,
|
||||
ENB_SDU, 0, 10,
|
||||
ENB_SDU, 1, 10,
|
||||
ENB_SDU, 2, 10,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, 10,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, 87,
|
||||
ENB_PDU, 12, 0x80, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
||||
ENB_PDU, 12, 0x80, 0x01, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
|
||||
ENB_PDU, 12, 0x80, 0x02, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
|
||||
ENB_PDU, 12, 0xa0, 0x03, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* rlc am test max_retx_reached
|
||||
* eNB sends PDU, never received
|
||||
*/
|
||||
TIME, 1,
|
||||
MUST_FAIL,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_SDU, 0, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* rlc am test so_overlap
|
||||
* eNB sends PDU, not received
|
||||
* then PDU is segmented in 3 parts, part 1 & 3 not received,
|
||||
* then we generate a fake control PDU from UE to eNB that
|
||||
* contains NACK with so_start/so_end being inside part 2.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 2, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e2
|
||||
* rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start
|
||||
* rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 8,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_SDU, 1, 30,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 48,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 49,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 50,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 8, 0x00, 0x0a, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00,
|
||||
TIME, 70,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* rlc am test process_received_nack
|
||||
* Same events as for test15 except the fake control PDU
|
||||
* does not ACK anything (ack_sn = 0) so that PDU in the
|
||||
* wait_list are not transfered into the ack_list and
|
||||
* we cover the case:
|
||||
* } else {
|
||||
* prev = cur;
|
||||
* cur = cur->next;
|
||||
* }
|
||||
* for the wait_list case.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e2
|
||||
* rlc_pdu_encoder_put_bits(&e, 14, 15); // so_start
|
||||
* rlc_pdu_encoder_put_bits(&e, 16, 15); // so_end
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 8,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_SDU, 1, 30,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 48,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 49,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 50,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 8, 0x00, 0x02, 0x00, 0xa0, 0x03, 0x80, 0x08, 0x00,
|
||||
TIME, 70,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* rlc am test function process_received_nack
|
||||
* case 'check that VT(A) <= sn < VT(S)'
|
||||
* eNB sends PDU, not received, resends segmented
|
||||
* we generate a fake control PDU containing nack_sn == 10,
|
||||
* to fail the 'check ...' and cover the return.
|
||||
*
|
||||
* code to generate fake control PDU:
|
||||
* rlc_pdu_encoder_init(&e, out, 100);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 3); // CPT
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // ack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 10, 10); // nack_sn
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e1
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // e2
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 30,
|
||||
ENB_RECV_FAILS, 1,
|
||||
TIME, 20,
|
||||
ENB_PDU_SIZE, 14,
|
||||
TIME, 60,
|
||||
ENB_RECV_FAILS, 0,
|
||||
UE_PDU, 4, 0x00, 0x02, 0x05, 0x00,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* test rlc am simulate rx pdu buffer full
|
||||
* eNB sends too big PDU to UE, rejected because buffer full
|
||||
*/
|
||||
TIME, 1,
|
||||
MUST_FAIL,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 10, 10, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* test rlc am bad PDU
|
||||
* eNB sends custom PDUs to UE, all of them are wrong for a reason or another
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
/* data PDU, LI == 0
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // RF
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // P
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 2); // FI
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // E
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // SN
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // E
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 11); // LI
|
||||
*/
|
||||
ENB_PDU, 4, 0x84, 0x00, 0x00, 0x00,
|
||||
/* data PDU, no data
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // RF
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // P
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 2); // FI
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // E
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // SN
|
||||
*/
|
||||
ENB_PDU, 2, 0x80, 0x00,
|
||||
/* data PDU, LI == 2 > data size == 1
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // RF
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // P
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 2); // FI
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // E
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 10); // SN
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // E
|
||||
* rlc_pdu_encoder_put_bits(&e, 2, 11); // LI
|
||||
* rlc_pdu_encoder_align(&e);
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 8); // 1 byte of data
|
||||
*/
|
||||
ENB_PDU, 5, 0x84, 0x00, 0x00, 0x20, 0x00,
|
||||
/* control PDU, CPT != 0
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 2, 3); // CPT
|
||||
*/
|
||||
ENB_PDU, 1, 0x20,
|
||||
/* data PDU, but only 1 byte
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // D/C
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // RF
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 1); // P
|
||||
* rlc_pdu_encoder_put_bits(&e, 0, 2); // FI
|
||||
* rlc_pdu_encoder_put_bits(&e, 1, 1); // E
|
||||
*/
|
||||
ENB_PDU, 1, 0x84,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* basic am test:
|
||||
* at time 1, eNB receives an SDU of 16000 bytes
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 16000,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* rlc am test full tx window
|
||||
* for that eNB sends a lot of small PDUs
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 513,
|
||||
ENB_PDU_SIZE, 3,
|
||||
ENB_RECV_FAILS, 1,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 511,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 512,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 513,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 557,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 558,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 559,
|
||||
ENB_BUFFER_STATUS,
|
||||
TIME, 600,
|
||||
ENB_BUFFER_STATUS,
|
||||
ENB_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* rlc am test big SDU (size > 2047)
|
||||
* first generate SDU with exactly 2047 bytes
|
||||
* later on generate SDU with exactly 2048 bytes
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 20,
|
||||
ENB_SDU, 1, 2047,
|
||||
ENB_SDU, 2, 20,
|
||||
ENB_PDU_SIZE, 2200,
|
||||
TIME, 10,
|
||||
ENB_SDU, 3, 20,
|
||||
ENB_SDU, 4, 2048,
|
||||
ENB_SDU, 5, 20,
|
||||
TIME, -1
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* am test: ask for retx with TX buffer too small
|
||||
* then ask for status with buffer too small
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 100,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 47,
|
||||
ENB_PDU_SIZE, 4,
|
||||
ENB_BUFFER_STATUS,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 48,
|
||||
ENB_PDU_SIZE, 1000,
|
||||
UE_PDU_SIZE, 1,
|
||||
UE_BUFFER_STATUS,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 49,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, 50,
|
||||
UE_PDU_SIZE, 1000,
|
||||
UE_BUFFER_STATUS,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* am test: basic test with poll_byte == 1
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, 1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, 1, 4,
|
||||
ENB_SDU, 0, 30,
|
||||
ENB_PDU_SIZE, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* am test: basic test with poll_pdu == 2
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, 2, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, 2, -1, 4,
|
||||
ENB_SDU, 0, 50,
|
||||
ENB_PDU_SIZE, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* am test: reject SDU because not enough room in rx buffer
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 10, 10, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 10, 10, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 50,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* am test: test function check_t_poll_retransmit
|
||||
* case 'PDU with SN = VT(S)-1 not found?'
|
||||
* eNB sends some PDUs, UE receives none
|
||||
* then UE receives the first retransmitted PDU and nothing more
|
||||
* until poll retransmit occurs again in the eNB to trigger the case
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
ENB_SDU, 1, 10,
|
||||
TIME, 3,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 4,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, 50,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, 51,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 100,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* am test: test function check_t_poll_retransmit
|
||||
* case 'do we meet conditions of 36.322 5.2.2.3?'
|
||||
* eNB sends one PDU, UE does not receive
|
||||
* just before calling check_t_poll_retransmit, eNB receives a new SDU
|
||||
* for the function 'check_poll_after_pdu_assembly' to fail
|
||||
* then UE receives all what eNB sends
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 47,
|
||||
ENB_SDU, 1, 10,
|
||||
UE_RECV_FAILS, 0,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* am test: test function check_t_reordering,
|
||||
* case 'update VR(MS) to first SN >= VR(X) for which not
|
||||
* all PDU segments have been received'
|
||||
* eNB sends 3 PDUs, first not received, two others received
|
||||
* later on, everything is received
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_SDU, 1, 10,
|
||||
TIME, 3,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* am test: test function check_t_reordering,
|
||||
* case 'VR(H) > VR(MS)'
|
||||
* eNB sends 4 PDUs, only 1st and 3rd are received
|
||||
* later on, everything is received
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 10,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 2,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_SDU, 1, 10,
|
||||
TIME, 3,
|
||||
UE_RECV_FAILS, 1,
|
||||
ENB_SDU, 2, 10,
|
||||
TIME, 4,
|
||||
UE_RECV_FAILS, 0,
|
||||
ENB_SDU, 3, 10,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* basic am test:
|
||||
* at time 1, eNB receives an SDU of 16001 bytes
|
||||
*/
|
||||
|
||||
TIME, 1,
|
||||
MUST_FAIL,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 16001,
|
||||
TIME, -1
|
||||
Binary file not shown.
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* am test: test function generate_status
|
||||
* enter the while loop 'go to highest full sn+1 for ACK'
|
||||
* eNB sends several PDUs, only the last is received
|
||||
* UE sends status PDU of a chosen size that let the code enter the while
|
||||
*/
|
||||
TIME, 1,
|
||||
ENB_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
UE_AM, 100000, 100000, 35, 0, 45, -1, -1, 4,
|
||||
ENB_SDU, 0, 70,
|
||||
ENB_PDU_SIZE, 12,
|
||||
UE_RECV_FAILS, 1,
|
||||
TIME, 7,
|
||||
UE_RECV_FAILS, 0,
|
||||
UE_PDU_SIZE, 12,
|
||||
TIME, -1
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user