forked from acouzens/open5gs
825 lines
22 KiB
C
825 lines
22 KiB
C
#define TRACE_MODULE _pgw_context
|
|
|
|
#include "core_debug.h"
|
|
#include "core_pool.h"
|
|
#include "core_index.h"
|
|
#include "core_lib.h"
|
|
|
|
#include "fd_lib.h"
|
|
#include "gtp_path.h"
|
|
|
|
#include "context.h"
|
|
#include "pgw_context.h"
|
|
|
|
static pgw_context_t self;
|
|
|
|
index_declare(pgw_sess_pool, pgw_sess_t, MAX_NUM_OF_UE);
|
|
index_declare(pgw_bearer_pool, pgw_bearer_t, MAX_NUM_OF_UE_BEARER);
|
|
|
|
pool_declare(pgw_ip_pool_pool, pgw_ip_pool_t, MAX_NUM_OF_UE);
|
|
|
|
static int context_initiaized = 0;
|
|
|
|
status_t pgw_context_init()
|
|
{
|
|
d_assert(context_initiaized == 0, return CORE_ERROR,
|
|
"PGW context already has been initialized");
|
|
|
|
memset(&self, 0, sizeof(pgw_context_t));
|
|
|
|
index_init(&pgw_sess_pool, MAX_NUM_OF_UE);
|
|
index_init(&pgw_bearer_pool, MAX_NUM_OF_UE_BEARER);
|
|
|
|
pool_init(&pgw_ip_pool_pool, MAX_NUM_OF_UE);
|
|
|
|
list_init(&self.s5c_node.local_list);
|
|
list_init(&self.s5c_node.remote_list);
|
|
|
|
self.sess_hash = hash_make();
|
|
|
|
context_initiaized = 1;
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
status_t pgw_context_final()
|
|
{
|
|
d_assert(context_initiaized == 1, return CORE_ERROR,
|
|
"PGW context already has been finalized");
|
|
|
|
gtp_xact_delete_all(&self.s5c_node);
|
|
pgw_sess_remove_all();
|
|
|
|
d_assert(self.sess_hash, , "Null param");
|
|
hash_destroy(self.sess_hash);
|
|
|
|
if (index_size(&pgw_sess_pool) != pool_avail(&pgw_sess_pool))
|
|
d_warn("%d not freed in pgw_sess_pool[%d] in PGW-Context",
|
|
index_size(&pgw_sess_pool) - pool_avail(&pgw_sess_pool),
|
|
index_size(&pgw_sess_pool));
|
|
d_trace(3, "%d not freed in pgw_sess_pool[%d] in PGW-Context\n",
|
|
index_size(&pgw_sess_pool) - pool_avail(&pgw_sess_pool),
|
|
index_size(&pgw_sess_pool));
|
|
|
|
if (index_size(&pgw_ip_pool_pool) != pool_avail(&pgw_ip_pool_pool))
|
|
{
|
|
d_warn("%d not freed in pgw_ip_pool[%d] in PGW-Context",
|
|
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
|
|
index_size(&pgw_ip_pool_pool));
|
|
}
|
|
d_trace(3, "%d not freed in pgw_ip_pool[%d] in PGW-Context\n",
|
|
index_size(&pgw_ip_pool_pool) - pool_avail(&pgw_ip_pool_pool),
|
|
index_size(&pgw_ip_pool_pool));
|
|
|
|
pool_final(&pgw_ip_pool_pool);
|
|
|
|
index_final(&pgw_bearer_pool);
|
|
index_final(&pgw_sess_pool);
|
|
|
|
context_initiaized = 0;
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
pgw_context_t* pgw_self()
|
|
{
|
|
return &self;
|
|
}
|
|
|
|
static status_t pgw_context_prepare()
|
|
{
|
|
self.s5c_port = GTPV2_C_UDP_PORT;
|
|
self.s5c_node.port = GTPV2_C_UDP_PORT;
|
|
|
|
self.s5u_port = GTPV1_U_UDP_PORT;
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
static status_t pgw_context_validation()
|
|
{
|
|
if (self.fd_conf_path == NULL)
|
|
{
|
|
d_error("No PGW.FD_CONF_PATH in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.s5c_node.addr == 0)
|
|
{
|
|
d_error("No SGW.NEWORK.S5C_ADDR in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.s5c_addr == 0)
|
|
{
|
|
d_error("No PGW.NEWORK.S5C_ADDR in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.s5u_addr == 0)
|
|
{
|
|
d_error("No PGW.NEWORK.S5U_ADDR in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.tun_dev_name == NULL)
|
|
{
|
|
d_error("No PGW.TUNNEL.DEV_NAME in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.num_of_ip_pool == 0)
|
|
{
|
|
d_error("No PGW.IP_POOL.CIDR in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
if (self.primary_dns_addr == 0)
|
|
{
|
|
d_error("No PGW.DNS.PRIMARY_ADDR in '%s'",
|
|
context_self()->config.path);
|
|
return CORE_ERROR;
|
|
}
|
|
return CORE_OK;
|
|
}
|
|
|
|
status_t pgw_context_parse_config()
|
|
{
|
|
status_t rv;
|
|
config_t *config = &context_self()->config;
|
|
|
|
char *json = config->json;
|
|
jsmntok_t *token = config->token;
|
|
|
|
typedef enum {
|
|
START, ROOT,
|
|
SGW_START, SGW_ROOT,
|
|
PGW_START, PGW_ROOT,
|
|
SKIP, STOP
|
|
} parse_state;
|
|
parse_state state = START;
|
|
parse_state stack = STOP;
|
|
|
|
size_t root_tokens = 0;
|
|
size_t sgw_tokens = 0;
|
|
size_t pgw_tokens = 0;
|
|
size_t skip_tokens = 0;
|
|
int i, j, m, n;
|
|
int arr, size;
|
|
|
|
rv = pgw_context_prepare();
|
|
if (rv != CORE_OK) return rv;
|
|
|
|
for (i = 0, j = 1; j > 0; i++, j--)
|
|
{
|
|
jsmntok_t *t = &token[i];
|
|
|
|
j += t->size;
|
|
|
|
switch (state)
|
|
{
|
|
case START:
|
|
{
|
|
state = ROOT;
|
|
root_tokens = t->size;
|
|
|
|
break;
|
|
}
|
|
case ROOT:
|
|
{
|
|
if (jsmntok_equal(json, t, "SGW") == 0)
|
|
{
|
|
state = SGW_START;
|
|
}
|
|
else if (jsmntok_equal(json, t, "PGW") == 0)
|
|
{
|
|
state = PGW_START;
|
|
}
|
|
else
|
|
{
|
|
state = SKIP;
|
|
stack = ROOT;
|
|
skip_tokens = t->size;
|
|
|
|
root_tokens--;
|
|
if (root_tokens == 0) state = STOP;
|
|
}
|
|
break;
|
|
}
|
|
case SGW_START:
|
|
{
|
|
state = SGW_ROOT;
|
|
sgw_tokens = t->size;
|
|
|
|
break;
|
|
}
|
|
case SGW_ROOT:
|
|
{
|
|
if (jsmntok_equal(json, t, "NETWORK") == 0)
|
|
{
|
|
m = 1;
|
|
size = 1;
|
|
|
|
if ((t+1)->type == JSMN_ARRAY)
|
|
{
|
|
m = 2;
|
|
}
|
|
|
|
for (arr = 0; arr < size; arr++)
|
|
{
|
|
for (n = 1; n > 0; m++, n--)
|
|
{
|
|
n += (t+m)->size;
|
|
|
|
if (jsmntok_equal(json, t+m, "S5C_ADDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5c_node.addr = inet_addr(v);
|
|
}
|
|
else if (jsmntok_equal(json, t+m, "S5C_PORT") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5c_node.port = atoi(v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
state = SKIP;
|
|
stack = SGW_ROOT;
|
|
skip_tokens = t->size;
|
|
|
|
sgw_tokens--;
|
|
if (sgw_tokens == 0) stack = ROOT;
|
|
break;
|
|
}
|
|
case PGW_START:
|
|
{
|
|
state = PGW_ROOT;
|
|
pgw_tokens = t->size;
|
|
|
|
break;
|
|
}
|
|
case PGW_ROOT:
|
|
{
|
|
if (jsmntok_equal(json, t, "FD_CONF_PATH") == 0)
|
|
{
|
|
self.fd_conf_path = jsmntok_to_string(json, t+1);
|
|
}
|
|
else if (jsmntok_equal(json, t, "NETWORK") == 0)
|
|
{
|
|
m = 1;
|
|
size = 1;
|
|
|
|
if ((t+1)->type == JSMN_ARRAY)
|
|
{
|
|
m = 2;
|
|
}
|
|
|
|
for (arr = 0; arr < size; arr++)
|
|
{
|
|
for (n = 1; n > 0; m++, n--)
|
|
{
|
|
n += (t+m)->size;
|
|
|
|
if (jsmntok_equal(json, t+m, "S5C_ADDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5c_addr = inet_addr(v);
|
|
}
|
|
else if (jsmntok_equal(json, t+m, "S5C_PORT") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5c_port = atoi(v);
|
|
}
|
|
else if (jsmntok_equal(json, t+m, "S5U_ADDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5u_addr = inet_addr(v);
|
|
}
|
|
else if (jsmntok_equal(json, t+m, "S5U_PORT") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.s5u_port = atoi(v);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (jsmntok_equal(json, t, "TUNNEL") == 0)
|
|
{
|
|
m = 1;
|
|
size = 1;
|
|
|
|
if ((t+1)->type == JSMN_ARRAY)
|
|
{
|
|
m = 2;
|
|
}
|
|
|
|
for (arr = 0; arr < size; arr++)
|
|
{
|
|
for (n = 1; n > 0; m++, n--)
|
|
{
|
|
n += (t+m)->size;
|
|
|
|
if (jsmntok_equal(json, t+m, "DEV_NAME") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
self.tun_dev_name = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (jsmntok_equal(json, t, "IP_POOL") == 0)
|
|
{
|
|
m = 1;
|
|
size = 1;
|
|
|
|
if ((t+1)->type == JSMN_ARRAY)
|
|
{
|
|
m = 2;
|
|
size = (t+1)->size;
|
|
}
|
|
|
|
for (arr = 0; arr < size; arr++)
|
|
{
|
|
for (n = 1; n > 0; m++, n--)
|
|
{
|
|
n += (t+m)->size;
|
|
|
|
if (jsmntok_equal(json, t+m, "CIDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v)
|
|
{
|
|
char *prefix = strsep(&v, "/");
|
|
if (prefix)
|
|
{
|
|
self.ip_pool[self.num_of_ip_pool].prefix
|
|
= inet_addr(prefix);
|
|
self.ip_pool[self.num_of_ip_pool].mask
|
|
= atoi(v);
|
|
}
|
|
}
|
|
|
|
self.num_of_ip_pool++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (jsmntok_equal(json, t, "DNS") == 0)
|
|
{
|
|
for (m = 1, n = 1; n > 0; m++, n--)
|
|
{
|
|
n += (t+m)->size;
|
|
if (jsmntok_equal(json, t+m, "PRIMARY_ADDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.primary_dns_addr = inet_addr(v);
|
|
}
|
|
else if (jsmntok_equal(
|
|
json, t+m, "SECONDARY_ADDR") == 0)
|
|
{
|
|
char *v = jsmntok_to_string(json, t+m+1);
|
|
if (v) self.secondary_dns_addr = inet_addr(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
state = SKIP;
|
|
stack = PGW_ROOT;
|
|
skip_tokens = t->size;
|
|
|
|
pgw_tokens--;
|
|
if (pgw_tokens == 0) stack = ROOT;
|
|
break;
|
|
}
|
|
case SKIP:
|
|
{
|
|
skip_tokens += t->size;
|
|
|
|
skip_tokens--;
|
|
if (skip_tokens == 0) state = stack;
|
|
break;
|
|
}
|
|
case STOP:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
d_error("Failed to parse configuration in the state(%u)",
|
|
state);
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
rv = pgw_context_validation();
|
|
if (rv != CORE_OK) return rv;
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
status_t pgw_context_setup_trace_module()
|
|
{
|
|
int fd = context_self()->trace_level.fd;
|
|
int gtp = context_self()->trace_level.gtp;
|
|
int others = context_self()->trace_level.others;
|
|
|
|
if (fd)
|
|
{
|
|
if (fd <= 1) fd_g_debug_lvl = FD_LOG_ERROR;
|
|
else if (fd <= 3) fd_g_debug_lvl = FD_LOG_NOTICE;
|
|
else if (fd <= 5) fd_g_debug_lvl = FD_LOG_DEBUG;
|
|
else fd_g_debug_lvl = FD_LOG_ANNOYING;
|
|
|
|
extern int _pgw_fd_path;
|
|
d_trace_level(&_pgw_fd_path, fd);
|
|
extern int _fd_init;
|
|
d_trace_level(&_fd_init, fd);
|
|
extern int _fd_logger;
|
|
d_trace_level(&_fd_logger, fd);
|
|
}
|
|
|
|
if (gtp)
|
|
{
|
|
extern int _pgw_sm;
|
|
d_trace_level(&_pgw_sm, gtp);
|
|
extern int _pgw_s5c_handler;
|
|
d_trace_level(&_pgw_s5c_handler, gtp);
|
|
extern int _gtp_path;
|
|
d_trace_level(&_gtp_path, gtp);
|
|
extern int _pgw_gtp_path;
|
|
d_trace_level(&_pgw_gtp_path, gtp);
|
|
extern int _tlv_msg;
|
|
d_trace_level(&_tlv_msg, gtp);
|
|
extern int _gtp_xact;
|
|
d_trace_level(&_gtp_xact, gtp);
|
|
}
|
|
|
|
if (others)
|
|
{
|
|
extern int _mutex;
|
|
d_trace_level(&_mutex, others);
|
|
extern int _pkbuf;
|
|
d_trace_level(&_pkbuf, others);
|
|
|
|
extern int _context;
|
|
d_trace_level(&_context, others);
|
|
extern int _pgw_context;
|
|
d_trace_level(&_pgw_context, others);
|
|
}
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
static void *sess_hash_keygen(c_uint8_t *out, int *out_len,
|
|
c_uint8_t *imsi, int imsi_len, c_int8_t *apn)
|
|
{
|
|
memcpy(out, imsi, imsi_len);
|
|
core_cpystrn((char*)(out+imsi_len), apn, MAX_APN_LEN+1);
|
|
*out_len = imsi_len+strlen((char*)(out+imsi_len));
|
|
|
|
return out;
|
|
}
|
|
|
|
pgw_sess_t *pgw_sess_add(
|
|
c_uint8_t *imsi, int imsi_len, c_int8_t *apn, c_uint8_t id)
|
|
{
|
|
pgw_sess_t *sess = NULL;
|
|
pgw_bearer_t *bearer = NULL;
|
|
|
|
index_alloc(&pgw_sess_pool, &sess);
|
|
d_assert(sess, return NULL, "Null param");
|
|
|
|
sess->pgw_s5c_teid = sess->index; /* derived from an index */
|
|
sess->pgw_s5c_addr = pgw_self()->s5c_addr;
|
|
|
|
/* Set IMSI */
|
|
sess->imsi_len = imsi_len;
|
|
memcpy(sess->imsi, imsi, sess->imsi_len);
|
|
core_buffer_to_bcd(sess->imsi, sess->imsi_len, sess->imsi_bcd);
|
|
|
|
/* Set APN */
|
|
core_cpystrn(sess->pdn.apn, apn, MAX_APN_LEN+1);
|
|
|
|
list_init(&sess->bearer_list);
|
|
|
|
core_cpystrn(sess->pdn.apn, apn, MAX_APN_LEN+1);
|
|
|
|
bearer = pgw_bearer_add(sess, id);
|
|
d_assert(bearer, pgw_sess_remove(sess); return NULL,
|
|
"Can't add default bearer context");
|
|
|
|
sess->ip_pool = pgw_ip_pool_alloc();
|
|
d_assert(sess->ip_pool, pgw_sess_remove(sess); return NULL,
|
|
"Can't add default bearer context");
|
|
|
|
/* Generate Hash Key : IMSI + APN */
|
|
sess_hash_keygen(sess->hash_keybuf, &sess->hash_keylen,
|
|
imsi, imsi_len, apn);
|
|
hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, sess);
|
|
|
|
return sess;
|
|
}
|
|
|
|
status_t pgw_sess_remove(pgw_sess_t *sess)
|
|
{
|
|
d_assert(self.sess_hash, return CORE_ERROR, "Null param");
|
|
d_assert(sess, return CORE_ERROR, "Null param");
|
|
|
|
hash_set(self.sess_hash, sess->hash_keybuf, sess->hash_keylen, NULL);
|
|
|
|
pgw_ip_pool_free(sess->ip_pool);
|
|
|
|
pgw_bearer_remove_all(sess);
|
|
|
|
index_free(&pgw_sess_pool, sess);
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
status_t pgw_sess_remove_all()
|
|
{
|
|
hash_index_t *hi = NULL;
|
|
pgw_sess_t *sess = NULL;
|
|
|
|
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
|
{
|
|
sess = pgw_sess_this(hi);
|
|
pgw_sess_remove(sess);
|
|
}
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
pgw_sess_t* pgw_sess_find(index_t index)
|
|
{
|
|
d_assert(index, return NULL, "Invalid Index");
|
|
return index_find(&pgw_sess_pool, index);
|
|
}
|
|
|
|
pgw_sess_t* pgw_sess_find_by_teid(c_uint32_t teid)
|
|
{
|
|
return pgw_sess_find(teid);
|
|
}
|
|
|
|
pgw_sess_t* pgw_sess_find_by_imsi_apn(
|
|
c_uint8_t *imsi, int imsi_len, c_int8_t *apn)
|
|
{
|
|
c_uint8_t keybuf[MAX_IMSI_LEN+MAX_APN_LEN+1];
|
|
int keylen = 0;
|
|
|
|
d_assert(self.sess_hash, return NULL, "Null param");
|
|
|
|
sess_hash_keygen(keybuf, &keylen, imsi, imsi_len, apn);
|
|
return (pgw_sess_t *)hash_get(self.sess_hash, keybuf, keylen);
|
|
}
|
|
|
|
pgw_sess_t *pgw_sess_find_or_add_by_message(gtp_message_t *gtp_message)
|
|
{
|
|
pgw_sess_t *sess = NULL;
|
|
|
|
gtp_create_session_request_t *req = >p_message->create_session_request;
|
|
c_int8_t apn[MAX_APN_LEN];
|
|
|
|
if (req->sender_f_teid_for_control_plane.presence == 0)
|
|
{
|
|
d_error("No IMSI");
|
|
return NULL;
|
|
}
|
|
|
|
if (req->access_point_name.presence == 0)
|
|
{
|
|
d_error("No APN");
|
|
return NULL;
|
|
}
|
|
|
|
apn_parse(apn, req->access_point_name.data, req->access_point_name.len);
|
|
sess = pgw_sess_find_by_imsi_apn(req->imsi.data, req->imsi.len, apn);
|
|
if (!sess)
|
|
{
|
|
sess = pgw_sess_add(req->imsi.data, req->imsi.len, apn,
|
|
req->bearer_contexts_to_be_created.eps_bearer_id.u8);
|
|
d_assert(sess, return NULL, "No Session Context");
|
|
}
|
|
|
|
return sess;
|
|
}
|
|
|
|
hash_index_t* pgw_sess_first()
|
|
{
|
|
d_assert(self.sess_hash, return NULL, "Null param");
|
|
return hash_first(self.sess_hash);
|
|
}
|
|
|
|
hash_index_t* pgw_sess_next(hash_index_t *hi)
|
|
{
|
|
return hash_next(hi);
|
|
}
|
|
|
|
pgw_sess_t *pgw_sess_this(hash_index_t *hi)
|
|
{
|
|
d_assert(hi, return NULL, "Null param");
|
|
return hash_this_val(hi);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_add(pgw_sess_t *sess, c_uint8_t id)
|
|
{
|
|
pgw_bearer_t *bearer = NULL;
|
|
|
|
d_assert(sess, return NULL, "Null param");
|
|
|
|
index_alloc(&pgw_bearer_pool, &bearer);
|
|
d_assert(bearer, return NULL, "Bearer context allocation failed");
|
|
|
|
bearer->id = id;
|
|
bearer->pgw_s5u_teid = bearer->index;
|
|
bearer->pgw_s5u_addr = pgw_self()->s5u_addr;
|
|
|
|
bearer->sess = sess;
|
|
list_append(&sess->bearer_list, bearer);
|
|
|
|
return bearer;
|
|
}
|
|
|
|
status_t pgw_bearer_remove(pgw_bearer_t *bearer)
|
|
{
|
|
d_assert(bearer, return CORE_ERROR, "Null param");
|
|
d_assert(bearer->sess, return CORE_ERROR, "Null param");
|
|
|
|
list_remove(&bearer->sess->bearer_list, bearer);
|
|
index_free(&pgw_bearer_pool, bearer);
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
status_t pgw_bearer_remove_all(pgw_sess_t *sess)
|
|
{
|
|
pgw_bearer_t *bearer = NULL, *next_bearer = NULL;
|
|
|
|
d_assert(sess, return CORE_ERROR, "Null param");
|
|
|
|
bearer = list_first(&sess->bearer_list);
|
|
while (bearer)
|
|
{
|
|
next_bearer = list_next(bearer);
|
|
|
|
pgw_bearer_remove(bearer);
|
|
|
|
bearer = next_bearer;
|
|
}
|
|
|
|
return CORE_OK;
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_find(index_t index)
|
|
{
|
|
d_assert(index, return NULL, "Invalid Index");
|
|
return index_find(&pgw_bearer_pool, index);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_find_by_pgw_s5u_teid(c_uint32_t pgw_s5u_teid)
|
|
{
|
|
return pgw_bearer_find(pgw_s5u_teid);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_find_by_id(pgw_sess_t *sess, c_uint8_t id)
|
|
{
|
|
pgw_bearer_t *bearer = NULL;
|
|
|
|
d_assert(sess, return NULL, "Null param");
|
|
|
|
bearer = list_first(&sess->bearer_list);
|
|
while (bearer)
|
|
{
|
|
if (bearer->id == id)
|
|
break;
|
|
|
|
bearer = list_next(bearer);
|
|
}
|
|
|
|
return bearer;
|
|
}
|
|
|
|
pgw_bearer_t* pgw_default_bearer_in_sess(pgw_sess_t *sess)
|
|
{
|
|
return pgw_bearer_first(sess);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_first(pgw_sess_t *sess)
|
|
{
|
|
d_assert(sess, return NULL, "Null param");
|
|
return list_first(&sess->bearer_list);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_next(pgw_bearer_t *bearer)
|
|
{
|
|
return list_next(bearer);
|
|
}
|
|
|
|
pgw_bearer_t* pgw_bearer_find_by_packet(pkbuf_t *pkt)
|
|
{
|
|
pgw_bearer_t *bearer = NULL;
|
|
hash_index_t *hi = NULL;
|
|
pgw_sess_t *sess = NULL;
|
|
struct ip *iph = NULL;
|
|
char buf1[INET_ADDRSTRLEN];
|
|
char buf2[INET_ADDRSTRLEN];
|
|
|
|
d_assert(pkt, return NULL, "pkt is NULL");
|
|
|
|
iph = (struct ip *)pkt->payload;
|
|
|
|
/* FIXME : Only support IPV4 */
|
|
if (iph->ip_v != 4) /* IPv4 */
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
d_trace(50, "Src(%s)-> Dst(%s), Protocol: %d\n",
|
|
INET_NTOP(&iph->ip_src.s_addr,buf1),
|
|
INET_NTOP(&iph->ip_dst.s_addr,buf2),
|
|
iph->ip_p);
|
|
|
|
/* FIXME: Need API to find the bearer with packet filter */
|
|
/* Iterate session */
|
|
for (hi = pgw_sess_first(); hi; hi = pgw_sess_next(hi))
|
|
{
|
|
sess = pgw_sess_this(hi);
|
|
d_trace(50, "Dst(%s) in Pkt : PAA(%s) in PDN\n",
|
|
INET_NTOP(&iph->ip_dst.s_addr,buf1),
|
|
INET_NTOP(&sess->pdn.paa.ipv4_addr, buf2));
|
|
|
|
if (iph->ip_dst.s_addr == sess->pdn.paa.ipv4_addr)
|
|
{
|
|
/* Found */
|
|
bearer = pgw_default_bearer_in_sess(sess);
|
|
d_assert(bearer, return NULL, "No Bearer");
|
|
|
|
d_trace(50, "Found bearer(id = %d)\n",bearer->id);
|
|
return bearer;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
status_t pgw_ip_pool_generate()
|
|
{
|
|
int i, j, k;
|
|
int pool_index = 0;
|
|
|
|
for (i = 0; i < self.num_of_ip_pool; i++)
|
|
{
|
|
c_uint32_t mask = htonl(0xffffffff << (32 - self.ip_pool[i].mask));
|
|
c_uint32_t prefix = self.ip_pool[i].prefix & mask;
|
|
|
|
/* 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_UE; 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++;
|
|
}
|
|
}
|
|
|
|
return CORE_OK;
|
|
}
|
|
pgw_ip_pool_t* pgw_ip_pool_alloc()
|
|
{
|
|
pgw_ip_pool_t *ip_pool = NULL;
|
|
|
|
pool_alloc_node(&pgw_ip_pool_pool, &ip_pool);
|
|
d_assert(ip_pool, return NULL, "IP Pool context allocation failed");
|
|
|
|
list_append(&self.ip_pool_list, ip_pool);
|
|
|
|
return ip_pool;
|
|
}
|
|
status_t pgw_ip_pool_free(pgw_ip_pool_t *ip_pool)
|
|
{
|
|
list_remove(&self.ip_pool_list, ip_pool);
|
|
pool_free_node(&pgw_ip_pool_pool, ip_pool);
|
|
|
|
return CORE_OK;
|
|
}
|