forked from acouzens/open5gs
update it
This commit is contained in:
parent
8e72d3af1d
commit
582c07d3e1
|
@ -3,10 +3,10 @@
|
|||
noinst_LTLIBRARIES = libhss.la
|
||||
|
||||
libhss_la_SOURCES = \
|
||||
milenage.h hss_kdf.h hss_context.h hss_db.h
|
||||
milenage.h hss_kdf.h hss_context.h hss_s6a_handler.h
|
||||
|
||||
nodist_libhss_la_SOURCES = \
|
||||
milenage.c hss_kdf.c hss_init.c hss_context.c hss_db.c
|
||||
milenage.c hss_kdf.c hss_init.c hss_context.c hss_s6a_handler.c
|
||||
|
||||
libhss_la_DEPENDENCIES = \
|
||||
$(top_srcdir)/lib/core/src/libcore.la \
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
#define TRACE_MODULE _hss_context
|
||||
|
||||
#include <mongoc.h>
|
||||
|
||||
#include "core_debug.h"
|
||||
#include "core_pool.h"
|
||||
#include "core_lib.h"
|
||||
|
||||
#include "hss_db.h"
|
||||
#include "context.h"
|
||||
#include "hss_context.h"
|
||||
|
||||
#define HSS_MAX_NUM_OF_PROFILE 8
|
||||
|
||||
static hss_context_t self;
|
||||
|
||||
pool_declare(hss_profile_pool, hss_profile_t, HSS_MAX_NUM_OF_PROFILE);
|
||||
pool_declare(hss_pdn_pool, pdn_t, MAX_NUM_OF_PDN);
|
||||
pool_declare(hss_ue_pool, hss_ue_t, MAX_NUM_OF_UE);
|
||||
static int context_initialized = 0;
|
||||
|
||||
hss_context_t* hss_self()
|
||||
{
|
||||
|
@ -22,363 +18,412 @@ hss_context_t* hss_self()
|
|||
|
||||
status_t hss_context_init(void)
|
||||
{
|
||||
char buf[HSS_KEY_LEN];
|
||||
|
||||
hss_profile_id_t profile_id = 1;
|
||||
hss_profile_t *profile;
|
||||
pdn_t *pdn;
|
||||
hss_ue_t *ue;
|
||||
c_int8_t apn[MAX_APN_LEN];
|
||||
d_assert(context_initialized == 0, return CORE_ERROR,
|
||||
"HSS context already has been context_initialized");
|
||||
|
||||
/* Initialize HSS context */
|
||||
memset(&self, 0, sizeof(hss_context_t));
|
||||
|
||||
pool_init(&hss_profile_pool, HSS_MAX_NUM_OF_PROFILE);
|
||||
pool_init(&hss_pdn_pool, MAX_NUM_OF_PDN);
|
||||
pool_init(&hss_ue_pool, MAX_NUM_OF_UE);
|
||||
|
||||
list_init(&self.profile_list);
|
||||
list_init(&self.pdn_list);
|
||||
list_init(&self.ue_list);
|
||||
|
||||
/***********************************************
|
||||
* Profile DB */
|
||||
profile = hss_profile_add(profile_id);
|
||||
d_assert(profile, return -1, "Profile context add failed");
|
||||
|
||||
#define OP "5F1D289C5D354D0A140C2548F5F3E3BA"
|
||||
#define AMF "8000"
|
||||
#define OPc "E8ED289DEBA952E4283B54E88E6183CA"
|
||||
#define K "465B5CE8B199B49FAA5F0A2EE238A6BC"
|
||||
memcpy(profile->op, CORE_HEX(OP, strlen(OP), buf), HSS_KEY_LEN);
|
||||
memcpy(profile->amf, CORE_HEX(AMF, strlen(AMF), buf), HSS_AMF_LEN);
|
||||
memcpy(profile->k, CORE_HEX(K, strlen(K), buf), HSS_KEY_LEN);
|
||||
profile->sqn = 64;
|
||||
|
||||
profile->access_restriction_data = 0;
|
||||
profile->subscriber_status = HSS_SUBSCRIBER_STATUS_SERVICE_GRANTED;
|
||||
profile->network_access_mode = HSS_NETWORK_ACCESS_MODE_ONLY_PACKET;
|
||||
profile->max_bandwidth_ul = 102400; /* Kbps */
|
||||
profile->max_bandwidth_dl = 102400; /* Kbps */
|
||||
|
||||
profile->subscribed_rau_tau_timer = 12; /* minutes */
|
||||
|
||||
/***********************************************
|
||||
* PDN DB */
|
||||
apn[0] = 0x08;
|
||||
strcpy(apn+1, "internet");
|
||||
|
||||
pdn = hss_pdn_add(apn);
|
||||
d_assert(pdn, return -1, "PDN context add failed");
|
||||
|
||||
pdn->s6a_type = S6A_PDN_TYPE_IPV4;
|
||||
|
||||
pdn->qci = PDN_QCI_9;
|
||||
pdn->priority_level = 8;
|
||||
|
||||
pdn->pre_emption_capability = PDN_PRE_EMPTION_CAPABILITY_DISABLED;
|
||||
pdn->pre_emption_vulnerability = PDN_PRE_EMPTION_VULNERABILITY_DISABLED;
|
||||
|
||||
pdn->max_bandwidth_ul = 102400; /* Kbps */
|
||||
pdn->max_bandwidth_dl = 102400; /* Kbps */
|
||||
|
||||
/***********************************************
|
||||
* UE DB */
|
||||
#define UE1_IMSI "001010123456800"
|
||||
#define UE2_IMSI "001010123456796"
|
||||
|
||||
#define UE3_IMSI "001010123456819"
|
||||
#define UE3_RAND "20080c3818183b52 2614162c07601d0d"
|
||||
|
||||
#define UE4_IMSI "001010123456826"
|
||||
#define UE4_RAND "2ae4fc021dd4d1c2 e0a277c2317c2e67"
|
||||
|
||||
ue = hss_ue_add(profile_id, UE1_IMSI);
|
||||
d_assert(ue, return -1, "UE context add failed");
|
||||
ue->pdn[0] = pdn;
|
||||
ue->num_of_pdn = 1;
|
||||
|
||||
ue = hss_ue_add(profile_id, UE2_IMSI);
|
||||
d_assert(ue, return -1, "UE context add failed");
|
||||
ue->pdn[0] = pdn;
|
||||
ue->num_of_pdn = 1;
|
||||
|
||||
ue = hss_ue_add(profile_id, UE3_IMSI);
|
||||
d_assert(ue, return -1, "UE context add failed");
|
||||
ue->pdn[0] = pdn;
|
||||
ue->num_of_pdn = 1;
|
||||
memcpy(ue->rand, CORE_HEX(UE3_RAND, strlen(UE3_RAND), buf),
|
||||
RAND_LEN);
|
||||
ue->access_restriction_data = 32;
|
||||
ue->network_access_mode = 2;
|
||||
|
||||
ue = hss_ue_add(profile_id, UE4_IMSI);
|
||||
d_assert(ue, return -1, "UE context add failed");
|
||||
ue->pdn[0] = pdn;
|
||||
ue->num_of_pdn = 1;
|
||||
memcpy(ue->rand, CORE_HEX(UE4_RAND, strlen(UE4_RAND), buf),
|
||||
RAND_LEN);
|
||||
ue->access_restriction_data = 32;
|
||||
ue->network_access_mode = 2;
|
||||
|
||||
hss_db_init();
|
||||
context_initialized = 1;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
void hss_context_final(void)
|
||||
status_t hss_context_final(void)
|
||||
{
|
||||
hss_db_final();
|
||||
d_assert(context_initialized == 1, return CORE_ERROR,
|
||||
"HSS context already has been finalized");
|
||||
|
||||
hss_ue_remove_all();
|
||||
hss_pdn_remove_all();
|
||||
hss_profile_remove_all();
|
||||
context_initialized = 0;
|
||||
|
||||
pool_final(&hss_ue_pool);
|
||||
pool_final(&hss_pdn_pool);
|
||||
pool_final(&hss_profile_pool);
|
||||
|
||||
return;
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pdn_t* hss_pdn_add(c_int8_t *apn)
|
||||
status_t hss_db_init()
|
||||
{
|
||||
pdn_t *pdn = NULL;
|
||||
|
||||
pool_alloc_node(&hss_pdn_pool, &pdn);
|
||||
d_assert(pdn, return NULL, "HSS-UE context allocation failed");
|
||||
|
||||
memset(pdn, 0, sizeof(pdn_t));
|
||||
|
||||
strcpy(pdn->apn, apn);
|
||||
pdn->id = NEXT_ID(self.pdn_id, 1, 0xffffffff);
|
||||
|
||||
list_append(&self.pdn_list, pdn);
|
||||
|
||||
return pdn;
|
||||
}
|
||||
|
||||
status_t hss_pdn_remove(pdn_t *pdn)
|
||||
{
|
||||
d_assert(pdn, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&self.pdn_list, pdn);
|
||||
pool_free_node(&hss_pdn_pool, pdn);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_pdn_remove_all()
|
||||
{
|
||||
pdn_t *pdn = NULL, *next_pdn = NULL;
|
||||
|
||||
pdn = list_first(&self.pdn_list);
|
||||
while (pdn)
|
||||
if (context_self()->db_client && context_self()->db_name)
|
||||
{
|
||||
next_pdn = list_next(pdn);
|
||||
|
||||
hss_pdn_remove(pdn);
|
||||
|
||||
pdn = next_pdn;
|
||||
self.subscriberCollection = mongoc_client_get_collection(
|
||||
context_self()->db_client,
|
||||
context_self()->db_name, "subscribers");
|
||||
d_assert(self.subscriberCollection, return CORE_ERROR,
|
||||
"Couldn't find Subscriber Collection in '%s'",
|
||||
context_self()->db_name)
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
pdn_t* hss_pdn_find_by_apn(c_int8_t *apn)
|
||||
status_t hss_db_final()
|
||||
{
|
||||
pdn_t *pdn = NULL;
|
||||
|
||||
pdn = list_first(&self.pdn_list);
|
||||
while (pdn)
|
||||
if (self.subscriberCollection)
|
||||
{
|
||||
if (strcmp(pdn->apn, apn) == 0)
|
||||
break;
|
||||
|
||||
pdn = list_next(pdn);
|
||||
}
|
||||
|
||||
return pdn;
|
||||
}
|
||||
|
||||
pdn_t* hss_pdn_first()
|
||||
{
|
||||
return list_first(&self.pdn_list);
|
||||
}
|
||||
|
||||
pdn_t* hss_pdn_next(pdn_t *pdn)
|
||||
{
|
||||
return list_next(pdn);
|
||||
}
|
||||
|
||||
hss_profile_t* hss_profile_add(hss_profile_id_t id)
|
||||
{
|
||||
hss_profile_t *profile = NULL;
|
||||
|
||||
pool_alloc_node(&hss_profile_pool, &profile);
|
||||
d_assert(profile, return NULL, "HSS-UE context allocation failed");
|
||||
|
||||
memset(profile, 0, sizeof(hss_profile_t));
|
||||
|
||||
profile->id = id;
|
||||
|
||||
list_append(&self.profile_list, profile);
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
status_t hss_profile_remove(hss_profile_t *profile)
|
||||
{
|
||||
d_assert(profile, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&self.profile_list, profile);
|
||||
pool_free_node(&hss_profile_pool, profile);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_profile_remove_all()
|
||||
{
|
||||
hss_profile_t *profile = NULL, *next_profile = NULL;
|
||||
|
||||
profile = list_first(&self.profile_list);
|
||||
while (profile)
|
||||
{
|
||||
next_profile = list_next(profile);
|
||||
|
||||
hss_profile_remove(profile);
|
||||
|
||||
profile = next_profile;
|
||||
mongoc_collection_destroy(self.subscriberCollection);
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
hss_profile_t* hss_profile_find_by_id(hss_profile_id_t id)
|
||||
status_t hss_db_auth_info(
|
||||
char *imsi_bcd, hss_db_auth_info_t *auth_info)
|
||||
{
|
||||
hss_profile_t *profile = NULL;
|
||||
|
||||
profile = list_first(&self.profile_list);
|
||||
while (profile)
|
||||
{
|
||||
if (profile->id == id)
|
||||
break;
|
||||
mongoc_cursor_t *cursor;
|
||||
bson_t *query;
|
||||
bson_error_t error;
|
||||
const bson_t *document;
|
||||
bson_iter_t iter;
|
||||
bson_iter_t inner_iter;
|
||||
char buf[HSS_KEY_LEN];
|
||||
char *utf8 = NULL;
|
||||
c_uint32_t length = 0;
|
||||
|
||||
profile = list_next(profile);
|
||||
d_assert(imsi_bcd, return CORE_ERROR, "Null param");
|
||||
d_assert(auth_info, return CORE_ERROR, "Null param");
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
cursor = mongoc_collection_find_with_opts(
|
||||
self.subscriberCollection, query, NULL, NULL);
|
||||
|
||||
mongoc_cursor_next(cursor, &document);
|
||||
if (mongoc_cursor_error(cursor, &error))
|
||||
{
|
||||
d_error("Cursor Failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
hss_profile_t* hss_profile_find_by_name(c_int8_t *name)
|
||||
{
|
||||
hss_profile_t *profile = NULL;
|
||||
|
||||
profile = list_first(&self.profile_list);
|
||||
while (profile)
|
||||
if (!bson_iter_init_find(&iter, document, "security"))
|
||||
{
|
||||
if (strcmp(profile->name, name) == 0)
|
||||
break;
|
||||
d_error("No 'security' field in this document");
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
return CORE_ERROR;
|
||||
|
||||
profile = list_next(profile);
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
memset(auth_info, 0, sizeof(hss_db_auth_info_t));
|
||||
bson_iter_recurse(&iter, &inner_iter);
|
||||
while(bson_iter_next(&inner_iter))
|
||||
{
|
||||
const char *key = bson_iter_key(&inner_iter);
|
||||
|
||||
hss_profile_t* hss_profile_first()
|
||||
{
|
||||
return list_first(&self.profile_list);
|
||||
}
|
||||
if (!strcmp(key, "k") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->k, CORE_HEX(utf8, length, buf), HSS_KEY_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "op") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->op, CORE_HEX(utf8, length, buf), HSS_KEY_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "amf") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->amf, CORE_HEX(utf8, length, buf), HSS_AMF_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "rand") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->rand, CORE_HEX(utf8, length, buf), RAND_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "sqn") && BSON_ITER_HOLDS_INT64(&inner_iter))
|
||||
{
|
||||
auth_info->sqn = bson_iter_int64(&inner_iter);
|
||||
}
|
||||
}
|
||||
|
||||
hss_profile_t* hss_profile_next(hss_profile_t *profile)
|
||||
{
|
||||
return list_next(profile);
|
||||
}
|
||||
|
||||
hss_ue_t* hss_ue_add(hss_profile_id_t id, c_int8_t *imsi_bcd)
|
||||
{
|
||||
hss_profile_t *profile = NULL;
|
||||
hss_ue_t *ue = NULL;
|
||||
|
||||
profile = hss_profile_find_by_id(id);
|
||||
d_assert(profile, return NULL, "Can't find Profile = %d", id);
|
||||
|
||||
pool_alloc_node(&hss_ue_pool, &ue);
|
||||
d_assert(ue, return NULL, "HSS-UE context allocation failed");
|
||||
|
||||
memset(ue, 0, sizeof(hss_ue_t));
|
||||
|
||||
memcpy(ue->k, profile->k, HSS_KEY_LEN);
|
||||
memcpy(ue->op, profile->op, HSS_KEY_LEN);
|
||||
memcpy(ue->amf, profile->amf, HSS_AMF_LEN);
|
||||
|
||||
strcpy(ue->imsi_bcd, imsi_bcd);
|
||||
|
||||
core_generate_random_bytes(ue->rand, RAND_LEN);
|
||||
ue->sqn = profile->sqn;
|
||||
|
||||
ue->access_restriction_data = profile->access_restriction_data;
|
||||
ue->subscriber_status = profile->subscriber_status;
|
||||
ue->network_access_mode = profile->network_access_mode;
|
||||
ue->max_bandwidth_ul = profile->max_bandwidth_ul;
|
||||
ue->max_bandwidth_dl = profile->max_bandwidth_dl;
|
||||
|
||||
ue->subscribed_rau_tau_timer = profile->subscribed_rau_tau_timer;
|
||||
|
||||
list_append(&self.ue_list, ue);
|
||||
|
||||
return ue;
|
||||
}
|
||||
|
||||
status_t hss_ue_remove(hss_ue_t *ue)
|
||||
{
|
||||
d_assert(ue, return CORE_ERROR, "Null param");
|
||||
|
||||
list_remove(&self.ue_list, ue);
|
||||
pool_free_node(&hss_ue_pool, ue);
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_ue_remove_all()
|
||||
status_t hss_db_update_rand_and_sqn(
|
||||
char *imsi_bcd, c_uint8_t *rand, c_uint64_t sqn)
|
||||
{
|
||||
hss_ue_t *ue = NULL, *next_ue = NULL;
|
||||
|
||||
ue = list_first(&self.ue_list);
|
||||
while (ue)
|
||||
bson_t *query;
|
||||
bson_t *update;
|
||||
bson_error_t error;
|
||||
char printable_rand[128];
|
||||
|
||||
d_assert(rand, return CORE_ERROR, "Null param");
|
||||
core_hex_to_ascii(rand, RAND_LEN, printable_rand, sizeof(printable_rand));
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
update = BCON_NEW("$set",
|
||||
"{",
|
||||
"security.rand", printable_rand,
|
||||
"security.sqn", BCON_INT64(sqn),
|
||||
"}");
|
||||
|
||||
if (!mongoc_collection_update(self.subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
next_ue = list_next(ue);
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
hss_ue_remove(ue);
|
||||
|
||||
ue = next_ue;
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
hss_ue_t* hss_ue_find_by_imsi_bcd(c_int8_t *imsi_bcd)
|
||||
status_t hss_db_increment_sqn(char *imsi_bcd)
|
||||
{
|
||||
hss_ue_t *ue = NULL;
|
||||
|
||||
ue = list_first(&self.ue_list);
|
||||
while (ue)
|
||||
{
|
||||
if (strcmp(ue->imsi_bcd, imsi_bcd) == 0)
|
||||
break;
|
||||
bson_t *query;
|
||||
bson_t *update;
|
||||
bson_error_t error;
|
||||
char printable_rand[128];
|
||||
c_uint64_t max_sqn = 0x7ffffffffff;
|
||||
|
||||
ue = list_next(ue);
|
||||
d_assert(rand, return CORE_ERROR, "Null param");
|
||||
core_hex_to_ascii(rand, RAND_LEN, printable_rand, sizeof(printable_rand));
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
|
||||
update = BCON_NEW("$inc",
|
||||
"{",
|
||||
"security.sqn", BCON_INT64(32),
|
||||
"}");
|
||||
if (!mongoc_collection_update(self.subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
bson_destroy(update);
|
||||
|
||||
update = BCON_NEW("$bit",
|
||||
"{",
|
||||
"security.sqn",
|
||||
"{", "and", BCON_INT64(max_sqn), "}",
|
||||
"}");
|
||||
if (!mongoc_collection_update(self.subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
bson_destroy(update);
|
||||
|
||||
bson_destroy(query);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_subscription_data(
|
||||
char *imsi_bcd, hss_db_subscription_data_t *subscription_data)
|
||||
{
|
||||
mongoc_cursor_t *cursor;
|
||||
bson_t *query;
|
||||
bson_error_t error;
|
||||
const bson_t *document;
|
||||
bson_iter_t iter;
|
||||
bson_iter_t child1_iter, child2_iter, child3_iter, child4_iter;
|
||||
const char *utf8 = NULL;
|
||||
c_uint32_t length = 0;
|
||||
|
||||
d_assert(imsi_bcd, return CORE_ERROR, "Null param");
|
||||
d_assert(subscription_data, return CORE_ERROR, "Null param");
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
cursor = mongoc_collection_find_with_opts(
|
||||
self.subscriberCollection, query, NULL, NULL);
|
||||
|
||||
mongoc_cursor_next(cursor, &document);
|
||||
if (mongoc_cursor_error(cursor, &error))
|
||||
{
|
||||
d_error("Cursor Failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
return ue;
|
||||
}
|
||||
if (!bson_iter_init(&iter, document))
|
||||
{
|
||||
d_error("bson_iter_init failed in this document");
|
||||
|
||||
hss_ue_t* hss_ue_first()
|
||||
{
|
||||
return list_first(&self.ue_list);
|
||||
}
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
return CORE_ERROR;
|
||||
|
||||
hss_ue_t* hss_ue_next(hss_ue_t *ue)
|
||||
{
|
||||
return list_next(ue);
|
||||
}
|
||||
|
||||
memset(subscription_data, 0, sizeof(hss_db_subscription_data_t));
|
||||
while(bson_iter_next(&iter))
|
||||
{
|
||||
const char *key = bson_iter_key(&iter);
|
||||
if (!strcmp(key, "access_restriction_data") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->access_restriction_data =
|
||||
bson_iter_int32(&iter);
|
||||
|
||||
}
|
||||
else if (!strcmp(key, "subscriber_status") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->subscriber_status =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "network_access_mode") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->network_access_mode =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "subscribed_rau_tau_timer") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->subscribed_rau_tau_timer =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "ue_ambr") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&iter))
|
||||
{
|
||||
bson_iter_recurse(&iter, &child1_iter);
|
||||
while(bson_iter_next(&child1_iter))
|
||||
{
|
||||
const char *child1_key = bson_iter_key(&child1_iter);
|
||||
if (!strcmp(child1_key, "max_bandwidth_ul") &&
|
||||
BSON_ITER_HOLDS_INT32(&child1_iter))
|
||||
{
|
||||
subscription_data->max_bandwidth_ul =
|
||||
bson_iter_int32(&child1_iter);
|
||||
}
|
||||
else if (!strcmp(child1_key, "max_bandwidth_dl") &&
|
||||
BSON_ITER_HOLDS_INT32(&child1_iter))
|
||||
{
|
||||
subscription_data->max_bandwidth_dl =
|
||||
bson_iter_int32(&child1_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(key, "pdn") &&
|
||||
BSON_ITER_HOLDS_ARRAY(&iter))
|
||||
{
|
||||
int pdn_index = 0;
|
||||
|
||||
bson_iter_recurse(&iter, &child1_iter);
|
||||
while(bson_iter_next(&child1_iter))
|
||||
{
|
||||
const char *child1_key = bson_iter_key(&child1_iter);
|
||||
pdn_t *pdn = NULL;
|
||||
|
||||
d_assert(child1_key, return CORE_ERROR, "PDN is not ARRAY");
|
||||
pdn_index = atoi(child1_key);
|
||||
d_assert(pdn_index < MAX_NUM_OF_PDN,
|
||||
return CORE_ERROR, "Overflow of PDN number(%d>%d)",
|
||||
pdn_index, MAX_NUM_OF_PDN);
|
||||
|
||||
pdn = &subscription_data->pdn[pdn_index];
|
||||
|
||||
bson_iter_recurse(&child1_iter, &child2_iter);
|
||||
while(bson_iter_next(&child2_iter))
|
||||
{
|
||||
const char *child2_key = bson_iter_key(&child2_iter);
|
||||
if (!strcmp(child2_key, "apn") &&
|
||||
BSON_ITER_HOLDS_UTF8(&child2_iter))
|
||||
{
|
||||
utf8 = bson_iter_utf8(&child2_iter, &length);
|
||||
core_cpystrn(pdn->apn+1, utf8, length+1);
|
||||
pdn->apn[0] = length;
|
||||
}
|
||||
else if (!strcmp(child2_key, "type") &&
|
||||
BSON_ITER_HOLDS_INT32(&child2_iter))
|
||||
{
|
||||
pdn->s6a_type = bson_iter_int32(&child2_iter);
|
||||
}
|
||||
else if (!strcmp(child2_key, "qos") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child2_iter))
|
||||
{
|
||||
bson_iter_recurse(&child2_iter, &child3_iter);
|
||||
while(bson_iter_next(&child3_iter))
|
||||
{
|
||||
const char *child3_key =
|
||||
bson_iter_key(&child3_iter);
|
||||
if (!strcmp(child3_key, "qci") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->qci = bson_iter_int32(&child3_iter);
|
||||
}
|
||||
else if (!strcmp(child3_key, "arp") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child3_iter))
|
||||
{
|
||||
bson_iter_recurse(&child3_iter, &child4_iter);
|
||||
while(bson_iter_next(&child4_iter))
|
||||
{
|
||||
const char *child4_key =
|
||||
bson_iter_key(&child4_iter);
|
||||
if (!strcmp(child4_key, "priority_level") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->priority_level =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
else if (!strcmp(child4_key,
|
||||
"pre_emption_capability") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->pre_emption_capability =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
else if (!strcmp(child4_key,
|
||||
"pre_emption_vulnerability") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->pre_emption_vulnerability =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(child2_key, "pdn_ambr") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child2_iter))
|
||||
{
|
||||
bson_iter_recurse(&child2_iter, &child3_iter);
|
||||
while(bson_iter_next(&child3_iter))
|
||||
{
|
||||
const char *child3_key =
|
||||
bson_iter_key(&child3_iter);
|
||||
if (!strcmp(child3_key, "max_bandwidth_ul") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->max_bandwidth_ul =
|
||||
bson_iter_int32(&child3_iter);
|
||||
}
|
||||
else if (!strcmp(child3_key, "max_bandwidth_dl") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->max_bandwidth_dl =
|
||||
bson_iter_int32(&child3_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
subscription_data->num_of_pdn = pdn_index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#ifndef __HSS_CONTEXT_H__
|
||||
#define __HSS_CONTEXT_H__
|
||||
|
||||
#include "core_list.h"
|
||||
#include "core_errno.h"
|
||||
#include "types.h"
|
||||
|
||||
|
@ -9,42 +8,18 @@
|
|||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define HSS_MAX_PROFILE_NAME_LEN 255
|
||||
|
||||
#define HSS_KEY_LEN 16
|
||||
#define HSS_AMF_LEN 2
|
||||
|
||||
typedef c_uint32_t hss_profile_id_t;
|
||||
typedef struct _hss_profile_t {
|
||||
lnode_t node; /**< A node of list_t */
|
||||
|
||||
hss_profile_id_t id;
|
||||
c_int8_t name[HSS_MAX_PROFILE_NAME_LEN];
|
||||
|
||||
/* Security Context */
|
||||
typedef struct _hss_db_auth_info_t {
|
||||
c_uint8_t k[HSS_KEY_LEN];
|
||||
c_uint8_t op[HSS_KEY_LEN];
|
||||
c_uint8_t amf[HSS_AMF_LEN];
|
||||
c_uint8_t rand[RAND_LEN];
|
||||
c_uint64_t sqn;
|
||||
} hss_db_auth_info_t;
|
||||
|
||||
c_uint32_t access_restriction_data;
|
||||
c_uint32_t subscriber_status;
|
||||
c_uint32_t network_access_mode;
|
||||
|
||||
c_uint32_t max_bandwidth_ul; /* Kbps */
|
||||
c_uint32_t max_bandwidth_dl; /* Kbps */
|
||||
|
||||
c_uint32_t subscribed_rau_tau_timer; /* minutes */
|
||||
} hss_profile_t;
|
||||
|
||||
typedef struct _hss_ue_t {
|
||||
lnode_t node; /**< A node of list_t */
|
||||
|
||||
/* UE Identitiy */
|
||||
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
||||
|
||||
plmn_id_t visited_plmn_id;
|
||||
|
||||
typedef struct _hss_db_subscription_data_t {
|
||||
#define HSS_ACCESS_RESTRICTION_UTRAN_NOT_ALLOWED (1)
|
||||
#define HSS_ACCESS_RESTRICTION_GERAN_NOT_ALLOWED (1<<1)
|
||||
#define HSS_ACCESS_RESTRICTION_GAN_NOT_ALLOWED (1<<2)
|
||||
|
@ -53,11 +28,9 @@ typedef struct _hss_ue_t {
|
|||
#define HSS_ACCESS_RESTRICTION_HO_TO_NON_3GPP_ACCESS_NOT_ALLOWED (1<<5)
|
||||
#define HSS_ACCESS_RESTRICTION_NB_IOT_NOT_ALLOWED (1<<6)
|
||||
c_uint32_t access_restriction_data;
|
||||
|
||||
#define HSS_SUBSCRIBER_STATUS_SERVICE_GRANTED 0
|
||||
#define HSS_SUBSCRIBER_STATUS_OPERATOR_DETERMINED_BARRING 1
|
||||
c_uint32_t subscriber_status;
|
||||
|
||||
#define HSS_NETWORK_ACCESS_MODE_PACKET_AND_CIRCUIT 0
|
||||
#define HSS_NETWORK_ACCESS_MODE_RESERVED 1
|
||||
#define HSS_NETWORK_ACCESS_MODE_ONLY_PACKET 2
|
||||
|
@ -68,53 +41,30 @@ typedef struct _hss_ue_t {
|
|||
|
||||
c_uint32_t subscribed_rau_tau_timer; /* minutes */
|
||||
|
||||
pdn_t *pdn[MAX_NUM_OF_PDN];
|
||||
pdn_t pdn[MAX_NUM_OF_PDN];
|
||||
int num_of_pdn;
|
||||
|
||||
/* Security Context */
|
||||
c_uint8_t k[HSS_KEY_LEN];
|
||||
c_uint64_t sqn;
|
||||
c_uint8_t rand[RAND_LEN];
|
||||
c_uint8_t opc[HSS_KEY_LEN];
|
||||
c_uint8_t op[HSS_KEY_LEN];
|
||||
c_uint8_t amf[HSS_AMF_LEN];
|
||||
|
||||
} hss_ue_t;
|
||||
} hss_db_subscription_data_t;
|
||||
|
||||
typedef struct _hss_context_t {
|
||||
c_uint32_t pdn_id;
|
||||
void *subscriberCollection;
|
||||
|
||||
list_t profile_list;
|
||||
list_t pdn_list;
|
||||
list_t ue_list;
|
||||
} hss_context_t;
|
||||
|
||||
CORE_DECLARE(status_t) hss_context_init(void);
|
||||
CORE_DECLARE(void) hss_context_final(void);
|
||||
CORE_DECLARE(status_t) hss_context_init(void);
|
||||
CORE_DECLARE(status_t) hss_context_final(void);
|
||||
CORE_DECLARE(hss_context_t*) hss_self(void);
|
||||
|
||||
CORE_DECLARE(pdn_t*) hss_pdn_add(c_int8_t *apn);
|
||||
CORE_DECLARE(status_t) hss_pdn_remove(pdn_t *pdn);
|
||||
CORE_DECLARE(status_t) hss_pdn_remove_all(void);
|
||||
CORE_DECLARE(pdn_t*) hss_pdn_find_by_apn(c_int8_t *apn);
|
||||
CORE_DECLARE(pdn_t*) hss_pdn_first(void);
|
||||
CORE_DECLARE(pdn_t*) hss_pdn_next(pdn_t *pdn);
|
||||
CORE_DECLARE(status_t) hss_db_init(void);
|
||||
CORE_DECLARE(status_t) hss_db_final(void);
|
||||
|
||||
CORE_DECLARE(hss_profile_t*) hss_profile_add(hss_profile_id_t id);
|
||||
CORE_DECLARE(status_t) hss_profile_remove(hss_profile_t *profile);
|
||||
CORE_DECLARE(status_t) hss_profile_remove_all(void);
|
||||
CORE_DECLARE(hss_profile_t*) hss_profile_find_by_id(hss_profile_id_t id);
|
||||
CORE_DECLARE(hss_profile_t*) hss_profile_find_by_name(c_int8_t *name);
|
||||
CORE_DECLARE(hss_profile_t*) hss_profile_first(void);
|
||||
CORE_DECLARE(hss_profile_t*) hss_profile_next(hss_profile_t *profile);
|
||||
CORE_DECLARE(status_t) hss_db_auth_info(
|
||||
char *imsi_bcd, hss_db_auth_info_t *auth_info);
|
||||
CORE_DECLARE(status_t) hss_db_update_rand_and_sqn(
|
||||
char *imsi_bcd, c_uint8_t *rand, c_uint64_t sqn);
|
||||
CORE_DECLARE(status_t) hss_db_increment_sqn(char *imsi_bcd);
|
||||
|
||||
CORE_DECLARE(hss_ue_t*) hss_ue_add(
|
||||
hss_profile_id_t id, c_int8_t *imsi_bcd);
|
||||
CORE_DECLARE(status_t) hss_ue_remove(hss_ue_t *ue);
|
||||
CORE_DECLARE(status_t) hss_ue_remove_all(void);
|
||||
CORE_DECLARE(hss_ue_t*) hss_ue_find_by_imsi_bcd(c_int8_t *imsi_bcd);
|
||||
CORE_DECLARE(hss_ue_t*) hss_ue_first(void);
|
||||
CORE_DECLARE(hss_ue_t*) hss_ue_next(hss_ue_t *ue);
|
||||
CORE_DECLARE(status_t) hss_db_subscription_data(
|
||||
char *imsi_bcd, hss_db_subscription_data_t *subscription_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
399
src/hss/hss_db.c
399
src/hss/hss_db.c
|
@ -1,399 +0,0 @@
|
|||
#define TRACE_MODULE _hss_db
|
||||
|
||||
#include <mongoc.h>
|
||||
|
||||
#include "core_lib.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "hss_db.h"
|
||||
|
||||
static mongoc_collection_t *subscriberCollection = NULL;
|
||||
|
||||
status_t hss_db_init()
|
||||
{
|
||||
if (context_self()->db_client && context_self()->db_name)
|
||||
{
|
||||
subscriberCollection = mongoc_client_get_collection(
|
||||
context_self()->db_client,
|
||||
context_self()->db_name, "subscribers");
|
||||
d_assert(subscriberCollection, return CORE_ERROR,
|
||||
"Couldn't find Subscriber Collection in '%s'",
|
||||
context_self()->db_name)
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_final()
|
||||
{
|
||||
if (subscriberCollection)
|
||||
{
|
||||
mongoc_collection_destroy(subscriberCollection);
|
||||
}
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_auth_info(
|
||||
char *imsi_bcd, hss_db_auth_info_t *auth_info)
|
||||
{
|
||||
mongoc_cursor_t *cursor;
|
||||
bson_t *query;
|
||||
bson_error_t error;
|
||||
const bson_t *document;
|
||||
bson_iter_t iter;
|
||||
bson_iter_t inner_iter;
|
||||
char buf[HSS_KEY_LEN];
|
||||
char *utf8 = NULL;
|
||||
c_uint32_t length = 0;
|
||||
|
||||
d_assert(imsi_bcd, return CORE_ERROR, "Null param");
|
||||
d_assert(auth_info, return CORE_ERROR, "Null param");
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
cursor = mongoc_collection_find_with_opts(
|
||||
subscriberCollection, query, NULL, NULL);
|
||||
|
||||
mongoc_cursor_next(cursor, &document);
|
||||
if (mongoc_cursor_error(cursor, &error))
|
||||
{
|
||||
d_error("Cursor Failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
if (!bson_iter_init_find(&iter, document, "security"))
|
||||
{
|
||||
d_error("No 'security' field in this document");
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
return CORE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
memset(auth_info, 0, sizeof(hss_db_auth_info_t));
|
||||
bson_iter_recurse(&iter, &inner_iter);
|
||||
while(bson_iter_next(&inner_iter))
|
||||
{
|
||||
const char *key = bson_iter_key(&inner_iter);
|
||||
|
||||
if (!strcmp(key, "k") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->k, CORE_HEX(utf8, length, buf), HSS_KEY_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "op") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->op, CORE_HEX(utf8, length, buf), HSS_KEY_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "amf") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->amf, CORE_HEX(utf8, length, buf), HSS_AMF_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "rand") && BSON_ITER_HOLDS_UTF8(&inner_iter))
|
||||
{
|
||||
utf8 = (char *)bson_iter_utf8(&inner_iter, &length);
|
||||
memcpy(auth_info->rand, CORE_HEX(utf8, length, buf), RAND_LEN);
|
||||
}
|
||||
else if (!strcmp(key, "sqn") && BSON_ITER_HOLDS_INT64(&inner_iter))
|
||||
{
|
||||
auth_info->sqn = bson_iter_int64(&inner_iter);
|
||||
}
|
||||
}
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_update_rand_and_sqn(
|
||||
char *imsi_bcd, c_uint8_t *rand, c_uint64_t sqn)
|
||||
{
|
||||
bson_t *query;
|
||||
bson_t *update;
|
||||
bson_error_t error;
|
||||
char printable_rand[128];
|
||||
|
||||
d_assert(rand, return CORE_ERROR, "Null param");
|
||||
core_hex_to_ascii(rand, RAND_LEN, printable_rand, sizeof(printable_rand));
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
update = BCON_NEW("$set",
|
||||
"{",
|
||||
"security.rand", printable_rand,
|
||||
"security.sqn", BCON_INT64(sqn),
|
||||
"}");
|
||||
|
||||
if (!mongoc_collection_update(subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_increment_sqn(char *imsi_bcd)
|
||||
{
|
||||
bson_t *query;
|
||||
bson_t *update;
|
||||
bson_error_t error;
|
||||
char printable_rand[128];
|
||||
c_uint64_t max_sqn = 0x7ffffffffff;
|
||||
|
||||
d_assert(rand, return CORE_ERROR, "Null param");
|
||||
core_hex_to_ascii(rand, RAND_LEN, printable_rand, sizeof(printable_rand));
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
|
||||
update = BCON_NEW("$inc",
|
||||
"{",
|
||||
"security.sqn", BCON_INT64(32),
|
||||
"}");
|
||||
if (!mongoc_collection_update(subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
bson_destroy(update);
|
||||
|
||||
update = BCON_NEW("$bit",
|
||||
"{",
|
||||
"security.sqn",
|
||||
"{", "and", BCON_INT64(max_sqn), "}",
|
||||
"}");
|
||||
if (!mongoc_collection_update(subscriberCollection,
|
||||
MONGOC_UPDATE_NONE, query, update, NULL, &error))
|
||||
{
|
||||
d_error("mongoc_collection_update() failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
bson_destroy(update);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
bson_destroy(update);
|
||||
|
||||
bson_destroy(query);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t hss_db_subscription_data(
|
||||
char *imsi_bcd, hss_db_subscription_data_t *subscription_data)
|
||||
{
|
||||
mongoc_cursor_t *cursor;
|
||||
bson_t *query;
|
||||
bson_error_t error;
|
||||
const bson_t *document;
|
||||
bson_iter_t iter;
|
||||
bson_iter_t child1_iter, child2_iter, child3_iter, child4_iter;
|
||||
const char *utf8 = NULL;
|
||||
c_uint32_t length = 0;
|
||||
|
||||
d_assert(imsi_bcd, return CORE_ERROR, "Null param");
|
||||
d_assert(subscription_data, return CORE_ERROR, "Null param");
|
||||
|
||||
query = BCON_NEW("imsi", BCON_UTF8(imsi_bcd));
|
||||
cursor = mongoc_collection_find_with_opts(
|
||||
subscriberCollection, query, NULL, NULL);
|
||||
|
||||
mongoc_cursor_next(cursor, &document);
|
||||
if (mongoc_cursor_error(cursor, &error))
|
||||
{
|
||||
d_error("Cursor Failure: %s", error.message);
|
||||
|
||||
bson_destroy(query);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
if (!bson_iter_init(&iter, document))
|
||||
{
|
||||
d_error("bson_iter_init failed in this document");
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
return CORE_ERROR;
|
||||
|
||||
}
|
||||
|
||||
memset(subscription_data, 0, sizeof(hss_db_subscription_data_t));
|
||||
while(bson_iter_next(&iter))
|
||||
{
|
||||
const char *key = bson_iter_key(&iter);
|
||||
if (!strcmp(key, "access_restriction_data") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->access_restriction_data =
|
||||
bson_iter_int32(&iter);
|
||||
|
||||
}
|
||||
else if (!strcmp(key, "subscriber_status") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->subscriber_status =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "network_access_mode") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->network_access_mode =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "subscribed_rau_tau_timer") &&
|
||||
BSON_ITER_HOLDS_INT32(&iter))
|
||||
{
|
||||
subscription_data->subscribed_rau_tau_timer =
|
||||
bson_iter_int32(&iter);
|
||||
}
|
||||
else if (!strcmp(key, "ue_ambr") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&iter))
|
||||
{
|
||||
bson_iter_recurse(&iter, &child1_iter);
|
||||
while(bson_iter_next(&child1_iter))
|
||||
{
|
||||
const char *child1_key = bson_iter_key(&child1_iter);
|
||||
if (!strcmp(child1_key, "max_bandwidth_ul") &&
|
||||
BSON_ITER_HOLDS_INT32(&child1_iter))
|
||||
{
|
||||
subscription_data->max_bandwidth_ul =
|
||||
bson_iter_int32(&child1_iter);
|
||||
}
|
||||
else if (!strcmp(child1_key, "max_bandwidth_dl") &&
|
||||
BSON_ITER_HOLDS_INT32(&child1_iter))
|
||||
{
|
||||
subscription_data->max_bandwidth_dl =
|
||||
bson_iter_int32(&child1_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(key, "pdn") &&
|
||||
BSON_ITER_HOLDS_ARRAY(&iter))
|
||||
{
|
||||
int pdn_index = 0;
|
||||
|
||||
bson_iter_recurse(&iter, &child1_iter);
|
||||
while(bson_iter_next(&child1_iter))
|
||||
{
|
||||
const char *child1_key = bson_iter_key(&child1_iter);
|
||||
pdn_t *pdn = NULL;
|
||||
|
||||
d_assert(child1_key, return CORE_ERROR, "PDN is not ARRAY");
|
||||
pdn_index = atoi(child1_key);
|
||||
d_assert(pdn_index < MAX_NUM_OF_PDN,
|
||||
return CORE_ERROR, "Overflow of PDN number(%d>%d)",
|
||||
pdn_index, MAX_NUM_OF_PDN);
|
||||
|
||||
pdn = &subscription_data->pdn[pdn_index];
|
||||
|
||||
bson_iter_recurse(&child1_iter, &child2_iter);
|
||||
while(bson_iter_next(&child2_iter))
|
||||
{
|
||||
const char *child2_key = bson_iter_key(&child2_iter);
|
||||
if (!strcmp(child2_key, "apn") &&
|
||||
BSON_ITER_HOLDS_UTF8(&child2_iter))
|
||||
{
|
||||
utf8 = bson_iter_utf8(&child2_iter, &length);
|
||||
core_cpystrn(pdn->apn+1, utf8, length+1);
|
||||
pdn->apn[0] = length;
|
||||
}
|
||||
else if (!strcmp(child2_key, "type") &&
|
||||
BSON_ITER_HOLDS_INT32(&child2_iter))
|
||||
{
|
||||
pdn->s6a_type = bson_iter_int32(&child2_iter);
|
||||
}
|
||||
else if (!strcmp(child2_key, "qos") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child2_iter))
|
||||
{
|
||||
bson_iter_recurse(&child2_iter, &child3_iter);
|
||||
while(bson_iter_next(&child3_iter))
|
||||
{
|
||||
const char *child3_key =
|
||||
bson_iter_key(&child3_iter);
|
||||
if (!strcmp(child3_key, "qci") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->qci = bson_iter_int32(&child3_iter);
|
||||
}
|
||||
else if (!strcmp(child3_key, "arp") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child3_iter))
|
||||
{
|
||||
bson_iter_recurse(&child3_iter, &child4_iter);
|
||||
while(bson_iter_next(&child4_iter))
|
||||
{
|
||||
const char *child4_key =
|
||||
bson_iter_key(&child4_iter);
|
||||
if (!strcmp(child4_key, "priority_level") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->priority_level =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
else if (!strcmp(child4_key,
|
||||
"pre_emption_capability") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->pre_emption_capability =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
else if (!strcmp(child4_key,
|
||||
"pre_emption_vulnerability") &&
|
||||
BSON_ITER_HOLDS_INT32(&child4_iter))
|
||||
{
|
||||
pdn->pre_emption_vulnerability =
|
||||
bson_iter_int32(&child4_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(child2_key, "pdn_ambr") &&
|
||||
BSON_ITER_HOLDS_DOCUMENT(&child2_iter))
|
||||
{
|
||||
bson_iter_recurse(&child2_iter, &child3_iter);
|
||||
while(bson_iter_next(&child3_iter))
|
||||
{
|
||||
const char *child3_key =
|
||||
bson_iter_key(&child3_iter);
|
||||
if (!strcmp(child3_key, "max_bandwidth_ul") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->max_bandwidth_ul =
|
||||
bson_iter_int32(&child3_iter);
|
||||
}
|
||||
else if (!strcmp(child3_key, "max_bandwidth_dl") &&
|
||||
BSON_ITER_HOLDS_INT32(&child3_iter))
|
||||
{
|
||||
pdn->max_bandwidth_dl =
|
||||
bson_iter_int32(&child3_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
subscription_data->num_of_pdn = pdn_index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bson_destroy(query);
|
||||
mongoc_cursor_destroy(cursor);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef __HSS_DB_H__
|
||||
#define __HSS_DB_H__
|
||||
|
||||
#include "core_errno.h"
|
||||
#include "types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define HSS_KEY_LEN 16
|
||||
#define HSS_AMF_LEN 2
|
||||
|
||||
typedef struct _hss_db_auth_info_t {
|
||||
c_uint8_t k[HSS_KEY_LEN];
|
||||
c_uint8_t op[HSS_KEY_LEN];
|
||||
c_uint8_t amf[HSS_AMF_LEN];
|
||||
c_uint8_t rand[RAND_LEN];
|
||||
c_uint64_t sqn;
|
||||
} hss_db_auth_info_t;
|
||||
|
||||
typedef struct _hss_db_subscription_data_t {
|
||||
c_uint32_t access_restriction_data;
|
||||
c_uint32_t subscriber_status;
|
||||
c_uint32_t network_access_mode;
|
||||
|
||||
c_uint32_t max_bandwidth_ul; /* Kbps */
|
||||
c_uint32_t max_bandwidth_dl; /* Kbps */
|
||||
|
||||
c_uint32_t subscribed_rau_tau_timer; /* minutes */
|
||||
|
||||
pdn_t pdn[MAX_NUM_OF_PDN];
|
||||
int num_of_pdn;
|
||||
} hss_db_subscription_data_t;
|
||||
|
||||
CORE_DECLARE(status_t) hss_db_init(void);
|
||||
CORE_DECLARE(status_t) hss_db_final(void);
|
||||
|
||||
CORE_DECLARE(status_t) hss_db_auth_info(
|
||||
char *imsi_bcd, hss_db_auth_info_t *auth_info);
|
||||
CORE_DECLARE(status_t) hss_db_update_rand_and_sqn(
|
||||
char *imsi_bcd, c_uint8_t *rand, c_uint64_t sqn);
|
||||
CORE_DECLARE(status_t) hss_db_increment_sqn(char *imsi_bcd);
|
||||
|
||||
CORE_DECLARE(status_t) hss_db_subscription_data(
|
||||
char *imsi_bcd, hss_db_subscription_data_t *subscription_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __HSS_DB_H__ */
|
|
@ -1,496 +1,13 @@
|
|||
#define TRACE_MODULE _hss_init
|
||||
|
||||
#include "core_debug.h"
|
||||
#include "core_lib.h"
|
||||
#include "core_sha2.h"
|
||||
|
||||
#include "s6a_lib.h"
|
||||
|
||||
#include "hss_context.h"
|
||||
#include "hss_db.h"
|
||||
#include "hss_kdf.h"
|
||||
#include "milenage.h"
|
||||
|
||||
#define HSS_SQN_LEN 6
|
||||
#define HSS_AK_LEN 6
|
||||
|
||||
/* handler for fallback cb */
|
||||
static struct disp_hdl *hdl_fb = NULL;
|
||||
/* handler for Authentication-Information-Request cb */
|
||||
static struct disp_hdl *hdl_air = NULL;
|
||||
/* handler for Update-Location-Request cb */
|
||||
static struct disp_hdl *hdl_ulr = NULL;
|
||||
|
||||
/* Default callback for the application. */
|
||||
static int hss_fb_cb(struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
/* This CB should never be called */
|
||||
d_warn("Unexpected message received!");
|
||||
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
/* Callback for incoming Authentication-Information-Request messages */
|
||||
static int hss_air_cb( struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
struct msg *ans, *qry;
|
||||
struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn;
|
||||
struct avp_hdr *hdr;
|
||||
union avp_value val;
|
||||
|
||||
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
||||
c_uint8_t opc[HSS_KEY_LEN];
|
||||
c_uint8_t sqn[HSS_SQN_LEN];
|
||||
c_uint8_t autn[AUTN_LEN];
|
||||
c_uint8_t ik[HSS_KEY_LEN];
|
||||
c_uint8_t ck[HSS_KEY_LEN];
|
||||
c_uint8_t ak[HSS_AK_LEN];
|
||||
c_uint8_t xres[MAX_RES_LEN];
|
||||
c_uint8_t kasme[SHA256_DIGEST_SIZE];
|
||||
size_t xres_len = 8;
|
||||
|
||||
hss_db_auth_info_t auth_info;
|
||||
c_uint8_t zero[RAND_LEN];
|
||||
status_t rv;
|
||||
|
||||
d_assert(msg, return EINVAL,);
|
||||
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
|
||||
ans = *msg;
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_user_name, &avp) == 0 && avp,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
memcpy(imsi_bcd, (char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
imsi_bcd[hdr->avp_value->os.len] = 0;
|
||||
|
||||
rv = hss_db_auth_info(imsi_bcd, &auth_info);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot get Auth-Info for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(zero, 0, sizeof(zero));
|
||||
if (memcmp(auth_info.rand, zero, RAND_LEN) == 0)
|
||||
{
|
||||
core_generate_random_bytes(auth_info.rand, RAND_LEN);
|
||||
}
|
||||
|
||||
rv = hss_db_update_rand_and_sqn(imsi_bcd, auth_info.rand, auth_info.sqn);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 0
|
||||
rv = hss_db_increment_sqn(imsi_bcd);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_visited_plmn_id, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
if (hdr && hdr->avp_value && hdr->avp_value->os.data)
|
||||
{
|
||||
#if 0 // TODO : check visited_plmn_id
|
||||
memcpy(visited_plmn_id,
|
||||
hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
#endif
|
||||
}
|
||||
|
||||
milenage_opc(auth_info.k, auth_info.op, opc);
|
||||
milenage_generate(opc, auth_info.amf, auth_info.k,
|
||||
core_uint64_to_buffer(auth_info.sqn, HSS_SQN_LEN, sqn), auth_info.rand,
|
||||
autn, ik, ck, ak, xres, &xres_len);
|
||||
hss_kdf_kasme(ck, ik, hdr->avp_value->os.data, sqn, ak, kasme);
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
d_assert(fd_msg_rescode_set(ans, "DIAMETER_SUCCESS", NULL, NULL, 1) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set the Auth-Session-State AVP */
|
||||
d_assert(fd_msg_avp_new(s6a_auth_session_state, 0, &avp) == 0, goto out,);
|
||||
val.i32 = 1;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Set the Authentication-Info */
|
||||
d_assert(fd_msg_avp_new(s6a_authentication_info, 0, &avp) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_e_utran_vector, 0, &avp_e_utran_vector) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_rand, 0, &avp_rand) == 0, goto out,);
|
||||
val.os.data = auth_info.rand;
|
||||
val.os.len = HSS_KEY_LEN;
|
||||
d_assert(fd_msg_avp_setvalue(avp_rand, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_rand) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_xres, 0, &avp_xres) == 0, goto out,);
|
||||
val.os.data = xres;
|
||||
val.os.len = xres_len;
|
||||
d_assert(fd_msg_avp_setvalue(avp_xres, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_xres) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_autn, 0, &avp_autn) == 0, goto out,);
|
||||
val.os.data = autn;
|
||||
val.os.len = AUTN_LEN;
|
||||
d_assert(fd_msg_avp_setvalue(avp_autn, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_autn) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_kasme, 0, &avp_kasme) == 0, goto out,);
|
||||
val.os.data = kasme;
|
||||
val.os.len = SHA256_DIGEST_SIZE;
|
||||
d_assert(fd_msg_avp_setvalue(avp_kasme, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_kasme) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_e_utran_vector) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Send the answer */
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
/* Add this value to the stats */
|
||||
pthread_mutex_lock(&s6a_config->stats_lock);
|
||||
s6a_config->stats.nb_echoed++;
|
||||
pthread_mutex_unlock(&s6a_config->stats_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
fd_msg_rescode_set(ans, "DIAMETER_AUTHENTICATION_REJECTED", NULL, NULL, 1);
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback for incoming Update-Location-Request messages */
|
||||
static int hss_ulr_cb( struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
struct msg *ans, *qry;
|
||||
|
||||
struct avp_hdr *hdr;
|
||||
union avp_value val;
|
||||
|
||||
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
||||
|
||||
status_t rv;
|
||||
hss_db_subscription_data_t subscription_data;
|
||||
|
||||
d_assert(msg, return EINVAL,);
|
||||
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
|
||||
ans = *msg;
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_user_name, &avp) == 0 && avp,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
memcpy(imsi_bcd, (char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
imsi_bcd[hdr->avp_value->os.len] = 0;
|
||||
|
||||
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_visited_plmn_id, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
if (hdr && hdr->avp_value && hdr->avp_value->os.data)
|
||||
{
|
||||
#if 0 // TODO : check visited_plmn_id
|
||||
memcpy(visited_plmn_id,
|
||||
hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
d_assert(fd_msg_rescode_set(ans, "DIAMETER_SUCCESS", NULL, NULL, 1) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set the Auth-Session-Statee AVP */
|
||||
d_assert(fd_msg_avp_new(s6a_auth_session_state, 0, &avp) == 0, goto out,);
|
||||
val.i32 = 1;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Set the ULA Flags */
|
||||
d_assert(fd_msg_avp_new(s6a_ula_flags, 0, &avp) == 0, goto out,);
|
||||
val.i32 = S6A_ULA_MME_REGISTERED_FOR_SMS;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_ulr_flags, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
if (hdr && hdr->avp_value &&
|
||||
!(hdr->avp_value->u32 & S6A_ULR_SKIP_SUBSCRIBER_DATA))
|
||||
{
|
||||
struct avp *avp_msisdn, *avp_access_restriction_data;
|
||||
struct avp *avp_subscriber_status, *avp_network_access_mode;
|
||||
struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl;
|
||||
int i;
|
||||
c_uint8_t msisdn[MAX_IMSI_LEN];
|
||||
int msisdn_len;
|
||||
|
||||
/* Set the Subscription Data */
|
||||
d_assert(fd_msg_avp_new(s6a_subscription_data, 0, &avp) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_msisdn, 0, &avp_msisdn) == 0, goto out,);
|
||||
core_bcd_to_buffer(imsi_bcd, msisdn, &msisdn_len);
|
||||
val.os.data = msisdn;
|
||||
val.os.len = msisdn_len;
|
||||
d_assert(fd_msg_avp_setvalue(avp_msisdn, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_msisdn) == 0,
|
||||
goto out,);
|
||||
|
||||
if (subscription_data.access_restriction_data)
|
||||
{
|
||||
d_assert(fd_msg_avp_new(s6a_access_restriction_data, 0,
|
||||
&avp_access_restriction_data) == 0, goto out,);
|
||||
val.i32 = subscription_data.access_restriction_data;
|
||||
d_assert(fd_msg_avp_setvalue(
|
||||
avp_access_restriction_data, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_access_restriction_data) == 0, goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_subscriber_status, 0,
|
||||
&avp_subscriber_status) == 0, goto out,);
|
||||
val.i32 = subscription_data.subscriber_status;
|
||||
d_assert(fd_msg_avp_setvalue(avp_subscriber_status, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_subscriber_status) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_network_access_mode, 0,
|
||||
&avp_network_access_mode) == 0, goto out,);
|
||||
val.i32 = subscription_data.network_access_mode;
|
||||
d_assert(fd_msg_avp_setvalue(avp_network_access_mode, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_network_access_mode) == 0, goto out,);
|
||||
|
||||
/* Set the AMBR */
|
||||
d_assert(fd_msg_avp_new(s6a_ambr, 0, &avp_ambr) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_ul, 0,
|
||||
&avp_max_bandwidth_ul) == 0, goto out,);
|
||||
val.i32 = subscription_data.max_bandwidth_ul * 1024; /* bits per second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_ul) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_dl, 0,
|
||||
&avp_max_bandwidth_dl) == 0, goto out,);
|
||||
val.i32 = subscription_data.max_bandwidth_dl * 1024; /* bitsper second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_dl) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr) == 0,
|
||||
goto out,);
|
||||
|
||||
if (subscription_data.num_of_pdn)
|
||||
{
|
||||
/* Set the APN Configuration Profile */
|
||||
struct avp *apn_configuration_profile;
|
||||
struct avp *context_identifier, *all_apn_conf_inc_ind;
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_apn_configuration_profile, 0,
|
||||
&apn_configuration_profile) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_context_identifier, 0,
|
||||
&context_identifier) == 0, goto out,);
|
||||
val.i32 = 0; /* FIXME : default PDN Context Identifier */
|
||||
d_assert(fd_msg_avp_setvalue(context_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, context_identifier) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_all_apn_conf_inc_ind, 0,
|
||||
&all_apn_conf_inc_ind) == 0, goto out,);
|
||||
val.i32 = 0;
|
||||
d_assert(fd_msg_avp_setvalue(all_apn_conf_inc_ind, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, all_apn_conf_inc_ind) == 0, goto out,);
|
||||
|
||||
for (i = 0; i < subscription_data.num_of_pdn; i++)
|
||||
{
|
||||
/* Set the APN Configuration */
|
||||
struct avp *apn_configuration, *context_identifier;
|
||||
struct avp *pdn_type, *service_selection;
|
||||
struct avp *eps_subscribed_qos_profile, *qos_class_identifier;
|
||||
struct avp *allocation_retention_priority, *priority_level;
|
||||
struct avp *pre_emption_capability, *pre_emption_vulnerability;
|
||||
|
||||
pdn_t *pdn = &subscription_data.pdn[i];
|
||||
d_assert(pdn, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_apn_configuration, 0,
|
||||
&apn_configuration) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_context_identifier, 0,
|
||||
&context_identifier) == 0, goto out,);
|
||||
val.i32 = pdn->id;
|
||||
d_assert(fd_msg_avp_setvalue(context_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, context_identifier) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pdn_type, 0,
|
||||
&pdn_type) == 0, goto out,);
|
||||
val.i32 = pdn->s6a_type;
|
||||
d_assert(fd_msg_avp_setvalue(pdn_type, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, pdn_type) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_service_selection, 0,
|
||||
&service_selection) == 0, goto out,);
|
||||
val.os.data = (c_uint8_t *)pdn->apn;
|
||||
val.os.len = strlen(pdn->apn);
|
||||
d_assert(fd_msg_avp_setvalue(service_selection, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, service_selection) == 0, goto out,);
|
||||
|
||||
/* Set the EPS Subscribed QoS Profile */
|
||||
d_assert(fd_msg_avp_new(s6a_eps_subscribed_qos_profile, 0,
|
||||
&eps_subscribed_qos_profile) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_qos_class_identifier, 0,
|
||||
&qos_class_identifier) == 0, goto out,);
|
||||
val.i32 = pdn->qci;
|
||||
d_assert(fd_msg_avp_setvalue(qos_class_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(eps_subscribed_qos_profile,
|
||||
MSG_BRW_LAST_CHILD, qos_class_identifier) == 0, goto out,);
|
||||
|
||||
/* Set Allocation retention priority */
|
||||
d_assert(fd_msg_avp_new(s6a_allocation_retention_priority, 0,
|
||||
&allocation_retention_priority) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_priority_level, 0,
|
||||
&priority_level) == 0, goto out,);
|
||||
val.u32 = pdn->priority_level;
|
||||
d_assert(fd_msg_avp_setvalue(priority_level, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, priority_level) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pre_emption_capability, 0,
|
||||
&pre_emption_capability) == 0, goto out,);
|
||||
val.u32 = pdn->pre_emption_capability;
|
||||
d_assert(fd_msg_avp_setvalue(pre_emption_capability, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, pre_emption_capability) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pre_emption_vulnerability, 0,
|
||||
&pre_emption_vulnerability) == 0, goto out,);
|
||||
val.u32 = pdn->pre_emption_vulnerability;
|
||||
d_assert(fd_msg_avp_setvalue(pre_emption_vulnerability, &val)
|
||||
== 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, pre_emption_vulnerability) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(eps_subscribed_qos_profile,
|
||||
MSG_BRW_LAST_CHILD, allocation_retention_priority) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set AMBR */
|
||||
d_assert(fd_msg_avp_new(s6a_ambr, 0, &avp_ambr) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_ul, 0,
|
||||
&avp_max_bandwidth_ul) == 0, goto out,);
|
||||
val.i32 = pdn->max_bandwidth_ul * 1024; /* bits per second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_ul) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_dl, 0,
|
||||
&avp_max_bandwidth_dl) == 0, goto out,);
|
||||
val.i32 = pdn->max_bandwidth_dl * 1024; /* bitsper second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_dl) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, avp_ambr) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, apn_configuration) == 0,
|
||||
goto out,);
|
||||
}
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
apn_configuration_profile) == 0, goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0,
|
||||
goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_subscribed_rau_tau_timer, 0, &avp) == 0, goto out,);
|
||||
val.i32 = subscription_data.subscribed_rau_tau_timer * 60; /* seconds */
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Send the answer */
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
/* Add this value to the stats */
|
||||
pthread_mutex_lock(&s6a_config->stats_lock);
|
||||
s6a_config->stats.nb_echoed++;
|
||||
pthread_mutex_unlock(&s6a_config->stats_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
fd_msg_rescode_set(ans, "DIAMETER_AUTHENTICATION_REJECTED", NULL, NULL, 1);
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include "hss_s6a_handler.h"
|
||||
|
||||
status_t hss_initialize(void)
|
||||
{
|
||||
status_t rv;
|
||||
int ret;
|
||||
struct disp_when data;
|
||||
|
||||
ret = s6a_init(MODE_HSS);
|
||||
if (ret != 0) return CORE_ERROR;
|
||||
|
@ -498,38 +15,19 @@ status_t hss_initialize(void)
|
|||
rv = hss_context_init();
|
||||
if (rv != CORE_OK) return rv;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = s6a_appli;
|
||||
|
||||
/* fallback CB if command != unexpected message received */
|
||||
d_assert(fd_disp_register(hss_fb_cb, DISP_HOW_APPID, &data, NULL,
|
||||
&hdl_fb) == 0, return CORE_ERROR,);
|
||||
|
||||
/* specific handler for Authentication-Information-Request */
|
||||
data.command = s6a_cmd_air;
|
||||
d_assert(fd_disp_register(hss_air_cb, DISP_HOW_CC, &data, NULL,
|
||||
&hdl_air) == 0, return CORE_ERROR,);
|
||||
rv = hss_db_init();
|
||||
if (rv != CORE_OK) return rv;
|
||||
|
||||
/* specific handler for Location-Update-Request */
|
||||
data.command = s6a_cmd_ulr;
|
||||
d_assert(fd_disp_register(hss_ulr_cb, DISP_HOW_CC, &data, NULL,
|
||||
&hdl_ulr) == 0, return CORE_ERROR,);
|
||||
rv = hss_s6a_init();
|
||||
if (rv != CORE_OK) return rv;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
void hss_terminate(void)
|
||||
{
|
||||
if (hdl_fb) {
|
||||
(void) fd_disp_unregister(&hdl_fb, NULL);
|
||||
}
|
||||
if (hdl_air) {
|
||||
(void) fd_disp_unregister(&hdl_air, NULL);
|
||||
}
|
||||
if (hdl_ulr) {
|
||||
(void) fd_disp_unregister(&hdl_ulr, NULL);
|
||||
}
|
||||
|
||||
hss_s6a_final();
|
||||
hss_db_final();
|
||||
hss_context_final();
|
||||
s6a_final();
|
||||
|
||||
|
|
|
@ -0,0 +1,523 @@
|
|||
#define TRACE_MODULE _hss_s6a_handler
|
||||
|
||||
#include "core_debug.h"
|
||||
#include "core_lib.h"
|
||||
#include "core_sha2.h"
|
||||
|
||||
#include "s6a_lib.h"
|
||||
|
||||
#include "hss_context.h"
|
||||
#include "hss_kdf.h"
|
||||
#include "milenage.h"
|
||||
|
||||
#define HSS_SQN_LEN 6
|
||||
#define HSS_AK_LEN 6
|
||||
|
||||
/* handler for fallback cb */
|
||||
static struct disp_hdl *hdl_fb = NULL;
|
||||
/* handler for Authentication-Information-Request cb */
|
||||
static struct disp_hdl *hdl_air = NULL;
|
||||
/* handler for Update-Location-Request cb */
|
||||
static struct disp_hdl *hdl_ulr = NULL;
|
||||
|
||||
/* Default callback for the application. */
|
||||
static int hss_fb_cb(struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
/* This CB should never be called */
|
||||
d_warn("Unexpected message received!");
|
||||
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
/* Callback for incoming Authentication-Information-Request messages */
|
||||
static int hss_air_cb( struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
struct msg *ans, *qry;
|
||||
struct avp *avp_e_utran_vector, *avp_xres, *avp_kasme, *avp_rand, *avp_autn;
|
||||
struct avp_hdr *hdr;
|
||||
union avp_value val;
|
||||
|
||||
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
||||
c_uint8_t opc[HSS_KEY_LEN];
|
||||
c_uint8_t sqn[HSS_SQN_LEN];
|
||||
c_uint8_t autn[AUTN_LEN];
|
||||
c_uint8_t ik[HSS_KEY_LEN];
|
||||
c_uint8_t ck[HSS_KEY_LEN];
|
||||
c_uint8_t ak[HSS_AK_LEN];
|
||||
c_uint8_t xres[MAX_RES_LEN];
|
||||
c_uint8_t kasme[SHA256_DIGEST_SIZE];
|
||||
size_t xres_len = 8;
|
||||
|
||||
hss_db_auth_info_t auth_info;
|
||||
c_uint8_t zero[RAND_LEN];
|
||||
status_t rv;
|
||||
|
||||
d_assert(msg, return EINVAL,);
|
||||
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
|
||||
ans = *msg;
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_user_name, &avp) == 0 && avp,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
memcpy(imsi_bcd, (char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
imsi_bcd[hdr->avp_value->os.len] = 0;
|
||||
|
||||
rv = hss_db_auth_info(imsi_bcd, &auth_info);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot get Auth-Info for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(zero, 0, sizeof(zero));
|
||||
if (memcmp(auth_info.rand, zero, RAND_LEN) == 0)
|
||||
{
|
||||
core_generate_random_bytes(auth_info.rand, RAND_LEN);
|
||||
}
|
||||
|
||||
rv = hss_db_update_rand_and_sqn(imsi_bcd, auth_info.rand, auth_info.sqn);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot update rand and sqn for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 0
|
||||
rv = hss_db_increment_sqn(imsi_bcd);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot increment sqn for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_visited_plmn_id, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
if (hdr && hdr->avp_value && hdr->avp_value->os.data)
|
||||
{
|
||||
#if 0 // TODO : check visited_plmn_id
|
||||
memcpy(visited_plmn_id,
|
||||
hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
#endif
|
||||
}
|
||||
|
||||
milenage_opc(auth_info.k, auth_info.op, opc);
|
||||
milenage_generate(opc, auth_info.amf, auth_info.k,
|
||||
core_uint64_to_buffer(auth_info.sqn, HSS_SQN_LEN, sqn), auth_info.rand,
|
||||
autn, ik, ck, ak, xres, &xres_len);
|
||||
hss_kdf_kasme(ck, ik, hdr->avp_value->os.data, sqn, ak, kasme);
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
d_assert(fd_msg_rescode_set(ans, "DIAMETER_SUCCESS", NULL, NULL, 1) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set the Auth-Session-State AVP */
|
||||
d_assert(fd_msg_avp_new(s6a_auth_session_state, 0, &avp) == 0, goto out,);
|
||||
val.i32 = 1;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Set the Authentication-Info */
|
||||
d_assert(fd_msg_avp_new(s6a_authentication_info, 0, &avp) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_e_utran_vector, 0, &avp_e_utran_vector) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_rand, 0, &avp_rand) == 0, goto out,);
|
||||
val.os.data = auth_info.rand;
|
||||
val.os.len = HSS_KEY_LEN;
|
||||
d_assert(fd_msg_avp_setvalue(avp_rand, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_rand) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_xres, 0, &avp_xres) == 0, goto out,);
|
||||
val.os.data = xres;
|
||||
val.os.len = xres_len;
|
||||
d_assert(fd_msg_avp_setvalue(avp_xres, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_xres) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_autn, 0, &avp_autn) == 0, goto out,);
|
||||
val.os.data = autn;
|
||||
val.os.len = AUTN_LEN;
|
||||
d_assert(fd_msg_avp_setvalue(avp_autn, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_autn) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_kasme, 0, &avp_kasme) == 0, goto out,);
|
||||
val.os.data = kasme;
|
||||
val.os.len = SHA256_DIGEST_SIZE;
|
||||
d_assert(fd_msg_avp_setvalue(avp_kasme, &val) == 0, goto out,);
|
||||
d_assert(
|
||||
fd_msg_avp_add(avp_e_utran_vector, MSG_BRW_LAST_CHILD, avp_kasme) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_e_utran_vector) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Send the answer */
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
/* Add this value to the stats */
|
||||
pthread_mutex_lock(&s6a_config->stats_lock);
|
||||
s6a_config->stats.nb_echoed++;
|
||||
pthread_mutex_unlock(&s6a_config->stats_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
fd_msg_rescode_set(ans, "DIAMETER_AUTHENTICATION_REJECTED", NULL, NULL, 1);
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Callback for incoming Update-Location-Request messages */
|
||||
static int hss_ulr_cb( struct msg **msg, struct avp *avp,
|
||||
struct session *sess, void *opaque, enum disp_action *act)
|
||||
{
|
||||
struct msg *ans, *qry;
|
||||
|
||||
struct avp_hdr *hdr;
|
||||
union avp_value val;
|
||||
|
||||
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
||||
|
||||
status_t rv;
|
||||
hss_db_subscription_data_t subscription_data;
|
||||
|
||||
d_assert(msg, return EINVAL,);
|
||||
|
||||
/* Create answer header */
|
||||
qry = *msg;
|
||||
fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
|
||||
ans = *msg;
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_user_name, &avp) == 0 && avp,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
memcpy(imsi_bcd, (char*)hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
imsi_bcd[hdr->avp_value->os.len] = 0;
|
||||
|
||||
rv = hss_db_subscription_data(imsi_bcd, &subscription_data);
|
||||
if (rv != CORE_OK)
|
||||
{
|
||||
d_error("Cannot get Subscription-Data for IMSI:'%s'", imsi_bcd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_visited_plmn_id, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
|
||||
if (hdr && hdr->avp_value && hdr->avp_value->os.data)
|
||||
{
|
||||
#if 0 // TODO : check visited_plmn_id
|
||||
memcpy(visited_plmn_id,
|
||||
hdr->avp_value->os.data, hdr->avp_value->os.len);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
|
||||
d_assert(fd_msg_rescode_set(ans, "DIAMETER_SUCCESS", NULL, NULL, 1) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set the Auth-Session-Statee AVP */
|
||||
d_assert(fd_msg_avp_new(s6a_auth_session_state, 0, &avp) == 0, goto out,);
|
||||
val.i32 = 1;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Set the ULA Flags */
|
||||
d_assert(fd_msg_avp_new(s6a_ula_flags, 0, &avp) == 0, goto out,);
|
||||
val.i32 = S6A_ULA_MME_REGISTERED_FOR_SMS;
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_search_avp(qry, s6a_ulr_flags, &avp) == 0 &&
|
||||
avp, goto out,);
|
||||
d_assert(fd_msg_avp_hdr(avp, &hdr) == 0 && hdr,,);
|
||||
if (hdr && hdr->avp_value &&
|
||||
!(hdr->avp_value->u32 & S6A_ULR_SKIP_SUBSCRIBER_DATA))
|
||||
{
|
||||
struct avp *avp_msisdn, *avp_access_restriction_data;
|
||||
struct avp *avp_subscriber_status, *avp_network_access_mode;
|
||||
struct avp *avp_ambr, *avp_max_bandwidth_ul, *avp_max_bandwidth_dl;
|
||||
int i;
|
||||
c_uint8_t msisdn[MAX_IMSI_LEN];
|
||||
int msisdn_len;
|
||||
|
||||
/* Set the Subscription Data */
|
||||
d_assert(fd_msg_avp_new(s6a_subscription_data, 0, &avp) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_msisdn, 0, &avp_msisdn) == 0, goto out,);
|
||||
core_bcd_to_buffer(imsi_bcd, msisdn, &msisdn_len);
|
||||
val.os.data = msisdn;
|
||||
val.os.len = msisdn_len;
|
||||
d_assert(fd_msg_avp_setvalue(avp_msisdn, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_msisdn) == 0,
|
||||
goto out,);
|
||||
|
||||
if (subscription_data.access_restriction_data)
|
||||
{
|
||||
d_assert(fd_msg_avp_new(s6a_access_restriction_data, 0,
|
||||
&avp_access_restriction_data) == 0, goto out,);
|
||||
val.i32 = subscription_data.access_restriction_data;
|
||||
d_assert(fd_msg_avp_setvalue(
|
||||
avp_access_restriction_data, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_access_restriction_data) == 0, goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_subscriber_status, 0,
|
||||
&avp_subscriber_status) == 0, goto out,);
|
||||
val.i32 = subscription_data.subscriber_status;
|
||||
d_assert(fd_msg_avp_setvalue(avp_subscriber_status, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_subscriber_status) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_network_access_mode, 0,
|
||||
&avp_network_access_mode) == 0, goto out,);
|
||||
val.i32 = subscription_data.network_access_mode;
|
||||
d_assert(fd_msg_avp_setvalue(avp_network_access_mode, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
avp_network_access_mode) == 0, goto out,);
|
||||
|
||||
/* Set the AMBR */
|
||||
d_assert(fd_msg_avp_new(s6a_ambr, 0, &avp_ambr) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_ul, 0,
|
||||
&avp_max_bandwidth_ul) == 0, goto out,);
|
||||
val.i32 = subscription_data.max_bandwidth_ul * 1024; /* bits per second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_ul) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_dl, 0,
|
||||
&avp_max_bandwidth_dl) == 0, goto out,);
|
||||
val.i32 = subscription_data.max_bandwidth_dl * 1024; /* bitsper second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_dl) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_ambr) == 0,
|
||||
goto out,);
|
||||
|
||||
if (subscription_data.num_of_pdn)
|
||||
{
|
||||
/* Set the APN Configuration Profile */
|
||||
struct avp *apn_configuration_profile;
|
||||
struct avp *context_identifier, *all_apn_conf_inc_ind;
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_apn_configuration_profile, 0,
|
||||
&apn_configuration_profile) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_context_identifier, 0,
|
||||
&context_identifier) == 0, goto out,);
|
||||
val.i32 = 0; /* FIXME : default PDN Context Identifier */
|
||||
d_assert(fd_msg_avp_setvalue(context_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, context_identifier) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_all_apn_conf_inc_ind, 0,
|
||||
&all_apn_conf_inc_ind) == 0, goto out,);
|
||||
val.i32 = 0;
|
||||
d_assert(fd_msg_avp_setvalue(all_apn_conf_inc_ind, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, all_apn_conf_inc_ind) == 0, goto out,);
|
||||
|
||||
for (i = 0; i < subscription_data.num_of_pdn; i++)
|
||||
{
|
||||
/* Set the APN Configuration */
|
||||
struct avp *apn_configuration, *context_identifier;
|
||||
struct avp *pdn_type, *service_selection;
|
||||
struct avp *eps_subscribed_qos_profile, *qos_class_identifier;
|
||||
struct avp *allocation_retention_priority, *priority_level;
|
||||
struct avp *pre_emption_capability, *pre_emption_vulnerability;
|
||||
|
||||
pdn_t *pdn = &subscription_data.pdn[i];
|
||||
d_assert(pdn, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_apn_configuration, 0,
|
||||
&apn_configuration) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_context_identifier, 0,
|
||||
&context_identifier) == 0, goto out,);
|
||||
val.i32 = pdn->id;
|
||||
d_assert(fd_msg_avp_setvalue(context_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, context_identifier) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pdn_type, 0,
|
||||
&pdn_type) == 0, goto out,);
|
||||
val.i32 = pdn->s6a_type;
|
||||
d_assert(fd_msg_avp_setvalue(pdn_type, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, pdn_type) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_service_selection, 0,
|
||||
&service_selection) == 0, goto out,);
|
||||
val.os.data = (c_uint8_t *)pdn->apn;
|
||||
val.os.len = strlen(pdn->apn);
|
||||
d_assert(fd_msg_avp_setvalue(service_selection, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, service_selection) == 0, goto out,);
|
||||
|
||||
/* Set the EPS Subscribed QoS Profile */
|
||||
d_assert(fd_msg_avp_new(s6a_eps_subscribed_qos_profile, 0,
|
||||
&eps_subscribed_qos_profile) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_qos_class_identifier, 0,
|
||||
&qos_class_identifier) == 0, goto out,);
|
||||
val.i32 = pdn->qci;
|
||||
d_assert(fd_msg_avp_setvalue(qos_class_identifier, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(eps_subscribed_qos_profile,
|
||||
MSG_BRW_LAST_CHILD, qos_class_identifier) == 0, goto out,);
|
||||
|
||||
/* Set Allocation retention priority */
|
||||
d_assert(fd_msg_avp_new(s6a_allocation_retention_priority, 0,
|
||||
&allocation_retention_priority) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_priority_level, 0,
|
||||
&priority_level) == 0, goto out,);
|
||||
val.u32 = pdn->priority_level;
|
||||
d_assert(fd_msg_avp_setvalue(priority_level, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, priority_level) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pre_emption_capability, 0,
|
||||
&pre_emption_capability) == 0, goto out,);
|
||||
val.u32 = pdn->pre_emption_capability;
|
||||
d_assert(fd_msg_avp_setvalue(pre_emption_capability, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, pre_emption_capability) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_pre_emption_vulnerability, 0,
|
||||
&pre_emption_vulnerability) == 0, goto out,);
|
||||
val.u32 = pdn->pre_emption_vulnerability;
|
||||
d_assert(fd_msg_avp_setvalue(pre_emption_vulnerability, &val)
|
||||
== 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(allocation_retention_priority,
|
||||
MSG_BRW_LAST_CHILD, pre_emption_vulnerability) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(eps_subscribed_qos_profile,
|
||||
MSG_BRW_LAST_CHILD, allocation_retention_priority) == 0,
|
||||
goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, eps_subscribed_qos_profile) == 0,
|
||||
goto out,);
|
||||
|
||||
/* Set AMBR */
|
||||
d_assert(fd_msg_avp_new(s6a_ambr, 0, &avp_ambr) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_ul, 0,
|
||||
&avp_max_bandwidth_ul) == 0, goto out,);
|
||||
val.i32 = pdn->max_bandwidth_ul * 1024; /* bits per second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_ul, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_ul) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_new(s6a_max_bandwidth_dl, 0,
|
||||
&avp_max_bandwidth_dl) == 0, goto out,);
|
||||
val.i32 = pdn->max_bandwidth_dl * 1024; /* bitsper second */
|
||||
d_assert(fd_msg_avp_setvalue(avp_max_bandwidth_dl, &val) == 0,
|
||||
goto out,);
|
||||
d_assert(fd_msg_avp_add(avp_ambr, MSG_BRW_LAST_CHILD,
|
||||
avp_max_bandwidth_dl) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration,
|
||||
MSG_BRW_LAST_CHILD, avp_ambr) == 0, goto out,);
|
||||
|
||||
d_assert(fd_msg_avp_add(apn_configuration_profile,
|
||||
MSG_BRW_LAST_CHILD, apn_configuration) == 0,
|
||||
goto out,);
|
||||
}
|
||||
d_assert(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD,
|
||||
apn_configuration_profile) == 0, goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0,
|
||||
goto out,);
|
||||
}
|
||||
|
||||
d_assert(fd_msg_avp_new(s6a_subscribed_rau_tau_timer, 0, &avp) == 0, goto out,);
|
||||
val.i32 = subscription_data.subscribed_rau_tau_timer * 60; /* seconds */
|
||||
d_assert(fd_msg_avp_setvalue(avp, &val) == 0, goto out,);
|
||||
d_assert(fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp) == 0, goto out,);
|
||||
|
||||
/* Send the answer */
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
/* Add this value to the stats */
|
||||
pthread_mutex_lock(&s6a_config->stats_lock);
|
||||
s6a_config->stats.nb_echoed++;
|
||||
pthread_mutex_unlock(&s6a_config->stats_lock);
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
fd_msg_rescode_set(ans, "DIAMETER_AUTHENTICATION_REJECTED", NULL, NULL, 1);
|
||||
fd_msg_send(msg, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
status_t hss_s6a_init(void)
|
||||
{
|
||||
struct disp_when data;
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.app = s6a_appli;
|
||||
|
||||
/* fallback CB if command != unexpected message received */
|
||||
d_assert(fd_disp_register(hss_fb_cb, DISP_HOW_APPID, &data, NULL,
|
||||
&hdl_fb) == 0, return CORE_ERROR,);
|
||||
|
||||
/* specific handler for Authentication-Information-Request */
|
||||
data.command = s6a_cmd_air;
|
||||
d_assert(fd_disp_register(hss_air_cb, DISP_HOW_CC, &data, NULL,
|
||||
&hdl_air) == 0, return CORE_ERROR,);
|
||||
|
||||
/* specific handler for Location-Update-Request */
|
||||
data.command = s6a_cmd_ulr;
|
||||
d_assert(fd_disp_register(hss_ulr_cb, DISP_HOW_CC, &data, NULL,
|
||||
&hdl_ulr) == 0, return CORE_ERROR,);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
void hss_s6a_final(void)
|
||||
{
|
||||
if (hdl_fb) {
|
||||
(void) fd_disp_unregister(&hdl_fb, NULL);
|
||||
}
|
||||
if (hdl_air) {
|
||||
(void) fd_disp_unregister(&hdl_air, NULL);
|
||||
}
|
||||
if (hdl_ulr) {
|
||||
(void) fd_disp_unregister(&hdl_ulr, NULL);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __HSS_S6A_HANDLER_H__
|
||||
#define __HSS_S6A_HANDLER_H__
|
||||
|
||||
#include "core_errno.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
CORE_DECLARE(status_t) hss_s6a_init(void);
|
||||
CORE_DECLARE(void) hss_s6a_final(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __HSS_S6A_HANDLER_H__ */
|
||||
|
Loading…
Reference in New Issue