示例#1
0
int mme_app_config_init(char* lib_config_file_name_pP, mme_app_config_t* config_pP) {

  config_t          cfg;
  config_setting_t *setting_sgw                          = NULL;
  char             *sgw_interface_name_for_S1u_S12_S4_up = NULL;
  char             *sgw_ipv4_address_for_S1u_S12_S4_up   = NULL;
  char             *sgw_interface_name_for_S5_S8_up      = NULL;
  char             *sgw_ipv4_address_for_S5_S8_up        = NULL;
  char             *sgw_interface_name_for_S11           = NULL;
  char             *sgw_ipv4_address_for_S11             = NULL;

  config_setting_t *setting_pgw                  = NULL;
  config_setting_t *subsetting                   = NULL;
  config_setting_t *sub2setting                  = NULL;
  char             *pgw_interface_name_for_S5_S8 = NULL;
  char             *pgw_ipv4_address_for_S5_S8   = NULL;
  char             *pgw_interface_name_for_SGI   = NULL;
  char             *pgw_ipv4_address_for_SGI     = NULL;

  char             *delimiters=NULL;
  char             *saveptr1= NULL;
  char             *astring = NULL;
  char             *atoken  = NULL;
  char             *atoken2 = NULL;
  char             *address = NULL;
  char             *cidr    = NULL;
  char             *mask    = NULL;
  int               num     = 0;
  int               i       = 0;
  int               jh, jn;
  unsigned char     buf_in6_addr[sizeof(struct in6_addr)];
  struct in6_addr   addr6_start;
  struct in6_addr   addr6_mask;
  int               prefix_mask;
  uint64_t          counter64;
  unsigned char     buf_in_addr[sizeof(struct in_addr)];
  struct in_addr    addr_start;
  struct in_addr    addr_end;


  memset((char*)config_pP, 0 , sizeof(mme_app_config_t));

  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))
      {
          MME_APP_ERROR("%s:%d - %s\n", lib_config_file_name_pP, config_error_line(&cfg), config_error_text(&cfg));
          config_destroy(&cfg);
          AssertFatal (1 == 0, "Failed to parse eNB configuration file %s!\n", lib_config_file_name_pP);
      }
  }
  else
  {
      SPGW_APP_ERROR("No SP-GW configuration file provided!\n");
      config_destroy(&cfg);
      AssertFatal (0, "No SP-GW configuration file provided!\n");
  }

  setting_sgw = config_lookup(&cfg, SGW_CONFIG_STRING_SGW_CONFIG);
  if(setting_sgw != NULL) {
      subsetting = config_setting_get_member (setting_sgw, SGW_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
      if(subsetting != NULL) {
          if(  (
                     config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP, (const char **)&sgw_interface_name_for_S1u_S12_S4_up)
                  && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP,   (const char **)&sgw_ipv4_address_for_S1u_S12_S4_up)
                  && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_INTERFACE_NAME_FOR_S5_S8_UP,      (const char **)&sgw_interface_name_for_S5_S8_up)
                  && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_IPV4_ADDRESS_FOR_S5_S8_UP,        (const char **)&sgw_ipv4_address_for_S5_S8_up)
                  && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_INTERFACE_NAME_FOR_S11,           (const char **)&sgw_interface_name_for_S11)
                  && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_IPV4_ADDRESS_FOR_S11,             (const char **)&sgw_ipv4_address_for_S11)
                )
            ) {
              config_pP->sgw_config.ipv4.sgw_interface_name_for_S1u_S12_S4_up = strdup(sgw_interface_name_for_S1u_S12_S4_up);
              cidr = strdup(sgw_ipv4_address_for_S1u_S12_S4_up);
              address = strtok(cidr, "/");
              mask    = strtok(NULL, "/");
              IPV4_STR_ADDR_TO_INT_NWBO ( address, config_pP->sgw_config.ipv4.sgw_ipv4_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR S1u_S12_S4 !\n" )
              config_pP->sgw_config.ipv4.sgw_ip_netmask_for_S1u_S12_S4_up = atoi(mask);
              free(cidr);

              config_pP->sgw_config.ipv4.sgw_interface_name_for_S5_S8_up = strdup(sgw_interface_name_for_S5_S8_up);
              cidr = strdup(sgw_ipv4_address_for_S5_S8_up);
              address = strtok(cidr, "/");
              mask    = strtok(NULL, "/");
              IPV4_STR_ADDR_TO_INT_NWBO ( address, config_pP->sgw_config.ipv4.sgw_ipv4_address_for_S5_S8_up, "BAD IP ADDRESS FORMAT FOR S5_S8 !\n" )
              config_pP->sgw_config.ipv4.sgw_ip_netmask_for_S5_S8_up = atoi(mask);
              free(cidr);

              config_pP->sgw_config.ipv4.sgw_interface_name_for_S11 = strdup(sgw_interface_name_for_S11);
              cidr = strdup(sgw_ipv4_address_for_S11);
              address = strtok(cidr, "/");
              mask    = strtok(NULL, "/");
              IPV4_STR_ADDR_TO_INT_NWBO ( address, config_pP->sgw_config.ipv4.sgw_ipv4_address_for_S11, "BAD IP ADDRESS FORMAT FOR S11 !\n" )
              config_pP->sgw_config.ipv4.sgw_ip_netmask_for_S11 = atoi(mask);
              free(cidr);
          }
      }
  }

  setting_pgw = config_lookup(&cfg, PGW_CONFIG_STRING_PGW_CONFIG);
  if(setting_pgw != NULL)
  {
      subsetting = config_setting_get_member (setting_pgw, SGW_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
      if(subsetting != NULL) {
          if(  (
                  config_setting_lookup_string(subsetting,
                          PGW_CONFIG_STRING_PGW_INTERFACE_NAME_FOR_S5_S8,
                          (const char **)&pgw_interface_name_for_S5_S8)
                  && config_setting_lookup_string(subsetting,
                          PGW_CONFIG_STRING_PGW_IPV4_ADDRESS_FOR_S5_S8,
                          (const char **)&pgw_ipv4_address_for_S5_S8)
                  && config_setting_lookup_string(subsetting,
                          PGW_CONFIG_STRING_PGW_INTERFACE_NAME_FOR_SGI,
                          (const char **)&pgw_interface_name_for_SGI)
                  && config_setting_lookup_string(subsetting,
                          PGW_CONFIG_STRING_PGW_IPV4_ADDR_FOR_SGI,
                          (const char **)&pgw_ipv4_address_for_SGI)
                )
            ) {
              config_pP->pgw_config.ipv4.pgw_interface_name_for_S5_S8 = strdup(pgw_interface_name_for_S5_S8);
              cidr = strdup(pgw_ipv4_address_for_S5_S8);
              address = strtok(cidr, "/");
              mask    = strtok(NULL, "/");
              IPV4_STR_ADDR_TO_INT_NWBO ( address, config_pP->pgw_config.ipv4.pgw_ipv4_address_for_S5_S8, "BAD IP ADDRESS FORMAT FOR S5_S8 !\n" )
              config_pP->pgw_config.ipv4.pgw_ip_netmask_for_S5_S8 = atoi(mask);
              free(cidr);

              config_pP->pgw_config.ipv4.pgw_interface_name_for_SGI = strdup(pgw_interface_name_for_SGI);
              cidr = strdup(pgw_ipv4_address_for_SGI);
              address = strtok(cidr, "/");
              mask    = strtok(NULL, "/");
              IPV4_STR_ADDR_TO_INT_NWBO ( address, config_pP->pgw_config.ipv4.pgw_ipv4_address_for_SGI, "BAD IP ADDRESS FORMAT FOR SGI !\n" )
              config_pP->pgw_config.ipv4.pgw_ip_netmask_for_SGI = atoi(mask);
              free(cidr);
          }
      }
      subsetting = config_setting_get_member (setting_pgw, PGW_CONFIG_STRING_IP_ADDRESS_POOL);
      if(subsetting != NULL) {
          sub2setting = config_setting_get_member (subsetting, PGW_CONFIG_STRING_IPV4_ADDRESS_LIST);
          if(sub2setting != NULL) {
              num     = config_setting_length(sub2setting);
              for (i = 0; i < num; i++) {
                  astring = config_setting_get_string_elem(sub2setting,i);
                  if (astring != NULL) {
                      trim(astring, strlen(astring)+1);
                      if (inet_pton(AF_INET, astring, buf_in_addr) < 1) {
                          // failure, test if there is a range specified in the string
                          atoken = strtok(astring, PGW_CONFIG_STRING_IP_ADDRESS_RANGE_DELIMITERS);
                          if (inet_pton(AF_INET, astring, buf_in_addr) == 1) {
                              memcpy (&addr_start, buf_in_addr, sizeof(struct in_addr));
                              // valid address
                              atoken2 = strtok(NULL, PGW_CONFIG_STRING_IP_ADDRESS_RANGE_DELIMITERS);
                              if (inet_pton(AF_INET, atoken2, buf_in_addr) == 1) {
                                  memcpy (&addr_end, buf_in_addr, sizeof(struct in_addr));
                                  // valid address
                                  for (jh = ntohl(addr_start.s_addr); jh <= ntohl(addr_end.s_addr); jh++) {
                                      DevAssert(PGW_MAX_ALLOCATED_PDN_ADDRESSES > config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses);
                                      jn = htonl(jh);
                                      if (IN_CLASSA(addr_start.s_addr)) {
                                          if ((jh & 0xFF) && (jh & 0xFF) != 0xFF) {
                                              config_pP->pgw_config.pool_pdn_addresses.ipv4_addresses[config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses++].s_addr = jn;
                                          }
                                      } else if (IN_CLASSB(addr_start.s_addr)) {
                                          if ((jh & 0xFF) && (jh & 0xFF) != 0xFF) {
                                              config_pP->pgw_config.pool_pdn_addresses.ipv4_addresses[config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses++].s_addr = jn;
                                          }
                                      } else if (IN_CLASSC(addr_start.s_addr)) {
                                          if ((jh & 0xFF) && (jh & 0xFF) != 0xFF) {
                                              config_pP->pgw_config.pool_pdn_addresses.ipv4_addresses[config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses++].s_addr = jn;
                                          }
                                      } else {
                                          printf("ERROR ON ADDRESS CLASS %d.%d.%d.%d\n", NIPADDR(jn));
                                      }
                                  }
                              }
                          }
                      } else {
                          DevAssert(PGW_MAX_ALLOCATED_PDN_ADDRESSES > config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses);
                          memcpy (&addr_start, buf_in_addr, sizeof(struct in_addr));
                          config_pP->pgw_config.pool_pdn_addresses.ipv4_addresses[config_pP->pgw_config.pool_pdn_addresses.num_ipv4_addresses++].s_addr = addr_start.s_addr;
                      }
                  }
              }
          }
          sub2setting = config_setting_get_member (subsetting, PGW_CONFIG_STRING_IPV6_ADDRESS_LIST);
          if(sub2setting != NULL) {
              num     = config_setting_length(sub2setting);
              for (i = 0; i < num; i++) {
                  astring = config_setting_get_string_elem(sub2setting,i);
                  if (astring != NULL) {
                      trim(astring, strlen(astring)+1);
                      if (inet_pton(AF_INET6, astring, buf_in6_addr) < 1) {
                          // failure, test if there is a range specified in the string
                          atoken = strtok(astring, PGW_CONFIG_STRING_IPV6_PREFIX_DELIMITER);
                          if (inet_pton(AF_INET6, astring, buf_in6_addr) == 1) {
                              atoken2 = strtok(NULL, PGW_CONFIG_STRING_IPV6_PREFIX_DELIMITER);
                              prefix_mask = atoi(atoken2);
                              // arbitrary values
                              DevAssert((prefix_mask < 128) && (prefix_mask >= 64));

                              memcpy (&addr6_start, buf_in6_addr, sizeof(struct in6_addr));
                              memcpy (&addr6_mask,  buf_in6_addr, sizeof(struct in6_addr));
                              sgw_ipv6_mask_in6_addr(&addr6_mask, prefix_mask);

                              if (memcmp(&addr6_start, &addr6_mask, sizeof(struct in6_addr)) != 0) {
                                  AssertFatal(0, "BAD IPV6 ADDR CONFIG/MASK PAIRING %s/%d\n", astring, prefix_mask);
                              }

                              counter64 = 0xFFFFFFFFFFFFFFFF >> prefix_mask; // address Prefix_mask/0..0 not valid
                              do {
                                  addr6_start.s6_addr32[3] = addr6_start.s6_addr32[3] + htonl(1);
                                  if (addr6_start.s6_addr32[3] == 0) {
                                      addr6_start.s6_addr32[2] = addr6_start.s6_addr32[2] + htonl(1);
                                      if (addr6_start.s6_addr32[2] == 0) {
                                          // should not happen since mask is no less than 64
                                          addr6_start.s6_addr32[1] = addr6_start.s6_addr32[1] + htonl(1);
                                          if (addr6_start.s6_addr32[1] == 0) {
                                              addr6_start.s6_addr32[0] = addr6_start.s6_addr32[0] + htonl(1);
                                          }
                                      }
                                  }
                                  memcpy (&config_pP->pgw_config.pool_pdn_addresses.ipv6_addresses[config_pP->pgw_config.pool_pdn_addresses.num_ipv6_addresses++],
                                          &addr6_start,
                                          sizeof(struct in6_addr));
                                  counter64 = counter64 - 1;
                              } while (counter64 > 0);
                          }
                      } else {
示例#2
0
static int config_parse_file(mme_config_t *mme_config_p)
{
  config_t          cfg;
  config_setting_t *setting_mme                      = NULL;
  config_setting_t *setting                          = NULL;
  config_setting_t *subsetting                       = NULL;
  config_setting_t *sub2setting                      = NULL;

  long int         alongint;
  int              i, num;
  char             *astring                          = NULL;
  char             *address                          = NULL;
  char             *cidr                             = NULL;

  const char*       tac                              = NULL;
  const char*       mcc                              = NULL;
  const char*       mnc                              = NULL;

  char             *sgw_ip_address_for_S1u_S12_S4_up = NULL;
  char             *mme_interface_name_for_S1_MME    = NULL;
  char             *mme_ip_address_for_S1_MME        = NULL;
  char             *mme_interface_name_for_S11       = NULL;
  char             *mme_ip_address_for_S11           = NULL;
  char             *sgw_ip_address_for_S11           = NULL;
  char                system_cmd[256];

  config_init(&cfg);

  if(mme_config_p->config_file != NULL) {
    /* Read the file. If there is an error, report it and exit. */
    if(! config_read_file(&cfg, mme_config_p->config_file)) {
      fprintf(stdout, "ERROR: %s:%d - %s\n", mme_config_p->config_file, config_error_line(&cfg), config_error_text(&cfg));
      config_destroy(&cfg);
      AssertFatal (1 == 0, "Failed to parse MME configuration file %s!\n", mme_config_p->config_file);
    }
  } else {
    fprintf(stdout, "ERROR No MME configuration file provided!\n");
    config_destroy(&cfg);
    AssertFatal (0, "No MME configuration file provided!\n");
  }

  setting_mme = config_lookup(&cfg, MME_CONFIG_STRING_MME_CONFIG);

  if(setting_mme != NULL) {
    // GENERAL MME SETTINGS
    if(  (config_setting_lookup_string( setting_mme, MME_CONFIG_STRING_REALM, (const char **)&astring) )) {
      mme_config_p->realm = strdup(astring);
      mme_config_p->realm_length = strlen(mme_config_p->realm);
    }

    if(  (config_setting_lookup_int( setting_mme, MME_CONFIG_STRING_MAXENB, &alongint) )) {
      mme_config_p->max_eNBs = (uint32_t)alongint;
    }

    if(  (config_setting_lookup_int( setting_mme, MME_CONFIG_STRING_MAXUE, &alongint) )) {
      mme_config_p->max_ues = (uint32_t)alongint;
    }

    if(  (config_setting_lookup_int( setting_mme, MME_CONFIG_STRING_RELATIVE_CAPACITY, &alongint) )) {
      mme_config_p->relative_capacity = (uint8_t)alongint;
    }

    if(  (config_setting_lookup_int( setting_mme, MME_CONFIG_STRING_STATISTIC_TIMER, &alongint) )) {
      mme_config_p->mme_statistic_timer = (uint32_t)alongint;
    }

    if(  (config_setting_lookup_string( setting_mme, MME_CONFIG_STRING_EMERGENCY_ATTACH_SUPPORTED, (const char **)&astring) )) {
      if (strcasecmp(astring , "yes") == 0)
        mme_config_p->emergency_attach_supported = 1;
      else
        mme_config_p->emergency_attach_supported = 0;
    }

    if(  (config_setting_lookup_string( setting_mme, MME_CONFIG_STRING_UNAUTHENTICATED_IMSI_SUPPORTED, (const char **)&astring) )) {
      if (strcasecmp(astring , "yes") == 0)
        mme_config_p->unauthenticated_imsi_supported = 1;
      else
        mme_config_p->unauthenticated_imsi_supported = 0;
    }

    if(  (config_setting_lookup_string( setting_mme, MME_CONFIG_STRING_ASN1_VERBOSITY, (const char **)&astring) )) {
      if (strcasecmp(astring , MME_CONFIG_STRING_ASN1_VERBOSITY_NONE) == 0)
        mme_config_p->verbosity_level = 0;
      else if (strcasecmp(astring , MME_CONFIG_STRING_ASN1_VERBOSITY_ANNOYING) == 0)
        mme_config_p->verbosity_level = 2;
      else if (strcasecmp(astring , MME_CONFIG_STRING_ASN1_VERBOSITY_INFO) == 0)
        mme_config_p->verbosity_level = 1;
      else
        mme_config_p->verbosity_level = 0;
    }

    // ITTI SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_INTERTASK_INTERFACE_CONFIG);

    if (setting != NULL) {
      if(  (config_setting_lookup_int( setting, MME_CONFIG_STRING_INTERTASK_INTERFACE_QUEUE_SIZE, &alongint) )) {
        mme_config_p->itti_config.queue_size = (uint32_t)alongint;
      }
    }

    // S6A SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_S6A_CONFIG);

    if (setting != NULL) {
      if(  (config_setting_lookup_string( setting, MME_CONFIG_STRING_S6A_CONF_FILE_PATH, (const char **)&astring) )) {
        if (astring != NULL)
          mme_config_p->s6a_config.conf_file = strdup(astring);
      }

      if(  (config_setting_lookup_string( setting, MME_CONFIG_STRING_S6A_HSS_HOSTNAME, (const char **)&astring) )) {
        if (astring != NULL)
          mme_config_p->s6a_config.hss_host_name  = strdup(astring);
        else
          AssertFatal (1 == 0,
                       "You have to provide a valid HSS hostname %s=...\n",
                       MME_CONFIG_STRING_S6A_HSS_HOSTNAME);
      }
    }

    // SCTP SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_SCTP_CONFIG);

    if (setting != NULL) {
      if(  (config_setting_lookup_int( setting, MME_CONFIG_STRING_SCTP_INSTREAMS, &alongint) )) {
        mme_config_p->sctp_config.in_streams = (uint16_t)alongint;
      }

      if(  (config_setting_lookup_int( setting, MME_CONFIG_STRING_SCTP_OUTSTREAMS, &alongint) )) {
        mme_config_p->sctp_config.out_streams = (uint16_t)alongint;
      }
    }

    // S1AP SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_S1AP_CONFIG);

    if (setting != NULL) {
      if(  (config_setting_lookup_int( setting, MME_CONFIG_STRING_S1AP_OUTCOME_TIMER, &alongint) )) {
        mme_config_p->s1ap_config.outcome_drop_timer_sec = (uint8_t)alongint;
      }

      if(  (config_setting_lookup_int( setting, MME_CONFIG_STRING_S1AP_PORT, &alongint) )) {
        mme_config_p->s1ap_config.port_number = (uint16_t)alongint;
      }
    }

    // GUMMEI SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_GUMMEI_CONFIG);

    if (setting != NULL) {
      subsetting = config_setting_get_member (setting, MME_CONFIG_STRING_MME_CODE);

      if (subsetting != NULL) {
        num     = config_setting_length(subsetting);

        if (mme_config_p->gummei.nb_mmec != num) {
          if (mme_config_p->gummei.mmec != NULL) {
            free(mme_config_p->gummei.mmec);
          }

          mme_config_p->gummei.mmec = calloc(num, sizeof(*mme_config_p->gummei.mmec));
        }

        mme_config_p->gummei.nb_mmec = num;

        for (i = 0; i < num; i++) {
          mme_config_p->gummei.mmec[i] = config_setting_get_int_elem(subsetting, i);
        }
      }

      subsetting = config_setting_get_member (setting, MME_CONFIG_STRING_MME_GID);

      if (subsetting != NULL) {
        num     = config_setting_length(subsetting);

        if (mme_config_p->gummei.nb_mme_gid != num) {
          if (mme_config_p->gummei.mme_gid != NULL) {
            free(mme_config_p->gummei.mme_gid);
          }

          mme_config_p->gummei.mme_gid = calloc(num, sizeof(*mme_config_p->gummei.mme_gid));
        }

        mme_config_p->gummei.nb_mme_gid = num;

        for (i = 0; i < num; i++) {
          mme_config_p->gummei.mme_gid[i] = config_setting_get_int_elem(subsetting, i);
        }
      }

      subsetting = config_setting_get_member (setting, MME_CONFIG_STRING_TAI_LIST);

      if (subsetting != NULL) {
        num     = config_setting_length(subsetting);

        if (mme_config_p->gummei.nb_plmns != num) {
          if (mme_config_p->gummei.plmn_mcc != NULL)     free(mme_config_p->gummei.plmn_mcc);

          if (mme_config_p->gummei.plmn_mnc != NULL)     free(mme_config_p->gummei.plmn_mnc);

          if (mme_config_p->gummei.plmn_mnc_len != NULL) free(mme_config_p->gummei.plmn_mnc_len);

          if (mme_config_p->gummei.plmn_tac != NULL)     free(mme_config_p->gummei.plmn_tac);

          mme_config_p->gummei.plmn_mcc     = calloc(num, sizeof(*mme_config_p->gummei.plmn_mcc));
          mme_config_p->gummei.plmn_mnc     = calloc(num, sizeof(*mme_config_p->gummei.plmn_mnc));
          mme_config_p->gummei.plmn_mnc_len = calloc(num, sizeof(*mme_config_p->gummei.plmn_mnc_len));
          mme_config_p->gummei.plmn_tac     = calloc(num, sizeof(*mme_config_p->gummei.plmn_tac));
        }

        mme_config_p->gummei.nb_plmns = num;

        for (i = 0; i < num; i++) {
          sub2setting =  config_setting_get_elem(subsetting, i);

          if (sub2setting != NULL) {
            if(  (config_setting_lookup_string( sub2setting, MME_CONFIG_STRING_MCC, &mcc) )) {
              mme_config_p->gummei.plmn_mcc[i] = (uint16_t)atoi(mcc);
            }

            if(  (config_setting_lookup_string( sub2setting, MME_CONFIG_STRING_MNC, &mnc) )) {
              mme_config_p->gummei.plmn_mnc[i] = (uint16_t)atoi(mnc);
              mme_config_p->gummei.plmn_mnc_len[i] = strlen(mnc);
              AssertFatal((mme_config_p->gummei.plmn_mnc_len[i] == 2) || (mme_config_p->gummei.plmn_mnc_len[i] == 3),
                          "Bad MNC length %u, must be 2 or 3", mme_config_p->gummei.plmn_mnc_len[i]);
            }

            if(  (config_setting_lookup_string( sub2setting, MME_CONFIG_STRING_TAC, &tac) )) {
              mme_config_p->gummei.plmn_tac[i] = (uint16_t)atoi(tac);
              AssertFatal(mme_config_p->gummei.plmn_tac[i] != 0,
                          "TAC must not be 0");
            }
          }
        }
      }
    }

    // NETWORK INTERFACE SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);

    if(setting != NULL) {
      if(  (
             config_setting_lookup_string( setting, MME_CONFIG_STRING_INTERFACE_NAME_FOR_S1_MME,
                                           (const char **)&mme_interface_name_for_S1_MME)
             && config_setting_lookup_string( setting, MME_CONFIG_STRING_IPV4_ADDRESS_FOR_S1_MME,
                                              (const char **)&mme_ip_address_for_S1_MME)
             && config_setting_lookup_string( setting, MME_CONFIG_STRING_INTERFACE_NAME_FOR_S11_MME,
                                              (const char **)&mme_interface_name_for_S11)
             && config_setting_lookup_string( setting, MME_CONFIG_STRING_IPV4_ADDRESS_FOR_S11_MME,
                                              (const char **)&mme_ip_address_for_S11)
           )
        ) {
        mme_config_p->ipv4.mme_interface_name_for_S1_MME = strdup(mme_interface_name_for_S1_MME);
        cidr = strdup(mme_ip_address_for_S1_MME);
        address = strtok(cidr, "/");
        IPV4_STR_ADDR_TO_INT_NWBO ( address, mme_config_p->ipv4.mme_ip_address_for_S1_MME, "BAD IP ADDRESS FORMAT FOR MME S1_MME !\n" )
        free(cidr);

        mme_config_p->ipv4.mme_interface_name_for_S11 = strdup(mme_interface_name_for_S11);
        cidr = strdup(mme_ip_address_for_S11);
        address = strtok(cidr, "/");
        IPV4_STR_ADDR_TO_INT_NWBO ( address, mme_config_p->ipv4.mme_ip_address_for_S11, "BAD IP ADDRESS FORMAT FOR MME S11 !\n" )
        free(cidr);

        if (strncasecmp("tun",mme_config_p->ipv4.mme_interface_name_for_S1_MME, strlen("tun")) == 0) {
          if (snprintf(system_cmd, 256,
                       "ip link set %s down ;openvpn --rmtun --dev %s",
                       mme_config_p->ipv4.mme_interface_name_for_S1_MME,
                       mme_config_p->ipv4.mme_interface_name_for_S1_MME
                      ) > 0) {
            mme_system(system_cmd, 1);
          } else {
            fprintf(stderr, "Del %s\n", mme_config_p->ipv4.mme_interface_name_for_S1_MME);
          }

          if (snprintf(system_cmd, 256,
                       "openvpn --mktun --dev %s;sync;ifconfig  %s up;sync",
                       mme_config_p->ipv4.mme_interface_name_for_S1_MME,
                       mme_config_p->ipv4.mme_interface_name_for_S1_MME) > 0) {
            mme_system(system_cmd, 1);
          } else {
            fprintf(stderr, "Create %s\n", mme_config_p->ipv4.mme_interface_name_for_S1_MME);
          }

          if (snprintf(system_cmd, 256,
                       "ip -4 addr add %s  dev %s",
                       mme_ip_address_for_S1_MME,
                       mme_config_p->ipv4.mme_interface_name_for_S1_MME) > 0) {
            mme_system(system_cmd, 1);
          } else {
            fprintf(stderr, "Set IPv4 address on %s\n", mme_config_p->ipv4.mme_interface_name_for_S1_MME);
          }
        }

      }
    }

    // NAS SETTING
    setting = config_setting_get_member (setting_mme, MME_CONFIG_STRING_NAS_CONFIG);

    if (setting != NULL) {
      subsetting = config_setting_get_member (setting, MME_CONFIG_STRING_NAS_SUPPORTED_INTEGRITY_ALGORITHM_LIST);

      if (subsetting != NULL) {
        num     = config_setting_length(subsetting);

        if (num <= 8) {
          for (i = 0; i < num; i++) {
            astring = config_setting_get_string_elem(subsetting, i);

            if (strcmp("EIA0", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
            else if (strcmp("EIA1", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA1;
            else if (strcmp("EIA2", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA2;
            else if (strcmp("EIA3", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
            else if (strcmp("EIA4", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
            else if (strcmp("EIA5", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
            else if (strcmp("EIA6", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
            else if (strcmp("EIA7", astring) == 0) mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
          }

          for (i = num; i < 8; i++) {
            mme_config_p->nas_config.prefered_integrity_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EIA0;
          }
        }
      }

      subsetting = config_setting_get_member (setting, MME_CONFIG_STRING_NAS_SUPPORTED_CIPHERING_ALGORITHM_LIST);

      if (subsetting != NULL) {
        num     = config_setting_length(subsetting);

        if (num <= 8) {
          for (i = 0; i < num; i++) {
            astring = config_setting_get_string_elem(subsetting, i);

            if (strcmp("EEA0", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
            else if (strcmp("EEA1", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA1;
            else if (strcmp("EEA2", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA2;
            else if (strcmp("EEA3", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
            else if (strcmp("EEA4", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
            else if (strcmp("EEA5", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
            else if (strcmp("EEA6", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
            else if (strcmp("EEA7", astring) == 0) mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
          }

          for (i = num; i < 8; i++) {
            mme_config_p->nas_config.prefered_ciphering_algorithm[i] = NAS_CONFIG_SECURITY_ALGORITHMS_EEA0;
          }
        }
      }

    }
  }

  setting = config_lookup(&cfg, SGW_CONFIG_STRING_SGW_CONFIG);

  if(setting != NULL) {
    subsetting = config_setting_get_member (setting, SGW_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);

    if(subsetting != NULL) {
      if(  (
             config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_IPV4_ADDRESS_FOR_S1U_S12_S4_UP,
                                           (const char **)&sgw_ip_address_for_S1u_S12_S4_up)
             && config_setting_lookup_string( subsetting, SGW_CONFIG_STRING_SGW_IPV4_ADDRESS_FOR_S11,
                                              (const char **)&sgw_ip_address_for_S11)
             && config_setting_lookup_int( subsetting, SGW_CONFIG_STRING_SGW_PORT_FOR_S1U_S12_S4_UP, &alongint)
           )
        ) {
        cidr = strdup(sgw_ip_address_for_S1u_S12_S4_up);
        address = strtok(cidr, "/");
        IPV4_STR_ADDR_TO_INT_NWBO ( address, mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up, "BAD IP ADDRESS FORMAT FOR SGW S1u_S12_S4 !\n" )
        free(cidr);

        cidr = strdup(sgw_ip_address_for_S11);
        address = strtok(cidr, "/");
        IPV4_STR_ADDR_TO_INT_NWBO ( address, mme_config_p->ipv4.sgw_ip_address_for_S11, "BAD IP ADDRESS FORMAT FOR SGW S11 !\n" )
        free(cidr);

        mme_config_p->gtpv1u_config.port_number = (uint16_t) alongint;
      }
    }
  }

  return 0;
}
//------------------------------------------------------------------------------
const Enb_properties_array_t *enb_config_init(char* lib_config_file_name_pP)
//------------------------------------------------------------------------------
{
  config_t          cfg;
  config_setting_t *setting                       = NULL;
  config_setting_t *subsetting                    = NULL;
  config_setting_t *setting_srb1                  = NULL;
  config_setting_t *setting_mme_addresses         = NULL;
  config_setting_t *setting_mme_address           = NULL;
  config_setting_t *setting_enb                   = NULL;
  int               num_enb_properties            = 0;
  int               enb_properties_index          = 0;
  int               num_enbs                      = 0;
  int               num_mme_address               = 0;
  int               num_otg_elements              =0;
  int               num_component_carriers        =0;
  int               i                             = 0;
  int               j                             = 0;
  int               parse_errors                  = 0;
  libconfig_int     enb_id                        = 0;
  const char*       cell_type                     = NULL;
  const char*       tac                           = 0;
  const char*       enb_name                      = NULL;
  const char*       mcc                           = 0;
  const char*       mnc                           = 0;
  const char*       frame_type                    = NULL;
  const char*            prefix_type              = NULL;
  libconfig_int     Nid_cell                      = 0;

  libconfig_int     my_int;

  char*             ipv4                          = NULL;
  char*             ipv6                          = NULL;
  char*             active                        = NULL;
  char*             preference                    = NULL;
  const char*       active_enb[EPC_TEST_SCENARIO_MAX_ENB];
  char*             enb_interface_name_for_S1U    = NULL;
  char*             enb_ipv4_address_for_S1U      = NULL;
  libconfig_int     enb_port_for_S1U              = 0;
  char*             enb_interface_name_for_S1_MME = NULL;
  char*             enb_ipv4_address_for_S1_MME   = NULL;
  char             *address                       = NULL;
  char             *cidr                          = NULL;
  char             *astring                       = NULL;

  memset((char*)active_enb,     0 , EPC_TEST_SCENARIO_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)) {
      config_destroy(&cfg);
      AssertFatal (0, "Failed to parse eNB configuration file %s!\n", lib_config_file_name_pP);
    }
  } else {
    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_errors      = 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)) {
        /* Calculate a default eNB ID */
# if defined(ENABLE_USE_MME)
        uint32_t hash;

        hash = s1ap_generate_eNB_id ();
        enb_id = i + (hash & 0xFFFF8);
# else
        enb_id = i;
# endif
      }

      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_string(setting_enb, ENB_CONFIG_STRING_TRACKING_AREA_CODE,  &tac)
                    && config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE, &mcc)
                    && config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_NETWORK_CODE, &mnc)


            )
        ) {
        AssertError (0, parse_errors ++,
                     "Failed to parse eNB configuration file %s, %u th enb\n",
                     lib_config_file_name_pP, i);
        continue; // FIXME this prevents segfaults below, not sure what happens after function exit
      }

      // search if in active list
      for (j=0; j < num_enb_properties; j++) {
        if (strcmp(active_enb[j], enb_name) == 0) {
          g_enb_properties.properties[enb_properties_index] = calloc(1, sizeof(Enb_properties_t));

          g_enb_properties.properties[enb_properties_index]->eNB_id   = enb_id;

          if (strcmp(cell_type, "CELL_MACRO_ENB") == 0) {
            g_enb_properties.properties[enb_properties_index]->cell_type = CELL_MACRO_ENB;
          } else  if (strcmp(cell_type, "CELL_HOME_ENB") == 0) {
            g_enb_properties.properties[enb_properties_index]->cell_type = CELL_HOME_ENB;
          } else {
            AssertError (0, parse_errors ++,
                         "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);
          }

          g_enb_properties.properties[enb_properties_index]->eNB_name         = strdup(enb_name);
          g_enb_properties.properties[enb_properties_index]->tac              = (uint16_t)atoi(tac);
          g_enb_properties.properties[enb_properties_index]->mcc              = (uint16_t)atoi(mcc);
          g_enb_properties.properties[enb_properties_index]->mnc              = (uint16_t)atoi(mnc);
          g_enb_properties.properties[enb_properties_index]->mnc_digit_length = strlen(mnc);
          AssertFatal((g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 2) ||
                      (g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 3),
                      "BAD MNC DIGIT LENGTH %d",
                      g_enb_properties.properties[i]->mnc_digit_length);


          setting_mme_addresses = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_MME_IP_ADDRESS);
          num_mme_address     = config_setting_length(setting_mme_addresses);
          g_enb_properties.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_errors ++,
                           "Failed to parse eNB configuration file %s, %u th enb %u th mme address !\n",
                           lib_config_file_name_pP, i, j);
              continue; // FIXME will prevent segfaults below, not sure what happens at function exit...
            }

            g_enb_properties.properties[enb_properties_index]->nb_mme += 1;

            g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4_address = strdup(ipv4);
            g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6_address = strdup(ipv6);

            if (strcmp(active, "yes") == 0) {
              g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].active = 1;
            } // else { (calloc)

            if (strcmp(preference, "ipv4") == 0) {
              g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
            } else if (strcmp(preference, "ipv6") == 0) {
              g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
            } else if (strcmp(preference, "no") == 0) {
              g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
              g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
            }
          }


          // NETWORK_INTERFACES
          subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);

          if (subsetting != NULL) {
            if (  (
                   config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME,
                                                 (const char **)&enb_interface_name_for_S1_MME)
                   && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDRESS_FOR_S1_MME,
                                                    (const char **)&enb_ipv4_address_for_S1_MME)
                   && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1U,
                                                    (const char **)&enb_interface_name_for_S1U)
                   && config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U,
                                                    (const char **)&enb_ipv4_address_for_S1U)
                   && config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_S1U,
                                                &enb_port_for_S1U)
                 )
              ) {
              g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1U = strdup(enb_interface_name_for_S1U);
              cidr = enb_ipv4_address_for_S1U;
              address = strtok(cidr, "/");

              if (address) {
                IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1U, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" );
              }

              g_enb_properties.properties[enb_properties_index]->enb_port_for_S1U = enb_port_for_S1U;

              g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1_MME = strdup(enb_interface_name_for_S1_MME);
              cidr = enb_ipv4_address_for_S1_MME;
              address = strtok(cidr, "/");

              if (address) {
                IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1_MME, "BAD IP ADDRESS FORMAT FOR eNB S1_MME !\n" );
              }
            }
          }
        }
      }
    }
  }

  g_enb_properties.number = num_enb_properties;

  AssertError (enb_properties_index == num_enb_properties, parse_errors ++,
               "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_errors == 0,
               "Failed to parse eNB configuration file %s, found %d error%s !\n",
               lib_config_file_name_pP, parse_errors, parse_errors > 1 ? "s" : "");
  enb_config_display();
  return &g_enb_properties;

}