/******************************************************************************* 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. *******************************************************************************/ /*! \file flexran_agent_mac.c * \brief FlexRAN agent message handler for MAC layer * \author Xenofon Foukas, Mohamed Kassem and Navid Nikaein * \date 2016 * \version 0.1 */ #include "flexran_agent_mac.h" #include "flexran_agent_extern.h" #include "flexran_agent_common.h" #include "flexran_agent_mac_internal.h" #include "LAYER2/MAC/proto.h" #include "LAYER2/MAC/flexran_agent_mac_proto.h" #include "LAYER2/MAC/flexran_agent_scheduler_dlsch_ue_remote.h" #include "liblfds700.h" #include "log.h" /*Flags showing if a mac agent has already been registered*/ unsigned int mac_agent_registered[NUM_MAX_ENB]; /*Array containing the Agent-MAC interfaces*/ AGENT_MAC_xface *agent_mac_xface[NUM_MAX_ENB]; /* Ringbuffer related structs used for maintaining the dl mac config messages */ //message_queue_t *dl_mac_config_queue; struct lfds700_misc_prng_state ps[NUM_MAX_ENB]; struct lfds700_ringbuffer_element *dl_mac_config_array[NUM_MAX_ENB]; struct lfds700_ringbuffer_state ringbuffer_state[NUM_MAX_ENB]; int flexran_agent_mac_handle_stats(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg){ // TODO: Must deal with sanitization of input // TODO: Must check if RNTIs and cell ids of the request actually exist // TODO: Must resolve conflicts among stats requests int i; void *buffer; int size; err_code_t err_code; xid_t xid; uint32_t usec_interval, sec_interval; //TODO: We do not deal with multiple CCs at the moment and eNB id is 0 int cc_id = 0; int enb_id = mod_id; //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; //UE_list_t *eNB_UE_list= &eNB->UE_list; report_config_t report_config; uint32_t ue_flags = 0; uint32_t c_flags = 0; Protocol__FlexranMessage *input = (Protocol__FlexranMessage *)params; Protocol__FlexStatsRequest *stats_req = input->stats_request_msg; xid = (stats_req->header)->xid; // Check the type of request that is made switch(stats_req->body_case) { case PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST: ; Protocol__FlexCompleteStatsRequest *comp_req = stats_req->complete_stats_request; if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_OFF) { /*Disable both periodic and continuous updates*/ flexran_agent_disable_cont_mac_stats_update(mod_id); flexran_agent_destroy_timer_by_task_id(xid); *msg = NULL; return 0; } else { //One-off, periodical or continuous reporting //Set the proper flags ue_flags = comp_req->ue_report_flags; c_flags = comp_req->cell_report_flags; //Create a list of all eNB RNTIs and cells //Set the number of UEs and create list with their RNTIs stats configs report_config.nr_ue = flexran_get_num_ues(mod_id); //eNB_UE_list->num_UEs report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); if (report_config.ue_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } for (i = 0; i < report_config.nr_ue; i++) { report_config.ue_report_type[i].ue_rnti = flexran_get_ue_crnti(enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].crnti; report_config.ue_report_type[i].ue_report_flags = ue_flags; } //Set the number of CCs and create a list with the cell stats configs report_config.nr_cc = MAX_NUM_CCs; report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); if (report_config.cc_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } for (i = 0; i < report_config.nr_cc; i++) { //TODO: Must fill in the proper cell ids report_config.cc_report_type[i].cc_id = i; report_config.cc_report_type[i].cc_report_flags = c_flags; } /* Check if request was periodical */ if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_PERIODICAL) { /* Create a one off flexran message as an argument for the periodical task */ Protocol__FlexranMessage *timer_msg; stats_request_config_t request_config; request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; request_config.period = 0; /* Need to make sure that the ue flags are saved (Bug) */ if (report_config.nr_ue == 0) { report_config.nr_ue = 1; report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); if (report_config.ue_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } report_config.ue_report_type[0].ue_rnti = 0; // Dummy value report_config.ue_report_type[0].ue_report_flags = ue_flags; } request_config.config = &report_config; flexran_agent_mac_stats_request(enb_id, xid, &request_config, &timer_msg); /* Create a timer */ long timer_id = 0; flexran_agent_timer_args_t *timer_args; timer_args = malloc(sizeof(flexran_agent_timer_args_t)); memset (timer_args, 0, sizeof(flexran_agent_timer_args_t)); timer_args->mod_id = enb_id; timer_args->msg = timer_msg; /*Convert subframes to usec time*/ usec_interval = 1000*comp_req->sf; sec_interval = 0; /*add seconds if required*/ if (usec_interval >= 1000*1000) { sec_interval = usec_interval/(1000*1000); usec_interval = usec_interval%(1000*1000); } flexran_agent_create_timer(sec_interval, usec_interval, FLEXRAN_AGENT_DEFAULT, enb_id, FLEXRAN_AGENT_TIMER_TYPE_PERIODIC, xid, flexran_agent_handle_timed_task,(void*) timer_args, &timer_id); } else if (comp_req->report_frequency == PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_CONTINUOUS) { /*If request was for continuous updates, disable the previous configuration and set up a new one*/ flexran_agent_disable_cont_mac_stats_update(mod_id); stats_request_config_t request_config; request_config.report_type = PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS; request_config.report_frequency = PROTOCOL__FLEX_STATS_REPORT_FREQ__FLSRF_ONCE; request_config.period = 0; /* Need to make sure that the ue flags are saved (Bug) */ if (report_config.nr_ue == 0) { report_config.nr_ue = 1; report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t)); if (report_config.ue_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } report_config.ue_report_type[0].ue_rnti = 0; // Dummy value report_config.ue_report_type[0].ue_report_flags = ue_flags; } request_config.config = &report_config; flexran_agent_enable_cont_mac_stats_update(enb_id, xid, &request_config); } } break; case PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST:; Protocol__FlexCellStatsRequest *cell_req = stats_req->cell_stats_request; // UE report config will be blank report_config.nr_ue = 0; report_config.ue_report_type = NULL; report_config.nr_cc = cell_req->n_cell; report_config.cc_report_type = (cc_report_type_t *) malloc(sizeof(cc_report_type_t) * report_config.nr_cc); if (report_config.cc_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } for (i = 0; i < report_config.nr_cc; i++) { //TODO: Must fill in the proper cell ids report_config.cc_report_type[i].cc_id = cell_req->cell[i]; report_config.cc_report_type[i].cc_report_flags = cell_req->flags; } break; case PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST:; Protocol__FlexUeStatsRequest *ue_req = stats_req->ue_stats_request; // Cell report config will be blank report_config.nr_cc = 0; report_config.cc_report_type = NULL; report_config.nr_ue = ue_req->n_rnti; report_config.ue_report_type = (ue_report_type_t *) malloc(sizeof(ue_report_type_t) * report_config.nr_ue); if (report_config.ue_report_type == NULL) { // TODO: Add appropriate error code err_code = -100; goto error; } for (i = 0; i < report_config.nr_ue; i++) { report_config.ue_report_type[i].ue_rnti = ue_req->rnti[i]; report_config.ue_report_type[i].ue_report_flags = ue_req->flags; } break; default: //TODO: Add appropriate error code err_code = -100; goto error; } if (flexran_agent_mac_stats_reply(enb_id, xid, &report_config, msg) < 0 ){ err_code = PROTOCOL__FLEXRAN_ERR__MSG_BUILD; goto error; } free(report_config.ue_report_type); free(report_config.cc_report_type); return 0; error : LOG_E(FLEXRAN_AGENT, "errno %d occured\n", err_code); return err_code; } int flexran_agent_mac_stats_request(mid_t mod_id, xid_t xid, const stats_request_config_t *report_config, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REQUEST, &header) != 0) goto error; Protocol__FlexStatsRequest *stats_request_msg; stats_request_msg = malloc(sizeof(Protocol__FlexStatsRequest)); if(stats_request_msg == NULL) goto error; protocol__flex_stats_request__init(stats_request_msg); stats_request_msg->header = header; stats_request_msg->type = report_config->report_type; stats_request_msg->has_type = 1; switch (report_config->report_type) { case PROTOCOL__FLEX_STATS_TYPE__FLST_COMPLETE_STATS: stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_COMPLETE_STATS_REQUEST; Protocol__FlexCompleteStatsRequest *complete_stats; complete_stats = malloc(sizeof(Protocol__FlexCompleteStatsRequest)); if(complete_stats == NULL) goto error; protocol__flex_complete_stats_request__init(complete_stats); complete_stats->report_frequency = report_config->report_frequency; complete_stats->has_report_frequency = 1; complete_stats->sf = report_config->period; complete_stats->has_sf = 1; complete_stats->has_cell_report_flags = 1; complete_stats->has_ue_report_flags = 1; if (report_config->config->nr_cc > 0) { complete_stats->cell_report_flags = report_config->config->cc_report_type[0].cc_report_flags; } if (report_config->config->nr_ue > 0) { complete_stats->ue_report_flags = report_config->config->ue_report_type[0].ue_report_flags; } stats_request_msg->complete_stats_request = complete_stats; break; case PROTOCOL__FLEX_STATS_TYPE__FLST_CELL_STATS: stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST; Protocol__FlexCellStatsRequest *cell_stats; cell_stats = malloc(sizeof(Protocol__FlexCellStatsRequest)); if(cell_stats == NULL) goto error; protocol__flex_cell_stats_request__init(cell_stats); cell_stats->n_cell = report_config->config->nr_cc; cell_stats->has_flags = 1; if (cell_stats->n_cell > 0) { uint32_t *cells; cells = (uint32_t *) malloc(sizeof(uint32_t)*cell_stats->n_cell); for (i = 0; i < cell_stats->n_cell; i++) { cells[i] = report_config->config->cc_report_type[i].cc_id; } cell_stats->cell = cells; cell_stats->flags = report_config->config->cc_report_type[i].cc_report_flags; } stats_request_msg->cell_stats_request = cell_stats; break; case PROTOCOL__FLEX_STATS_TYPE__FLST_UE_STATS: stats_request_msg->body_case = PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST; Protocol__FlexUeStatsRequest *ue_stats; ue_stats = malloc(sizeof(Protocol__FlexUeStatsRequest)); if(ue_stats == NULL) goto error; protocol__flex_ue_stats_request__init(ue_stats); ue_stats->n_rnti = report_config->config->nr_ue; ue_stats->has_flags = 1; if (ue_stats->n_rnti > 0) { uint32_t *ues; ues = (uint32_t *) malloc(sizeof(uint32_t)*ue_stats->n_rnti); for (i = 0; i < ue_stats->n_rnti; i++) { ues[i] = report_config->config->ue_report_type[i].ue_rnti; } ue_stats->rnti = ues; ue_stats->flags = report_config->config->ue_report_type[i].ue_report_flags; } stats_request_msg->ue_stats_request = ue_stats; break; default: goto error; } *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->stats_request_msg = stats_request_msg; return 0; error: // TODO: Need to make proper error handling if (header != NULL) free(header); if (stats_request_msg != NULL) free(stats_request_msg); if(*msg != NULL) free(*msg); //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_destroy_stats_request(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REQUEST_MSG) goto error; free(msg->stats_request_msg->header); if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_CELL_STATS_REQUEST) { free(msg->stats_request_msg->cell_stats_request->cell); } if (msg->stats_request_msg->body_case == PROTOCOL__FLEX_STATS_REQUEST__BODY_UE_STATS_REQUEST) { free(msg->stats_request_msg->ue_stats_request->rnti); } free(msg->stats_request_msg); free(msg); return 0; error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_stats_reply(mid_t mod_id, xid_t xid, const report_config_t *report_config, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i, j, k; int cc_id = 0; int enb_id = mod_id; //eNB_MAC_INST *eNB = &eNB_mac_inst[enb_id]; //UE_list_t *eNB_UE_list= &eNB->UE_list; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_STATS_REPLY, &header) != 0) goto error; Protocol__FlexStatsReply *stats_reply_msg; stats_reply_msg = malloc(sizeof(Protocol__FlexStatsReply)); if (stats_reply_msg == NULL) goto error; protocol__flex_stats_reply__init(stats_reply_msg); stats_reply_msg->header = header; stats_reply_msg->n_ue_report = report_config->nr_ue; stats_reply_msg->n_cell_report = report_config->nr_cc; Protocol__FlexUeStatsReport **ue_report; Protocol__FlexCellStatsReport **cell_report; /* Allocate memory for list of UE reports */ if (report_config->nr_ue > 0) { ue_report = malloc(sizeof(Protocol__FlexUeStatsReport *) * report_config->nr_ue); if (ue_report == NULL) goto error; for (i = 0; i < report_config->nr_ue; i++) { ue_report[i] = malloc(sizeof(Protocol__FlexUeStatsReport)); protocol__flex_ue_stats_report__init(ue_report[i]); ue_report[i]->rnti = report_config->ue_report_type[i].ue_rnti; ue_report[i]->has_rnti = 1; ue_report[i]->flags = report_config->ue_report_type[i].ue_report_flags; ue_report[i]->has_flags = 1; /* Check the types of reports that need to be constructed based on flag values */ /* Check flag for creation of buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_BSR) { ue_report[i]->n_bsr = 4; uint32_t *elem; elem = (uint32_t *) malloc(sizeof(uint32_t)*ue_report[i]->n_bsr); if (elem == NULL) goto error; for (j = 0; j++; j < ue_report[i]->n_bsr) { // NN: we need to know the cc_id here, consider the first one elem[j] = flexran_get_ue_bsr (enb_id, i, j); } ue_report[i]->bsr = elem; } /* Check flag for creation of PRH report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PRH) { ue_report[i]->phr = flexran_get_ue_phr (enb_id, i); // eNB_UE_list->UE_template[UE_PCCID(enb_id,i)][i].phr_info; ue_report[i]->has_phr = 1; } /* Check flag for creation of RLC buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RLC_BS) { ue_report[i]->n_rlc_report = 3; // Set this to the number of LCs for this UE. This needs to be generalized for for LCs Protocol__FlexRlcBsr ** rlc_reports; rlc_reports = malloc(sizeof(Protocol__FlexRlcBsr *) * ue_report[i]->n_rlc_report); if (rlc_reports == NULL) goto error; // NN: see LAYER2/openair2_proc.c for rlc status for (j = 0; j < ue_report[i]->n_rlc_report; j++) { rlc_reports[j] = malloc(sizeof(Protocol__FlexRlcBsr)); if (rlc_reports[j] == NULL) goto error; protocol__flex_rlc_bsr__init(rlc_reports[j]); rlc_reports[j]->lc_id = j+1; rlc_reports[j]->has_lc_id = 1; rlc_reports[j]->tx_queue_size = flexran_get_tx_queue_size(enb_id,i,j+1); rlc_reports[j]->has_tx_queue_size = 1; //TODO:Set tx queue head of line delay in ms rlc_reports[j]->tx_queue_hol_delay = 100; rlc_reports[j]->has_tx_queue_hol_delay = 0; //TODO:Set retransmission queue size in bytes rlc_reports[j]->retransmission_queue_size = 10; rlc_reports[j]->has_retransmission_queue_size = 0; //TODO:Set retransmission queue head of line delay in ms rlc_reports[j]->retransmission_queue_hol_delay = 100; rlc_reports[j]->has_retransmission_queue_hol_delay = 0; //TODO:Set current size of the pending message in bytes rlc_reports[j]->status_pdu_size = 100; rlc_reports[j]->has_status_pdu_size = 0; } // Add RLC buffer status reports to the full report if (ue_report[i]->n_rlc_report > 0) ue_report[i]->rlc_report = rlc_reports; } /* Check flag for creation of MAC CE buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_MAC_CE_BS) { // TODO: Fill in the actual MAC CE buffer status report ue_report[i]->pending_mac_ces = (flexran_get_MAC_CE_bitmap_TA(enb_id,i,0) | (0 << 1) | (0 << 2) | (0 << 3)) & 15; /* Use as bitmap. Set one or more of the; /* Use as bitmap. Set one or more of the PROTOCOL__FLEX_CE_TYPE__FLPCET_ values found in stats_common.pb-c.h. See flex_ce_type in FlexRAN specification */ ue_report[i]->has_pending_mac_ces = 1; } /* Check flag for creation of DL CQI report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { // TODO: Fill in the actual DL CQI report for the UE based on its configuration Protocol__FlexDlCqiReport * dl_report; dl_report = malloc(sizeof(Protocol__FlexDlCqiReport)); if (dl_report == NULL) goto error; protocol__flex_dl_cqi_report__init(dl_report); dl_report->sfn_sn = flexran_get_sfn_sf(enb_id); dl_report->has_sfn_sn = 1; //Set the number of DL CQI reports for this UE. One for each CC dl_report->n_csi_report = flexran_get_active_CC(enb_id,i); //Create the actual CSI reports. Protocol__FlexDlCsi **csi_reports; csi_reports = malloc(sizeof(Protocol__FlexDlCsi *)*dl_report->n_csi_report); if (csi_reports == NULL) goto error; for (j = 0; j < dl_report->n_csi_report; j++) { csi_reports[j] = malloc(sizeof(Protocol__FlexDlCsi)); if (csi_reports[j] == NULL) goto error; protocol__flex_dl_csi__init(csi_reports[j]); //The servCellIndex for this report csi_reports[j]->serv_cell_index = j; csi_reports[j]->has_serv_cell_index = 1; //The rank indicator value for this cc csi_reports[j]->ri = flexran_get_current_RI(enb_id,i,j); csi_reports[j]->has_ri = 1; //TODO: the type of CSI report based on the configuration of the UE //For now we only support type P10, which only needs a wideband value //The full set of types can be found in stats_common.pb-c.h and //in the FlexRAN specifications csi_reports[j]->type = PROTOCOL__FLEX_CSI_TYPE__FLCSIT_P10; csi_reports[j]->has_type = 1; csi_reports[j]->report_case = PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI; if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI){ Protocol__FlexCsiP10 *csi10; csi10 = malloc(sizeof(Protocol__FlexCsiP10)); if (csi10 == NULL) goto error; protocol__flex_csi_p10__init(csi10); //TODO: set the wideband value // NN: this is also depends on cc_id csi10->wb_cqi = flexran_get_ue_wcqi (enb_id, i); //eNB_UE_list->eNB_UE_stats[UE_PCCID(enb_id,i)][i].dl_cqi; csi10->has_wb_cqi = 1; //Add the type of measurements to the csi report in the proper union type csi_reports[j]->p10csi = csi10; } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI){ } else if(csi_reports[j]->report_case == PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI){ } } //Add the csi reports to the full DL CQI report dl_report->csi_report = csi_reports; //Add the DL CQI report to the stats report ue_report[i]->dl_cqi_report = dl_report; } /* Check flag for creation of paging buffer status report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { //TODO: Fill in the actual paging buffer status report. For this field to be valid, the RNTI //set in the report must be a P-RNTI Protocol__FlexPagingBufferReport *paging_report; paging_report = malloc(sizeof(Protocol__FlexPagingBufferReport)); if (paging_report == NULL) goto error; protocol__flex_paging_buffer_report__init(paging_report); //Set the number of pending paging messages paging_report->n_paging_info = 1; //Provide a report for each pending paging message Protocol__FlexPagingInfo **p_info; p_info = malloc(sizeof(Protocol__FlexPagingInfo *) * paging_report->n_paging_info); if (p_info == NULL) goto error; for (j = 0; j < paging_report->n_paging_info; j++) { p_info[j] = malloc(sizeof(Protocol__FlexPagingInfo)); if(p_info[j] == NULL) goto error; protocol__flex_paging_info__init(p_info[j]); //TODO: Set paging index. This index is the same that will be used for the scheduling of the //paging message by the controller p_info[j]->paging_index = 10; p_info[j]->has_paging_index = 0; //TODO:Set the paging message size p_info[j]->paging_message_size = 100; p_info[j]->has_paging_message_size = 0; //TODO: Set the paging subframe p_info[j]->paging_subframe = 10; p_info[j]->has_paging_subframe = 0; //TODO: Set the carrier index for the pending paging message p_info[j]->carrier_index = 0; p_info[j]->has_carrier_index = 0; } //Add all paging info to the paging buffer rerport paging_report->paging_info = p_info; //Add the paging report to the UE report ue_report[i]->pbr = paging_report; } /* Check flag for creation of UL CQI report */ if (report_config->ue_report_type[i].ue_report_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { //Fill in the full UL CQI report of the UE Protocol__FlexUlCqiReport *full_ul_report; full_ul_report = malloc(sizeof(Protocol__FlexUlCqiReport)); if(full_ul_report == NULL) goto error; protocol__flex_ul_cqi_report__init(full_ul_report); //TODO:Set the SFN and SF of the generated report full_ul_report->sfn_sn = flexran_get_sfn_sf(enb_id); full_ul_report->has_sfn_sn = 1; //TODO:Set the number of UL measurement reports based on the types of measurements //configured for this UE and on the servCellIndex full_ul_report->n_cqi_meas = 1; Protocol__FlexUlCqi **ul_report; ul_report = malloc(sizeof(Protocol__FlexUlCqi *) * full_ul_report->n_cqi_meas); if(ul_report == NULL) goto error; //Fill each UL report of the UE for each of the configured report types for(j = 0; j < full_ul_report->n_cqi_meas; j++) { ul_report[j] = malloc(sizeof(Protocol__FlexUlCqi)); if(ul_report[j] == NULL) goto error; protocol__flex_ul_cqi__init(ul_report[j]); //TODO: Set the type of the UL report. As an example set it to SRS UL report // See enum flex_ul_cqi_type in FlexRAN specification for more details ul_report[j]->type = PROTOCOL__FLEX_UL_CQI_TYPE__FLUCT_SRS; ul_report[j]->has_type = 1; //TODO:Set the number of SINR measurements based on the report type //See struct flex_ul_cqi in FlexRAN specification for more details ul_report[j]->n_sinr = 0; uint32_t *sinr_meas; sinr_meas = (uint32_t *) malloc(sizeof(uint32_t) * ul_report[j]->n_sinr); if (sinr_meas == NULL) goto error; //TODO:Set the SINR measurements for the specified type for (k = 0; k < ul_report[j]->n_sinr; k++) { sinr_meas[k] = 10; } ul_report[j]->sinr = sinr_meas; //TODO: Set the servCellIndex for this report ul_report[j]->serv_cell_index = 0; ul_report[j]->has_serv_cell_index = 1; //Set the list of UL reports of this UE to the full UL report full_ul_report->cqi_meas = ul_report; full_ul_report->n_pucch_dbm = MAX_NUM_CCs; full_ul_report->pucch_dbm = malloc(sizeof(Protocol__FlexPucchDbm *) * full_ul_report->n_pucch_dbm); for (j = 0; j < MAX_NUM_CCs; j++) { full_ul_report->pucch_dbm[j] = malloc(sizeof(Protocol__FlexPucchDbm)); protocol__flex_pucch_dbm__init(full_ul_report->pucch_dbm[j]); full_ul_report->pucch_dbm[j]->has_serv_cell_index = 1; full_ul_report->pucch_dbm[j]->serv_cell_index = j; if(flexran_get_p0_pucch_dbm(enb_id,i, j) != -1){ full_ul_report->pucch_dbm[j]->p0_pucch_dbm = flexran_get_p0_pucch_dbm(enb_id,i,j); full_ul_report->pucch_dbm[j]->has_p0_pucch_dbm = 1; } } //Add full UL CQI report to the UE report ue_report[i]->ul_cqi_report = full_ul_report; } } } /* Add list of all UE reports to the message */ stats_reply_msg->ue_report = ue_report; } /* Allocate memory for list of cell reports */ if (report_config->nr_cc > 0) { cell_report = malloc(sizeof(Protocol__FlexCellStatsReport *) * report_config->nr_cc); if (cell_report == NULL) goto error; // Fill in the Cell reports for (i = 0; i < report_config->nr_cc; i++) { cell_report[i] = malloc(sizeof(Protocol__FlexCellStatsReport)); if(cell_report[i] == NULL) goto error; protocol__flex_cell_stats_report__init(cell_report[i]); cell_report[i]->carrier_index = report_config->cc_report_type[i].cc_id; cell_report[i]->has_carrier_index = 1; cell_report[i]->flags = report_config->cc_report_type[i].cc_report_flags; cell_report[i]->has_flags = 1; /* Check flag for creation of noise and interference report */ if(report_config->cc_report_type[i].cc_report_flags & PROTOCOL__FLEX_CELL_STATS_TYPE__FLCST_NOISE_INTERFERENCE) { // TODO: Fill in the actual noise and interference report for this cell Protocol__FlexNoiseInterferenceReport *ni_report; ni_report = malloc(sizeof(Protocol__FlexNoiseInterferenceReport)); if(ni_report == NULL) goto error; protocol__flex_noise_interference_report__init(ni_report); // Current frame and subframe number ni_report->sfn_sf = flexran_get_sfn_sf(enb_id); ni_report->has_sfn_sf = 1; //TODO:Received interference power in dbm ni_report->rip = 0; ni_report->has_rip = 0; //TODO:Thermal noise power in dbm ni_report->tnp = 0; ni_report->has_tnp = 0; ni_report->p0_nominal_pucch = flexran_get_p0_nominal_pucch(enb_id, 0); ni_report->has_p0_nominal_pucch = 1; cell_report[i]->noise_inter_report = ni_report; } } /* Add list of all cell reports to the message */ stats_reply_msg->cell_report = cell_report; } *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__SUCCESSFUL_OUTCOME; (*msg)->stats_reply_msg = stats_reply_msg; return 0; error: // TODO: Need to make proper error handling if (header != NULL) free(header); if (stats_reply_msg != NULL) free(stats_reply_msg); if(*msg != NULL) free(*msg); //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_destroy_stats_reply(Protocol__FlexranMessage *msg) { //TODO: Need to deallocate memory for the stats reply message if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_STATS_REPLY_MSG) goto error; free(msg->stats_reply_msg->header); int i, j, k; Protocol__FlexStatsReply *reply = msg->stats_reply_msg; Protocol__FlexDlCqiReport *dl_report; Protocol__FlexUlCqiReport *ul_report; Protocol__FlexPagingBufferReport *paging_report; // Free the memory for the UE reports for (i = 0; i < reply->n_ue_report; i++) { free(reply->ue_report[i]->bsr); for (j = 0; j < reply->ue_report[i]->n_rlc_report; j++) { free(reply->ue_report[i]->rlc_report[j]); } free(reply->ue_report[i]->rlc_report); // If DL CQI report flag was set if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_DL_CQI) { dl_report = reply->ue_report[i]->dl_cqi_report; // Delete all CSI reports for (j = 0; j < dl_report->n_csi_report; j++) { //Must free memory based on the type of report switch(dl_report->csi_report[j]->report_case) { case PROTOCOL__FLEX_DL_CSI__REPORT_P10CSI: free(dl_report->csi_report[j]->p10csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_P11CSI: free(dl_report->csi_report[j]->p11csi->wb_cqi); free(dl_report->csi_report[j]->p11csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_P20CSI: free(dl_report->csi_report[j]->p20csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_P21CSI: free(dl_report->csi_report[j]->p21csi->wb_cqi); free(dl_report->csi_report[j]->p21csi->sb_cqi); free(dl_report->csi_report[j]->p21csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_A12CSI: free(dl_report->csi_report[j]->a12csi->wb_cqi); free(dl_report->csi_report[j]->a12csi->sb_pmi); free(dl_report->csi_report[j]->a12csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_A22CSI: free(dl_report->csi_report[j]->a22csi->wb_cqi); free(dl_report->csi_report[j]->a22csi->sb_cqi); free(dl_report->csi_report[j]->a22csi->sb_list); free(dl_report->csi_report[j]->a22csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_A20CSI: free(dl_report->csi_report[j]->a20csi->sb_list); free(dl_report->csi_report[j]->a20csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_A30CSI: free(dl_report->csi_report[j]->a30csi->sb_cqi); free(dl_report->csi_report[j]->a30csi); break; case PROTOCOL__FLEX_DL_CSI__REPORT_A31CSI: free(dl_report->csi_report[j]->a31csi->wb_cqi); for (k = 0; k < dl_report->csi_report[j]->a31csi->n_sb_cqi; k++) { free(dl_report->csi_report[j]->a31csi->sb_cqi[k]); } free(dl_report->csi_report[j]->a31csi->sb_cqi); break; } free(dl_report->csi_report[j]); } free(dl_report->csi_report); free(dl_report); } // If Paging buffer report flag was set if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_PBS) { paging_report = reply->ue_report[i]->pbr; // Delete all paging buffer reports for (j = 0; j < paging_report->n_paging_info; j++) { free(paging_report->paging_info[j]); } free(paging_report->paging_info); free(paging_report); } // If UL CQI report flag was set if (reply->ue_report[i]->flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_UL_CQI) { ul_report = reply->ue_report[i]->ul_cqi_report; for (j = 0; j < ul_report->n_cqi_meas; j++) { free(ul_report->cqi_meas[j]->sinr); free(ul_report->cqi_meas[j]); } free(ul_report->cqi_meas); for (j = 0; j < ul_report->n_pucch_dbm; j++) { free(ul_report->pucch_dbm[j]); } free(ul_report->pucch_dbm); } free(reply->ue_report[i]); } free(reply->ue_report); // Free memory for all Cell reports for (i = 0; i < reply->n_cell_report; i++) { free(reply->cell_report[i]->noise_inter_report); free(reply->cell_report[i]); } free(reply->cell_report); free(reply); free(msg); return 0; error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_sr_info(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i; const int xid = *((int *)params); if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UL_SR_INFO, &header) != 0) goto error; Protocol__FlexUlSrInfo *ul_sr_info_msg; ul_sr_info_msg = malloc(sizeof(Protocol__FlexUlSrInfo)); if (ul_sr_info_msg == NULL) { goto error; } protocol__flex_ul_sr_info__init(ul_sr_info_msg); ul_sr_info_msg->header = header; ul_sr_info_msg->has_sfn_sf = 1; ul_sr_info_msg->sfn_sf = flexran_get_sfn_sf(mod_id); /*TODO: Set the number of UEs that sent an SR */ ul_sr_info_msg->n_rnti = 1; ul_sr_info_msg->rnti = (uint32_t *) malloc(ul_sr_info_msg->n_rnti * sizeof(uint32_t)); if(ul_sr_info_msg->rnti == NULL) { goto error; } /*TODO:Set the rnti of the UEs that sent an SR */ for (i = 0; i < ul_sr_info_msg->n_rnti; i++) { ul_sr_info_msg->rnti[i] = 1; } *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->ul_sr_info_msg = ul_sr_info_msg; return 0; error: // TODO: Need to make proper error handling if (header != NULL) free(header); if (ul_sr_info_msg != NULL) { free(ul_sr_info_msg->rnti); free(ul_sr_info_msg); } if(*msg != NULL) free(*msg); //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_destroy_sr_info(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UL_SR_INFO_MSG) goto error; free(msg->ul_sr_info_msg->header); free(msg->ul_sr_info_msg->rnti); free(msg->ul_sr_info_msg); free(msg); return 0; error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_sf_trigger(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { Protocol__FlexHeader *header; int i,j; const int xid = *((int *)params); if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_SF_TRIGGER, &header) != 0) goto error; Protocol__FlexSfTrigger *sf_trigger_msg; sf_trigger_msg = malloc(sizeof(Protocol__FlexSfTrigger)); if (sf_trigger_msg == NULL) { goto error; } protocol__flex_sf_trigger__init(sf_trigger_msg); frame_t frame; sub_frame_t subframe; int ahead_of_time = 1; frame = (frame_t) flexran_get_current_system_frame_num(mod_id); subframe = (sub_frame_t) flexran_get_current_subframe(mod_id); subframe = ((subframe + ahead_of_time) % 10); int full_frames_ahead = ((ahead_of_time / 10) % 10); frame = frame + full_frames_ahead; if (subframe < flexran_get_current_subframe(mod_id)) { frame++; } sf_trigger_msg->header = header; sf_trigger_msg->has_sfn_sf = 1; sf_trigger_msg->sfn_sf = flexran_get_future_sfn_sf(mod_id, 1); /*TODO: Fill in the number of dl HARQ related info, based on the number of currently *transmitting UEs */ sf_trigger_msg->n_dl_info = flexran_get_num_ues(mod_id); Protocol__FlexDlInfo **dl_info = NULL; if (sf_trigger_msg->n_dl_info > 0) { dl_info = malloc(sizeof(Protocol__FlexDlInfo *) * sf_trigger_msg->n_dl_info); if(dl_info == NULL) goto error; //Fill the status of the current HARQ process for each UE for(i = 0; i < sf_trigger_msg->n_dl_info; i++) { dl_info[i] = malloc(sizeof(Protocol__FlexDlInfo)); if(dl_info[i] == NULL) goto error; protocol__flex_dl_info__init(dl_info[i]); dl_info[i]->rnti = flexran_get_ue_crnti(mod_id, i); dl_info[i]->has_rnti = 1; /*Fill in the right id of this round's HARQ process for this UE*/ int harq_id; int harq_status; flexran_get_harq(mod_id, UE_PCCID(mod_id,i), i, frame, subframe, &harq_id, &harq_status); dl_info[i]->harq_process_id = harq_id; dl_info[i]->has_harq_process_id = 1; /* Fill in the status of the HARQ process (2 TBs)*/ dl_info[i]->n_harq_status = 2; dl_info[i]->harq_status = malloc(sizeof(uint32_t) * dl_info[i]->n_harq_status); for (j = 0; j < dl_info[i]->n_harq_status; j++) { // TODO: This should be different per TB if(harq_status == 0) dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_ACK; else if (harq_status > 0) dl_info[i]->harq_status[j] = PROTOCOL__FLEX_HARQ_STATUS__FLHS_NACK; } /*Fill in the serving cell index for this UE */ dl_info[i]->serv_cell_index = UE_PCCID(mod_id,i); dl_info[i]->has_serv_cell_index = 1; } } sf_trigger_msg->dl_info = dl_info; /* Fill in the number of UL reception status related info, based on the number of currently * transmitting UEs */ sf_trigger_msg->n_ul_info = flexran_get_num_ues(mod_id); Protocol__FlexUlInfo **ul_info = NULL; if (sf_trigger_msg->n_ul_info > 0) { ul_info = malloc(sizeof(Protocol__FlexUlInfo *) * sf_trigger_msg->n_ul_info); if(ul_info == NULL) goto error; //Fill the reception info for each transmitting UE for(i = 0; i < sf_trigger_msg->n_ul_info; i++) { ul_info[i] = malloc(sizeof(Protocol__FlexUlInfo)); if(ul_info[i] == NULL) goto error; protocol__flex_ul_info__init(ul_info[i]); ul_info[i]->rnti = flexran_get_ue_crnti(mod_id, i); ul_info[i]->has_rnti = 1; /*Fill in the Tx power control command for this UE (if available)*/ if(flexran_get_tpc(mod_id,i) != 1){ ul_info[i]->tpc = flexran_get_tpc(mod_id,i); ul_info[i]->has_tpc = 1; } else{ ul_info[i]->tpc = flexran_get_tpc(mod_id,i); ul_info[i]->has_tpc = 0; } /*TODO: fill in the amount of data in bytes in the MAC SDU received in this subframe for the given logical channel*/ ul_info[i]->n_ul_reception = 0; ul_info[i]->ul_reception = malloc(sizeof(uint32_t) * ul_info[i]->n_ul_reception); for (j = 0; j < ul_info[i]->n_ul_reception; j++) { ul_info[i]->ul_reception[j] = 100; } /*TODO: Fill in the reception status for each UEs data*/ ul_info[i]->reception_status = PROTOCOL__FLEX_RECEPTION_STATUS__FLRS_OK; ul_info[i]->has_reception_status = 1; /*Fill in the serving cell index for this UE */ ul_info[i]->serv_cell_index = UE_PCCID(mod_id,i); ul_info[i]->has_serv_cell_index = 1; } } sf_trigger_msg->ul_info = ul_info; *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->sf_trigger_msg = sf_trigger_msg; return 0; error: if (header != NULL) free(header); if (sf_trigger_msg != NULL) { for (i = 0; i < sf_trigger_msg->n_dl_info; i++) { free(sf_trigger_msg->dl_info[i]->harq_status); } free(sf_trigger_msg->dl_info); for (i = 0; i < sf_trigger_msg->n_ul_info; i++) { free(sf_trigger_msg->ul_info[i]->reception_status); } free(sf_trigger_msg->ul_info); free(sf_trigger_msg); } if(*msg != NULL) free(*msg); //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_destroy_sf_trigger(Protocol__FlexranMessage *msg) { int i; if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_SF_TRIGGER_MSG) goto error; free(msg->sf_trigger_msg->header); for (i = 0; i < msg->sf_trigger_msg->n_dl_info; i++) { free(msg->sf_trigger_msg->dl_info[i]->harq_status); free(msg->sf_trigger_msg->dl_info[i]); } free(msg->sf_trigger_msg->dl_info); for (i = 0; i < msg->sf_trigger_msg->n_ul_info; i++) { free(msg->sf_trigger_msg->ul_info[i]->ul_reception); free(msg->sf_trigger_msg->ul_info[i]); } free(msg->sf_trigger_msg->ul_info); free(msg->sf_trigger_msg); free(msg); return 0; error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } int flexran_agent_mac_create_empty_dl_config(mid_t mod_id, Protocol__FlexranMessage **msg) { int xid = 0; Protocol__FlexHeader *header; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_DL_MAC_CONFIG, &header) != 0) goto error; Protocol__FlexDlMacConfig *dl_mac_config_msg; dl_mac_config_msg = malloc(sizeof(Protocol__FlexDlMacConfig)); if (dl_mac_config_msg == NULL) { goto error; } protocol__flex_dl_mac_config__init(dl_mac_config_msg); dl_mac_config_msg->header = header; dl_mac_config_msg->has_sfn_sf = 1; dl_mac_config_msg->sfn_sf = flexran_get_sfn_sf(mod_id); *msg = malloc(sizeof(Protocol__FlexranMessage)); if(*msg == NULL) goto error; protocol__flexran_message__init(*msg); (*msg)->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG; (*msg)->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; (*msg)->dl_mac_config_msg = dl_mac_config_msg; return 0; error: return -1; } int flexran_agent_mac_destroy_dl_config(Protocol__FlexranMessage *msg) { int i,j, k; if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_DL_MAC_CONFIG_MSG) goto error; Protocol__FlexDlDci *dl_dci; free(msg->dl_mac_config_msg->header); for (i = 0; i < msg->dl_mac_config_msg->n_dl_ue_data; i++) { free(msg->dl_mac_config_msg->dl_ue_data[i]->ce_bitmap); for (j = 0; j < msg->dl_mac_config_msg->dl_ue_data[i]->n_rlc_pdu; j++) { for (k = 0; k < msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->n_rlc_pdu_tb; k++) { free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb[k]); } free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]->rlc_pdu_tb); free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu[j]); } free(msg->dl_mac_config_msg->dl_ue_data[i]->rlc_pdu); dl_dci = msg->dl_mac_config_msg->dl_ue_data[i]->dl_dci; free(dl_dci->tbs_size); free(dl_dci->mcs); free(dl_dci->ndi); free(dl_dci->rv); free(dl_dci); free(msg->dl_mac_config_msg->dl_ue_data[i]); } free(msg->dl_mac_config_msg->dl_ue_data); for (i = 0; i < msg->dl_mac_config_msg->n_dl_rar; i++) { dl_dci = msg->dl_mac_config_msg->dl_rar[i]->rar_dci; free(dl_dci->tbs_size); free(dl_dci->mcs); free(dl_dci->ndi); free(dl_dci->rv); free(dl_dci); free(msg->dl_mac_config_msg->dl_rar[i]); } free(msg->dl_mac_config_msg->dl_rar); for (i = 0; i < msg->dl_mac_config_msg->n_dl_broadcast; i++) { dl_dci = msg->dl_mac_config_msg->dl_broadcast[i]->broad_dci; free(dl_dci->tbs_size); free(dl_dci->mcs); free(dl_dci->ndi); free(dl_dci->rv); free(dl_dci); free(msg->dl_mac_config_msg->dl_broadcast[i]); } free(msg->dl_mac_config_msg->dl_broadcast); for ( i = 0; i < msg->dl_mac_config_msg->n_ofdm_sym; i++) { free(msg->dl_mac_config_msg->ofdm_sym[i]); } free(msg->dl_mac_config_msg->ofdm_sym); free(msg->dl_mac_config_msg); free(msg); return 0; error: return -1; } void flexran_agent_get_pending_dl_mac_config(mid_t mod_id, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; lfds700_misc_prng_init(&ls); if (lfds700_ringbuffer_read(&ringbuffer_state[mod_id], NULL, (void **) msg, &ls) == 0) { *msg = NULL; } } int flexran_agent_mac_handle_dl_mac_config(mid_t mod_id, const void *params, Protocol__FlexranMessage **msg) { struct lfds700_misc_prng_state ls; enum lfds700_misc_flag overwrite_occurred_flag; Protocol__FlexranMessage *overwritten_dl_config; LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE; lfds700_misc_prng_init(&ls); lfds700_ringbuffer_write( &ringbuffer_state[mod_id], NULL, (void *) params, &overwrite_occurred_flag, NULL, (void **)&overwritten_dl_config, &ls); if (overwrite_occurred_flag == LFDS700_MISC_FLAG_RAISED) { // Delete unmanaged dl_config flexran_agent_mac_destroy_dl_config(overwritten_dl_config); } *msg = NULL; return 2; error: *msg = NULL; return -1; } void flexran_agent_init_mac_agent(mid_t mod_id) { lfds700_misc_library_init_valid_on_current_logical_core(); lfds700_misc_prng_init(&ps[mod_id]); int num_elements = RINGBUFFER_SIZE + 1; //Allow RINGBUFFER_SIZE messages to be stored in the ringbuffer at any time dl_mac_config_array[mod_id] = malloc( sizeof(struct lfds700_ringbuffer_element) * num_elements); lfds700_ringbuffer_init_valid_on_current_logical_core( &ringbuffer_state[mod_id], dl_mac_config_array[mod_id], num_elements, &ps[mod_id], NULL ); } /*********************************************** * FlexRAN agent - technology mac API implementation ***********************************************/ void flexran_agent_send_sr_info(mid_t mod_id) { int size; Protocol__FlexranMessage *msg; void *data; int priority; err_code_t err_code; int xid = 0; /*TODO: Must use a proper xid*/ err_code = flexran_agent_mac_sr_info(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } if (msg != NULL){ data=flexran_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: LOG_D(FLEXRAN_AGENT, "Could not send sr message\n"); } void flexran_agent_send_sf_trigger(mid_t mod_id) { int size; Protocol__FlexranMessage *msg; void *data; int priority; err_code_t err_code; int xid = 0; /*TODO: Must use a proper xid*/ err_code = flexran_agent_mac_sf_trigger(mod_id, (void *) &xid, &msg); if (err_code < 0) { goto error; } if (msg != NULL){ data=flexran_agent_pack_message(msg, &size); /*Send sr info using the MAC channel of the eNB*/ if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } void flexran_agent_send_update_mac_stats(mid_t mod_id) { Protocol__FlexranMessage *current_report = NULL, *msg; void *data; int size; err_code_t err_code; int priority; mac_stats_updates_context_t stats_context = mac_stats_context[mod_id]; if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { goto error; } if (mac_stats_context[mod_id].cont_update == 1) { /*Create a fresh report with the required flags*/ err_code = flexran_agent_mac_handle_stats(mod_id, (void *) mac_stats_context[mod_id].stats_req, ¤t_report); if (err_code < 0) { goto error; } } /* /\*TODO:Check if a previous reports exists and if yes, generate a report */ /* *that is the diff between the old and the new report, */ /* *respecting the thresholds. Otherwise send the new report*\/ */ /* if (mac_stats_context[mod_id].prev_stats_reply != NULL) { */ /* msg = flexran_agent_generate_diff_mac_stats_report(current_report, mac_stats_context[mod_id].prev_stats_reply); */ /* /\*Destroy the old stats*\/ */ /* flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); */ /* } */ /* /\*Use the current report for future comparissons*\/ */ /* mac_stats_context[mod_id].prev_stats_reply = current_report; */ if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { goto error; } if (current_report != NULL){ data=flexran_agent_pack_message(current_report, &size); /*Send any stats updates using the MAC channel of the eNB*/ if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_MAC, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); return; } error: LOG_D(FLEXRAN_AGENT, "Could not send sf trigger message\n"); } int flexran_agent_register_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { if (mac_agent_registered[mod_id]) { LOG_E(MAC, "MAC agent for eNB %d is already registered\n", mod_id); return -1; } //xface->agent_ctxt = &shared_ctxt[mod_id]; xface->flexran_agent_send_sr_info = flexran_agent_send_sr_info; xface->flexran_agent_send_sf_trigger = flexran_agent_send_sf_trigger; xface->flexran_agent_send_update_mac_stats = flexran_agent_send_update_mac_stats; xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_default; //xface->flexran_agent_schedule_ue_spec = flexran_schedule_ue_spec_remote; xface->flexran_agent_get_pending_dl_mac_config = flexran_agent_get_pending_dl_mac_config; xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; xface->dl_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 1; agent_mac_xface[mod_id] = xface; return 0; } int flexran_agent_unregister_mac_xface(mid_t mod_id, AGENT_MAC_xface *xface) { //xface->agent_ctxt = NULL; xface->flexran_agent_send_sr_info = NULL; xface->flexran_agent_send_sf_trigger = NULL; xface->flexran_agent_send_update_mac_stats = NULL; xface->flexran_agent_schedule_ue_spec = NULL; xface->flexran_agent_get_pending_dl_mac_config = NULL; xface->flexran_agent_notify_ue_state_change = NULL; xface->dl_scheduler_loaded_lib = NULL; mac_agent_registered[mod_id] = 0; agent_mac_xface[mod_id] = NULL; return 0; } /****************************************************** *Implementations of flexran_agent_mac_internal.h functions ******************************************************/ err_code_t flexran_agent_init_cont_mac_stats_update(mid_t mod_id) { /*Initialize the Mac stats update structure*/ /*Initially the continuous update is set to false*/ mac_stats_context[mod_id].cont_update = 0; mac_stats_context[mod_id].is_initialized = 1; mac_stats_context[mod_id].stats_req = NULL; mac_stats_context[mod_id].prev_stats_reply = NULL; mac_stats_context[mod_id].mutex = calloc(1, sizeof(pthread_mutex_t)); if (mac_stats_context[mod_id].mutex == NULL) goto error; if (pthread_mutex_init(mac_stats_context[mod_id].mutex, NULL)) goto error;; return 0; error: return -1; } err_code_t flexran_agent_destroy_cont_mac_stats_update(mid_t mod_id) { /*Disable the continuous updates for the MAC*/ mac_stats_context[mod_id].cont_update = 0; mac_stats_context[mod_id].is_initialized = 0; flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); free(mac_stats_context[mod_id].mutex); mac_agent_registered[mod_id] = NULL; return 1; } err_code_t flexran_agent_enable_cont_mac_stats_update(mid_t mod_id, xid_t xid, stats_request_config_t *stats_req) { /*Enable the continuous updates for the MAC*/ if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { goto error; } Protocol__FlexranMessage *req_msg; flexran_agent_mac_stats_request(mod_id, xid, stats_req, &req_msg); mac_stats_context[mod_id].stats_req = req_msg; mac_stats_context[mod_id].prev_stats_reply = NULL; mac_stats_context[mod_id].cont_update = 1; mac_stats_context[mod_id].xid = xid; if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { goto error; } return 0; error: LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; } err_code_t flexran_agent_disable_cont_mac_stats_update(mid_t mod_id) { /*Disable the continuous updates for the MAC*/ if (pthread_mutex_lock(mac_stats_context[mod_id].mutex)) { goto error; } mac_stats_context[mod_id].cont_update = 0; mac_stats_context[mod_id].xid = 0; if (mac_stats_context[mod_id].stats_req != NULL) { flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].stats_req); } if (mac_stats_context[mod_id].prev_stats_reply != NULL) { flexran_agent_destroy_flexran_message(mac_stats_context[mod_id].prev_stats_reply); } if (pthread_mutex_unlock(mac_stats_context[mod_id].mutex)) { goto error; } return 0; error: LOG_E(FLEXRAN_AGENT, "mac_stats_context for eNB %d is not initialized\n", mod_id); return -1; }