forked from acouzens/open5gs
Merge branch 'ipv6' of https://github.com/acetcom/nextepc into ipv6
This commit is contained in:
commit
7e84bd1aaf
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue