Merge branch 'ipv6' of https://github.com/acetcom/nextepc into ipv6

This commit is contained in:
Sukchan Lee 2017-12-14 08:58:04 +09:00
commit 7e84bd1aaf
14 changed files with 1056 additions and 521 deletions

View File

@ -14,8 +14,6 @@ extern "C" {
#define SCTP_S1AP_PPID 18
#define SCTP_X2AP_PPID 27
#define MAX_NUM_OF_S1AP_SERVER 4
#define MAX_NUM_OF_ENB 128
#define MAX_NUM_OF_UE 128
#define MAX_NUM_OF_SESS 4

View File

@ -93,6 +93,13 @@ typedef struct _sock_node_t {
c_sockaddr_t *list;
} sock_node_t;
typedef struct ipsubnet_t {
int family;
c_uint32_t sub[4]; /* big enough for IPv4 and IPv6 addresses */
c_uint32_t mask[4];
} ipsubnet_t;
/*
* Init/Final
*/
@ -120,7 +127,7 @@ CORE_DECLARE(c_sockaddr_t *) sock_local_addr(sock_id id);
CORE_DECLARE(c_sockaddr_t *) sock_remote_addr(sock_id id);
/*
* Socket Address
* Socket Node
*/
CORE_DECLARE(status_t) sock_add_node(
list_t *list, sock_node_t **node, c_sockaddr_t *sa_list, int family);
@ -131,6 +138,9 @@ CORE_DECLARE(status_t) sock_probe_node(
list_t *list, list_t *list6, const char *dev, c_uint16_t port);
CORE_DECLARE(status_t) sock_fill_scope_id_in_local(c_sockaddr_t *sa_list);
/*
* Socket Address
*/
CORE_DECLARE(status_t) core_getaddrinfo(c_sockaddr_t **sa_list,
int family, const char *hostname, c_uint16_t port, int flags);
CORE_DECLARE(status_t) core_freeaddrinfo(c_sockaddr_t *sa_list);
@ -153,6 +163,8 @@ CORE_DECLARE(status_t) core_inet_pton(int family, const char *src, void *addr);
CORE_DECLARE(socklen_t) sockaddr_len(const void *addr);
CORE_DECLARE(int) sockaddr_is_equal(void *p, void *q);
CORE_DECLARE(status_t) core_ipsubnet(
ipsubnet_t *ipsub, const char *ipstr, const char *mask_or_numbits);
/*
* UDP Socket
*/
@ -186,8 +198,8 @@ CORE_DECLARE(int) core_sctp_recvmsg(sock_id id, void *msg, size_t len,
*/
CORE_DECLARE(status_t) tun_open(sock_id *new,
char *ifname, int is_tap);
CORE_DECLARE(status_t) tun_set_ipv4(sock_id id,
c_uint32_t ip_addr, c_uint8_t bits);
CORE_DECLARE(status_t) tun_set_ip(sock_id id,
const char *ipstr, const char *mask_or_numbits);
/*
* Send/Recv

View File

@ -31,7 +31,7 @@ libcore_la_SOURCES = \
unix/rand.c unix/time.c unix/file.c \
unix/thread.c unix/signal.c \
unix/atomic.c unix/cond.c unix/mutex.c unix/rwlock.c unix/semaphore.c \
unix/socket.c unix/udp.c unix/tcp.c unix/tun.c \
unix/socket.c unix/sockaddr.c unix/udp.c unix/tcp.c unix/tun.c \
$(NULL)
if !USRSCTP

View File

@ -0,0 +1,502 @@
#define TRACE_MODULE _sockaddr
#include "core_debug.h"
#include "core_lib.h"
#include "core_pkbuf.h"
#include "core_arch_network.h"
status_t core_getaddrinfo(c_sockaddr_t **sa_list,
int family, const char *hostname, c_uint16_t port, int flags)
{
*sa_list = NULL;
return core_addaddrinfo(sa_list, family, hostname, port, flags);
}
status_t core_freeaddrinfo(c_sockaddr_t *sa_list)
{
c_sockaddr_t *next = NULL, *addr = NULL;
addr = sa_list;
while(addr)
{
next = addr->next;
core_free(addr);
addr = next;
}
return CORE_OK;
}
status_t core_addaddrinfo(c_sockaddr_t **sa_list,
int family, const char *hostname, c_uint16_t port, int flags)
{
int rc;
char service[NI_MAXSERV];
struct addrinfo hints, *ai, *ai_list;
c_sockaddr_t *prev;
char buf[CORE_ADDRSTRLEN];
d_assert(sa_list, return CORE_ERROR,);
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = flags;
snprintf(service, sizeof(service), "%u", port);
rc = getaddrinfo(hostname, service, &hints, &ai_list);
if (rc != 0)
{
d_error("getaddrinfo(%d:%s:%d:0x%x) failed(%d:%s)",
family, hostname, port, flags, errno, strerror(errno));
return CORE_ERROR;
}
prev = NULL;
if (*sa_list)
{
prev = *sa_list;
while(prev->next) prev = prev->next;
}
for (ai = ai_list; ai; ai = ai->ai_next)
{
c_sockaddr_t *new;
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
new = core_calloc(1, sizeof(c_sockaddr_t));
memcpy(&new->sa, ai->ai_addr, ai->ai_addrlen);
new->c_sa_port = htons(port);
d_trace(3, "addr:%s, port:%d\n", CORE_ADDR(new, buf), port);
if (!prev)
*sa_list = new;
else
prev->next = new;
prev = new;
}
freeaddrinfo(ai_list);
if (prev == NULL)
{
d_error("core_getaddrinfo(%d:%s:%d:%d) failed(%d:%s)",
family, hostname, port, flags, errno, strerror(errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t core_filteraddrinfo(c_sockaddr_t **sa_list, int family)
{
c_sockaddr_t *addr = NULL, *prev = NULL, *next = NULL;
d_assert(sa_list, return CORE_ERROR,);
prev = NULL;
addr = *sa_list;
while(addr)
{
next = addr->next;
if (addr->c_sa_family != family)
{
if (prev)
prev->next = addr->next;
else
*sa_list = addr->next;
core_free(addr);
}
else
{
prev = addr;
}
addr = next;
}
return CORE_OK;
}
status_t core_copyaddrinfo(c_sockaddr_t **dst, const c_sockaddr_t *src)
{
c_sockaddr_t *d;
const c_sockaddr_t *s;
for (*dst = d = NULL, s = src; s; s = s->next)
{
if (!d)
{
d = core_calloc(1, sizeof *s);
*dst = memcpy(d, s, sizeof *s);
}
else
{
d->next = core_calloc(1, sizeof(c_sockaddr_t));
d = memcpy(d->next, s, sizeof *s);
}
}
return CORE_OK;
}
status_t core_sortaddrinfo(c_sockaddr_t **sa_list, int family)
{
c_sockaddr_t *head = NULL, *addr = NULL, *new = NULL, *old = NULL;
d_assert(sa_list, return CORE_ERROR,);
old = *sa_list;
while(old)
{
addr = old;
old = old->next;
if (head == NULL || addr->c_sa_family == family)
{
addr->next = head;
head = addr;
}
else
{
new = head;
while(new->next != NULL && new->next->c_sa_family != family)
{
new = new->next;
}
addr->next = new->next;
new->next = addr;
}
}
*sa_list = head;
return CORE_OK;
}
const char *core_inet_ntop(void *sa, char *buf, int buflen)
{
int family;
c_sockaddr_t *sockaddr = NULL;
d_assert(buf, return NULL,);
sockaddr = sa;
d_assert(sockaddr, return NULL,);
family = sockaddr->c_sa_family;
switch(family)
{
case AF_INET:
d_assert(buflen >= INET_ADDRSTRLEN, return NULL,);
return inet_ntop(family,
&sockaddr->sin.sin_addr, buf, INET_ADDRSTRLEN);
case AF_INET6:
d_assert(buflen >= CORE_ADDRSTRLEN, return NULL,);
return inet_ntop(family,
&sockaddr->sin6.sin6_addr, buf, INET6_ADDRSTRLEN);
default:
d_assert(0, return NULL, "Unknown family(%d)", family);
}
}
status_t core_inet_pton(int family, const char *src, void *sa)
{
c_sockaddr_t *dst = NULL;
d_assert(src, return CORE_ERROR,);
dst = sa;
d_assert(dst, return CORE_ERROR,);
dst->c_sa_family = family;
switch(family)
{
case AF_INET:
return inet_pton(family, src, &dst->sin.sin_addr) == 1 ?
CORE_OK : CORE_ERROR;
case AF_INET6:
return inet_pton(family, src, &dst->sin6.sin6_addr) == 1 ?
CORE_OK : CORE_ERROR;
default:
d_assert(0, return CORE_ERROR, "Unknown family(%d)", family);
}
}
socklen_t sockaddr_len(const void *sa)
{
const c_sockaddr_t *sockaddr = sa;
d_assert(sa, return 0,);
switch(sockaddr->c_sa_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
d_assert(0, return 0, "Unknown family(%d)", sockaddr->c_sa_family);
}
}
int sockaddr_is_equal(void *p, void *q)
{
c_sockaddr_t *a, *b;
a = p;
d_assert(a, return 0,);
b = q;
d_assert(b, return 0,);
if (a->c_sa_family != b->c_sa_family)
return 0;
if (a->c_sa_family == AF_INET && memcmp(
&a->sin.sin_addr, &b->sin.sin_addr, sizeof(struct in_addr)) == 0)
return 1;
else if (a->c_sa_family == AF_INET6 && memcmp(
&a->sin6.sin6_addr, &b->sin6.sin6_addr, sizeof(struct in6_addr)) == 0)
return 1;
else
d_assert(0, return 0, "Unknown family(%d)", a->c_sa_family);
return 0;
}
static status_t parse_network(ipsubnet_t *ipsub, const char *network)
{
/* legacy syntax for ip addrs: a.b.c. ==> a.b.c.0/24 for example */
int shift;
char *s, *t;
int octet;
char buf[sizeof "255.255.255.255"];
if (strlen(network) < sizeof buf)
{
strcpy(buf, network);
}
else
{
return CORE_EBADIP;
}
/* parse components */
s = buf;
ipsub->sub[0] = 0;
ipsub->mask[0] = 0;
shift = 24;
while (*s)
{
t = s;
if (!c_isdigit(*t))
{
return CORE_EBADIP;
}
while (c_isdigit(*t))
{
++t;
}
if (*t == '.')
{
*t++ = 0;
}
else if (*t)
{
return CORE_EBADIP;
}
if (shift < 0)
{
return CORE_EBADIP;
}
octet = atoi(s);
if (octet < 0 || octet > 255)
{
return CORE_EBADIP;
}
ipsub->sub[0] |= octet << shift;
ipsub->mask[0] |= 0xFFUL << shift;
s = t;
shift -= 8;
}
ipsub->sub[0] = ntohl(ipsub->sub[0]);
ipsub->mask[0] = ntohl(ipsub->mask[0]);
ipsub->family = AF_INET;
return CORE_OK;
}
/* return values:
* CORE_EINVAL not an IP address; caller should see
* if it is something else
* CORE_BADIP IP address portion is is not valid
* CORE_BADMASK mask portion is not valid
*/
static status_t parse_ip(
ipsubnet_t *ipsub, const char *ipstr, int network_allowed)
{
/* supported flavors of IP:
*
* . IPv6 numeric address string (e.g., "fe80::1")
*
* IMPORTANT: Don't store IPv4-mapped IPv6 address as an IPv6 address.
*
* . IPv4 numeric address string (e.g., "127.0.0.1")
*
* . IPv4 network string (e.g., "9.67")
*
* IMPORTANT: This network form is only allowed if network_allowed is on.
*/
int rc;
rc = inet_pton(AF_INET6, ipstr, ipsub->sub);
if (rc == 1)
{
if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ipsub->sub))
{
/* ipsubnet_test() assumes that we don't create IPv4-mapped IPv6
* addresses; this of course forces the user to specify
* IPv4 addresses in a.b.c.d style instead of ::ffff:a.b.c.d style.
*/
d_error("Cannot support IPv4-mapped IPv6: "
"Use IPv4 address in a.b.c.d style "
"instead of ::ffff:a.b.c.d style");
return CORE_EBADIP;
}
ipsub->family = AF_INET6;
}
else
{
rc = inet_pton(AF_INET, ipstr, ipsub->sub);
if (rc == 1)
{
ipsub->family = AF_INET;
}
}
if (rc != 1)
{
if (network_allowed)
{
return parse_network(ipsub, ipstr);
}
else
{
return CORE_EBADIP;
}
}
return CORE_OK;
}
static int looks_like_ip(const char *ipstr)
{
if (strlen(ipstr) == 0)
{
return 0;
}
if (strchr(ipstr, ':'))
{
/* definitely not a hostname;
* assume it is intended to be an IPv6 address */
return 1;
}
/* simple IPv4 address string check */
while ((*ipstr == '.') || c_isdigit(*ipstr))
ipstr++;
return (*ipstr == '\0');
}
static void fix_subnet(ipsubnet_t *ipsub)
{
/* in case caller specified more bits in network address than are
* valid according to the mask, turn off the extra bits
*/
int i;
for (i = 0; i < sizeof ipsub->mask / sizeof(c_int32_t); i++)
{
ipsub->sub[i] &= ipsub->mask[i];
}
}
/* be sure not to store any IPv4 address as a v4-mapped IPv6 address */
CORE_DECLARE(status_t) core_ipsubnet(
ipsubnet_t *ipsub, const char *ipstr, const char *mask_or_numbits)
{
status_t rv;
char *endptr;
long bits, maxbits = 32;
d_assert(ipsub, return CORE_ERROR,);
d_assert(ipstr, return CORE_ERROR,);
/* filter out stuff which doesn't look remotely like an IP address;
* this helps callers like mod_access which have a syntax allowing
* hostname or IP address;
* CORE_EINVAL tells the caller that it was probably not intended
* to be an IP address
*/
if (!looks_like_ip(ipstr))
{
d_error("looks_like_ip() is failed");
return CORE_EINVAL;
}
/* assume ipstr is an individual IP address, not a subnet */
memset(ipsub->mask, 0xFF, sizeof ipsub->mask);
rv = parse_ip(ipsub, ipstr, mask_or_numbits == NULL);
if (rv != CORE_OK)
{
d_error("parse_ip() is failed");
return rv;
}
if (mask_or_numbits)
{
if (ipsub->family == AF_INET6)
{
maxbits = 128;
}
bits = strtol(mask_or_numbits, &endptr, 10);
if (*endptr == '\0' && bits > 0 && bits <= maxbits)
{
/* valid num-bits string; fill in mask appropriately */
int cur_entry = 0;
c_int32_t cur_bit_value;
memset(ipsub->mask, 0, sizeof ipsub->mask);
while (bits > 32)
{
ipsub->mask[cur_entry] = 0xFFFFFFFF; /* all 32 bits */
bits -= 32;
++cur_entry;
}
cur_bit_value = 0x80000000;
while (bits)
{
ipsub->mask[cur_entry] |= cur_bit_value;
--bits;
cur_bit_value /= 2;
}
ipsub->mask[cur_entry] = htonl(ipsub->mask[cur_entry]);
}
else if (inet_pton(AF_INET, mask_or_numbits, ipsub->mask) == 1 &&
ipsub->family == AF_INET)
{
/* valid IPv4 netmask */
}
else
{
d_error("Bad netmask");
return CORE_EBADMASK;
}
}
fix_subnet(ipsub);
return CORE_OK;
}

View File

@ -310,9 +310,8 @@ c_sockaddr_t *sock_remote_addr(sock_id id)
}
/*
* Socket Address
* Socket Node
*/
status_t sock_add_node(
list_t *list, sock_node_t **node, c_sockaddr_t *sa_list, int family)
{
@ -524,267 +523,6 @@ status_t sock_fill_scope_id_in_local(c_sockaddr_t *sa_list)
return CORE_OK;
}
status_t core_getaddrinfo(c_sockaddr_t **sa_list,
int family, const char *hostname, c_uint16_t port, int flags)
{
*sa_list = NULL;
return core_addaddrinfo(sa_list, family, hostname, port, flags);
}
status_t core_freeaddrinfo(c_sockaddr_t *sa_list)
{
c_sockaddr_t *next = NULL, *addr = NULL;
addr = sa_list;
while(addr)
{
next = addr->next;
core_free(addr);
addr = next;
}
return CORE_OK;
}
status_t core_addaddrinfo(c_sockaddr_t **sa_list,
int family, const char *hostname, c_uint16_t port, int flags)
{
int rc;
char service[NI_MAXSERV];
struct addrinfo hints, *ai, *ai_list;
c_sockaddr_t *prev;
char buf[CORE_ADDRSTRLEN];
d_assert(sa_list, return CORE_ERROR,);
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = flags;
snprintf(service, sizeof(service), "%u", port);
rc = getaddrinfo(hostname, service, &hints, &ai_list);
if (rc != 0)
{
d_error("getaddrinfo(%d:%s:%d:0x%x) failed(%d:%s)",
family, hostname, port, flags, errno, strerror(errno));
return CORE_ERROR;
}
prev = NULL;
if (*sa_list)
{
prev = *sa_list;
while(prev->next) prev = prev->next;
}
for (ai = ai_list; ai; ai = ai->ai_next)
{
c_sockaddr_t *new;
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
new = core_calloc(1, sizeof(c_sockaddr_t));
memcpy(&new->sa, ai->ai_addr, ai->ai_addrlen);
new->c_sa_port = htons(port);
d_trace(3, "addr:%s, port:%d\n", CORE_ADDR(new, buf), port);
if (!prev)
*sa_list = new;
else
prev->next = new;
prev = new;
}
freeaddrinfo(ai_list);
if (prev == NULL)
{
d_error("core_getaddrinfo(%d:%s:%d:%d) failed(%d:%s)",
family, hostname, port, flags, errno, strerror(errno));
return CORE_ERROR;
}
return CORE_OK;
}
status_t core_filteraddrinfo(c_sockaddr_t **sa_list, int family)
{
c_sockaddr_t *addr = NULL, *prev = NULL, *next = NULL;
d_assert(sa_list, return CORE_ERROR,);
prev = NULL;
addr = *sa_list;
while(addr)
{
next = addr->next;
if (addr->c_sa_family != family)
{
if (prev)
prev->next = addr->next;
else
*sa_list = addr->next;
core_free(addr);
}
else
{
prev = addr;
}
addr = next;
}
return CORE_OK;
}
status_t core_copyaddrinfo(c_sockaddr_t **dst, const c_sockaddr_t *src)
{
c_sockaddr_t *d;
const c_sockaddr_t *s;
for (*dst = d = NULL, s = src; s; s = s->next)
{
if (!d)
{
d = core_calloc(1, sizeof *s);
*dst = memcpy(d, s, sizeof *s);
}
else
{
d->next = core_calloc(1, sizeof(c_sockaddr_t));
d = memcpy(d->next, s, sizeof *s);
}
}
return CORE_OK;
}
status_t core_sortaddrinfo(c_sockaddr_t **sa_list, int family)
{
c_sockaddr_t *head = NULL, *addr = NULL, *new = NULL, *old = NULL;
d_assert(sa_list, return CORE_ERROR,);
old = *sa_list;
while(old)
{
addr = old;
old = old->next;
if (head == NULL || addr->c_sa_family == family)
{
addr->next = head;
head = addr;
}
else
{
new = head;
while(new->next != NULL && new->next->c_sa_family != family)
{
new = new->next;
}
addr->next = new->next;
new->next = addr;
}
}
*sa_list = head;
return CORE_OK;
}
const char *core_inet_ntop(void *sa, char *buf, int buflen)
{
int family;
c_sockaddr_t *sockaddr = NULL;
d_assert(buf, return NULL,);
sockaddr = sa;
d_assert(sockaddr, return NULL,);
family = sockaddr->c_sa_family;
switch(family)
{
case AF_INET:
d_assert(buflen >= INET_ADDRSTRLEN, return NULL,);
return inet_ntop(family,
&sockaddr->sin.sin_addr, buf, INET_ADDRSTRLEN);
case AF_INET6:
d_assert(buflen >= CORE_ADDRSTRLEN, return NULL,);
return inet_ntop(family,
&sockaddr->sin6.sin6_addr, buf, INET6_ADDRSTRLEN);
default:
d_assert(0, return NULL, "Unknown family(%d)", family);
}
}
status_t core_inet_pton(int family, const char *src, void *sa)
{
c_sockaddr_t *dst = NULL;
d_assert(src, return CORE_ERROR,);
dst = sa;
d_assert(dst, return CORE_ERROR,);
dst->c_sa_family = family;
switch(family)
{
case AF_INET:
return inet_pton(family, src, &dst->sin.sin_addr) == 1 ?
CORE_OK : CORE_ERROR;
case AF_INET6:
return inet_pton(family, src, &dst->sin6.sin6_addr) == 1 ?
CORE_OK : CORE_ERROR;
default:
d_assert(0, return CORE_ERROR, "Unknown family(%d)", family);
}
}
socklen_t sockaddr_len(const void *sa)
{
const c_sockaddr_t *sockaddr = sa;
d_assert(sa, return 0,);
switch(sockaddr->c_sa_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
default:
d_assert(0, return 0, "Unknown family(%d)", sockaddr->c_sa_family);
}
}
int sockaddr_is_equal(void *p, void *q)
{
c_sockaddr_t *a, *b;
a = p;
d_assert(a, return 0,);
b = q;
d_assert(b, return 0,);
if (a->c_sa_family != b->c_sa_family)
return 0;
if (a->c_sa_family == AF_INET && memcmp(
&a->sin.sin_addr, &b->sin.sin_addr, sizeof(struct in_addr)) == 0)
return 1;
else if (a->c_sa_family == AF_INET6 && memcmp(
&a->sin6.sin6_addr, &b->sin6.sin6_addr, sizeof(struct in6_addr)) == 0)
return 1;
else
d_assert(0, return 0, "Unknown family(%d)", a->c_sa_family);
return 0;
}
/*
* Send/Recv
*/

View File

@ -5,6 +5,9 @@
#if LINUX == 1
#include <linux/if_tun.h>
#else
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#endif
#if HAVE_NET_ROUTE_H
@ -79,7 +82,7 @@ cleanup:
#endif
}
status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
status_t tun_set_ipv4(sock_id id, ipsubnet_t *ipaddr, ipsubnet_t *ipsub)
{
#if LINUX != 1
sock_t *sock = NULL;
@ -89,7 +92,6 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
struct ifreq ifr;
struct sockaddr_in addr;
struct sockaddr_in mask;
c_uint32_t mask_addr = htonl(0xffffffff << (32 - bits));
char buf[512];
int len;
@ -97,10 +99,13 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
struct sockaddr_in dst, gw;
struct sockaddr_in *paddr;
d_assert(ipaddr, return CORE_ERROR,);
d_assert(ipsub, return CORE_ERROR,);
sock = (sock_t *)id;
d_assert(id, return CORE_ERROR,);
fd = socket(AF_INET, SOCK_DGRAM, 0);
fd = socket(ipaddr->family, SOCK_DGRAM, 0);
(void)memset(&ifa, '\0', sizeof ifa);
(void)strlcpy(ifa.ifra_name, sock->ifname, sizeof ifa.ifra_name);
@ -108,19 +113,21 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
(void)memset(&ifr, '\0', sizeof ifr);
(void)strlcpy(ifr.ifr_name, sock->ifname, sizeof ifr.ifr_name);
#if 0
/* Delete previously assigned address */
(void)ioctl(fd, SIOCDIFADDR, &ifr);
#endif
(void)memset(&addr, '\0', sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip_addr;
addr.sin_family = ipaddr->family;
addr.sin_addr.s_addr = ipaddr->sub[0];
addr.sin_len = sizeof(addr);
(void)memcpy(&ifa.ifra_addr, &addr, sizeof(addr));
(void)memcpy(&ifa.ifra_broadaddr, &addr, sizeof(addr));
(void)memset(&mask, '\0', sizeof(mask));
mask.sin_family = AF_INET;
mask.sin_addr.s_addr = 0xffffffff;
mask.sin_family = ipaddr->family;
mask.sin_addr.s_addr = ipaddr->mask[0];
mask.sin_len = sizeof(mask);
(void)memcpy(&ifa.ifra_mask, &mask, sizeof(ifa.ifra_mask));
@ -130,7 +137,7 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
return CORE_ERROR;
}
close(fd); /* AF_INET, SOCK_DGRAM */
close(fd); /* SOCK_DGRAM */
fd = socket(PF_ROUTE, SOCK_RAW, 0);
if (fd < 0)
@ -150,24 +157,24 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
paddr = (struct sockaddr_in *)(rtm + 1);
(void)memset(&dst, '\0', sizeof(dst));
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = ip_addr & mask_addr;
dst.sin_family = ipaddr->family;
dst.sin_addr.s_addr = ipsub->sub[0];
dst.sin_len = sizeof(dst);
(void)memcpy(paddr, &dst, sizeof(dst));
paddr = (struct sockaddr_in *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
(void)memset(&gw, '\0', sizeof(gw));
gw.sin_family = AF_INET;
gw.sin_addr.s_addr = ip_addr;
gw.sin_family = ipaddr->family;
gw.sin_addr.s_addr = ipaddr->sub[0];
gw.sin_len = sizeof(gw);
(void)memcpy(paddr, &gw, sizeof(gw));
paddr = (struct sockaddr_in *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
(void)memset(&mask, '\0', sizeof(mask));
mask.sin_family = AF_INET;
mask.sin_addr.s_addr = mask_addr;
mask.sin_family = ipaddr->family;
mask.sin_addr.s_addr = ipsub->mask[0];
mask.sin_len = sizeof(mask);
(void)memcpy(paddr, &mask, sizeof(mask));
paddr = (struct sockaddr_in *)((char *)paddr +
@ -185,5 +192,179 @@ status_t tun_set_ipv4(sock_id id, c_uint32_t ip_addr, c_uint8_t bits)
#endif /* LINUX == 1 */
return 0;
return CORE_OK;
}
status_t tun_set_ipv6(sock_id id, ipsubnet_t *ipaddr, ipsubnet_t *ipsub)
{
#if LINUX != 1
sock_t *sock = NULL;
int fd;
struct in6_aliasreq ifa;
struct in6_ifreq ifr;
struct sockaddr_in6 addr;
struct sockaddr_in6 mask;
char buf[512];
int len;
struct rt_msghdr *rtm;
#if 0
struct sockaddr_in6 dst, gw;
#else
struct sockaddr_in6 dst;
#endif
struct sockaddr_in6 *paddr;
d_assert(ipaddr, return CORE_ERROR,);
d_assert(ipsub, return CORE_ERROR,);
sock = (sock_t *)id;
d_assert(id, return CORE_ERROR,);
fd = socket(ipaddr->family, SOCK_DGRAM, 0);
(void)memset(&ifa, '\0', sizeof ifa);
(void)strlcpy(ifa.ifra_name, sock->ifname, sizeof ifa.ifra_name);
(void)memset(&ifr, '\0', sizeof ifr);
(void)strlcpy(ifr.ifr_name, sock->ifname, sizeof ifr.ifr_name);
#if 0
/* Delete previously assigned address */
(void)ioctl(fd, SIOCDIFADDR, &ifr);
#endif
(void)memset(&addr, '\0', sizeof(addr));
addr.sin6_family = ipaddr->family;
memcpy(addr.sin6_addr.s6_addr, ipaddr->sub, sizeof ipaddr->sub);
addr.sin6_len = sizeof(addr);
(void)memcpy(&ifa.ifra_addr, &addr, sizeof(addr));
(void)memcpy(&ifa.ifra_dstaddr, &addr, sizeof(addr));
(void)memset(&mask, '\0', sizeof(mask));
mask.sin6_family = ipaddr->family;
memcpy(mask.sin6_addr.s6_addr, ipaddr->mask, sizeof ipaddr->mask);
mask.sin6_len = sizeof(mask);
(void)memcpy(&ifa.ifra_prefixmask, &mask, sizeof(ifa.ifra_prefixmask));
ifa.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
ifa.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
if (ioctl(fd, SIOCAIFADDR_IN6, &ifa) == -1) {
d_error("Can't IP address(dev:%s err:%s)",
sock->ifname, strerror(errno));
return CORE_ERROR;
}
close(fd); /* SOCK_DGRAM */
fd = socket(PF_ROUTE, SOCK_RAW, 0);
if (fd < 0)
{
d_error("Can't open PF_ROUTE(%s)", strerror(errno));
return CORE_ERROR;
}
(void)memset(&buf, 0, sizeof(buf));
rtm = (struct rt_msghdr *)buf;
rtm->rtm_type = RTM_DELETE;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_pid = getpid();
rtm->rtm_seq = 0;
rtm->rtm_addrs = RTA_DST;
paddr = (struct sockaddr_in6 *)(rtm + 1);
(void)memset(&dst, '\0', sizeof(dst));
dst.sin6_family = ipaddr->family;
memcpy(dst.sin6_addr.s6_addr, ipaddr->sub, sizeof ipsub->sub);
dst.sin6_len = sizeof(dst);
(void)memcpy(paddr, &dst, sizeof(dst));
paddr = (struct sockaddr_in6 *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
len = (char*)paddr - buf;
rtm->rtm_msglen = len;
if (write(fd, buf, len) < 0)
{
d_error("Can't add routing(%s)", strerror(errno));
return CORE_ERROR;
}
#if 0
(void)memset(&buf, 0, sizeof(buf));
rtm = (struct rt_msghdr *)buf;
rtm->rtm_type = RTM_ADD;
rtm->rtm_version = RTM_VERSION;
rtm->rtm_pid = getpid();
rtm->rtm_seq = 0;
rtm->rtm_flags = RTF_UP | RTF_GATEWAY;
rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
paddr = (struct sockaddr_in6 *)(rtm + 1);
(void)memset(&dst, '\0', sizeof(dst));
dst.sin6_family = ipaddr->family;
memcpy(dst.sin6_addr.s6_addr, ipsub->sub, sizeof ipsub->sub);
dst.sin6_len = sizeof(dst);
(void)memcpy(paddr, &dst, sizeof(dst));
paddr = (struct sockaddr_in6 *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
(void)memset(&gw, '\0', sizeof(gw));
gw.sin6_family = ipaddr->family;
memcpy(gw.sin6_addr.s6_addr, ipaddr->sub, sizeof ipaddr->sub);
gw.sin6_len = sizeof(gw);
(void)memcpy(paddr, &gw, sizeof(gw));
paddr = (struct sockaddr_in6 *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
(void)memset(&mask, '\0', sizeof(mask));
mask.sin6_family = ipaddr->family;
memcpy(mask.sin6_addr.s6_addr, ipsub->mask, sizeof ipsub->mask);
mask.sin6_len = sizeof(mask);
(void)memcpy(paddr, &mask, sizeof(mask));
paddr = (struct sockaddr_in6 *)((char *)paddr +
CORE_ALIGN(sizeof(*paddr), sizeof(c_uintptr_t)));
len = (char*)paddr - buf;
rtm->rtm_msglen = len;
if (write(fd, buf, len) < 0)
{
d_error("Can't add routing(%s)", strerror(errno));
return CORE_ERROR;
}
#endif
close(fd); /* PF_ROUTE, SOCK_RAW */
#endif /* LINUX == 1 */
return CORE_OK;
}
status_t tun_set_ip(sock_id id, const char *ipstr, const char *mask_or_numbits)
{
ipsubnet_t ipaddr, ipsub;
status_t rv;
d_assert(id, return CORE_ERROR,);
d_assert(ipstr, return CORE_ERROR,);
d_assert(mask_or_numbits, return CORE_ERROR,);
rv = core_ipsubnet(&ipaddr, ipstr, NULL);
d_assert(rv == CORE_OK, return CORE_ERROR,);
rv = core_ipsubnet(&ipsub, ipstr, mask_or_numbits);
d_assert(rv == CORE_OK, return CORE_ERROR,);
if (ipsub.family == AF_INET)
{
rv = tun_set_ipv4(id, &ipaddr, &ipsub);
}
else
{
rv = tun_set_ipv6(id, &ipaddr, &ipsub);
}
return rv;
}

View File

@ -417,6 +417,30 @@ static void sock_test7(abts_case *tc, void *data)
sock_remove_all_nodes(&list6);
}
static void sock_test8(abts_case *tc, void *data)
{
status_t rv;
ipsubnet_t ipsub;
rv = core_ipsubnet(&ipsub, "127.0.0.1", "8");
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = core_ipsubnet(&ipsub, "fe80::1", "64");
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = core_ipsubnet(&ipsub, "172.16.0.1", "16");
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = core_ipsubnet(&ipsub, "cafe::1", "64");
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = core_ipsubnet(&ipsub, "172.16.0.1", NULL);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = core_ipsubnet(&ipsub, "cafe::1", NULL);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
}
abts_suite *testsock(abts_suite *suite)
{
suite = ADD_SUITE(suite)
@ -428,6 +452,7 @@ abts_suite *testsock(abts_suite *suite)
abts_run_test(suite, sock_test5, NULL);
abts_run_test(suite, sock_test6, NULL);
abts_run_test(suite, sock_test7, NULL);
abts_run_test(suite, sock_test8, NULL);
return suite;
}

View File

@ -3,6 +3,7 @@
#include "core_pool.h"
#include "core_index.h"
#include "core_lib.h"
#include "core_network.h"
#include <mongoc.h>
#include <yaml.h>
@ -27,10 +28,22 @@ index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
pool_declare(pgw_ip_pool_pool, pgw_ip_pool_t, MAX_POOL_OF_SESS);
pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF);
typedef struct _ue_pool_t {
int head, tail;
int size, avail;
mutex_id mut;
pgw_ue_ip_t *free[MAX_POOL_OF_SESS], pool[MAX_POOL_OF_SESS];
} ue_pool_t;
#define INVALID_POOL_INDEX MAX_NUM_OF_UE_POOL
static ue_pool_t ue_pool[MAX_NUM_OF_UE_POOL];
static int context_initiaized = 0;
status_t pgw_context_init()
{
int i;
d_assert(context_initiaized == 0, return CORE_ERROR,
"PGW context already has been initialized");
@ -51,6 +64,9 @@ status_t pgw_context_init()
pool_init(&pgw_ip_pool_pool, MAX_POOL_OF_SESS);
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
pool_init(&ue_pool[i], MAX_POOL_OF_UE);
self.sess_hash = hash_make();
context_initiaized = 1;
@ -60,6 +76,8 @@ status_t pgw_context_init()
status_t pgw_context_final()
{
int i;
d_assert(context_initiaized == 1, return CORE_ERROR,
"PGW context already has been finalized");
@ -89,6 +107,21 @@ status_t pgw_context_final()
pool_final(&pgw_pf_pool);
pool_final(&pgw_ip_pool_pool);
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
{
if (index_size(&ue_pool[i]) != pool_avail(&ue_pool[i]))
{
d_warn("[%d] %d not freed in ue_pool[%d] in PGW-Context",
i, index_size(&ue_pool[i]) - pool_avail(&ue_pool[i]),
index_size(&ue_pool[i]));
}
d_trace(3, "[%d] %d not freed in ue_pool[%d] in PGW-Context\n",
i, index_size(&ue_pool[i]) - pool_avail(&ue_pool[i]),
index_size(&ue_pool[i]));
pool_final(&ue_pool[i]);
}
index_final(&pgw_bearer_pool);
index_final(&pgw_sess_pool);
@ -116,6 +149,8 @@ static status_t pgw_context_prepare()
self.gtpc_port = GTPV2_C_UDP_PORT;
self.gtpu_port = GTPV1_U_UDP_PORT;
self.tun_ifname = "pgwtun";
return CORE_OK;
}
@ -141,12 +176,6 @@ static status_t pgw_context_validation()
context_self()->config.path);
return CORE_ERROR;
}
if (self.num_of_ue_network == 0)
{
d_error("No pgw.pdn.addr in '%s'",
context_self()->config.path);
return CORE_ERROR;
}
if (self.dns.primary == 0)
{
d_error("No pgw.dns in '%s'",
@ -481,34 +510,33 @@ status_t pgw_context_parse_config()
d_assert(rv == CORE_OK, return CORE_ERROR,);
}
}
else if (!strcmp(pgw_key, "ue_network"))
else if (!strcmp(pgw_key, "ue_pool"))
{
yaml_iter_t ue_network_array, ue_network_iter;
yaml_iter_recurse(&pgw_iter, &ue_network_array);
yaml_iter_t ue_pool_array, ue_pool_iter;
yaml_iter_recurse(&pgw_iter, &ue_pool_array);
do
{
c_uint32_t addr = 0;
c_uint8_t bits = 0;
const char *dev = NULL;
const char *ipstr = NULL;
const char *mask_or_numbits = NULL;
const char *apn = NULL;
d_assert(self.num_of_ue_network <=
MAX_NUM_OF_UE_NETWORK, return CORE_ERROR,);
if (yaml_iter_type(&ue_network_array) ==
d_assert(self.num_of_ue_pool <=
MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
if (yaml_iter_type(&ue_pool_array) ==
YAML_MAPPING_NODE)
{
memcpy(&ue_network_iter, &ue_network_array,
memcpy(&ue_pool_iter, &ue_pool_array,
sizeof(yaml_iter_t));
}
else if (yaml_iter_type(&ue_network_array) ==
else if (yaml_iter_type(&ue_pool_array) ==
YAML_SEQUENCE_NODE)
{
if (!yaml_iter_next(&ue_network_array))
if (!yaml_iter_next(&ue_pool_array))
break;
yaml_iter_recurse(&ue_network_array,
&ue_network_iter);
yaml_iter_recurse(&ue_pool_array,
&ue_pool_iter);
}
else if (yaml_iter_type(&ue_network_array) ==
else if (yaml_iter_type(&ue_pool_array) ==
YAML_SCALAR_NODE)
{
break;
@ -516,79 +544,47 @@ status_t pgw_context_parse_config()
else
d_assert(0, return CORE_ERROR,);
while(yaml_iter_next(&ue_network_iter))
while(yaml_iter_next(&ue_pool_iter))
{
const char *ue_network_key =
yaml_iter_key(&ue_network_iter);
d_assert(ue_network_key,
const char *ue_pool_key =
yaml_iter_key(&ue_pool_iter);
d_assert(ue_pool_key,
return CORE_ERROR,);
if (!strcmp(ue_network_key, "addr"))
if (!strcmp(ue_pool_key, "addr"))
{
yaml_iter_t addr_iter;
yaml_iter_recurse(&ue_network_iter, &addr_iter);
d_assert(yaml_iter_type(&addr_iter) !=
YAML_MAPPING_NODE, return CORE_ERROR,);
do
char *v =
(char *)yaml_iter_value(&ue_pool_iter);
if (v)
{
char *v = NULL;
#if 0
d_assert(ue_network->num_of_addr <=
MAX_NUM_OF_PDN_ADDR,
return CORE_ERROR,);
#endif
if (yaml_iter_type(&addr_iter) ==
YAML_SEQUENCE_NODE)
ipstr = (const char *)strsep(&v, "/");
if (ipstr)
{
if (!yaml_iter_next(&addr_iter))
break;
mask_or_numbits = (const char *)v;
}
v = (char *)yaml_iter_value(&addr_iter);
if (v)
{
char *str = strsep(&v, "/");
if (str)
{
addr = inet_addr(str);
bits = atoi(v);
}
}
} while(
yaml_iter_type(&addr_iter) ==
YAML_SEQUENCE_NODE);
}
}
else if (!strcmp(ue_network_key, "dev"))
else if (!strcmp(ue_pool_key, "apn"))
{
dev = yaml_iter_value(&ue_network_iter);
}
else if (!strcmp(ue_network_key, "apn"))
{
apn = yaml_iter_value(&ue_network_iter);
d_warn("Not implemented apn=%s", apn);
apn = yaml_iter_value(&ue_pool_iter);
}
else
d_warn("unknown key `%s`", ue_network_key);
d_warn("unknown key `%s`", ue_pool_key);
}
if (addr && bits)
if (ipstr && mask_or_numbits)
{
self.ue_network[self.num_of_ue_network].ipv4.addr =
addr;
self.ue_network[self.num_of_ue_network].ipv4.bits =
bits;
self.ue_network[self.num_of_ue_network].if_name =
dev;
self.num_of_ue_network++;
self.ue_pool[self.num_of_ue_pool].ipstr = ipstr;
self.ue_pool[self.num_of_ue_pool].mask_or_numbits =
mask_or_numbits;
self.ue_pool[self.num_of_ue_pool].apn = apn;
self.num_of_ue_pool++;
}
else
{
d_warn("Ignore ue_network : addr(0x%x), bits(%d)",
addr, bits);
d_warn("Ignore : addr(%s/%s), apn(%s)",
ipstr, mask_or_numbits, apn);
}
} while(yaml_iter_type(&ue_network_array) ==
} while(yaml_iter_type(&ue_pool_array) ==
YAML_SEQUENCE_NODE);
}
else if (!strcmp(pgw_key, "dns"))
@ -775,8 +771,8 @@ pgw_sess_t *pgw_sess_add(
"Can't add default bearer context");
bearer->ebi = ebi;
sess->ip_pool = pgw_ip_pool_alloc();
d_assert(sess->ip_pool, pgw_sess_remove(sess); return NULL,
sess->ue_ip = pgw_ue_ip_alloc(AF_INET, apn);
d_assert(sess->ue_ip, pgw_sess_remove(sess); return NULL,
"Can't add default bearer context");
/* Generate Hash Key : IMSI + APN */
@ -794,7 +790,7 @@ status_t pgw_sess_remove(pgw_sess_t *sess)
hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL);
pgw_ip_pool_free(sess->ip_pool);
pgw_ue_ip_free(sess->ue_ip);
pgw_bearer_remove_all(sess);
@ -1332,82 +1328,170 @@ pgw_pf_t* pgw_pf_next(pgw_pf_t *pf)
return list_next(pf);
}
status_t pgw_ip_pool_generate()
status_t pgw_ue_pool_generate()
{
status_t rv;
int i, j;
int pool_index = 0;
for (i = 0; i < self.num_of_ue_network; i++)
for (i = 0; i < self.num_of_ue_pool; i++)
{
c_uint32_t mask =
htonl(0xffffffff << (32 - self.ue_network[i].ipv4.bits));
c_uint32_t prefix = self.ue_network[i].ipv4.addr & mask;
int pool_index = 0;
ipsubnet_t ipaddr, ipsub;
c_uint32_t bits;
c_uint32_t mask_count;
c_uint32_t broadcast[4];
#if 1 /* Update IP assign rule from bradon's comment */
c_uint32_t broadcast = prefix + ~mask;
rv = core_ipsubnet(&ipaddr, self.ue_pool[i].ipstr, NULL);
d_assert(rv == CORE_OK, return CORE_ERROR,);
for (j = 1; j < (0xffffffff >> self.ue_network[i].ipv4.bits) &&
pool_index < MAX_POOL_OF_SESS; j++)
rv = core_ipsubnet(&ipsub,
self.ue_pool[i].ipstr, self.ue_pool[i].mask_or_numbits);
d_assert(rv == CORE_OK, return CORE_ERROR,);
d_assert(self.ue_pool[i].mask_or_numbits, return CORE_ERROR,);
bits = atoi(self.ue_pool[i].mask_or_numbits);
if (ipsub.family == AF_INET)
{
pgw_ip_pool_t *ip_pool = &pgw_ip_pool_pool.pool[pool_index];
ip_pool->ue_addr = prefix + htonl(j);
if (bits == 32)
mask_count = 1;
else if (bits < 32)
mask_count = (0xffffffff >> bits) + 1;
else
d_assert(0, return CORE_ERROR,);
}
else if (ipsub.family == AF_INET6)
{
if (bits == 128)
mask_count = 1;
else if (bits > 96 && bits < 128)
mask_count = (0xffffffff >> (bits - 96)) + 1;
else if (bits <= 96)
mask_count = 0xffffffff;
else
d_assert(0, return CORE_ERROR,);
}
else
d_assert(0, return CORE_ERROR,);
self.ue_pool[i].family = ipsub.family;
for (j = 0; j < 4; j++)
{
broadcast[j] = ipsub.sub[j] + ~ipsub.mask[j];
}
for (j = 0; j < mask_count && pool_index < MAX_POOL_OF_SESS; j++)
{
pgw_ue_ip_t *ue_ip = NULL;
int maxbytes = 0;
int lastindex = 0;
ue_ip = &ue_pool[i].pool[pool_index];
d_assert(ue_ip, return CORE_ERROR,);
memset(ue_ip, 0, sizeof *ue_ip);
if (ipsub.family == AF_INET)
{
maxbytes = 4;
lastindex = 0;
}
else if (ipsub.family == AF_INET6)
{
maxbytes = 16;
lastindex = 3;
}
memcpy(ue_ip->addr, ipsub.sub, maxbytes);
ue_ip->addr[lastindex] += htonl(j);
/* Exclude Network Address */
if (ip_pool->ue_addr == prefix) continue;
if (memcmp(ue_ip->addr, ipsub.sub, maxbytes) == 0) continue;
/* Exclude Broadcast Address */
if (ip_pool->ue_addr == broadcast) continue;
if (memcmp(ue_ip->addr, broadcast, maxbytes) == 0) continue;
/* Exclude TUN IP Address */
if (ip_pool->ue_addr == self.ue_network[i].ipv4.addr) continue;
if (memcmp(ue_ip->addr, ipaddr.sub, maxbytes) == 0) continue;
pool_index++;
}
#else /* Deprecated */
/* Exclude X.X.X.0, X.X.X.255 addresses from ip pool */
c_uint32_t exclude_mask[] = { 0, 255 };
for (j = 1; j < (0xffffffff >> self.ip_pool[i].mask) &&
pool_index < MAX_NUM_OF_SESS; j++)
{
int exclude = 0;
pgw_ip_pool_t *ip_pool = &pgw_ip_pool_pool.pool[pool_index];
ip_pool->ue_addr = prefix + htonl(j);
for (k = 0; k < sizeof(exclude_mask)/sizeof(exclude_mask[0]); k++)
{
if ((htonl(ip_pool->ue_addr) & 0x000000ff) == exclude_mask[k])
{
exclude = 1;
}
}
if (exclude)
{
continue;
}
pool_index++;
}
#endif
}
return CORE_OK;
}
pgw_ip_pool_t* pgw_ip_pool_alloc()
static c_uint8_t find_ue_pool_index(int family, const char *apn)
{
pgw_ip_pool_t *ip_pool = NULL;
int i;
c_uint8_t pool_index = INVALID_POOL_INDEX;
pool_alloc_node(&pgw_ip_pool_pool, &ip_pool);
d_assert(ip_pool, return NULL, "IP Pool context allocation failed");
d_assert(apn, return INVALID_POOL_INDEX,);
d_assert(family == AF_INET || family == AF_INET6,
return INVALID_POOL_INDEX,);
list_append(&self.ip_pool_list, ip_pool);
for (i = 0; i < self.num_of_ue_pool; i++)
{
if (self.ue_pool[i].apn)
{
if (self.ue_pool[i].family == family &&
strcmp(self.ue_pool[i].apn, apn) == 0)
{
pool_index = i;
break;
}
}
}
return ip_pool;
if (pool_index == INVALID_POOL_INDEX)
{
for (i = 0; i < self.num_of_ue_pool; i++)
{
if (self.ue_pool[i].apn == NULL)
{
if (self.ue_pool[i].family == family)
{
pool_index = i;
break;
}
}
}
}
if (pool_index == INVALID_POOL_INDEX)
{
d_error("CHECK CONFIGURATION: Cannot find UE Pool");
return INVALID_POOL_INDEX;
}
return pool_index;
}
status_t pgw_ip_pool_free(pgw_ip_pool_t *ip_pool)
pgw_ue_ip_t *pgw_ue_ip_alloc(int family, const char *apn)
{
list_remove(&self.ip_pool_list, ip_pool);
pool_free_node(&pgw_ip_pool_pool, ip_pool);
c_uint8_t pool_index = INVALID_POOL_INDEX;
pgw_ue_ip_t *ue_ip = NULL;
d_assert(apn, return NULL,);
pool_index = find_ue_pool_index(family, apn);
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return NULL,);
pool_alloc_node(&ue_pool[pool_index], &ue_ip);
d_assert(ue_ip, return NULL,);
ue_ip->index = pool_index;
return ue_ip;
}
status_t pgw_ue_ip_free(pgw_ue_ip_t *ue_ip)
{
c_uint8_t pool_index;
d_assert(ue_ip, return CORE_ERROR,);
pool_index = ue_ip->index;
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
pool_free_node(&ue_pool[pool_index], ue_ip);
return CORE_OK;
}

View File

@ -12,7 +12,7 @@
#include "gtp_types.h"
#include "gtp_message.h"
#define MAX_NUM_OF_UE_NETWORK 16
#define MAX_NUM_OF_UE_POOL 16
#ifdef __cplusplus
extern "C" {
@ -39,15 +39,15 @@ typedef struct _pgw_context_t {
msgq_id queue_id; /* Qsesssess for processing PGW control plane */
tm_service_t tm_service; /* Timer Service */
sock_id tun_sock; /* PGW Tun Interace for UE */
const char *tun_ifname; /* default : pgwtun */
struct {
sock_id tun_link; /* PGW Tun Interace for U-plane */
const char *if_name;
struct {
c_uint32_t addr;
c_uint8_t bits;
} ipv4;
} ue_network[MAX_NUM_OF_UE_NETWORK];
c_uint8_t num_of_ue_network;
const char *ipstr; /* IP : "172.16.0.1", "cafe::1", ... */
const char *mask_or_numbits; /* MASK : "16, 64, ... */
const char *apn; /* APN : "internet", "volte", .. */
int family; /* AF_INET or AF_INET6 */
} ue_pool[MAX_NUM_OF_UE_POOL];
c_uint8_t num_of_ue_pool;
struct {
c_uint32_t primary;
@ -67,6 +67,11 @@ typedef struct _pgw_ip_pool_t {
c_uint32_t ue_addr;
} pgw_ip_pool_t;
typedef struct _pgw_ue_ip_t {
c_uint8_t index; /* Pool index */
c_uint32_t addr[4];
} pgw_ue_ip_t;
typedef struct _pgw_sess_t {
lnode_t node; /**< A node of list_t */
index_t index; /**< An index of this node */
@ -81,7 +86,7 @@ typedef struct _pgw_sess_t {
/* APN Configuration */
pdn_t pdn;
pgw_ip_pool_t* ip_pool;
pgw_ue_ip_t* ue_ip;
/* User-Lication-Info */
tai_t tai;
@ -203,9 +208,9 @@ CORE_DECLARE(pgw_pf_t*) pgw_pf_find_by_id(
CORE_DECLARE(pgw_pf_t*) pgw_pf_first(pgw_bearer_t *bearer);
CORE_DECLARE(pgw_pf_t*) pgw_pf_next(pgw_pf_t *pf);
CORE_DECLARE(status_t ) pgw_ip_pool_generate();
CORE_DECLARE(pgw_ip_pool_t*) pgw_ip_pool_alloc();
CORE_DECLARE(status_t ) pgw_ip_pool_free(pgw_ip_pool_t *ip_pool);
CORE_DECLARE(status_t ) pgw_ue_pool_generate();
CORE_DECLARE(pgw_ue_ip_t *) pgw_ue_ip_alloc(int family, const char *apn);
CORE_DECLARE(status_t) pgw_ue_ip_free(pgw_ue_ip_t *ip);
#ifdef __cplusplus
}

View File

@ -39,7 +39,7 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess,
struct session *session = NULL;
d_assert(sess, return, "Null param");
d_assert(sess->ip_pool, return, "Null param");
d_assert(sess->ue_ip, return, "Null param");
/* Create the random value to store with the session */
pool_alloc_node(&pgw_gx_sess_pool, &mi);
@ -138,8 +138,8 @@ void pgw_gx_send_ccr(gtp_xact_t *xact, pgw_sess_t *sess,
/* Set Framed-IP-Address */
CHECK_FCT_DO( fd_msg_avp_new(gx_framed_ip_address, 0, &avp),
goto out );
val.os.data = (c_uint8_t*)&sess->ip_pool->ue_addr;
val.os.len = sizeof(sess->ip_pool->ue_addr);
val.os.data = (c_uint8_t*)&sess->ue_ip->addr[0];
val.os.len = sizeof(sess->ue_ip->addr[0]);
CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), goto out );
CHECK_FCT_DO( fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp), goto out );

View File

@ -136,8 +136,7 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
return -1;
}
if (sock_write(pgw_self()->ue_network[(c_uintptr_t)data].tun_link,
pkbuf->payload, pkbuf->len) <= 0)
if (sock_write(pgw_self()->tun_sock, pkbuf->payload, pkbuf->len) <= 0)
{
d_error("Can not send packets to tuntap");
}
@ -175,67 +174,59 @@ status_t pgw_gtp_open()
d_assert(pgw_self()->gtpu_addr || pgw_self()->gtpu_addr6,
return CORE_ERROR, "No GTP Server");
for (i = 0; i < pgw_self()->num_of_ue_network; i++)
/* NOTE : tun device can be created via following command.
*
* $ sudo ip tuntap add name pgwtun mode tun
*
* Also, before running pgw, assign the one IP from IP pool of UE
* to pgwtun. The IP should not be assigned to UE
*
* $ sudo ifconfig pgwtun 45.45.0.1/16 up
*
*/
/* Open Tun interface */
rc = tun_open(&pgw_self()->tun_sock, (char *)pgw_self()->tun_ifname, 0);
if (rc != 0)
{
/* NOTE : tun device can be created via following command.
*
* $ sudo ip tuntap add name pgwtun mode tun
*
* Also, before running pgw, assign the one IP from IP pool of UE
* to pgwtun. The IP should not be assigned to UE
*
* $ sudo ifconfig pgwtun 45.45.0.1/16 up
*
*/
d_error("Can not open tun(dev : %s)", pgw_self()->tun_ifname);
return CORE_ERROR;
}
/* Open Tun interface */
rc = tun_open(&pgw_self()->ue_network[i].tun_link,
(char *)pgw_self()->ue_network[i].if_name, 0);
/*
* On Linux, it is possible to create a persistent tun/tap
* interface which will continue to exist even if nextepc quit,
* although this is normally not required.
* It can be useful to set up a tun/tap interface owned
* by a non-root user, so nextepc can be started without
* needing any root privileges at all.
*/
/* Set P-to-P IP address with Netmask
* Note that Linux will skip this configuration */
for (i = 0; i < pgw_self()->num_of_ue_pool; i++)
{
rc = tun_set_ip(pgw_self()->tun_sock,
pgw_self()->ue_pool[i].ipstr,
pgw_self()->ue_pool[i].mask_or_numbits);
if (rc != 0)
{
d_error("Can not open tun(dev : %s)",
pgw_self()->ue_network[i].if_name);
d_error("Can not configure tun(dev : %s for %s/%s)",
pgw_self()->tun_ifname,
pgw_self()->ue_pool[i].ipstr,
pgw_self()->ue_pool[i].mask_or_numbits);
return CORE_ERROR;
}
}
/*
* On Linux, it is possible to create a persistent tun/tap
* interface which will continue to exist even if nextepc quit,
* although this is normally not required.
* It can be useful to set up a tun/tap interface owned
* by a non-root user, so nextepc can be started without
* needing any root privileges at all.
*/
/* Set P-to-P IP address with Netmask
* Note that Linux will skip this configuration */
rc = tun_set_ipv4(pgw_self()->ue_network[i].tun_link,
pgw_self()->ue_network[i].ipv4.addr,
pgw_self()->ue_network[i].ipv4.bits);
if (rc != 0)
{
#if 0 /* ADDR */
d_error("Can not configure tun(dev : %s for %s/%d)",
pgw_self()->ue_network[i].if_name,
INET_NTOP(&pgw_self()->ue_network[i].ipv4.addr, buf),
pgw_self()->ue_network[i].ipv4.bits);
#else
d_error("Can not configure tun(dev : %s for /%d)",
pgw_self()->ue_network[i].if_name,
pgw_self()->ue_network[i].ipv4.bits);
#endif
return CORE_ERROR;
}
rc = sock_register(pgw_self()->ue_network[i].tun_link,
_gtpv1_tun_recv_cb, (void *)(c_uintptr_t)i);
if (rc != 0)
{
d_error("Can not register tun(dev : %s)",
pgw_self()->ue_network[i].if_name);
sock_delete(pgw_self()->ue_network[i].tun_link);
return CORE_ERROR;
}
rc = sock_register(pgw_self()->tun_sock, _gtpv1_tun_recv_cb, NULL);
if (rc != 0)
{
d_error("Can not register tun(dev : %s)",
pgw_self()->tun_ifname);
sock_delete(pgw_self()->tun_sock);
return CORE_ERROR;
}
return CORE_OK;
@ -243,18 +234,13 @@ status_t pgw_gtp_open()
status_t pgw_gtp_close()
{
int i;
sock_delete_list(&pgw_self()->gtpc_list);
sock_delete_list(&pgw_self()->gtpc_list6);
sock_delete_list(&pgw_self()->gtpu_list);
sock_delete_list(&pgw_self()->gtpu_list6);
for (i = 0; i < pgw_self()->num_of_ue_network; i++)
{
sock_delete(pgw_self()->ue_network[i].tun_link);
}
sock_delete(pgw_self()->tun_sock);
return CORE_OK;
}

View File

@ -30,7 +30,7 @@ status_t pgw_initialize()
rv = pgw_context_setup_trace_module();
if (rv != CORE_OK) return rv;
rv = pgw_ip_pool_generate();
rv = pgw_ue_pool_generate();
if (rv != CORE_OK) return rv;
ret = pgw_fd_init();

View File

@ -59,9 +59,9 @@ status_t pgw_s5c_build_create_session_response(
len = len;
/* PDN Address Allocation */
d_assert(sess->ip_pool, return CORE_ERROR, "No IP Pool");
d_assert(sess->ue_ip, return CORE_ERROR, "No IP Pool");
sess->pdn.paa.pdn_type = GTP_PDN_TYPE_IPV4;
sess->pdn.paa.addr = sess->ip_pool->ue_addr;
sess->pdn.paa.addr = sess->ue_ip->addr[0];
rsp->pdn_address_allocation.presence = 1;
rsp->pdn_address_allocation.data = &sess->pdn.paa;

View File

@ -286,37 +286,41 @@ pgw:
- addr: fe80::3%@LO_DEV@
#
# <UE network>
# <UE Pool>
#
# o IPv4/IPv6 with `pgwtun` device
# ue_network:
# addr:
# - 45.45.0.1/16
# - 2001:200:903::1/96
# o IPv4 Pool
# $ sudo ip addr add 45.45.0.1/16 dev pgwtun
#
# o Multiple Device
# ue_network:
# ue_pool:
# addr: 45.45.0.1/16
#
# o IPv4/IPv6 Pool
# $ sudo ip addr add 45.45.0.1/16 dev pgwtun
# $ sudo ip addr add cafe:1::1/64 dev pgwtun
#
# ue_pool:
# - addr: 45.45.0.1/16
# dev: pgwtun1
# - addr:
# - 46.46.0.1/16
# - 2001:200:903::1/96
# dev: pgwtun2
# - addr: cafe:1::1/64
#
# o Per-APN
# ue_network:
#
# o Specific APN(e.g 'volte') uses 45.46.0.1/16, cafe:2::1/64
# All other APN uses 45.45.0.1/16, cafe:1::1/64
# $ sudo ip addr add 45.45.0.1/16 dev pgwtun
# $ sudo ip addr add 45.46.0.1/16 dev pgwtun
# $ sudo ip addr add cafe:1::1/64 dev pgwtun
# $ sudo ip addr add cafe:2::1/64 dev pgwtun
#
# ue_pool:
# - addr: 45.45.0.1/16
# dev: pgwtun1
# apn : internet
# - addr:
# - 46.46.0.1/16
# - 2001:200:903::1/96
# dev: pgwtun2
# apn : volte
# - addr: cafe:1::1/64
# - addr: 45.46.0.1/16
# apn: volte
# - addr: cafe:2::1/64
# apn: volte
#
ue_network:
addr: 45.45.0.1/16
dev: pgwtun
ue_pool:
- addr: 45.45.0.1/16
- addr: cafe::1/64
#
# <Domain Name Server>