/* * 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 flexran_agent_rrc.c * \brief FlexRAN agent Control Module RRC * \author shahab SHARIAT BAGHERI * \date 2017 * \version 0.1 */ #include "flexran_agent_rrc.h" #include "flexran_agent_ran_api.h" #include "liblfds700.h" #include "common/utils/LOG/log.h" /*Trigger boolean for RRC measurement*/ bool triggered_rrc = false; /*Array containing the Agent-RRC interfaces*/ AGENT_RRC_xface *agent_rrc_xface[NUM_MAX_ENB]; void flexran_agent_ue_state_change(mid_t mod_id, uint32_t rnti, uint8_t state_change) { int size; Protocol__FlexranMessage *msg = NULL; Protocol__FlexHeader *header = NULL; Protocol__FlexUeStateChange *ue_state_change_msg = NULL; Protocol__FlexUeConfig *config = NULL; void *data; int priority = 0; err_code_t err_code=0; int xid = 0; if (flexran_create_header(xid, PROTOCOL__FLEX_TYPE__FLPT_UE_STATE_CHANGE, &header) != 0) goto error; ue_state_change_msg = malloc(sizeof(Protocol__FlexUeStateChange)); if(ue_state_change_msg == NULL) { goto error; } protocol__flex_ue_state_change__init(ue_state_change_msg); ue_state_change_msg->has_type = 1; ue_state_change_msg->type = state_change; config = malloc(sizeof(Protocol__FlexUeConfig)); if (config == NULL) { goto error; } protocol__flex_ue_config__init(config); switch (state_change) { case PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED: config->has_rnti = 1; config->rnti = rnti; break; case PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_UPDATED: case PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_ACTIVATED: flexran_agent_fill_rrc_ue_config(mod_id, rnti, config); /* we don't call into the MAC CM here; it will be called later through an * ue_config_request */ break; case PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_MOVED: default: LOG_E(FLEXRAN_AGENT, "state change FLUESC_MOVED or unknown state occured for RNTI %x\n", rnti); } ue_state_change_msg->config = config; msg = malloc(sizeof(Protocol__FlexranMessage)); if (msg == NULL) { goto error; } protocol__flexran_message__init(msg); msg->msg_case = PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG; msg->msg_dir = PROTOCOL__FLEXRAN_DIRECTION__INITIATING_MESSAGE; msg->ue_state_change_msg = ue_state_change_msg; 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_DEFAULT, data, size, priority)) { err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; goto error; } LOG_D(FLEXRAN_AGENT,"sent message with size %d\n", size); free(header); return; error: if (err_code != 0) LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d for RNTI %x\n", err_code, rnti); if (header){ free(header); } if (ue_state_change_msg) { free(ue_state_change_msg); } if (config) { free(config); } if (msg) { free(msg); } } int flexran_agent_destroy_ue_state_change(Protocol__FlexranMessage *msg) { if(msg->msg_case != PROTOCOL__FLEXRAN_MESSAGE__MSG_UE_STATE_CHANGE_MSG) goto error; free(msg->ue_state_change_msg->header); if (msg->ue_state_change_msg->config->capabilities) free(msg->ue_state_change_msg->config->capabilities); if (msg->ue_state_change_msg->config->info) { if (msg->ue_state_change_msg->config->info->cell_individual_offset) { free(msg->ue_state_change_msg->config->info->cell_individual_offset); } if (msg->ue_state_change_msg->config->info->event) { if (msg->ue_state_change_msg->config->info->event->a3) { free(msg->ue_state_change_msg->config->info->event->a3); } free(msg->ue_state_change_msg->config->info->event); } free(msg->ue_state_change_msg->config->info); } free(msg->ue_state_change_msg->config); free(msg->ue_state_change_msg); free(msg); return 0; error: //LOG_E(MAC, "%s: an error occured\n", __FUNCTION__); return -1; } /* this is called by RRC as a part of rrc xface . The controller previously requested this*/ void flexran_trigger_rrc_measurements (mid_t mod_id, LTE_MeasResults_t* measResults) { // int priority = 0; // Warning Preventing // void *data; // int size; // err_code_t err_code = -100; triggered_rrc = true; /* TODO do we need this at the current state? meas_stats is never put into a * protobuf message?! int num = flexran_get_rrc_num_ues (mod_id); rnti_t rntis[num]; flexran_get_rrc_rnti_list(mod_id, rntis, num); meas_stats = malloc(sizeof(rrc_meas_stats) * num); for (int i = 0; i < num; i++){ const rnti_t rnti = rntis[i]; meas_stats[i].rnti = rnti; meas_stats[i].meas_id = flexran_get_rrc_pcell_measid(mod_id, rnti); meas_stats[i].rsrp = flexran_get_rrc_pcell_rsrp(mod_id, rnti) - 140; // measResults->measResultPCell.rsrpResult - 140; meas_stats[i].rsrq = flexran_get_rrc_pcell_rsrq(mod_id, rnti)/2 - 20; */ // repl->neigh_meas = NULL; // if (meas->measResultNeighCells != NULL) { // /* // * Neighboring cells measurements performed by UE. // */ // NeighCellsMeasurements *neigh_meas; // neigh_meas = malloc(sizeof(NeighCellsMeasurements)); // if (neigh_meas == NULL) // goto error; // neigh_cells_measurements__init(neigh_meas); // /* EUTRAN RRC Measurements. */ // if (meas->measResultNeighCells->present == // MeasResults__measResultNeighCells_PR_measResultListEUTRA) { // MeasResultListEUTRA_t meas_list = meas->measResultNeighCells-> // choice.measResultListEUTRA; // /* Set the number of EUTRAN measurements present in report. */ // neigh_meas->n_eutra_meas = meas_list.list.count; // if (neigh_meas->n_eutra_meas > 0) { // /* Initialize EUTRAN measurements. */ // EUTRAMeasurements **eutra_meas; // eutra_meas = malloc(sizeof(EUTRAMeasurements *) * // neigh_meas->n_eutra_meas); // for (i = 0; i < neigh_meas->n_eutra_meas; i++) { // eutra_meas[i] = malloc(sizeof(EUTRAMeasurements)); // eutra_measurements__init(eutra_meas[i]); // /* Fill in the physical cell identifier. */ // eutra_meas[i]->has_phys_cell_id = 1; // eutra_meas[i]->phys_cell_id = meas_list.list.array[i]-> // physCellId; // // log_i(agent,"PCI of Target %d", eutra_meas[i]->phys_cell_id); // /* Check for Reference signal measurements. */ // if (&(meas_list.list.array[i]->measResult)) { // /* Initialize Ref. signal measurements. */ // EUTRARefSignalMeas *meas_result; // meas_result = malloc(sizeof(EUTRARefSignalMeas)); // eutra_ref_signal_meas__init(meas_result); // if (meas_list.list.array[i]->measResult.rsrpResult) { // meas_result->has_rsrp = 1; // meas_result->rsrp = RSRP_meas_mapping[*(meas_list. // list.array[i]->measResult.rsrpResult)]; // // log_i(agent,"RSRP of Target %d", meas_result->rsrp); // } // if (meas_list.list.array[i]->measResult.rsrqResult) { // meas_result->has_rsrq = 1; // meas_result->rsrq = RSRQ_meas_mapping[*(meas_list. // list.array[i]->measResult.rsrqResult)]; // // log_i(agent,"RSRQ of Target %d", meas_result->rsrq); // } // eutra_meas[i]->meas_result = meas_result; // } // /* Check for CGI measurements. */ // if (meas_list.list.array[i]->cgi_Info) { // /* Initialize CGI measurements. */ // EUTRACgiMeasurements *cgi_meas; // cgi_meas = malloc(sizeof(EUTRACgiMeasurements)); // eutra_cgi_measurements__init(cgi_meas); // /* EUTRA Cell Global Identity (CGI). */ // CellGlobalIdEUTRA *cgi; // cgi = malloc(sizeof(CellGlobalIdEUTRA)); // cell_global_id__eutra__init(cgi); // cgi->has_cell_id = 1; // CellIdentity_t cId = meas_list.list.array[i]-> // cgi_Info->cellGlobalId.cellIdentity; // cgi->cell_id = (cId.buf[0] << 20) + (cId.buf[1] << 12) + // (cId.buf[2] << 4) + (cId.buf[3] >> 4); // /* Public land mobile network identifier of neighbor // * cell. // */ // PlmnIdentity *plmn_id; // plmn_id = malloc(sizeof(PlmnIdentity)); // plmn_identity__init(plmn_id); // MNC_t mnc = meas_list.list.array[i]-> // cgi_Info->cellGlobalId.plmn_Identity.mnc; // plmn_id->has_mnc = 1; // plmn_id->mnc = 0; // for (m = 0; m < mnc.list.count; m++) { // plmn_id->mnc += *mnc.list.array[m] * // ((uint32_t) pow(10, mnc.list.count - m - 1)); // } // MCC_t *mcc = meas_list.list.array[i]-> // cgi_Info->cellGlobalId.plmn_Identity.mcc; // plmn_id->has_mcc = 1; // plmn_id->mcc = 0; // for (m = 0; m < mcc->list.count; m++) { // plmn_id->mcc += *mcc->list.array[m] * // ((uint32_t) pow(10, mcc->list.count - m - 1)); // } // TrackingAreaCode_t tac = meas_list.list.array[i]-> // cgi_Info->trackingAreaCode; // cgi_meas->has_tracking_area_code = 1; // cgi_meas->tracking_area_code = (tac.buf[0] << 8) + // (tac.buf[1]); // PLMN_IdentityList2_t *plmn_l = meas_list.list.array[i]-> // cgi_Info->plmn_IdentityList; // cgi_meas->n_plmn_id = plmn_l->list.count; // /* Set the PLMN ID list in CGI measurements. */ // PlmnIdentity **plmn_id_l; // plmn_id_l = malloc(sizeof(PlmnIdentity *) * // cgi_meas->n_plmn_id); // MNC_t mnc2; // MCC_t *mcc2; // for (m = 0; m < cgi_meas->n_plmn_id; m++) { // plmn_id_l[m] = malloc(sizeof(PlmnIdentity)); // plmn_identity__init(plmn_id_l[m]); // mnc2 = plmn_l->list.array[m]->mnc; // plmn_id_l[m]->has_mnc = 1; // plmn_id_l[m]->mnc = 0; // for (k = 0; k < mnc2.list.count; k++) { // plmn_id_l[m]->mnc += *mnc2.list.array[k] * // ((uint32_t) pow(10, mnc2.list.count - k - 1)); // } // mcc2 = plmn_l->list.array[m]->mcc; // plmn_id_l[m]->has_mcc = 1; // plmn_id_l[m]->mcc = 0; // for (k = 0; k < mcc2->list.count; k++) { // plmn_id_l[m]->mcc += *mcc2->list.array[k] * // ((uint32_t) pow(10, mcc2->list.count - k - 1)); // } // } // cgi_meas->plmn_id = plmn_id_l; // eutra_meas[i]->cgi_meas = cgi_meas; // } // } // neigh_meas->eutra_meas = eutra_meas; // } // } // repl->neigh_meas = neigh_meas; // } /* Attach the RRC measurement reply message to RRC measurements message. */ // mrrc_meas->repl = repl; /* Attach RRC measurement message to triggered event message. */ // te->mrrc_meas = mrrc_meas; // te->has_action = 0; /* Attach the triggered event message to main message. */ // reply->te = te; /* Send the report to controller. */ // if (flexran_agent_msg_send(b_id, reply) < 0) { // goto error; // } /* Free the measurement report received from UE. */ // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); /* Free the params. */ // free(p); // stats_reply_msg->cell_report = cell_report; // stats_reply_msg->ue_report = ue_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; // data = flexran_agent_pack_message(msg, &size); // if (flexran_agent_msg_send(mod_id, FLEXRAN_AGENT_DEFAULT, data, size, priority)) { // err_code = PROTOCOL__FLEXRAN_ERR__MSG_ENQUEUING; // goto error; // } // LOG_I(FLEXRAN_AGENT,"RRC Trigger is done \n"); return; // error: // LOG_E(FLEXRAN_AGENT, "Could not send UE state message becasue of %d \n",err_code); /* Free the measurement report received from UE. */ // ASN_STRUCT_FREE(asn_DEF_MeasResults, p->meas); /* Free the params. */ // free(p); // return -1; } int flexran_agent_rrc_stats_reply(mid_t mod_id, Protocol__FlexUeStatsReport **ue_report, int n_ue, uint32_t ue_flags) { if (n_ue > 0) { for (int i = 0; i < n_ue; i++) { const rnti_t rnti = ue_report[i]->rnti; /* Check flag for creation of buffer status report */ if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS) { /*Source cell EUTRA Measurements*/ Protocol__FlexRrcMeasurements *rrc_measurements; rrc_measurements = malloc(sizeof(Protocol__FlexRrcMeasurements)); if (rrc_measurements == NULL) goto error; protocol__flex_rrc_measurements__init(rrc_measurements); rrc_measurements->measid = flexran_get_rrc_pcell_measid(mod_id, rnti); rrc_measurements->has_measid = 1; rrc_measurements->pcell_rsrp = flexran_get_rrc_pcell_rsrp(mod_id, rnti); rrc_measurements->has_pcell_rsrp = 1; rrc_measurements->pcell_rsrq = flexran_get_rrc_pcell_rsrq(mod_id, rnti); rrc_measurements->has_pcell_rsrq = 1 ; /* Neighbouring cells EUTRA Measurements*/ Protocol__FlexNeighCellsMeasurements *neigh_meas; neigh_meas = malloc(sizeof(Protocol__FlexNeighCellsMeasurements)); if (neigh_meas == NULL) { free(rrc_measurements); rrc_measurements = NULL; goto error; } protocol__flex_neigh_cells_measurements__init(neigh_meas); neigh_meas->n_eutra_meas = flexran_get_rrc_num_ncell(mod_id, rnti); Protocol__FlexEutraMeasurements **eutra_meas = NULL; if (neigh_meas->n_eutra_meas > 0) { eutra_meas = malloc(sizeof(Protocol__FlexEutraMeasurements) * neigh_meas->n_eutra_meas); if (eutra_meas == NULL) { free(neigh_meas); free(rrc_measurements); rrc_measurements = NULL; goto error; } for (int j = 0; j < neigh_meas->n_eutra_meas; j++ ) { eutra_meas[j] = malloc(sizeof(Protocol__FlexEutraMeasurements)); if (eutra_meas[j] == NULL) { for (int k = 0 ; k < j ; k++) free(eutra_meas[k]); free(eutra_meas); free(neigh_meas); free(rrc_measurements); rrc_measurements = NULL; goto error; } protocol__flex_eutra_measurements__init(eutra_meas[j]); /* Fill in the physical cell identifier. */ eutra_meas[j]->phys_cell_id = flexran_get_rrc_neigh_phy_cell_id(mod_id, rnti, j); eutra_meas[j]->has_phys_cell_id = 1; /* The following is not correctly implemented */ //if (flexran_get_rrc_neigh_cgi(mod_id, rnti, j)) { // /* Initialize CGI measurements. */ // Protocol__FlexEutraCgiMeasurements *cgi_meas; // cgi_meas = malloc(sizeof(Protocol__FlexEutraCgiMeasurements)); // if (cgi_meas) { // protocol__flex_eutra_cgi_measurements__init(cgi_meas); // cgi_meas->tracking_area_code = flexran_get_rrc_neigh_cgi_tac(mod_id, rnti, j); // cgi_meas->has_tracking_area_code = 1; // /* EUTRA Cell Global Identity (CGI) */ // Protocol__FlexCellGlobalEutraId *cgi; // cgi = malloc(sizeof(Protocol__FlexCellGlobalEutraId)); // if (cgi) { // protocol__flex_cell_global_eutra_id__init(cgi); // cgi->cell_id = flexran_get_rrc_neigh_cgi_cell_id(mod_id, rnti, j); // cgi->has_cell_id = 1; // /* PLMN for neighbouring cell */ // Protocol__FlexPlmnIdentity *plmn_id; // plmn_id = malloc(sizeof(Protocol__FlexPlmnIdentity)); // if (plmn_id) { // protocol__flex_plmn_identity__init(plmn_id); // plmn_id->mcc = 0; // plmn_id->n_mcc = flexran_get_rrc_neigh_cgi_num_mcc(mod_id, rnti, j); // for (int m = 0; m < plmn_id->n_mcc; m++) { // plmn_id->mcc += flexran_get_rrc_neigh_cgi_mcc(mod_id, rnti, j, m); // } // plmn_id->mnc = 0; // plmn_id->n_mnc = flexran_get_rrc_neigh_cgi_num_mnc(mod_id, rnti, j); // for (int m = 0; m < plmn_id->n_mnc; m++) { // plmn_id->mnc += flexran_get_rrc_neigh_cgi_mnc(mod_id, rnti, j, m); // } // cgi->plmn_id = plmn_id; // } // cgi_meas->cgi = cgi; // } // eutra_meas[j]->cgi_meas = cgi_meas; // } //} /*RSRP/RSRQ of the neighbouring cell */ Protocol__FlexEutraRefSignalMeas *meas_result; meas_result = malloc(sizeof(Protocol__FlexEutraRefSignalMeas)); if (meas_result) { protocol__flex_eutra_ref_signal_meas__init(meas_result); meas_result->rsrp = flexran_get_rrc_neigh_rsrp(mod_id, rnti, j); meas_result->has_rsrp = 1; meas_result->rsrq = flexran_get_rrc_neigh_rsrq(mod_id, rnti, j); meas_result->has_rsrq = 1; eutra_meas[j]->meas_result = meas_result; } } neigh_meas->eutra_meas = eutra_meas; rrc_measurements->neigh_meas = neigh_meas; } else { free(neigh_meas); } ue_report[i]->rrc_measurements = rrc_measurements; ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_RRC_MEASUREMENTS; } } } return 0; error: for (int i = 0; i < n_ue; i++) { if (ue_report[i]->rrc_measurements && ue_report[i]->rrc_measurements->neigh_meas != NULL) { for (int j = 0; j < ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) { free(ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]); } free(ue_report[i]->rrc_measurements->neigh_meas); } } if (ue_report != NULL) free(ue_report); return -1; } int flexran_agent_rrc_destroy_stats_reply(Protocol__FlexStatsReply *reply) { for (int i = 0; i < reply->n_ue_report; i++){ if (reply->ue_report[i]->rrc_measurements && reply->ue_report[i]->rrc_measurements->neigh_meas) { for (int j = 0; j < reply->ue_report[i]->rrc_measurements->neigh_meas->n_eutra_meas; j++) { //if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas) { // if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi) { // if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->plmn_id) { // free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi->plmn_id); // } // free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas->cgi); // } // free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->cgi_meas); //} if (reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->meas_result) { free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]->meas_result); } free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas[j]); } free(reply->ue_report[i]->rrc_measurements->neigh_meas->eutra_meas); free(reply->ue_report[i]->rrc_measurements->neigh_meas); free(reply->ue_report[i]->rrc_measurements); } } return 0; } int flexran_agent_rrc_gtp_stats_reply(mid_t mod_id, Protocol__FlexUeStatsReport **ue_report, int n_ue, uint32_t ue_flags) { /* This function fills the GTP part of the statistics. The necessary * information is, for our purposes, completely maintained in the RRC layer. * It would be possible to add a GTP module that handles this, though. */ if (n_ue > 0) { for (int i = 0; i < n_ue; i++) { const rnti_t rnti = ue_report[i]->rnti; /* Check flag for creation of buffer status report */ if (ue_flags & PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS) { /* get number of rabs for this UE */ const int num_e_rab = flexran_agent_rrc_gtp_num_e_rab(mod_id, rnti); Protocol__FlexGtpStats **gtp_stats = NULL; if (num_e_rab > 0) { gtp_stats = calloc(num_e_rab, sizeof(Protocol__FlexGtpStats *)); if (!gtp_stats) goto error; for (int r = 0; r < num_e_rab; ++r) { gtp_stats[r] = malloc(sizeof(Protocol__FlexGtpStats)); if (!gtp_stats[r]) goto error; protocol__flex_gtp_stats__init(gtp_stats[r]); gtp_stats[r]->e_rab_id = flexran_agent_rrc_gtp_get_e_rab_id(mod_id, rnti, r); gtp_stats[r]->has_e_rab_id = 1; gtp_stats[r]->teid_enb = flexran_agent_rrc_gtp_get_teid_enb(mod_id, rnti, r); gtp_stats[r]->has_teid_enb = 1; gtp_stats[r]->addr_enb = NULL; gtp_stats[r]->teid_sgw = flexran_agent_rrc_gtp_get_teid_sgw(mod_id, rnti, r); gtp_stats[r]->has_teid_sgw = 1; gtp_stats[r]->addr_sgw = NULL; } } ue_report[i]->n_gtp_stats = num_e_rab; ue_report[i]->gtp_stats = gtp_stats; ue_report[i]->flags |= PROTOCOL__FLEX_UE_STATS_TYPE__FLUST_GTP_STATS; } } } return 0; error: for (int i = 0; i < n_ue; i++) { if (!ue_report[i]->gtp_stats) continue; for (int r = 0; r < ue_report[i]->n_gtp_stats; ++r) { if (ue_report[i]->gtp_stats[r]) { free(ue_report[i]->gtp_stats[r]); ue_report[i]->gtp_stats[r] = NULL; } } free(ue_report[i]->gtp_stats); ue_report[i]->gtp_stats = NULL; } return -1; } int flexran_agent_rrc_gtp_destroy_stats_reply(Protocol__FlexStatsReply *reply) { for (int i = 0; i < reply->n_ue_report; ++i) { if (!reply->ue_report[i]->n_gtp_stats == 0) continue; for (int r = 0; r < reply->ue_report[i]->n_gtp_stats; ++r) { //if (reply->ue_report[i]->gtp_stats[r]->addr_enb) // free(reply->ue_report[i]->gtp_stats[r]->addr_enb); //if (reply->ue_report[i]->gtp_stats[r]->addr_sgw) // free(reply->ue_report[i]->gtp_stats[r]->addr_sgw); free(reply->ue_report[i]->gtp_stats[r]); } } return 0; } void flexran_agent_fill_rrc_ue_config(mid_t mod_id, rnti_t rnti, Protocol__FlexUeConfig *ue_conf) { if (ue_conf->has_rnti && ue_conf->rnti != rnti) { LOG_E(FLEXRAN_AGENT, "ue_config existing RNTI %x does not match RRC RNTI %x\n", ue_conf->rnti, rnti); return; } ue_conf->has_rnti = 1; ue_conf->rnti = rnti; ue_conf->imsi = flexran_get_ue_imsi(mod_id, rnti); ue_conf->has_imsi = 1; //TODO: Set the DRX configuration (optional) //Not supported for now, so we do not set it ue_conf->time_alignment_timer = flexran_get_time_alignment_timer(mod_id, rnti); ue_conf->has_time_alignment_timer = 1; ue_conf->meas_gap_config_pattern = flexran_get_meas_gap_config(mod_id, rnti); ue_conf->has_meas_gap_config_pattern = 1; if(ue_conf->meas_gap_config_pattern != PROTOCOL__FLEX_MEAS_GAP_CONFIG_PATTERN__FLMGCP_OFF) { ue_conf->meas_gap_config_sf_offset = flexran_get_meas_gap_config_offset(mod_id, rnti); ue_conf->has_meas_gap_config_sf_offset = 1; } //TODO: Set the SPS configuration (Optional) //Not supported for now, so we do not set it //TODO: Set the SR configuration (Optional) //We do not set it for now //TODO: Set the CQI configuration (Optional) //We do not set it for now ue_conf->transmission_mode = flexran_get_ue_transmission_mode(mod_id, rnti); ue_conf->has_transmission_mode = 1; Protocol__FlexUeCapabilities *c_capabilities; c_capabilities = malloc(sizeof(Protocol__FlexUeCapabilities)); if (c_capabilities) { protocol__flex_ue_capabilities__init(c_capabilities); c_capabilities->has_half_duplex = 1; c_capabilities->half_duplex = flexran_get_half_duplex(mod_id, rnti); c_capabilities->has_intra_sf_hopping = 1; c_capabilities->intra_sf_hopping = flexran_get_intra_sf_hopping(mod_id, rnti); c_capabilities->has_type2_sb_1 = 1; c_capabilities->type2_sb_1 = flexran_get_type2_sb_1(mod_id, rnti); c_capabilities->has_ue_category = 1; c_capabilities->ue_category = flexran_get_ue_category(mod_id, rnti); c_capabilities->has_res_alloc_type1 = 1; c_capabilities->res_alloc_type1 = flexran_get_res_alloc_type1(mod_id, rnti); ue_conf->capabilities = c_capabilities; } ue_conf->has_ue_transmission_antenna = 1; ue_conf->ue_transmission_antenna = flexran_get_ue_transmission_antenna(mod_id, rnti); ue_conf->has_tti_bundling = 1; ue_conf->tti_bundling = flexran_get_tti_bundling(mod_id, rnti); ue_conf->has_max_harq_tx = 1; ue_conf->max_harq_tx = flexran_get_maxHARQ_TX(mod_id, rnti); ue_conf->has_beta_offset_ack_index = 1; ue_conf->beta_offset_ack_index = flexran_get_beta_offset_ack_index(mod_id, rnti); ue_conf->has_beta_offset_ri_index = 1; ue_conf->beta_offset_ri_index = flexran_get_beta_offset_ri_index(mod_id, rnti); ue_conf->has_beta_offset_cqi_index = 1; ue_conf->beta_offset_cqi_index = flexran_get_beta_offset_cqi_index(mod_id, rnti); /* assume primary carrier */ ue_conf->has_ack_nack_simultaneous_trans = 1; ue_conf->ack_nack_simultaneous_trans = flexran_get_ack_nack_simultaneous_trans(mod_id,0); ue_conf->has_simultaneous_ack_nack_cqi = 1; ue_conf->simultaneous_ack_nack_cqi = flexran_get_simultaneous_ack_nack_cqi(mod_id, rnti); ue_conf->has_aperiodic_cqi_rep_mode = 1; ue_conf->aperiodic_cqi_rep_mode = flexran_get_aperiodic_cqi_rep_mode(mod_id, rnti); ue_conf->has_tdd_ack_nack_feedback = 1; ue_conf->tdd_ack_nack_feedback = flexran_get_tdd_ack_nack_feedback_mode(mod_id, rnti); ue_conf->has_ack_nack_repetition_factor = 1; ue_conf->ack_nack_repetition_factor = flexran_get_ack_nack_repetition_factor(mod_id, rnti); ue_conf->has_extended_bsr_size = 1; ue_conf->extended_bsr_size = flexran_get_extended_bsr_size(mod_id, rnti); Protocol__FlexMeasurementInfo *meas_info; meas_info = malloc(sizeof(Protocol__FlexMeasurementInfo)); if (meas_info) { protocol__flex_measurement_info__init(meas_info); meas_info->has_offset_freq_serving = 1; meas_info->offset_freq_serving = flexran_get_rrc_ofp(mod_id, rnti); meas_info->has_offset_freq_neighbouring = 1; meas_info->offset_freq_neighbouring = flexran_get_rrc_ofn(mod_id, rnti); int num_adj_cells = flexran_get_rrc_num_adj_cells(mod_id); meas_info->n_cell_individual_offset = num_adj_cells + 1; int64_t *cell_individual_offset; if (num_adj_cells > 0) { cell_individual_offset = malloc(sizeof(int64_t)*(num_adj_cells+1)); if (cell_individual_offset) { cell_individual_offset[0] = flexran_get_rrc_ocp(mod_id, rnti); for (int i=0; i < num_adj_cells; i++) { cell_individual_offset[i+1] = flexran_get_rrc_ocn(mod_id, rnti,i); } meas_info->cell_individual_offset = cell_individual_offset; } } else { cell_individual_offset = malloc(sizeof(int64_t)); if (cell_individual_offset) { *cell_individual_offset = flexran_get_rrc_ocp(mod_id, rnti); meas_info->cell_individual_offset = cell_individual_offset; } } meas_info->has_filter_coefficient_rsrp = 1; meas_info->filter_coefficient_rsrp = flexran_get_filter_coeff_rsrp(mod_id, rnti); meas_info->has_filter_coefficient_rsrq = 1; meas_info->filter_coefficient_rsrq = flexran_get_filter_coeff_rsrq(mod_id, rnti); Protocol__FlexMeasurementEvent *event; event = malloc(sizeof(Protocol__FlexMeasurementEvent)); if (event) { protocol__flex_measurement_event__init(event); Protocol__FlexA3Event *a3_event; a3_event = malloc(sizeof(Protocol__FlexA3Event)); if (a3_event) { protocol__flex_a3_event__init(a3_event); a3_event->has_a3_offset = 1; a3_event->a3_offset = flexran_get_rrc_a3_event_a3_offset(mod_id, rnti); a3_event->has_report_on_leave = 1; a3_event->report_on_leave = flexran_get_rrc_a3_event_reportOnLeave(mod_id, rnti); a3_event->has_hysteresis = 1; a3_event->hysteresis = flexran_get_rrc_a3_event_hysteresis(mod_id, rnti); a3_event->has_time_to_trigger = 1; a3_event->time_to_trigger = flexran_get_rrc_a3_event_timeToTrigger(mod_id, rnti); a3_event->has_max_report_cells = 1; a3_event->max_report_cells = flexran_get_rrc_a3_event_maxReportCells(mod_id, rnti); event->a3 = a3_event; } meas_info->event = event; } ue_conf->info = meas_info; } } int flexran_agent_register_rrc_xface(mid_t mod_id) { if (agent_rrc_xface[mod_id]) { LOG_E(FLEXRAN_AGENT, "RRC agent for eNB %d is already registered\n", mod_id); return -1; } AGENT_RRC_xface *xface = malloc(sizeof(AGENT_RRC_xface)); if (!xface) { LOG_E(FLEXRAN_AGENT, "could not allocate memory for RRC agent xface %d\n", mod_id); return -1; } // xface->flexran_agent_send_update_rrc_stats = flexran_agent_send_update_rrc_stats; xface->flexran_agent_notify_ue_state_change = flexran_agent_ue_state_change; xface->flexran_trigger_rrc_measurements = flexran_trigger_rrc_measurements; agent_rrc_xface[mod_id] = xface; return 0; } void flexran_agent_fill_rrc_cell_config(mid_t mod_id, uint8_t cc_id, Protocol__FlexCellConfig *conf) { if (!conf->si_config) { conf->si_config = malloc(sizeof(Protocol__FlexSiConfig)); if (conf->si_config) protocol__flex_si_config__init(conf->si_config); } if (conf->si_config) { // TODO THIS IS DU RRC conf->si_config->sib1_length = flexran_get_sib1_length(mod_id, cc_id); conf->si_config->has_sib1_length = 1; conf->si_config->si_window_length = (uint32_t) flexran_get_si_window_length(mod_id, cc_id); conf->si_config->has_si_window_length = 1; conf->si_config->n_si_message = 0; /* Protocol__FlexSiMessage **si_message; */ /* si_message = malloc(sizeof(Protocol__FlexSiMessage *) * si_config->n_si_message); */ /* if(si_message == NULL) */ /* goto error; */ /* for(j = 0; j < si_config->n_si_message; j++){ */ /* si_message[j] = malloc(sizeof(Protocol__FlexSiMessage)); */ /* if(si_message[j] == NULL) */ /* goto error; */ /* protocol__flex_si_message__init(si_message[j]); */ /* //TODO: Fill in with actual value, Periodicity of SI msg in radio frames */ /* si_message[j]->periodicity = 1; //SIPeriod */ /* si_message[j]->has_periodicity = 1; */ /* //TODO: Fill in with actual value, rhe length of the SI message in bytes */ /* si_message[j]->length = 10; */ /* si_message[j]->has_length = 1; */ /* } */ /* if(si_config->n_si_message > 0){ */ /* si_config->si_message = si_message; */ /* } */ } conf->ra_response_window_size = flexran_get_ra_ResponseWindowSize(mod_id, cc_id); conf->has_ra_response_window_size = 1; // belongs to MAC but is read in RRC conf->mac_contention_resolution_timer = flexran_get_mac_ContentionResolutionTimer(mod_id, cc_id); conf->has_mac_contention_resolution_timer = 1; conf->ul_pusch_power = flexran_agent_get_operating_pusch_p0 (mod_id, cc_id); conf->has_ul_pusch_power = 1; conf->n_plmn_id = flexran_get_rrc_num_plmn_ids(mod_id); conf->plmn_id = calloc(conf->n_plmn_id, sizeof(Protocol__FlexPlmn *)); if (conf->plmn_id) { for (int i = 0; i < conf->n_plmn_id; i++) { conf->plmn_id[i] = malloc(sizeof(Protocol__FlexPlmn)); if (!conf->plmn_id[i]) continue; protocol__flex_plmn__init(conf->plmn_id[i]); conf->plmn_id[i]->mcc = flexran_get_rrc_mcc(mod_id, i); conf->plmn_id[i]->has_mcc = 1; conf->plmn_id[i]->mnc = flexran_get_rrc_mnc(mod_id, i); conf->plmn_id[i]->has_mnc = 1; conf->plmn_id[i]->mnc_length = flexran_get_rrc_mnc_digit_length(mod_id, i); conf->plmn_id[i]->has_mnc_length = 1; } } else { conf->n_plmn_id = 0; } conf->x2_ho_net_control = flexran_get_x2_ho_net_control(mod_id); conf->has_x2_ho_net_control = 1; } int flexran_agent_unregister_rrc_xface(mid_t mod_id) { if (!agent_rrc_xface[mod_id]) { LOG_E(FLEXRAN_AGENT, "RRC agent for eNB %d is not registered\n", mod_id); return -1; } //xface->agent_ctxt = NULL; // xface->flexran_agent_send_update_rrc_stats = NULL; agent_rrc_xface[mod_id]->flexran_agent_notify_ue_state_change = NULL; agent_rrc_xface[mod_id]->flexran_trigger_rrc_measurements = NULL; free(agent_rrc_xface[mod_id]); agent_rrc_xface[mod_id] = NULL; return 0; }