//---------------------------------------------------------------------------
// Search the entity with the IPv4 address 'addr'
struct cx_entity *nasmt_CLASS_cx4(struct sk_buff *skb, unsigned char dscp, int *paddr_type, unsigned char *cx_index) {
  //---------------------------------------------------------------------------
  unsigned char cxi;
  uint32_t daddr;
  struct cx_entity *cx=NULL;
  struct classifier_entity *pclassifier=NULL;
  struct in_addr masked_addr;

  #ifdef NAS_DEBUG_CLASS
  printk("nasmt_CLASS_cx4: begin\n");
  #endif
  if (skb!=NULL) {
    daddr = ((struct iphdr*)(skb_network_header(skb)))->daddr;
    if (daddr != INADDR_ANY) {
      #ifdef NAS_DEBUG_CLASS
      printk("nasmt_CLASS_cx4: SOURCE ADDR %d.%d.%d.%d",NIPADDR(ip_hdr(skb)->saddr));
      printk(" DEST ADDR %d.%d.%d.%d\n",NIPADDR(ip_hdr(skb)->daddr));
      #endif
      if (ipv4_is_multicast(ip_hdr(skb)->daddr)) {
        // TO BE CHECKED
        *paddr_type = NAS_IPV4_ADDR_MC_SIGNALLING;
      } else {
        if (ipv4_is_lbcast(ip_hdr(skb)->daddr)) {
        // TO BE CHECKED
        *paddr_type = NAS_IPV4_ADDR_BROADCAST;
        } else {
          if (IN_CLASSA(ip_hdr(skb)->daddr) || IN_CLASSB(ip_hdr(skb)->daddr) || IN_CLASSC(ip_hdr(skb)->daddr)) {
            *paddr_type = NAS_IPV4_ADDR_UNICAST;
            cxi = 0;
            (*cx_index)++;
            pclassifier = gpriv->cx[cxi].sclassifier[dscp];
            while (pclassifier!=NULL) {
              // verify that this is an IPv4 classifier
              if ((pclassifier->version == NAS_VERSION_4)  || (pclassifier->version == NAS_VERSION_DEFAULT)) {
                  nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
                  if (IN_ARE_ADDR_MASKED_EQUAL(&ip_hdr(skb)->daddr, &(pclassifier->daddr.ipv4), &masked_addr)) {
                    #ifdef NAS_DEBUG_CLASS
                    printk("nasmt_CLASS_cx4: IP MASK MATCHED: found cx %d: %d.%d.%d.%d/%d\n",cxi, NIPADDR(pclassifier->daddr.ipv4), pclassifier->dplen);
                    #endif
                  return &gpriv->cx[cxi];
                  }
              }
              // goto to next classification rule for the connection
              pclassifier = pclassifier->next;
            }
          } else {
            *paddr_type = NAS_IPV4_ADDR_UNKNOWN;
          }
        }
      }
    }
  }
  return cx;
}
Example #2
0
int 
start_connect (hs_key *pksid, hs_body *pbsid)
{   
    int         n, dret;
    struct      sockaddr_in stServerAddr;

    stServerAddr.sin_family         = AF_INET;
    stServerAddr.sin_addr.s_addr    = pbsid->dest_ipaddr;
    stServerAddr.sin_port           = pbsid->dest_port;

    if ( (n = connect (pbsid->cfd, (struct sockaddr *)&stServerAddr, sizeof(stServerAddr))) < 0) {

        if (errno != EINPROGRESS) {         
            dAppLog (LOG_DEBUG, "Nonblocking connect error! %d.%s-%s", errno, strerror(errno), __FUNCTION__);
            return -1;
        }

#if 0
        epollOne_cli_add (pbsid->tcpsock.sockfd);
        dAppLog(LOG_DEBUG, "--->] Nonblocking connect succss!! Dst:%d.%d.%d.%d : %d",
                                            NIPADDR(pbsid->dest_ipaddr), ntohs(pbsid->dest_port));
#endif
    
    }
    
    return 0;        
}
Example #3
0
void
rcv_tcpsock (struct epoll_event *event)
{
	int				flags, event_fd;
	int             n, error, dret;
	char            rbuf[1024*4];
	int				tcp_readlen;
	_hkey_fd		hfd_key;
	_hbody_fd		*phfd_body;

	hfd_key.sockfd = event_fd = event->data.fd;

	phfd_body = find_fd_session (&hfd_key);
	if (phfd_body == NULL) {

		dAppLog(LOG_DEBUG, "<--%d] Not found FD Session! %s-%d", hfd_key.sockfd, __FUNCTION__, __LINE__);
		/** clean **/
		del_fd_session(event_fd);
		return -1;
	}


	flags = phfd_body->tcpsock.f_flags;
	
	if ((flags & F_CONNECTING) && (event->events == EPOLLIN || event->events == EPOLLOUT)) {

        n = sizeof (error);
        if ((getsockopt(event_fd, SOL_SOCKET, SO_ERROR, &error, &n) < 0) || (error != 0)) {
                    
            dAppLog(LOG_WARN, "---]  nonblocking connect failed (reset)aaa %d-%s..%s-line:%d",
                    error, strerror(error),
                    __FUNCTION__, __LINE__);
		}

		phfd_body->tcpsock.f_flags = F_READING;
		epollin_cli_mod (event_fd);
		phfd_body->tcpsock.sock_idx = g_sock_cnt;
		g_sock [g_sock_cnt++] = event_fd;

		// write 
		if (g_auto_send == 1)
		{
			send_http_num_only (event_fd);
		}
	} else if (flags & F_READING) {
		tcp_readlen = read (event_fd, rbuf, sizeof (rbuf));
		dAppLog (LOG_DEBUG, "tcp_readlen: %d", tcp_readlen);

#ifdef SHOW_TRAFFIC
        rcurr_traffic += tcp_readlen;
        rtotal_cnt ++;
        rcurr_cnt ++;

		rnew_time = time(NULL);

        if ((rnew_time - rold_time) >= 5) {
            dAppLog (LOG_CRI, "WCLI TCP Traffic: %6.3f Kbps, Count: total=%d, %6.3f/sec",
                    (float)rcurr_traffic*8 / ((float)(rnew_time-rold_time)*1024), rtotal_cnt, (float)rcurr_cnt/(rnew_time-rold_time));
            
            rold_time = rnew_time;
            rcurr_traffic = 0;
            rcurr_cnt = 0;
        }
#endif

#ifdef TCP_DUMP
	    dAppLog (LOG_DEBUG,"[TCP RECV] ==============================>>>=================================");
		dAppDump((char*)rbuf, tcpreadlen);
#endif

		if (tcp_readlen == 0) { 	// tcp close 

			timerN_del(pReTimerInfo, phfd_body->send_timer);
			del_fd_session(event_fd);
			event_fd = -1;
		} else if (tcp_readlen > 0) {
//			dAppDump((char*)rbuf, tcp_readlen);
//			dAppLog (LOG_DEBUG, "%s", rbuf);
//	        phfd_body->send_timer = timerN_update (pReTimerInfo, phfd_body->send_timer, time(0) + g_wait_timeout);
//			dAppLog (LOG_CRI, "phfd_body->send_timer :%d", phfd_body->send_timer);
		} else {
			dAppLog (LOG_DEBUG, "read fail %d-%s", errno, strerror(errno));
		}

	} else {
		tcp_readlen = read (event_fd, rbuf, sizeof (rbuf));
		dAppLog (LOG_CRI, "??? read %d-", tcp_readlen);
		if (tcp_readlen <= 0) {

            dAppLog(LOG_WARN, "---] nonblocking connect refuse (reset)eeee %d-%s..",
                                            errno, strerror(errno));
			dAppLog(LOG_CRI, "---%d] Proxy off2! DestIP: %d.%d.%d.%d : %d connect failed", event_fd,
                   		NIPADDR(phfd_body->dest_ipaddr), ntohs(phfd_body->dest_port));

			del_fd_session(event_fd);
		}
	}
}
//---------------------------------------------------------------------------
// Search the sending function for IP Packet
void nasmt_CLASS_send(struct sk_buff *skb)
{
  //---------------------------------------------------------------------------
  struct classifier_entity  *pclassifier, *sp;
  uint8_t *protocolh = NULL;
  uint8_t version;
  uint8_t protocol, dscp;
  uint16_t classref;
  struct cx_entity *cx;
#ifdef NAS_DEBUG_CLASS
  char sfct[10], sprotocol[10];
#endif
  struct net_device *dev = gdev;
  unsigned char cx_index,no_connection;
  int addr_type;
  struct in6_addr masked6_addr;
  struct in_addr  masked_addr;
  // RARP vars
  struct arphdr  *rarp;
  unsigned char  *rarp_ptr;
  /* s for "source", t for "target" */
  __be32 sip, tip;
  unsigned char *sha, *tha;

#ifdef NAS_DEBUG_CLASS
  printk("nasmt_CLASS_send: begin -\n");
#endif

  if (skb==NULL) {
    printk("nasmt_CLASS_send - input parameter skb is NULL \n");
    return;
  }

  //***
#ifdef NAS_DEBUG_SEND
  printk("nasmt_CLASS_send - Received IP packet to transmit:");

  if ((skb->data) != NULL) {
    if (skb->len<100)
      nasmt_TOOL_print_buffer(skb->data,skb->len);
    else
      nasmt_TOOL_print_buffer(skb->data,100);
  }

#endif
  //***
  // find all connections related to socket
  cx_index   = 0;
  no_connection = 1;
  cx = NULL;
#ifdef NAS_DEBUG_CLASS
  printk("nasmt_CLASS_send: [before switch on IP protocol version] \n");
#endif


  // Get mobile connexion entity, protocol and dscp from IP packet
  switch (ntohs(skb->protocol)) {
  case ETH_P_IPV6:
#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send : skb->protocol : IPv6 \n");
#endif
    version = NAS_VERSION_6;
    addr_type = NAS_IPV6_ADDR_UNKNOWN;
    protocolh = nasmt_TOOL_get_protocol6(ipv6_hdr(skb), &protocol);
    dscp      = nasmt_TOOL_get_dscp6 (ipv6_hdr(skb));
    cx        = nasmt_CLASS_cx6 (skb, dscp, &addr_type, &cx_index);
#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send - ETH_P_IPV6 skb %p dscp %d gpriv %p cx_index %p \n",skb, dscp, gpriv, &cx_index);
#endif

    // find in default DSCP a valid classification
    if (cx == NULL) {
      switch (addr_type) {
      case NAS_IPV6_ADDR_MC_SIGNALLING:
      case NAS_IPV6_ADDR_UNICAST:
        pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT];

        while (pclassifier!=NULL) {
          if ((pclassifier->version == NAS_VERSION_6) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
            // ok found default classifier for this packet
            nasmt_create_mask_ipv6_addr(&masked6_addr, pclassifier->dplen);

            if (IN6_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv6, &ipv6_hdr(skb)->daddr, &masked6_addr)) {
              // then force dscp
              cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
              printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen);
#endif
              dscp = NAS_DSCP_DEFAULT;
              break;
            } else {
              if(IN6_IS_ADDR_UNSPECIFIED(&pclassifier->daddr.ipv6)) {
                cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
                printk("nasmt_CLASS_send - ETH_P_IPV6 FOUND NAS_DSCP_DEFAULT with IN6_IS_ADDR_UNSPECIFIED\n");
#endif
                dscp = NAS_DSCP_DEFAULT;
                break;
              }
            }
          }

          pclassifier = pclassifier->next;
        }

        break;

        // should have found a valid classification rule
      case NAS_IPV6_ADDR_UNKNOWN:
      default:
        printk("nasmt_CLASS_send: No corresponding address type\n");
      }
    }

    break;

  case ETH_P_ARP:
#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send : skb->protocol : ARP \n");
#endif
    version = NAS_VERSION_4;
    addr_type = NAS_IPV4_ADDR_BROADCAST;
    dscp = 0;
    cx = NULL;
    // Basic sanity checks can be done without the lock
    rarp = (struct arphdr *)skb_network_header(skb);

    if (rarp) {
      if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) {
        printk("nasmt_CLASS_send: ARP PACKET WRONG ADDR LEN or WRONG ARP HEADER TYPE\n");
        break;
      }
    } else {
      printk("nasmt_CLASS_send: ARP HEADER POINTER IS NULL\n");
      break;
    }

    // If it's not Ethernet, delete it.
    if (rarp->ar_pro != htons(ETH_P_IP)) {
      printk("nasmt_CLASS_send: ARP PACKET PROTOCOL IS NOT ETHERNET\n");
      break;
    }

    rarp_ptr = (unsigned char *) (rarp + 1);
    sha = rarp_ptr;
    rarp_ptr += dev->addr_len;
    memcpy(&sip, rarp_ptr, 4);
    rarp_ptr += 4;
    tha = rarp_ptr;
    rarp_ptr += dev->addr_len;
    memcpy(&tip, rarp_ptr, 4);
#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send: ARP DEST IP transport IP = %d.%d.%d.%d\n",NIPADDR(tip));
#endif
    pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT];

    while (pclassifier!=NULL) {
      if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
        // ok found default classifier for this packet
        nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
#ifdef NAS_DEBUG_CLASS
        printk("nasmt_CLASS_send: MASK = %d.%d.%d.%d\n",NIPADDR(masked_addr.s_addr));
#endif

        //
        if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &tip, &masked_addr.s_addr)) {
          // then force dscp
          cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
          printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n", pclassifier->dplen);
#endif
          dscp = NAS_DSCP_DEFAULT;
          break;
        } else {
          if (INADDR_ANY == pclassifier->daddr.ipv4) {
            cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
            printk("nasmt_CLASS_send: ETH_P_ARP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n");
#endif
            dscp = NAS_DSCP_DEFAULT;
            break;
          }
        }
      }

      pclassifier = pclassifier->next;
    }

    break;

  case ETH_P_IP:
#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send : skb->protocol : IPv4 \n");
#endif
    version   = NAS_VERSION_4;
    addr_type = NAS_IPV4_ADDR_UNKNOWN;
    dscp      = nasmt_TOOL_get_dscp4((struct iphdr *)(skb_network_header(skb)));
    cx        = nasmt_CLASS_cx4(skb, dscp, &addr_type, &cx_index);
    protocolh = nasmt_TOOL_get_protocol4((struct iphdr *)(skb_network_header(skb)), &protocol);

    // find in default DSCP a valid classification
    if (cx == NULL) {
      switch (addr_type) {
      case NAS_IPV4_ADDR_MC_SIGNALLING:
      case NAS_IPV4_ADDR_UNICAST:
      case NAS_IPV4_ADDR_BROADCAST:
        pclassifier=(&gpriv->cx[0])->sclassifier[NAS_DSCP_DEFAULT];

        while (pclassifier != NULL) {
          if ((pclassifier->version == NAS_VERSION_4) || (pclassifier->version == NAS_VERSION_DEFAULT)) {
            // ok found default classifier for this packet
            nasmt_create_mask_ipv4_addr(&masked_addr, pclassifier->dplen);
#ifdef NAS_DEBUG_CLASS
            printk("nasmt_CLASS_send : MASK = %d.%d.%d.%d\n", NIPADDR(masked_addr.s_addr));
#endif

            if (IN_ARE_ADDR_MASKED_EQUAL(&pclassifier->daddr.ipv4, &ip_hdr(skb)->daddr, &masked_addr.s_addr)) {
              // then force dscp
              cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
              printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with IN_ARE_ADDR_MASKED_EQUAL(%d bits)\n",pclassifier->dplen);
#endif
              dscp = NAS_DSCP_DEFAULT;
              break;
            } else {
              if(INADDR_ANY == pclassifier->daddr.ipv4) {
                cx = &gpriv->cx[0];
#ifdef NAS_DEBUG_CLASS
                printk("nasmt_CLASS_send : ETH_P_IP FOUND NAS_DSCP_DEFAULT with INADDR_ANY\n");
#endif
                dscp = NAS_DSCP_DEFAULT;
                break;
              }
            }
          }

          pclassifier = pclassifier->next;
        }

        break;

        // should have found a valid classification rule
      case NAS_IPV4_ADDR_UNKNOWN:
      default:
        printk("nasmt_CLASS_send: No corresponding address type\n");
      }
    }

#ifdef NAS_DEBUG_CLASS

    //printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %08X\n",ntohs(skb->protocol),dscp,cx);
    if (cx)
      printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, cx = %d\n",ntohs(skb->protocol),dscp,cx->lcr);
    else
      printk("nasmt_CLASS_send: ETH_P_IP Received IPv4 packet (%02X), dscp = %d, No valid connection\n",ntohs(skb->protocol),dscp);

#endif
    break;

  default:
    printk("nasmt_CLASS_send: Unknown IP version protocol\n");
    version = 0;
    return;
  }

#ifdef NAS_DEBUG_SEND_DETAIL
  printk("nasmt_CLASS_send: [before if (cx != NULL)]\n");
#endif

  // If a valid connection for the DSCP/EXP with destination address
  // is found scan all protocol-based classification rules
  if (cx != NULL) {
    classref = 0;
    sp       = NULL;

    if (cx->state!=NAS_CX_DCH) {
#ifdef NAS_DEBUG_CLASS
      printk("nasmt_CLASS_send: UE not connected, in state %d. Packet is dropped\n",cx->state);
#endif
      return;
    }

#ifdef NAS_DEBUG_CLASS
    printk("nasmt_CLASS_send: DSCP %d version %d: looking for classifier entry\n",dscp, version);
#endif

    for (pclassifier=cx->sclassifier[dscp]; pclassifier!=NULL; pclassifier=pclassifier->next) {
#ifdef NAS_DEBUG_CLASS
      printk("nasmt_CLASS_send: DSCP %d p->classref=%d,p->protocol=%d,p->version=%d\n",dscp,pclassifier->classref,pclassifier->protocol,pclassifier->version);
#endif

      // normal rule checks that network protocol version matches
      if ((pclassifier->version == version)  || (pclassifier->version == NAS_VERSION_DEFAULT)) {
        //printk("nasmt_CLASS_send: IP version are equals\n");
        sp=pclassifier;
        classref=sp->classref;
#ifdef NAS_DEBUG_SEND_DETAIL
        printk("nasmt_CLASS_send: classifier found for dscp %u \n", dscp);
#endif
        break;
      }
    }

    if (sp!=NULL) {
#ifdef NAS_DEBUG_CLASS

      //char sfct[10], sprotocol[10];
      // classifier entity found. Print its parameters
      if (sp->fct==nasmt_COMMON_QOS_send)
        strcpy(sfct, "data xfer");

      if (sp->fct==nasmt_CTL_send)
        strcpy(sfct, "iocontrol");

      if (sp->fct==nasmt_COMMON_del_send)
        strcpy(sfct, "delete");

      if (sp->fct==nasmt_ASCTL_DC_send_sig_data_request)
        strcpy(sfct, "DC-SAP");

      switch(protocol) {
      case NAS_PROTOCOL_UDP:
        strcpy(sprotocol, "udp");
        printk("udp packet\n");
        break;

      case NAS_PROTOCOL_TCP:
        strcpy(sprotocol, "tcp");
        printk("tcp packet\n");
        break;

      case NAS_PROTOCOL_ICMP4:
        strcpy(sprotocol, "icmp4");
        printk("icmp4 packet\n");
        break;

      case NAS_PROTOCOL_ICMP6:
        strcpy(sprotocol, "icmp6");
        nasmt_TOOL_pk_icmp6((struct icmp6hdr*)protocolh);
        break;

      default:
        strcpy(sprotocol, "other L4");
        break;
      }

      printk("nasmt_CLASS_send: (dscp %u, %s) received, (classref %u, fct %s, drb_id %u) classifier rule\n",
             dscp, sprotocol, sp->classref, sfct, sp->rab_id);
#endif

      //forward packet to the correct entity
      if (sp->fct!=NULL) {
        sp->fct(skb, cx, sp);
      } else {
        printk("\n\nnasmt_CLASS_send: ERROR : CLASSIFIER FUNCTION IS NULL\n\n");
      }

      no_connection = 0;
      // end : if classifier entry match found
    } else {
      printk("nasmt_CLASS_send: no corresponding item in the classifier list, so the message is dropped\n");
      printk("nasmt_CLASS_send: packet parameters: dscp %u, %s\n", dscp, sprotocol);
      nasmt_COMMON_del_send(skb, cx, NULL);  // Note MW: LG has commented this line. Why?
    }
  }   // if connection found

#ifdef NAS_DEBUG_CLASS

  if (no_connection == 1) {
    printk("nasmt_CLASS_send: no corresponding connection, so the message is dropped\n");
  }

  printk("nasmt_CLASS_send: end\n");
#endif
}
Example #5
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 {