forked from acouzens/open5gs
Merge branch 'ipv6' of https://github.com/acetcom/nextepc into ipv6
This commit is contained in:
commit
73fb7e1c30
|
@ -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,
|
CORE_DECLARE(status_t) tun_open(sock_id *new,
|
||||||
char *ifname, int is_tap);
|
char *ifname, int is_tap);
|
||||||
CORE_DECLARE(status_t) tun_set_ip(sock_id id,
|
CORE_DECLARE(status_t) tun_set_ip(sock_id id, ipsubnet_t *gw, ipsubnet_t *sub);
|
||||||
const char *ipstr, const char *mask_or_numbits);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send/Recv
|
* Send/Recv
|
||||||
|
|
|
@ -342,32 +342,20 @@ status_t tun_set_ipv6(sock_id id, ipsubnet_t *ipaddr, ipsubnet_t *ipsub)
|
||||||
return CORE_OK;
|
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;
|
status_t rv;
|
||||||
|
|
||||||
d_assert(id, return CORE_ERROR,);
|
d_assert(id, return CORE_ERROR,);
|
||||||
d_assert(ipstr, return CORE_ERROR,);
|
d_assert(gw, return CORE_ERROR,);
|
||||||
d_assert(mask_or_numbits, return CORE_ERROR,);
|
d_assert(sub, return CORE_ERROR,);
|
||||||
|
|
||||||
rv = core_ipsubnet(&ipaddr, ipstr, NULL);
|
if (gw->family == AF_INET)
|
||||||
d_assert(rv == CORE_OK, return CORE_ERROR,);
|
rv = tun_set_ipv4(id, gw, sub);
|
||||||
|
else if (gw->family == AF_INET6)
|
||||||
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 0
|
#if 0
|
||||||
rv = tun_set_ipv6(id, &ipaddr, &ipsub);
|
rv = tun_set_ipv6(id, gw, sub);
|
||||||
#endif
|
#endif
|
||||||
return CORE_OK;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
d_assert(0, return CORE_ERROR,);
|
d_assert(0, return CORE_ERROR,);
|
||||||
|
|
||||||
|
|
|
@ -22,27 +22,18 @@
|
||||||
|
|
||||||
static pgw_context_t self;
|
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_sess_pool, pgw_sess_t, MAX_POOL_OF_SESS);
|
||||||
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
|
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_POOL_OF_BEARER);
|
||||||
|
|
||||||
pool_declare(pgw_pf_pool, pgw_pf_t, MAX_POOL_OF_PF);
|
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;
|
static int context_initiaized = 0;
|
||||||
|
|
||||||
status_t pgw_context_init()
|
status_t pgw_context_init()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
d_assert(context_initiaized == 0, return CORE_ERROR,
|
d_assert(context_initiaized == 0, return CORE_ERROR,
|
||||||
"PGW context already has been initialized");
|
"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_s5c_list);
|
||||||
list_init(&self.sgw_s5u_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_sess_pool, MAX_POOL_OF_SESS);
|
||||||
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
|
index_init(&pgw_bearer_pool, MAX_POOL_OF_BEARER);
|
||||||
|
|
||||||
pool_init(&pgw_pf_pool, MAX_POOL_OF_PF);
|
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();
|
self.sess_hash = hash_make();
|
||||||
|
|
||||||
context_initiaized = 1;
|
context_initiaized = 1;
|
||||||
|
@ -74,8 +67,6 @@ status_t pgw_context_init()
|
||||||
|
|
||||||
status_t pgw_context_final()
|
status_t pgw_context_final()
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
d_assert(context_initiaized == 1, return CORE_ERROR,
|
d_assert(context_initiaized == 1, return CORE_ERROR,
|
||||||
"PGW context already has been finalized");
|
"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",
|
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));
|
index_used(&pgw_sess_pool), index_size(&pgw_sess_pool));
|
||||||
|
|
||||||
pool_final(&pgw_pf_pool);
|
pgw_dev_remove_all();
|
||||||
|
pgw_subnet_remove_all();
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
index_final(&pgw_bearer_pool);
|
index_final(&pgw_bearer_pool);
|
||||||
index_final(&pgw_sess_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_s5c_list);
|
||||||
gtp_remove_all_nodes(&self.sgw_s5u_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);
|
yaml_iter_recurse(&pgw_iter, &ue_pool_array);
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
pgw_subnet_t *subnet = NULL;
|
||||||
const char *ipstr = NULL;
|
const char *ipstr = NULL;
|
||||||
const char *mask_or_numbits = NULL;
|
const char *mask_or_numbits = NULL;
|
||||||
const char *apn = 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) ==
|
if (yaml_iter_type(&ue_pool_array) ==
|
||||||
YAML_MAPPING_NODE)
|
YAML_MAPPING_NODE)
|
||||||
{
|
{
|
||||||
|
@ -550,17 +533,19 @@ status_t pgw_context_parse_config()
|
||||||
{
|
{
|
||||||
apn = yaml_iter_value(&ue_pool_iter);
|
apn = yaml_iter_value(&ue_pool_iter);
|
||||||
}
|
}
|
||||||
|
else if (!strcmp(ue_pool_key, "dev"))
|
||||||
|
{
|
||||||
|
dev = yaml_iter_value(&ue_pool_iter);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
d_warn("unknown key `%s`", ue_pool_key);
|
d_warn("unknown key `%s`", ue_pool_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ipstr && mask_or_numbits)
|
if (ipstr && mask_or_numbits)
|
||||||
{
|
{
|
||||||
self.ue_pool[self.num_of_ue_pool].ipstr = ipstr;
|
subnet = pgw_subnet_add(
|
||||||
self.ue_pool[self.num_of_ue_pool].mask_or_numbits =
|
ipstr, mask_or_numbits, apn, dev);
|
||||||
mask_or_numbits;
|
d_assert(subnet, return CORE_ERROR,);
|
||||||
self.ue_pool[self.num_of_ue_pool].apn = apn;
|
|
||||||
self.num_of_ue_pool++;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1131,42 +1116,31 @@ pgw_pf_t* pgw_pf_next(pgw_pf_t *pf)
|
||||||
|
|
||||||
status_t pgw_ue_pool_generate()
|
status_t pgw_ue_pool_generate()
|
||||||
{
|
{
|
||||||
status_t rv;
|
int j;
|
||||||
int i, 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;
|
int index = 0;
|
||||||
ipsubnet_t ipaddr, ipsub;
|
|
||||||
c_uint32_t prefixlen;
|
|
||||||
c_uint32_t mask_count;
|
c_uint32_t mask_count;
|
||||||
c_uint32_t broadcast[4];
|
c_uint32_t broadcast[4];
|
||||||
|
|
||||||
rv = core_ipsubnet(&ipaddr, self.ue_pool[i].ipstr, NULL);
|
if (subnet->family == AF_INET)
|
||||||
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 (prefixlen == 32)
|
if (subnet->prefixlen == 32)
|
||||||
mask_count = 1;
|
mask_count = 1;
|
||||||
else if (prefixlen < 32)
|
else if (subnet->prefixlen < 32)
|
||||||
mask_count = (0xffffffff >> prefixlen) + 1;
|
mask_count = (0xffffffff >> subnet->prefixlen) + 1;
|
||||||
else
|
else
|
||||||
d_assert(0, return CORE_ERROR,);
|
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;
|
mask_count = 1;
|
||||||
else if (prefixlen > 96 && prefixlen < 128)
|
else if (subnet->prefixlen > 96 && subnet->prefixlen < 128)
|
||||||
mask_count = (0xffffffff >> (prefixlen - 96)) + 1;
|
mask_count = (0xffffffff >> (subnet->prefixlen - 96)) + 1;
|
||||||
else if (prefixlen <= 96)
|
else if (subnet->prefixlen <= 96)
|
||||||
mask_count = 0xffffffff;
|
mask_count = 0xffffffff;
|
||||||
else
|
else
|
||||||
d_assert(0, return CORE_ERROR,);
|
d_assert(0, return CORE_ERROR,);
|
||||||
|
@ -1174,11 +1148,9 @@ status_t pgw_ue_pool_generate()
|
||||||
else
|
else
|
||||||
d_assert(0, return CORE_ERROR,);
|
d_assert(0, return CORE_ERROR,);
|
||||||
|
|
||||||
self.ue_pool[i].family = ipsub.family;
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++)
|
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++)
|
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 maxbytes = 0;
|
||||||
int lastindex = 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,);
|
d_assert(ue_ip, return CORE_ERROR,);
|
||||||
memset(ue_ip, 0, sizeof *ue_ip);
|
memset(ue_ip, 0, sizeof *ue_ip);
|
||||||
|
|
||||||
if (ipsub.family == AF_INET)
|
if (subnet->family == AF_INET)
|
||||||
{
|
{
|
||||||
maxbytes = 4;
|
maxbytes = 4;
|
||||||
lastindex = 0;
|
lastindex = 0;
|
||||||
}
|
}
|
||||||
else if (ipsub.family == AF_INET6)
|
else if (subnet->family == AF_INET6)
|
||||||
{
|
{
|
||||||
maxbytes = 16;
|
maxbytes = 16;
|
||||||
lastindex = 3;
|
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->addr[lastindex] += htonl(j);
|
||||||
|
ue_ip->subnet = subnet;
|
||||||
|
|
||||||
/* Exclude Network Address */
|
/* 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 */
|
/* Exclude Broadcast Address */
|
||||||
if (memcmp(ue_ip->addr, broadcast, maxbytes) == 0) continue;
|
if (memcmp(ue_ip->addr, broadcast, maxbytes) == 0) continue;
|
||||||
|
|
||||||
/* Exclude TUN IP Address */
|
/* 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++;
|
index++;
|
||||||
}
|
}
|
||||||
ue_ip_pool[i].size = ue_ip_pool[i].avail = index;
|
subnet->pool.size = subnet->pool.avail = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CORE_OK;
|
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;
|
pgw_subnet_t *subnet = NULL;
|
||||||
c_uint8_t pool_index = INVALID_POOL_INDEX;
|
|
||||||
|
|
||||||
d_assert(apn, return INVALID_POOL_INDEX,);
|
d_assert(apn, return NULL,);
|
||||||
d_assert(family == AF_INET || family == AF_INET6,
|
d_assert(family == AF_INET || family == AF_INET6, return NULL,);
|
||||||
return INVALID_POOL_INDEX,);
|
|
||||||
|
|
||||||
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 &&
|
if (subnet->family == family && strcmp(subnet->apn, apn) == 0 &&
|
||||||
strcmp(self.ue_pool[i].apn, apn) == 0 &&
|
pool_avail(&subnet->pool))
|
||||||
pool_avail(&ue_ip_pool[i]))
|
|
||||||
{
|
{
|
||||||
pool_index = i;
|
return subnet;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 &&
|
return subnet;
|
||||||
pool_avail(&ue_ip_pool[i]))
|
|
||||||
{
|
|
||||||
pool_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pool_index == INVALID_POOL_INDEX)
|
if (subnet == NULL)
|
||||||
{
|
|
||||||
d_error("CHECK CONFIGURATION: Cannot find UE Pool");
|
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)
|
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;
|
pgw_ue_ip_t *ue_ip = NULL;
|
||||||
|
|
||||||
d_assert(apn, return NULL,);
|
d_assert(apn, return NULL,);
|
||||||
|
|
||||||
pool_index = find_ue_pool_index(family, apn);
|
subnet = find_subnet(family, apn);
|
||||||
d_assert(pool_index < MAX_NUM_OF_UE_POOL, return NULL,);
|
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,);
|
d_assert(ue_ip, return NULL,);
|
||||||
ue_ip->index = pool_index;
|
|
||||||
|
|
||||||
return ue_ip;
|
return ue_ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t pgw_ue_ip_free(pgw_ue_ip_t *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,);
|
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,);
|
d_assert(subnet, return CORE_ERROR,);
|
||||||
pool_free_node(&ue_ip_pool[pool_index], ue_ip);
|
pool_free_node(&subnet->pool, ue_ip);
|
||||||
|
|
||||||
return CORE_OK;
|
return CORE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
c_uint8_t pgw_ue_ip_prefixlen(pgw_ue_ip_t *ue_ip)
|
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(ue_ip, return -1,);
|
||||||
d_assert(index < MAX_NUM_OF_UE_POOL, return CORE_ERROR,);
|
subnet = ue_ip->subnet;
|
||||||
d_assert(pgw_self()->ue_pool[index].mask_or_numbits,
|
d_assert(subnet, return -1,);
|
||||||
return CORE_ERROR,);
|
|
||||||
return atoi(pgw_self()->ue_pool[index].mask_or_numbits);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,15 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define MAX_NUM_OF_DEV 16
|
||||||
|
#define MAX_NUM_OF_SUBNET 16
|
||||||
|
|
||||||
typedef struct _gtp_node_t gtp_node_t;
|
typedef struct _gtp_node_t gtp_node_t;
|
||||||
|
|
||||||
typedef struct _pgw_context_t {
|
typedef struct _pgw_context_t {
|
||||||
c_uint32_t gtpc_port; /* PGW GTP-C local port */
|
c_uint32_t gtpc_port; /* Default: PGW GTP-C local port */
|
||||||
c_uint32_t gtpu_port; /* PGW GTP-U 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 */
|
list_t gtpc_list; /* PGW GTPC IPv4 Server List */
|
||||||
c_sockaddr_t *gtpc_addr; /* PGW GTPC IPv4 Address */
|
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 */
|
list_t gtpu_list6; /* PGW GTPU IPv6 Server List */
|
||||||
c_sockaddr_t *gtpu_addr6; /* PGW GTPU IPv6 Address */
|
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 */
|
const char* fd_conf_path; /* PGW freeDiameter conf path */
|
||||||
|
|
||||||
msgq_id queue_id; /* Qsesssess for processing PGW control plane */
|
msgq_id queue_id; /* Qsesssess for processing PGW control plane */
|
||||||
tm_service_t tm_service; /* Timer Service */
|
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
|
#define MAX_NUM_OF_DNS 2
|
||||||
const char *dns[2]; /* Primary/Secondanry */
|
const char *dns[MAX_NUM_OF_DNS]; /* Primary/Secondanry */
|
||||||
const char *dns6[2]; /* Primary/Secondanry */
|
const char *dns6[MAX_NUM_OF_DNS]; /* Primary/Secondanry */
|
||||||
|
|
||||||
list_t sgw_s5c_list; /* SGW GTPC Node List */
|
list_t sgw_s5c_list; /* SGW GTPC Node List */
|
||||||
list_t sgw_s5u_list; /* SGW GTPU 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) */
|
hash_t *sess_hash; /* hash table (IMSI+APN) */
|
||||||
} pgw_context_t;
|
} pgw_context_t;
|
||||||
|
|
||||||
typedef struct _pgw_ip_pool_t {
|
typedef struct _pgw_subnet_t pgw_subnet_t;
|
||||||
lnode_t node; /**< A node of list_t */
|
|
||||||
|
|
||||||
c_uint32_t ue_addr;
|
|
||||||
} pgw_ip_pool_t;
|
|
||||||
|
|
||||||
typedef struct _pgw_ue_ip_t {
|
typedef struct _pgw_ue_ip_t {
|
||||||
c_uint8_t index; /* Pool index */
|
|
||||||
c_uint32_t addr[4];
|
c_uint32_t addr[4];
|
||||||
|
|
||||||
|
/* Related Context */
|
||||||
|
pgw_subnet_t *subnet;
|
||||||
} pgw_ue_ip_t;
|
} 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 {
|
typedef struct _pgw_sess_t {
|
||||||
lnode_t node; /**< A node of list_t */
|
lnode_t node; /**< A node of list_t */
|
||||||
index_t index; /**< An index of this node */
|
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(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(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
c_uint16_t in_cksum(c_uint16_t *addr, int len);
|
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_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_to_bearer(pgw_bearer_t *bearer, pkbuf_t *sendbuf);
|
||||||
static status_t pgw_gtp_send_router_advertisement(pgw_sess_t *sess);
|
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;
|
pkbuf_t *pkbuf = NULL;
|
||||||
c_uint32_t size = GTPV1U_HEADER_LEN;
|
c_uint32_t size = GTPV1U_HEADER_LEN;
|
||||||
gtp_header_t *gtp_h = NULL;
|
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");
|
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_trace_hex(50, pkbuf->payload, pkbuf->len);
|
||||||
|
|
||||||
|
|
||||||
d_assert(pkbuf->payload, return 0,);
|
d_assert(pkbuf->payload, goto cleanup,);
|
||||||
gtp_h = pkbuf->payload;
|
gtp_h = pkbuf->payload;
|
||||||
if (gtp_h->flags & GTPU_FLAGS_S) size += 4;
|
if (gtp_h->flags & GTPU_FLAGS_S) size += 4;
|
||||||
|
teid = ntohl(gtp_h->teid);
|
||||||
|
|
||||||
/* Remove GTP header and send packets to TUN interface */
|
/* Remove GTP header and send packets to TUN interface */
|
||||||
if (pkbuf_header(pkbuf, -size) != CORE_OK)
|
d_assert(pkbuf_header(pkbuf, -size) == CORE_OK, goto cleanup,);
|
||||||
{
|
|
||||||
d_error("pkbuf_header error");
|
|
||||||
|
|
||||||
pkbuf_free(pkbuf);
|
ip_h = pkbuf->payload;
|
||||||
return -1;
|
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 */
|
/* 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)
|
if (rv == PGW_GTP_HANDLED)
|
||||||
{
|
{
|
||||||
pkbuf_free(pkbuf);
|
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");
|
d_assert(rv == CORE_OK,, "pgw_gtp_handle_slacc() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sock_write(pgw_self()->tun_sock, pkbuf->payload, pkbuf->len) <= 0)
|
dev = subnet->dev;
|
||||||
{
|
d_assert(dev, goto cleanup,);
|
||||||
d_error("Can not send packets to tuntap");
|
if (sock_write(dev->sock, pkbuf->payload, pkbuf->len) <= 0)
|
||||||
}
|
d_error("sock_write() failed");
|
||||||
|
|
||||||
|
cleanup:
|
||||||
pkbuf_free(pkbuf);
|
pkbuf_free(pkbuf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +173,8 @@ static int _gtpv1_u_recv_cb(sock_id sock, void *data)
|
||||||
status_t pgw_gtp_open()
|
status_t pgw_gtp_open()
|
||||||
{
|
{
|
||||||
status_t rv;
|
status_t rv;
|
||||||
int i;
|
pgw_dev_t *dev = NULL;
|
||||||
|
pgw_subnet_t *subnet = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb);
|
rv = gtp_server_list(&pgw_self()->gtpc_list, _gtpv2_c_recv_cb);
|
||||||
|
@ -193,13 +211,24 @@ status_t pgw_gtp_open()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Open Tun interface */
|
/* Open Tun interface */
|
||||||
rc = tun_open(&pgw_self()->tun_sock, (char *)pgw_self()->tun_ifname, 0);
|
for (dev = pgw_dev_first(); dev; dev = pgw_dev_next(dev))
|
||||||
|
{
|
||||||
|
rc = tun_open(&dev->sock, (char *)dev->ifname, 0);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
d_error("Can not open tun(dev : %s)", pgw_self()->tun_ifname);
|
d_error("tun_open(dev:%s) failed", dev->ifname);
|
||||||
return CORE_ERROR;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On Linux, it is possible to create a persistent tun/tap
|
* On Linux, it is possible to create a persistent tun/tap
|
||||||
* interface which will continue to exist even if nextepc quit,
|
* interface which will continue to exist even if nextepc quit,
|
||||||
|
@ -211,43 +240,32 @@ status_t pgw_gtp_open()
|
||||||
|
|
||||||
/* Set P-to-P IP address with Netmask
|
/* Set P-to-P IP address with Netmask
|
||||||
* Note that Linux will skip this configuration */
|
* 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,
|
d_assert(subnet->dev, return CORE_ERROR,);
|
||||||
pgw_self()->ue_pool[i].ipstr,
|
rc = tun_set_ip(subnet->dev->sock, &subnet->gw, &subnet->sub);
|
||||||
pgw_self()->ue_pool[i].mask_or_numbits);
|
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
{
|
{
|
||||||
d_error("Can not configure tun(dev : %s for %s/%s)",
|
d_error("tun_set_ip(dev:%s) failed", subnet->dev->ifname);
|
||||||
pgw_self()->tun_ifname,
|
|
||||||
pgw_self()->ue_pool[i].ipstr,
|
|
||||||
pgw_self()->ue_pool[i].mask_or_numbits);
|
|
||||||
|
|
||||||
return CORE_ERROR;
|
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;
|
return CORE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t pgw_gtp_close()
|
status_t pgw_gtp_close()
|
||||||
{
|
{
|
||||||
|
pgw_dev_t *dev = NULL;
|
||||||
|
|
||||||
sock_delete_list(&pgw_self()->gtpc_list);
|
sock_delete_list(&pgw_self()->gtpc_list);
|
||||||
sock_delete_list(&pgw_self()->gtpc_list6);
|
sock_delete_list(&pgw_self()->gtpc_list6);
|
||||||
|
|
||||||
sock_delete_list(&pgw_self()->gtpu_list);
|
sock_delete_list(&pgw_self()->gtpu_list);
|
||||||
sock_delete_list(&pgw_self()->gtpu_list6);
|
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;
|
return CORE_OK;
|
||||||
}
|
}
|
||||||
|
@ -290,11 +308,12 @@ static status_t pgw_gtp_handle_multicast(pkbuf_t *recvbuf)
|
||||||
return CORE_OK;
|
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;
|
status_t rv;
|
||||||
struct ip *ip_h = NULL;
|
struct ip *ip_h = NULL;
|
||||||
|
|
||||||
|
d_assert(sess, return CORE_ERROR,);
|
||||||
d_assert(recvbuf, return CORE_ERROR,);
|
d_assert(recvbuf, return CORE_ERROR,);
|
||||||
d_assert(recvbuf->payload, return CORE_ERROR,);
|
d_assert(recvbuf->payload, return CORE_ERROR,);
|
||||||
ip_h = (struct ip *)recvbuf->payload;
|
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));
|
(struct icmp6_hdr *)(recvbuf->payload + sizeof(struct ip6_hdr));
|
||||||
if (icmp_h->icmp6_type == ND_ROUTER_SOLICIT)
|
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)
|
if (sess->ipv6)
|
||||||
{
|
{
|
||||||
rv = pgw_gtp_send_router_advertisement(sess);
|
rv = pgw_gtp_send_router_advertisement(sess);
|
||||||
|
|
Loading…
Reference in New Issue