[MME] Support for Insert Subscriber Data (#1794)

* [MME] Support for Insert Subscriber Data

* Supported AVPs in IDR will overwrite existing subscription information
* Provide error on partial APN updates
* IDR and ULA use same function to process AVPs
* Move subdatamask values into s6a, so both HSS and MME can use them
* Updates are not actioned at this time.  A Re-attach is required for
  most changes to take effect

* Memory issue on IDR exceptions

* Remove of handling MSIDSN change until DSR is used
This commit is contained in:
jmasterfunk84 2022-10-02 04:36:24 -06:00 committed by GitHub
parent 35ae3317b7
commit 1f2a8678ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 822 additions and 711 deletions

View File

@ -77,6 +77,19 @@ extern "C" {
#define OGS_DIAM_S6A_CT_UPDATE_PROCEDURE_IWF (3)
#define OGS_DIAM_S6A_CT_INITIAL_ATTACH_PROCEDURE (4)
#define OGS_DIAM_S6A_SUBDATA_NO_UPDATE (0)
#define OGS_DIAM_S6A_SUBDATA_SUB_STATUS (1)
#define OGS_DIAM_S6A_SUBDATA_MSISDN (1 << 1)
#define OGS_DIAM_S6A_SUBDATA_A_MSISDN (1 << 2)
#define OGS_DIAM_S6A_SUBDATA_NAM (1 << 3)
#define OGS_DIAM_S6A_SUBDATA_ODB (1 << 4)
#define OGS_DIAM_S6A_SUBDATA_ARD (1 << 5)
#define OGS_DIAM_S6A_SUBDATA_CC (1 << 6)
#define OGS_DIAM_S6A_SUBDATA_UEAMBR (1 << 7)
#define OGS_DIAM_S6A_SUBDATA_APN_CONFIG (1 << 8)
#define OGS_DIAM_S6A_SUBDATA_RAU_TAU_TIMER (1 << 9)
#define OGS_DIAM_S6A_SUBDATA_ALL 0xFFFFFFFF
extern struct dict_object *ogs_diam_s6a_application;
extern struct dict_object *ogs_diam_s6a_cmd_air;
@ -179,6 +192,7 @@ typedef struct ogs_diam_s6a_idr_message_s {
#define OGS_DIAM_S6A_IDR_FLAGS_RAT_TYPE (1 << 7)
#define OGS_DIAM_S6A_IDR_FLAGS_PCSCF_Restoration (1 << 8)
uint32_t idr_flags;
uint32_t subdatamask;
ogs_subscription_data_t subscription_data;
} ogs_diam_s6a_idr_message_t;

View File

@ -651,6 +651,7 @@ typedef struct ogs_slice_data_s {
bool default_indicator;
uint32_t context_identifier; /* EPC for checking default APN */
uint32_t all_apn_config_inc;
int num_of_session;
ogs_session_t session[OGS_MAX_NUM_OF_SESS];

View File

@ -1238,50 +1238,36 @@ int hss_handle_change_event(const bson_t *document)
"request_cancel_location") &&
BSON_ITER_HOLDS_BOOL(&child2_iter)) {
send_clr_flag = (char *)bson_iter_bool(&child2_iter);
} else if (!strncmp(child2_key, "msisdn",
strlen("msisdn"))) {
int msisdn_count = 0;
bson_iter_recurse(&child2_iter, &child3_iter);
while (bson_iter_next(&child3_iter)) {
if (BSON_ITER_HOLDS_UTF8(&child3_iter)) {
msisdn_count++;
}
}
if (msisdn_count) {
send_idr_flag = true;
subdatamask = (subdatamask |
OGS_HSS_SUBDATA_MSISDN);
} else {
send_clr_flag = true;
}
} else if (!strncmp(child2_key,
"access_restriction_data",
strlen("access_restriction_data"))) {
send_idr_flag = true;
subdatamask = (subdatamask | OGS_HSS_SUBDATA_ARD);
subdatamask = (subdatamask | OGS_DIAM_S6A_SUBDATA_ARD);
} else if (!strncmp(child2_key,
"subscriber_status",
strlen("subscriber_status"))) {
send_idr_flag = true;
subdatamask = (subdatamask |
OGS_HSS_SUBDATA_SUB_STATUS);
OGS_DIAM_S6A_SUBDATA_SUB_STATUS);
} else if (!strncmp(child2_key,
"network_access_mode",
strlen("network_access_mode"))) {
send_idr_flag = true;
subdatamask = (subdatamask | OGS_HSS_SUBDATA_NAM);
subdatamask = (subdatamask | OGS_DIAM_S6A_SUBDATA_NAM);
} else if (!strncmp(child2_key, "ambr", strlen("ambr"))) {
send_idr_flag = true;
subdatamask = (subdatamask | OGS_HSS_SUBDATA_UEAMBR);
subdatamask = (subdatamask |
OGS_DIAM_S6A_SUBDATA_UEAMBR);
} else if (!strncmp(child2_key,
"subscribed_rau_tau_timer",
strlen("subscribed_rau_tau_timer"))) {
send_idr_flag = true;
subdatamask = (subdatamask |
OGS_HSS_SUBDATA_RAU_TAU_TIMER);
OGS_DIAM_S6A_SUBDATA_RAU_TAU_TIMER);
} else if (!strncmp(child2_key, "slice", strlen("slice"))) {
send_idr_flag = true;
subdatamask = (subdatamask | OGS_HSS_SUBDATA_SLICE);
subdatamask = (subdatamask |
OGS_DIAM_S6A_SUBDATA_APN_CONFIG);
}
}
}

View File

@ -314,7 +314,7 @@ static int hss_s6a_avp_add_subscription_data(
int i;
if (subdatamask & OGS_HSS_SUBDATA_MSISDN) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_MSISDN) {
/*
* TS29.328
* 6.3.2 MSISDN AVP
@ -350,7 +350,7 @@ static int hss_s6a_avp_add_subscription_data(
}
}
if (subdatamask & OGS_HSS_SUBDATA_ARD) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_ARD) {
if (subscription_data->access_restriction_data) {
ret = fd_msg_avp_new(ogs_diam_s6a_access_restriction_data, 0,
&avp_access_restriction_data);
@ -364,7 +364,7 @@ static int hss_s6a_avp_add_subscription_data(
}
}
if (subdatamask & OGS_HSS_SUBDATA_SUB_STATUS) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_SUB_STATUS) {
ret = fd_msg_avp_new(
ogs_diam_s6a_subscriber_status, 0, &avp_subscriber_status);
ogs_assert(ret == 0);
@ -375,7 +375,7 @@ static int hss_s6a_avp_add_subscription_data(
ogs_assert(ret == 0);
}
if (subdatamask & OGS_HSS_SUBDATA_NAM) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_NAM) {
ret = fd_msg_avp_new(ogs_diam_s6a_network_access_mode, 0,
&avp_network_access_mode);
ogs_assert(ret == 0);
@ -386,7 +386,7 @@ static int hss_s6a_avp_add_subscription_data(
ogs_assert(ret == 0);
}
if (subdatamask & OGS_HSS_SUBDATA_UEAMBR) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_UEAMBR) {
/* Set the AMBR */
ret = fd_msg_avp_new(ogs_diam_s6a_ambr, 0, &avp_ambr);
ogs_assert(ret == 0);
@ -412,7 +412,7 @@ static int hss_s6a_avp_add_subscription_data(
ogs_assert(ret == 0);
}
if (subdatamask & OGS_HSS_SUBDATA_RAU_TAU_TIMER) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_RAU_TAU_TIMER) {
/* Set the Subscribed RAU TAU Timer */
ret = fd_msg_avp_new(
ogs_diam_s6a_subscribed_rau_tau_timer, 0, &avp_rau_tau_timer);
@ -425,7 +425,7 @@ static int hss_s6a_avp_add_subscription_data(
ogs_assert(ret == 0);
}
if (subdatamask & OGS_HSS_SUBDATA_SLICE) {
if (subdatamask & OGS_DIAM_S6A_SUBDATA_APN_CONFIG) {
/* For EPC, we'll use first Slice in Subscription */
if (subscription_data->num_of_slice)
slice_data = &subscription_data->slice[0];
@ -910,7 +910,7 @@ static int hss_ogs_diam_s6a_ulr_cb( struct msg **msg, struct avp *avp,
ret = fd_msg_avp_new(ogs_diam_s6a_subscription_data, 0, &avp);
ogs_assert(ret == 0);
rv = hss_s6a_avp_add_subscription_data(&subscription_data,
avp, OGS_HSS_SUBDATA_ALL);
avp, OGS_DIAM_S6A_SUBDATA_ALL);
if (rv != OGS_OK) {
result_code = OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION;
goto out;

View File

@ -26,16 +26,6 @@
extern "C" {
#endif
#define OGS_HSS_SUBDATA_NO_UPDATE (0)
#define OGS_HSS_SUBDATA_MSISDN (1)
#define OGS_HSS_SUBDATA_ARD (1 << 1)
#define OGS_HSS_SUBDATA_SUB_STATUS (1 << 2)
#define OGS_HSS_SUBDATA_NAM (1 << 3)
#define OGS_HSS_SUBDATA_UEAMBR (1 << 4)
#define OGS_HSS_SUBDATA_RAU_TAU_TIMER (1 << 5)
#define OGS_HSS_SUBDATA_SLICE (1 << 6)
#define OGS_HSS_SUBDATA_ALL 0xFFFFFFFF
/* HSS Sends Cancel Location Request to MME */
void hss_s6a_send_clr(char *imsi_bcd, char *mme_host, char *mme_realm,
uint32_t cancellation_type);

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,9 @@
static uint8_t emm_cause_from_diameter(
const uint32_t *dia_err, const uint32_t *dia_exp_err);
static uint8_t mme_ue_session_from_slice_data(mme_ue_t *mme_ue,
ogs_slice_data_t *slice_data);
uint8_t mme_s6a_handle_aia(
mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message)
{
@ -74,7 +77,7 @@ uint8_t mme_s6a_handle_ula(
ogs_diam_s6a_ula_message_t *ula_message = NULL;
ogs_subscription_data_t *subscription_data = NULL;
ogs_slice_data_t *slice_data = NULL;
int i, rv;
int rv;
ogs_assert(mme_ue);
ogs_assert(s6a_message);
@ -95,58 +98,13 @@ uint8_t mme_s6a_handle_ula(
mme_session_remove_all(mme_ue);
for (i = 0; i < slice_data->num_of_session; i++) {
if (i >= OGS_MAX_NUM_OF_SESS) {
ogs_warn("Ignore max session count overflow [%d>=%d]",
slice_data->num_of_session, OGS_MAX_NUM_OF_SESS);
break;
}
if (slice_data->session[i].name) {
mme_ue->session[i].name = ogs_strdup(slice_data->session[i].name);
ogs_assert(mme_ue->session[i].name);
}
mme_ue->session[i].context_identifier =
slice_data->session[i].context_identifier;
if (slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV4 ||
slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV6 ||
slice_data->session[i].session_type ==
OGS_PDU_SESSION_TYPE_IPV4V6) {
mme_ue->session[i].session_type =
slice_data->session[i].session_type;
} else {
ogs_error("Invalid PDN_TYPE[%d]",
slice_data->session[i].session_type);
if (mme_ue->session[i].name)
ogs_free(mme_ue->session[i].name);
break;
}
memcpy(&mme_ue->session[i].paa, &slice_data->session[i].paa,
sizeof(mme_ue->session[i].paa));
memcpy(&mme_ue->session[i].qos, &slice_data->session[i].qos,
sizeof(mme_ue->session[i].qos));
memcpy(&mme_ue->session[i].ambr, &slice_data->session[i].ambr,
sizeof(mme_ue->session[i].ambr));
memcpy(&mme_ue->session[i].smf_ip, &slice_data->session[i].smf_ip,
sizeof(mme_ue->session[i].smf_ip));
memcpy(&mme_ue->session[i].charging_characteristics,
&slice_data->session[i].charging_characteristics,
sizeof(mme_ue->session[i].charging_characteristics));
mme_ue->session[i].charging_characteristics_presence =
slice_data->session[i].charging_characteristics_presence;
}
if (i == 0) {
rv = mme_ue_session_from_slice_data(mme_ue, slice_data);
if (rv == 0) {
ogs_error("No Session");
return OGS_NAS_EMM_CAUSE_SEVERE_NETWORK_FAILURE;
}
mme_ue->num_of_session = rv;
mme_ue->num_of_session = i;
mme_ue->context_identifier = slice_data->context_identifier;
if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) {
@ -168,6 +126,48 @@ uint8_t mme_s6a_handle_ula(
return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED;
}
uint8_t mme_s6a_handle_idr(
mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message)
{
ogs_diam_s6a_idr_message_t *idr_message = NULL;
ogs_subscription_data_t *subscription_data = NULL;
ogs_slice_data_t *slice_data = NULL;
int rv;
ogs_assert(mme_ue);
ogs_assert(s6a_message);
idr_message = &s6a_message->idr_message;
ogs_assert(idr_message);
subscription_data = &idr_message->subscription_data;
ogs_assert(subscription_data);
if (idr_message->subdatamask & OGS_DIAM_S6A_SUBDATA_UEAMBR) {
memcpy(&mme_ue->ambr, &subscription_data->ambr, sizeof(ogs_bitrate_t));
}
if (idr_message->subdatamask & OGS_DIAM_S6A_SUBDATA_APN_CONFIG) {
ogs_assert(subscription_data->num_of_slice == 1);
slice_data = &subscription_data->slice[0];
if (!slice_data->all_apn_config_inc) {
mme_session_remove_all(mme_ue);
rv = mme_ue_session_from_slice_data(mme_ue, slice_data);
if (rv == 0) {
ogs_error("No Session");
return OGS_ERROR;
}
mme_ue->num_of_session = rv;
} else {
ogs_error ("Partial APN-Configuration Not Supported in IDR.");
return OGS_ERROR;
}
mme_ue->context_identifier = slice_data->context_identifier;
}
return OGS_OK;
}
void mme_s6a_handle_clr(
mme_ue_t *mme_ue, ogs_diam_s6a_clr_message_t *clr_message)
{
@ -215,7 +215,60 @@ void mme_s6a_handle_clr(
}
}
/* 3GPP TS 29.272 Annex A; Table !.a:
static uint8_t mme_ue_session_from_slice_data(mme_ue_t *mme_ue,
ogs_slice_data_t *slice_data)
{
int i;
for (i = 0; i < slice_data->num_of_session; i++) {
if (i >= OGS_MAX_NUM_OF_SESS) {
ogs_warn("Ignore max session count overflow [%d>=%d]",
slice_data->num_of_session, OGS_MAX_NUM_OF_SESS);
break;
}
if (slice_data->session[i].name) {
mme_ue->session[i].name = ogs_strdup(slice_data->session[i].name);
ogs_assert(mme_ue->session[i].name);
}
mme_ue->session[i].context_identifier =
slice_data->session[i].context_identifier;
if (slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV4 ||
slice_data->session[i].session_type == OGS_PDU_SESSION_TYPE_IPV6 ||
slice_data->session[i].session_type ==
OGS_PDU_SESSION_TYPE_IPV4V6) {
mme_ue->session[i].session_type =
slice_data->session[i].session_type;
} else {
ogs_error("Invalid PDN_TYPE[%d]",
slice_data->session[i].session_type);
if (mme_ue->session[i].name)
ogs_free(mme_ue->session[i].name);
break;
}
memcpy(&mme_ue->session[i].paa, &slice_data->session[i].paa,
sizeof(mme_ue->session[i].paa));
memcpy(&mme_ue->session[i].qos, &slice_data->session[i].qos,
sizeof(mme_ue->session[i].qos));
memcpy(&mme_ue->session[i].ambr, &slice_data->session[i].ambr,
sizeof(mme_ue->session[i].ambr));
memcpy(&mme_ue->session[i].smf_ip, &slice_data->session[i].smf_ip,
sizeof(mme_ue->session[i].smf_ip));
memcpy(&mme_ue->session[i].charging_characteristics,
&slice_data->session[i].charging_characteristics,
sizeof(mme_ue->session[i].charging_characteristics));
mme_ue->session[i].charging_characteristics_presence =
slice_data->session[i].charging_characteristics_presence;
}
return i;
}
/* 3GPP TS 29.272 Annex A; Table A.1:
* Mapping from S6a error codes to NAS Cause Codes */
static uint8_t emm_cause_from_diameter(
const uint32_t *dia_err, const uint32_t *dia_exp_err)

View File

@ -30,6 +30,8 @@ uint8_t mme_s6a_handle_aia(
mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message);
uint8_t mme_s6a_handle_ula(
mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message);
uint8_t mme_s6a_handle_idr(
mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message);
void mme_s6a_handle_clr(
mme_ue_t *mme_ue, ogs_diam_s6a_clr_message_t *clr_message);

View File

@ -435,11 +435,13 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
mme_s6a_handle_clr(mme_ue, &s6a_message->clr_message);
break;
case OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA:
mme_s6a_handle_idr(mme_ue, s6a_message);
break;
default:
ogs_error("Invalid Type[%d]", s6a_message->cmd_code);
break;
}
ogs_subscription_data_free(&s6a_message->idr_message.subscription_data);
ogs_subscription_data_free(&s6a_message->ula_message.subscription_data);
ogs_free(s6a_message);
break;