/******************************************************************************* Eurecom OpenAirInterface Copyright(c) 1999 - 2014 Eurecom This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information Openair Admin: openair_admin@eurecom.fr Openair Tech : openair_tech@eurecom.fr Forums : http://forums.eurecom.fr/openairinterface Address : EURECOM, Campus SophiaTech, 450 Route des Chappes 06410 Biot FRANCE *******************************************************************************/ #include <string.h> #include <libconfig.h> #include "log.h" #include "assertions.h" #include "enb_config.h" #if defined(OAI_EMU) # include "OCG.h" # include "OCG_extern.h" #endif #if defined(ENABLE_ITTI) # include "intertask_interface.h" # if defined(ENABLE_USE_MME) # include "s1ap_eNB.h" # include "sctp_eNB_task.h" # endif #endif #include "LAYER2/MAC/extern.h" int enb_config_init(char* lib_config_file_name_pP, Enb_properties_t **enb_properties) { config_t cfg; config_setting_t *setting; config_setting_t *setting_mme_addresses; config_setting_t *setting_mme_address; config_setting_t *setting_enb; int num_enb_properties = 0; int enb_properties_index = 0; int num_enbs; int num_mme_address; int i; int j; int parse_error = 0; long int enb_id; const char* cell_type; long int tac; const char* enb_name; long int mcc; long int mnc; const char* default_drx; const char* frame_type; const char* prefix_type; long long int downlink_frequency; long int uplink_frequency_offset; char* ipv4; char* ipv6; char* active; char* preference; const char* active_enb[MAX_ENB]; memset((char*)enb_properties, 0 , MAX_ENB * sizeof(Enb_properties_t*)); memset((char*)active_enb, 0 , MAX_ENB * sizeof(char*)); config_init(&cfg); if(lib_config_file_name_pP != NULL) { /* Read the file. If there is an error, report it and exit. */ if(! config_read_file(&cfg, lib_config_file_name_pP)) { LOG_E(ENB_APP, "%s:%d - %s\n", lib_config_file_name_pP, config_error_line(&cfg), config_error_text(&cfg)); config_destroy(&cfg); AssertFatal (0, "Failed to parse eNB configuration file %s!\n", lib_config_file_name_pP); } } else { LOG_E(ENB_APP, "No eNB configuration file provided!\n"); config_destroy(&cfg); AssertFatal (0, "No eNB configuration file provided!\n"); } // Get list of active eNBs, (only these will be configured) setting = config_lookup(&cfg, ENB_CONFIG_STRING_ACTIVE_ENBS); if(setting != NULL) { num_enbs = config_setting_length(setting); for (i = 0; i < num_enbs; i++) { setting_enb = config_setting_get_elem(setting, i); active_enb[i] = config_setting_get_string (setting_enb); AssertFatal (active_enb[i] != NULL, "Failed to parse config file %s, %uth attribute %s \n", lib_config_file_name_pP, i, ENB_CONFIG_STRING_ACTIVE_ENBS); active_enb[i] = strdup(active_enb[i]); num_enb_properties += 1; } } /* Output a list of all eNBs. */ setting = config_lookup(&cfg, ENB_CONFIG_STRING_ENB_LIST); if(setting != NULL) { enb_properties_index = 0; parse_error = 0; num_enbs = config_setting_length(setting); for (i = 0; i < num_enbs; i++) { setting_enb = config_setting_get_elem(setting, i); if(! config_setting_lookup_int(setting_enb, ENB_CONFIG_STRING_ENB_ID, &enb_id)) { uint32_t hash; /* Calculate a default eNB ID */ hash = s1ap_generate_eNB_id (); enb_id = i + (hash & 0xFFFF8); } if( !( config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_CELL_TYPE, &cell_type) && config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_ENB_NAME, &enb_name) && config_setting_lookup_int (setting_enb, ENB_CONFIG_STRING_TRACKING_AREA_CODE, &tac) && config_setting_lookup_int (setting_enb, ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE, &mcc) && config_setting_lookup_int (setting_enb, ENB_CONFIG_STRING_MOBILE_NETWORK_CODE, &mnc) && config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_DEFAULT_PAGING_DRX, &default_drx) ) ) { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, %u th enb\n", lib_config_file_name_pP, i); } // search if in active list for (j=0; j < num_enb_properties; j++) { if (strcmp(active_enb[j], enb_name) == 0) { enb_properties[enb_properties_index] = calloc(1, sizeof(Enb_properties_t)); enb_properties[enb_properties_index]->eNB_id = enb_id; if (strcmp(cell_type, "CELL_MACRO_ENB") == 0) { enb_properties[enb_properties_index]->cell_type = CELL_MACRO_ENB; } else if (strcmp(cell_type, "CELL_HOME_ENB") == 0) { enb_properties[enb_properties_index]->cell_type = CELL_HOME_ENB; } else { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n", lib_config_file_name_pP, i, cell_type); } enb_properties[enb_properties_index]->eNB_name = strdup(enb_name); enb_properties[enb_properties_index]->tac = (uint16_t)tac; enb_properties[enb_properties_index]->mcc = (uint16_t)mcc; enb_properties[enb_properties_index]->mnc = (uint16_t)mnc; if (strcmp(default_drx, "PAGING_DRX_32") == 0) { enb_properties[enb_properties_index]->default_drx = PAGING_DRX_32; } else if (strcmp(default_drx, "PAGING_DRX_64") == 0) { enb_properties[enb_properties_index]->default_drx = PAGING_DRX_64; } else if (strcmp(default_drx, "PAGING_DRX_128") == 0) { enb_properties[enb_properties_index]->default_drx = PAGING_DRX_128; } else if (strcmp(default_drx, "PAGING_DRX_256") == 0) { enb_properties[enb_properties_index]->default_drx = PAGING_DRX_256; } else { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for default_drx choice: PAGING_DRX_32..PAGING_DRX_256 !\n", lib_config_file_name_pP, i, default_drx); } // Parse optional physical parameters if(config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_FRAME_TYPE, &frame_type)) { if (strcmp(frame_type, "FDD") == 0) { enb_properties[enb_properties_index]->frame_type = FDD; } else if (strcmp(frame_type, "TDD") == 0) { enb_properties[enb_properties_index]->frame_type = TDD; } else { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n", lib_config_file_name_pP, i, frame_type); } } else { enb_properties[enb_properties_index]->frame_type = FDD; // Default frame type } if(config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_PREFIX_TYPE, &prefix_type)) { if (strcmp(prefix_type, "NORMAL") == 0) { enb_properties[enb_properties_index]->prefix_type = NORMAL; } else if (strcmp(prefix_type, "EXTENDED") == 0) { enb_properties[enb_properties_index]->prefix_type = EXTENDED; } else { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for prefix_type choice: NORMAL or EXTENDED !\n", lib_config_file_name_pP, i, prefix_type); } } else { enb_properties[enb_properties_index]->prefix_type = NORMAL; // Default prefix type } if(config_setting_lookup_int64(setting_enb, ENB_CONFIG_STRING_DOWNLINK_FREQUENCY, &downlink_frequency)) { enb_properties[enb_properties_index]->downlink_frequency = downlink_frequency; } else { enb_properties[enb_properties_index]->downlink_frequency = 2680000000UL; // Default downlink frequency } if(config_setting_lookup_int(setting_enb, ENB_CONFIG_STRING_UPLINK_FREQUENCY_OFFSET, &uplink_frequency_offset)) { enb_properties[enb_properties_index]->uplink_frequency_offset = uplink_frequency_offset; } else { enb_properties[enb_properties_index]->uplink_frequency_offset = -120000000; // Default uplink frequency offset } setting_mme_addresses = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_MME_IP_ADDRESS); num_mme_address = config_setting_length(setting_mme_addresses); enb_properties[enb_properties_index]->nb_mme = 0; for (j = 0; j < num_mme_address; j++) { setting_mme_address = config_setting_get_elem(setting_mme_addresses, j); if( !( config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV4_ADDRESS, (const char **)&ipv4) && config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV6_ADDRESS, (const char **)&ipv6) && config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE, (const char **)&active) && config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE, (const char **)&preference) ) ) { AssertError (0, parse_error ++, "Failed to parse eNB configuration file %s, %u th enb %u th mme address !\n", lib_config_file_name_pP, i, j); } enb_properties[enb_properties_index]->nb_mme += 1; enb_properties[enb_properties_index]->mme_ip_address[j].ipv4_address = strdup(ipv4); enb_properties[enb_properties_index]->mme_ip_address[j].ipv6_address = strdup(ipv6); if (strcmp(active, "yes") == 0) { enb_properties[enb_properties_index]->mme_ip_address[j].active = 1; #if defined(ENABLE_USE_MME) EPC_MODE_ENABLED = 1; #endif } // else { (calloc) if (strcmp(preference, "ipv4") == 0) { enb_properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1; } else if (strcmp(preference, "ipv6") == 0) { enb_properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1; } else if (strcmp(preference, "no") == 0) { enb_properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1; enb_properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1; } } enb_properties_index += 1; break; } } } } AssertError (enb_properties_index == num_enb_properties, parse_error ++, "Failed to parse eNB configuration file %s, mismatch between %u active eNBs and %u corresponding defined eNBs !\n", lib_config_file_name_pP, num_enb_properties, enb_properties_index); AssertFatal (parse_error == 0, "Failed to parse eNB configuration file %s, found %d error%s !\n", lib_config_file_name_pP, parse_error, parse_error > 1 ? "s" : ""); return num_enb_properties; }