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

This commit is contained in:
Sukchan Lee 2017-12-18 00:48:34 +09:00
commit 73fb7e1c30
5 changed files with 361 additions and 209 deletions

View File

@ -207,8 +207,7 @@ 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_ip(sock_id id,
const char *ipstr, const char *mask_or_numbits);
CORE_DECLARE(status_t) tun_set_ip(sock_id id, ipsubnet_t *gw, ipsubnet_t *sub);
/*
* Send/Recv

View File

@ -342,32 +342,20 @@ status_t tun_set_ipv6(sock_id id, ipsubnet_t *ipaddr, ipsubnet_t *ipsub)
return CORE_OK;
}
status_t tun_set_ip(sock_id id, const char *ipstr, const char *mask_or_numbits)
status_t tun_set_ip(sock_id id, ipsubnet_t *gw, ipsubnet_t *sub)
{
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,);
d_assert(gw, return CORE_ERROR,);
d_assert(sub, 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 if (ipsub.family == AF_INET6)
{
if (gw->family == AF_INET)
rv = tun_set_ipv4(id, gw, sub);
else if (gw->family == AF_INET6)
#if 0
rv = tun_set_ipv6(id, &ipaddr, &ipsub);
rv = tun_set_ipv6(id, gw, sub);
#endif
return CORE_OK;
}
else
d_assert(0, return CORE_ERROR,);

View File

@ -22,27 +22,18 @@
static pgw_context_t self;
pool_declare(pgw_dev_pool, pgw_dev_t, MAX_NUM_OF_DEV);
pool_declare(pgw_subnet_pool, pgw_subnet_t, MAX_NUM_OF_SUBNET);
index_declare(pgw_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS);
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
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_ip_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");
@ -57,14 +48,16 @@ status_t pgw_context_init()
list_init(&self.sgw_s5c_list);
list_init(&self.sgw_s5u_list);
list_init(&self.dev_list);
pool_init(&pgw_dev_pool, MAX_NUM_OF_DEV);
list_init(&self.subnet_list);
pool_init(&pgw_subnet_pool, MAX_NUM_OF_SUBNET);
index_init(&pgw_sess_pool, MAX_POOL_OF_SESS);
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
pool_init(&ue_ip_pool[i], MAX_POOL_OF_UE);
self.sess_hash = hash_make();
context_initiaized = 1;
@ -74,8 +67,6 @@ 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");
@ -90,23 +81,15 @@ status_t pgw_context_final()
d_trace(3, "%d not freed in pgw_sess_pool[%d] in PGW-Context\n",
index_used(&pgw_sess_pool), index_size(&pgw_sess_pool));
pool_final(&pgw_pf_pool);
for (i = 0; i < MAX_NUM_OF_UE_POOL; i++)
{
if (pool_used(&ue_ip_pool[i]))
{
d_warn("[%d] %d not freed in ue_ip_pool[%d] in PGW-Context",
i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i]));
}
d_trace(3, "[%d] %d not freed in ue_ip_pool[%d] in PGW-Context\n",
i, pool_used(&ue_ip_pool[i]), index_size(&ue_ip_pool[i]));
pool_final(&ue_ip_pool[i]);
}
pgw_dev_remove_all();
pgw_subnet_remove_all();
index_final(&pgw_bearer_pool);
index_final(&pgw_sess_pool);
pool_final(&pgw_pf_pool);
pool_final(&pgw_dev_pool);
pool_final(&pgw_subnet_pool);
gtp_remove_all_nodes(&self.sgw_s5c_list);
gtp_remove_all_nodes(&self.sgw_s5u_list);
@ -499,12 +482,12 @@ status_t pgw_context_parse_config()
yaml_iter_recurse(&pgw_iter, &ue_pool_array);
do
{
pgw_subnet_t *subnet = NULL;
const char *ipstr = NULL;
const char *mask_or_numbits = NULL;
const char *apn = NULL;
const char *dev = self.tun_ifname;
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)
{
@ -550,17 +533,19 @@ status_t pgw_context_parse_config()
{
apn = yaml_iter_value(&ue_pool_iter);
}
else if (!strcmp(ue_pool_key, "dev"))
{
dev = yaml_iter_value(&ue_pool_iter);
}
else
d_warn("unknown key `%s`", ue_pool_key);
}
if (ipstr && mask_or_numbits)
{
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++;
subnet = pgw_subnet_add(
ipstr, mask_or_numbits, apn, dev);
d_assert(subnet, return CORE_ERROR,);
}
else
{
@ -1131,54 +1116,41 @@ pgw_pf_t* pgw_pf_next(pgw_pf_t *pf)
status_t pgw_ue_pool_generate()
{
status_t rv;
int i, j;
int j;
pgw_subnet_t *subnet = NULL;
for (i = 0; i < self.num_of_ue_pool; i++)
for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet))
{
int index = 0;
ipsubnet_t ipaddr, ipsub;
c_uint32_t prefixlen;
c_uint32_t mask_count;
c_uint32_t broadcast[4];
rv = core_ipsubnet(&ipaddr, self.ue_pool[i].ipstr, NULL);
d_assert(rv == CORE_OK, return CORE_ERROR,);
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,);
prefixlen = atoi(self.ue_pool[i].mask_or_numbits);
if (ipsub.family == AF_INET)
if (subnet->family == AF_INET)
{
if (prefixlen == 32)
if (subnet->prefixlen == 32)
mask_count = 1;
else if (prefixlen < 32)
mask_count = (0xffffffff >> prefixlen) + 1;
else if (subnet->prefixlen < 32)
mask_count = (0xffffffff >> subnet->prefixlen) + 1;
else
d_assert(0, return CORE_ERROR,);
}
else if (ipsub.family == AF_INET6)
else if (subnet->family == AF_INET6)
{
if (prefixlen == 128)
if (subnet->prefixlen == 128)
mask_count = 1;
else if (prefixlen > 96 && prefixlen < 128)
mask_count = (0xffffffff >> (prefixlen - 96)) + 1;
else if (prefixlen <= 96)
else if (subnet->prefixlen > 96 && subnet->prefixlen < 128)
mask_count = (0xffffffff >> (subnet->prefixlen - 96)) + 1;
else if (subnet->prefixlen <= 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];
broadcast[j] = subnet->sub.sub[j] + ~subnet->sub.mask[j];
}
for (j = 0; j < mask_count && index < MAX_POOL_OF_SESS; j++)
@ -1187,126 +1159,276 @@ status_t pgw_ue_pool_generate()
int maxbytes = 0;
int lastindex = 0;
ue_ip = &ue_ip_pool[i].pool[index];
ue_ip = &subnet->pool.pool[index];
d_assert(ue_ip, return CORE_ERROR,);
memset(ue_ip, 0, sizeof *ue_ip);
if (ipsub.family == AF_INET)
if (subnet->family == AF_INET)
{
maxbytes = 4;
lastindex = 0;
}
else if (ipsub.family == AF_INET6)
else if (subnet->family == AF_INET6)
{
maxbytes = 16;
lastindex = 3;
}
memcpy(ue_ip->addr, ipsub.sub, maxbytes);
memcpy(ue_ip->addr, subnet->sub.sub, maxbytes);
ue_ip->addr[lastindex] += htonl(j);
ue_ip->subnet = subnet;
/* Exclude Network Address */
if (memcmp(ue_ip->addr, ipsub.sub, maxbytes) == 0) continue;
if (memcmp(ue_ip->addr, subnet->sub.sub, maxbytes) == 0) continue;
/* Exclude Broadcast Address */
if (memcmp(ue_ip->addr, broadcast, maxbytes) == 0) continue;
/* Exclude TUN IP Address */
if (memcmp(ue_ip->addr, ipaddr.sub, maxbytes) == 0) continue;
if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0) continue;
index++;
}
ue_ip_pool[i].size = ue_ip_pool[i].avail = index;
subnet->pool.size = subnet->pool.avail = index;
}
return CORE_OK;
}
static c_uint8_t find_ue_pool_index(int family, const char *apn)
static pgw_subnet_t *find_subnet(int family, const char *apn)
{
int i;
c_uint8_t pool_index = INVALID_POOL_INDEX;
pgw_subnet_t *subnet = NULL;
d_assert(apn, return INVALID_POOL_INDEX,);
d_assert(family == AF_INET || family == AF_INET6,
return INVALID_POOL_INDEX,);
d_assert(apn, return NULL,);
d_assert(family == AF_INET || family == AF_INET6, return NULL,);
for (i = 0; i < self.num_of_ue_pool; i++)
for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet))
{
if (self.ue_pool[i].apn)
if (strlen(subnet->apn))
{
if (self.ue_pool[i].family == family &&
strcmp(self.ue_pool[i].apn, apn) == 0 &&
pool_avail(&ue_ip_pool[i]))
if (subnet->family == family && strcmp(subnet->apn, apn) == 0 &&
pool_avail(&subnet->pool))
{
pool_index = i;
break;
return subnet;
}
}
}
if (pool_index == INVALID_POOL_INDEX)
for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet))
{
for (i = 0; i < self.num_of_ue_pool; i++)
if (strlen(subnet->apn) == 0)
{
if (self.ue_pool[i].apn == NULL)
if (subnet->family == family &&
pool_avail(&subnet->pool))
{
if (self.ue_pool[i].family == family &&
pool_avail(&ue_ip_pool[i]))
{
pool_index = i;
break;
}
return subnet;
}
}
}
if (pool_index == INVALID_POOL_INDEX)
{
if (subnet == NULL)
d_error("CHECK CONFIGURATION: Cannot find UE Pool");
return INVALID_POOL_INDEX;
}
return pool_index;
return subnet;
}
pgw_ue_ip_t *pgw_ue_ip_alloc(int family, const char *apn)
{
c_uint8_t pool_index = INVALID_POOL_INDEX;
pgw_subnet_t *subnet = NULL;
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,);
subnet = find_subnet(family, apn);
d_assert(subnet, return NULL,);
pool_alloc_node(&ue_ip_pool[pool_index], &ue_ip);
pool_alloc_node(&subnet->pool, &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;
pgw_subnet_t *subnet = NULL;
d_assert(ue_ip, return CORE_ERROR,);
pool_index = ue_ip->index;
subnet = ue_ip->subnet;
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
pool_free_node(&ue_ip_pool[pool_index], ue_ip);
d_assert(subnet, return CORE_ERROR,);
pool_free_node(&subnet->pool, ue_ip);
return CORE_OK;
}
c_uint8_t pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip)
{
d_assert(ue_ip, return CORE_ERROR,);
pgw_subnet_t *subnet = NULL;
c_uint8_t index = ue_ip->index;
d_assert(index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
d_assert(pgw_self()->ue_pool[index].mask_or_numbits,
return CORE_ERROR,);
return atoi(pgw_self()->ue_pool[index].mask_or_numbits);
d_assert(ue_ip, return -1,);
subnet = ue_ip->subnet;
d_assert(subnet, return -1,);
return subnet->prefixlen;
}
pgw_dev_t *pgw_dev_add(const char *ifname)
{
pgw_dev_t *dev = NULL;
d_assert(ifname, return NULL,);
pool_alloc_node(&pgw_dev_pool, &dev);
d_assert(dev, return NULL,);
memset(dev, 0, sizeof *dev);
strcpy(dev->ifname, ifname);
list_append(&self.dev_list, dev);
return dev;
}
status_t pgw_dev_remove(pgw_dev_t *dev)
{
d_assert(dev, return CORE_ERROR, "Null param");
list_remove(&self.dev_list, dev);
pool_free_node(&pgw_dev_pool, dev);
return CORE_OK;
}
status_t pgw_dev_remove_all()
{
pgw_dev_t *dev = NULL, *next_dev = NULL;
dev = pgw_dev_first();
while (dev)
{
next_dev = pgw_dev_next(dev);
pgw_dev_remove(dev);
dev = next_dev;
}
return CORE_OK;
}
pgw_dev_t* pgw_dev_find_by_ifname(const char *ifname)
{
pgw_dev_t *dev = NULL;
d_assert(ifname, return NULL,);
dev = pgw_dev_first();
while (dev)
{
if (strcmp(dev->ifname, ifname) == 0)
return dev;
dev = pgw_dev_next(dev);
}
return CORE_OK;
}
pgw_dev_t* pgw_dev_first()
{
return list_first(&self.dev_list);
}
pgw_dev_t* pgw_dev_next(pgw_dev_t *dev)
{
return list_next(dev);
}
pgw_subnet_t *pgw_subnet_add(
const char *ipstr, const char *mask_or_numbits,
const char *apn, const char *ifname)
{
status_t rv;
pgw_dev_t *dev = NULL;
pgw_subnet_t *subnet = NULL;
d_assert(ipstr, return NULL,);
d_assert(mask_or_numbits, return NULL,);
d_assert(ifname, return NULL,);
dev = pgw_dev_find_by_ifname(ifname);
if (!dev)
dev = pgw_dev_add(ifname);
d_assert(dev, return NULL,);
pool_alloc_node(&pgw_subnet_pool, &subnet);
d_assert(subnet, return NULL,);
memset(subnet, 0, sizeof *subnet);
subnet->dev = dev;
rv = core_ipsubnet(&subnet->gw, ipstr, NULL);
d_assert(rv == CORE_OK, return NULL,);
rv = core_ipsubnet(&subnet->sub, ipstr, mask_or_numbits);
d_assert(rv == CORE_OK, return NULL,);
if (apn)
strcpy(subnet->apn, apn);
subnet->family = subnet->gw.family;
subnet->prefixlen = atoi(mask_or_numbits);
pool_init(&subnet->pool, MAX_POOL_OF_UE);
list_append(&self.subnet_list, subnet);
return subnet;
}
status_t pgw_subnet_remove(pgw_subnet_t *subnet)
{
d_assert(subnet, return CORE_ERROR, "Null param");
list_remove(&self.subnet_list, subnet);
if (pool_used(&subnet->pool))
{
d_warn("%d not freed in ue_ip_pool[%d] in PGW-Context",
pool_used(&subnet->pool), pool_size(&subnet->pool));
}
d_trace(3, "%d not freed in ue_ip_pool[%d] in PGW-Context\n",
pool_used(&subnet->pool), pool_size(&subnet->pool));
pool_final(&subnet->pool);
pool_free_node(&pgw_subnet_pool, subnet);
return CORE_OK;
}
status_t pgw_subnet_remove_all()
{
pgw_subnet_t *subnet = NULL, *next_subnet = NULL;
subnet = pgw_subnet_first();
while (subnet)
{
next_subnet = pgw_subnet_next(subnet);
pgw_subnet_remove(subnet);
subnet = next_subnet;
}
return CORE_OK;
}
pgw_subnet_t* pgw_subnet_first()
{
return list_first(&self.subnet_list);
}
pgw_subnet_t* pgw_subnet_next(pgw_subnet_t *subnet)
{
return list_next(subnet);
}

View File

@ -16,11 +16,15 @@
extern "C" {
#endif /* __cplusplus */
#define MAX_NUM_OF_DEV 16
#define MAX_NUM_OF_SUBNET 16
typedef struct _gtp_node_t gtp_node_t;
typedef struct _pgw_context_t {
c_uint32_t gtpc_port; /* PGW GTP-C local port */
c_uint32_t gtpu_port; /* PGW GTP-U local port */
c_uint32_t gtpc_port; /* Default: PGW GTP-C local port */
c_uint32_t gtpu_port; /* Default: PGW GTP-U local port */
const char *tun_ifname; /* Default:: pgwtun */
list_t gtpc_list; /* PGW GTPC IPv4 Server List */
c_sockaddr_t *gtpc_addr; /* PGW GTPC IPv4 Address */
@ -32,30 +36,17 @@ typedef struct _pgw_context_t {
list_t gtpu_list6; /* PGW GTPU IPv6 Server List */
c_sockaddr_t *gtpu_addr6; /* PGW GTPU IPv6 Address */
list_t dev_list; /* PGW Tun Device List */
list_t subnet_list; /* PGW UE Subnet List */
const char* fd_conf_path; /* PGW freeDiameter conf path */
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 */
#define MAX_NUM_OF_UE_POOL 16
struct {
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;
c_uint32_t secondary;
} old_dns;
#define MAX_NUM_OF_DNS 2
const char *dns[2]; /* Primary/Secondanry */
const char *dns6[2]; /* Primary/Secondanry */
const char *dns[MAX_NUM_OF_DNS]; /* Primary/Secondanry */
const char *dns6[MAX_NUM_OF_DNS]; /* Primary/Secondanry */
list_t sgw_s5c_list; /* SGW GTPC Node List */
list_t sgw_s5u_list; /* SGW GTPU Node List */
@ -64,17 +55,44 @@ typedef struct _pgw_context_t {
hash_t *sess_hash; /* hash table (IMSI+APN) */
} pgw_context_t;
typedef struct _pgw_ip_pool_t {
lnode_t node; /**< A node of list_t */
c_uint32_t ue_addr;
} pgw_ip_pool_t;
typedef struct _pgw_subnet_t pgw_subnet_t;
typedef struct _pgw_ue_ip_t {
c_uint8_t index; /* Pool index */
c_uint32_t addr[4];
/* Related Context */
pgw_subnet_t *subnet;
} pgw_ue_ip_t;
typedef struct _pgw_dev_t {
lnode_t node;
c_int8_t ifname[IFNAMSIZ];
sock_id sock;
c_uint8_t link_local_addr[IPV6_LEN];
} pgw_dev_t;
typedef struct _pgw_subnet_t {
lnode_t node;
ipsubnet_t sub; /* Subnet : cafe::0/64 */
ipsubnet_t gw; /* Gateway : cafe::1 */
c_int8_t apn[MAX_APN_LEN]; /* APN : "internet", "volte", .. */
int family; /* AF_INET or AF_INET6 */
c_uint8_t prefixlen; /* prefixlen */
struct {
int head, tail;
int size, avail;
mutex_id mut;
pgw_ue_ip_t *free[MAX_POOL_OF_SESS], pool[MAX_POOL_OF_SESS];
} pool;
/* Related Context */
pgw_dev_t *dev;
} pgw_subnet_t;
typedef struct _pgw_sess_t {
lnode_t node; /**< A node of list_t */
index_t index; /**< An index of this node */
@ -223,6 +241,21 @@ 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);
CORE_DECLARE(c_uint8_t) pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip);
CORE_DECLARE(pgw_dev_t*) pgw_dev_add(const char *ifname);
CORE_DECLARE(status_t ) pgw_dev_remove(pgw_dev_t *dev);
CORE_DECLARE(status_t ) pgw_dev_remove_all();
CORE_DECLARE(pgw_dev_t*) pgw_dev_find_by_ifname(const char *ifname);
CORE_DECLARE(pgw_dev_t*) pgw_dev_first();
CORE_DECLARE(pgw_dev_t*) pgw_dev_next(pgw_dev_t *dev);
CORE_DECLARE(pgw_subnet_t*) pgw_subnet_add(
const char *ipstr, const char *mask_or_numbits,
const char *apn, const char *ifname);
CORE_DECLARE(status_t ) pgw_subnet_remove(pgw_subnet_t *subnet);
CORE_DECLARE(status_t ) pgw_subnet_remove_all();
CORE_DECLARE(pgw_subnet_t*) pgw_subnet_first();
CORE_DECLARE(pgw_subnet_t*) pgw_subnet_next(pgw_subnet_t *subnet);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -15,7 +15,7 @@
c_uint16_t in_cksum(c_uint16_t *addr, int len);
static status_t pgw_gtp_handle_multicast(pkbuf_t *recvbuf);
static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf);
static status_t pgw_gtp_handle_slacc(pgw_sess_t *sess, pkbuf_t *recvbuf);
static status_t pgw_gtp_send_to_bearer(pgw_bearer_t *bearer, pkbuf_t *sendbuf);
static status_t pgw_gtp_send_router_advertisement(pgw_sess_t *sess);
@ -102,6 +102,13 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
pkbuf_t *pkbuf = NULL;
c_uint32_t size = GTPV1U_HEADER_LEN;
gtp_header_t *gtp_h = NULL;
struct ip *ip_h = NULL;
c_uint32_t teid;
pgw_bearer_t *bearer = NULL;
pgw_sess_t *sess = NULL;
pgw_subnet_t *subnet = NULL;
pgw_dev_t *dev = NULL;
d_assert(sock, return -1, "Null param");
@ -119,23 +126,32 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
d_trace_hex(50, pkbuf->payload, pkbuf->len);
d_assert(pkbuf->payload, return 0,);
d_assert(pkbuf->payload, goto cleanup,);
gtp_h = pkbuf->payload;
if (gtp_h->flags & GTPU_FLAGS_S) size += 4;
teid = ntohl(gtp_h->teid);
/* Remove GTP header and send packets to TUN interface */
if (pkbuf_header(pkbuf, -size) != CORE_OK)
{
d_error("pkbuf_header error");
d_assert(pkbuf_header(pkbuf, -size) == CORE_OK, goto cleanup,);
pkbuf_free(pkbuf);
return -1;
}
ip_h = pkbuf->payload;
d_assert(ip_h, goto cleanup,);
bearer = pgw_bearer_find_by_pgw_s5u_teid(teid);
d_assert(bearer, goto cleanup,);
sess = bearer->sess;
d_assert(sess, goto cleanup,);
if (ip_h->ip_v == 4 && sess->ipv4)
subnet = sess->ipv4->subnet;
else if (ip_h->ip_v == 6 && sess->ipv6)
subnet = sess->ipv6->subnet;
d_assert(subnet, goto cleanup,);
/* Check IPv6 */
if (context_self()->parameter.no_slaac == 0)
if (context_self()->parameter.no_slaac == 0 && ip_h->ip_v == 6)
{
rv = pgw_gtp_handle_slacc(ntohl(gtp_h->teid), pkbuf);
rv = pgw_gtp_handle_slacc(sess, pkbuf);
if (rv == PGW_GTP_HANDLED)
{
pkbuf_free(pkbuf);
@ -144,11 +160,12 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
d_assert(rv == CORE_OK,, "pgw_gtp_handle_slacc() failed");
}
if (sock_write(pgw_self()->tun_sock, pkbuf->payload, pkbuf->len) <= 0)
{
d_error("Can not send packets to tuntap");
}
dev = subnet->dev;
d_assert(dev, goto cleanup,);
if (sock_write(dev->sock, pkbuf->payload, pkbuf->len) <= 0)
d_error("sock_write() failed");
cleanup:
pkbuf_free(pkbuf);
return 0;
}
@ -156,7 +173,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
status_t pgw_gtp_open()
{
status_t rv;
int i;
pgw_dev_t *dev = NULL;
pgw_subnet_t *subnet = NULL;
int rc;
rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb);
@ -193,11 +211,22 @@ status_t pgw_gtp_open()
*/
/* Open Tun interface */
rc = tun_open(&pgw_self()->tun_sock, (char *)pgw_self()->tun_ifname, 0);
if (rc != 0)
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev))
{
d_error("Can not open tun(dev : %s)", pgw_self()->tun_ifname);
return CORE_ERROR;
rc = tun_open(&dev->sock, (char *)dev->ifname, 0);
if (rc != 0)
{
d_error("tun_open(dev:%s) failed", dev->ifname);
return CORE_ERROR;
}
rc = sock_register(dev->sock, _gtpv1_tun_recv_cb, NULL);
if (rc != 0)
{
d_error("sock_register(dev:%s) failed", dev->ifname);
sock_delete(dev->sock);
return CORE_ERROR;
}
}
/*
@ -211,43 +240,32 @@ status_t pgw_gtp_open()
/* 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++)
for (subnet = pgw_subnet_first(); subnet; subnet = pgw_subnet_next(subnet))
{
rc = tun_set_ip(pgw_self()->tun_sock,
pgw_self()->ue_pool[i].ipstr,
pgw_self()->ue_pool[i].mask_or_numbits);
d_assert(subnet->dev, return CORE_ERROR,);
rc = tun_set_ip(subnet->dev->sock, &subnet->gw, &subnet->sub);
if (rc != 0)
{
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);
d_error("tun_set_ip(dev:%s) failed", subnet->dev->ifname);
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;
}
status_t pgw_gtp_close()
{
pgw_dev_t *dev = NULL;
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);
sock_delete(pgw_self()->tun_sock);
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev))
sock_delete(dev->sock);
return CORE_OK;
}
@ -290,11 +308,12 @@ static status_t pgw_gtp_handle_multicast(pkbuf_t *recvbuf)
return CORE_OK;
}
static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf)
static status_t pgw_gtp_handle_slacc(pgw_sess_t *sess, pkbuf_t *recvbuf)
{
status_t rv;
struct ip *ip_h = NULL;
d_assert(sess, return CORE_ERROR,);
d_assert(recvbuf, return CORE_ERROR,);
d_assert(recvbuf->payload, return CORE_ERROR,);
ip_h = (struct ip *)recvbuf->payload;
@ -307,15 +326,6 @@ static status_t pgw_gtp_handle_slacc(c_uint32_t teid, pkbuf_t *recvbuf)
(struct icmp6_hdr *)(recvbuf->payload + sizeof(struct ip6_hdr));
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT)
{
pgw_bearer_t *bearer = NULL;
pgw_sess_t *sess = NULL;
bearer = pgw_bearer_find_by_pgw_s5u_teid(teid);
d_assert(teid, return CORE_ERROR,
"cannot find teid = %d", teid);
sess = bearer->sess;
d_assert(sess, return CORE_ERROR,);
if (sess->ipv6)
{
rv = pgw_gtp_send_router_advertisement(sess);