From 49349cdb75bcdc54be74790f4769217946a7fb6a Mon Sep 17 00:00:00 2001 From: jmasterfunk84 <48972964+jmasterfunk84@users.noreply.github.com> Date: Thu, 25 Aug 2022 00:43:21 -0600 Subject: [PATCH] [MME] Dictionary Updates and IDR Support (#1714) * Add Diameter Dictionary Elements * Initial IDR Framework * Resolve Compile Issues * Moving Closer * Compile error * Somewhat Working stuffing Code * Add Timestamp Changes * Cleanup some of this code. mme_s6a_handle_idr in s6a-handler.c removed for now, since it will only come in handy when IDR flag is set to request current location, which would involve breaking out into paging. I think there's a few other things we can do just within fd-path first. * further removal of mme_s6a_handle_idr --- lib/diameter/s6a/dict.c | 65 +++++++++++ lib/diameter/s6a/message.c | 19 +++- lib/diameter/s6a/message.h | 26 +++++ src/mme/emm-handler.c | 3 + src/mme/mme-context.h | 1 + src/mme/mme-fd-path.c | 225 +++++++++++++++++++++++++++++++++++++ src/mme/mme-sm.c | 2 + src/mme/s1ap-handler.c | 3 + 8 files changed, 343 insertions(+), 1 deletion(-) diff --git a/lib/diameter/s6a/dict.c b/lib/diameter/s6a/dict.c index d6768bcb6..297297152 100644 --- a/lib/diameter/s6a/dict.c +++ b/lib/diameter/s6a/dict.c @@ -583,6 +583,71 @@ int ogs_dict_s6a_entry(char *conffile) PARSE_loc_rules( rules, cmd ); } + /* Insert-Subscriber-Data-Request (IDR) Command - 3GPP TS 29.272 #7.2.9 */ + { + struct dict_object * cmd; + struct dict_cmd_data data = { + 319, /* Code */ + "Insert-Subscriber-Data-Request", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { + { { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 }, + { { .avp_name = "Vendor-Specific-Application-Id" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 }, + { { .avp_vendor = 10415, .avp_name = "Subscription-Data" }, RULE_REQUIRED, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "IDR-Flags" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 }, + { { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }, + }; + + CHECK_dict_new( DICT_COMMAND, &data, s6a, &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Insert-Subscriber-Data-Answer (IDA) Command - 3GPP TS 29.272 #7.2.10 */ + { + struct dict_object * cmd; + struct dict_cmd_data data = { + 319, /* Code */ + "Insert-Subscriber-Data-Answer", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ + CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { + { { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 }, + { { .avp_name = "Vendor-Specific-Application-Id" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 }, + { { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "IMS-Voice-Over-PS-Sessions-Supported" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "Last-UE-Activity-Time" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "RAT-Type" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "IDA-Flags" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "EPS-User-State" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "EPS-Location-Information" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "Local-Time-Zone" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_vendor = 10415, .avp_name = "Supported-Services" }, RULE_OPTIONAL, -1, 1 }, + { { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 }, + { { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 }, + { { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 }, + }; + + CHECK_dict_new( DICT_COMMAND, &data, s6a, &cmd); + PARSE_loc_rules( rules, cmd ); + } + } LOG_D( "Extension 'Dictionary definitions for DCCA 3GPP S6A' initialized"); diff --git a/lib/diameter/s6a/message.c b/lib/diameter/s6a/message.c index b770a666a..00ad16dd4 100644 --- a/lib/diameter/s6a/message.c +++ b/lib/diameter/s6a/message.c @@ -32,10 +32,13 @@ struct dict_object *ogs_diam_s6a_cmd_pur = NULL; struct dict_object *ogs_diam_s6a_cmd_pua = NULL; struct dict_object *ogs_diam_s6a_cmd_clr = NULL; struct dict_object *ogs_diam_s6a_cmd_cla = NULL; +struct dict_object *ogs_diam_s6a_cmd_idr = NULL; +struct dict_object *ogs_diam_s6a_cmd_ida = NULL; struct dict_object *ogs_diam_s6a_ulr_flags = NULL; struct dict_object *ogs_diam_s6a_ula_flags = NULL; struct dict_object *ogs_diam_s6a_clr_flags = NULL; +struct dict_object *ogs_diam_s6a_idr_flags = NULL; struct dict_object *ogs_diam_s6a_cancellation_type = NULL; struct dict_object *ogs_diam_s6a_subscription_data = NULL; struct dict_object *ogs_diam_s6a_req_eutran_auth_info = NULL; @@ -71,6 +74,11 @@ struct dict_object *ogs_diam_s6a_pre_emption_capability = NULL; struct dict_object *ogs_diam_s6a_pre_emption_vulnerability = NULL; struct dict_object *ogs_diam_s6a_pdn_gw_allocation_type = NULL; struct dict_object *ogs_diam_s6a_vplmn_dynamic_address_allowed = NULL; +struct dict_object *ogs_diam_s6a_eps_location_information = NULL; +struct dict_object *ogs_diam_s6a_mme_location_information = NULL; +struct dict_object *ogs_diam_s6a_e_utran_cell_global_identity = NULL; +struct dict_object *ogs_diam_s6a_tracking_area_identity = NULL; +struct dict_object *ogs_diam_s6a_age_of_location_information = NULL; struct dict_object *ogs_diam_s6a_terminal_information = NULL; struct dict_object *ogs_diam_s6a_imei = NULL; @@ -96,11 +104,14 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Request", &ogs_diam_s6a_cmd_pur); CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Answer", &ogs_diam_s6a_cmd_pua); CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Cancel-Location-Request", &ogs_diam_s6a_cmd_clr); - CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Cancel-Location-Answer", &ogs_diam_s6a_cmd_cla); + CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Cancel-Location-Answer", &ogs_diam_s6a_cmd_cla); + CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Insert-Subscriber-Data-Request", &ogs_diam_s6a_cmd_idr); + CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Insert-Subscriber-Data-Answer", &ogs_diam_s6a_cmd_ida); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULR-Flags", &ogs_diam_s6a_ulr_flags); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULA-Flags", &ogs_diam_s6a_ula_flags); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "CLR-Flags", &ogs_diam_s6a_clr_flags); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "IDR-Flags", &ogs_diam_s6a_idr_flags); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Cancellation-Type", &ogs_diam_s6a_cancellation_type); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "UE-SRVCC-Capability", &ogs_diam_s6a_ue_srvcc_capability); @@ -142,6 +153,12 @@ int ogs_diam_s6a_init(void) CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Access-Restriction-Data", &ogs_diam_s6a_access_restriction_data); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Subscribed-Periodic-RAU-TAU-Timer", &ogs_diam_s6a_subscribed_rau_tau_timer); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "EPS-Location-Information", &ogs_diam_s6a_eps_location_information); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "MME-Location-Information", &ogs_diam_s6a_mme_location_information); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "E-UTRAN-Cell-Global-Identity", &ogs_diam_s6a_e_utran_cell_global_identity); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Tracking-Area-Identity", &ogs_diam_s6a_tracking_area_identity); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Age-Of-Location-Information", &ogs_diam_s6a_age_of_location_information); + CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Terminal-Information", &ogs_diam_s6a_terminal_information); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "IMEI", &ogs_diam_s6a_imei); CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Software-Version", &ogs_diam_s6a_software_version); diff --git a/lib/diameter/s6a/message.h b/lib/diameter/s6a/message.h index 707e0b085..cf37cfbca 100644 --- a/lib/diameter/s6a/message.h +++ b/lib/diameter/s6a/message.h @@ -78,10 +78,13 @@ extern struct dict_object *ogs_diam_s6a_cmd_pur; extern struct dict_object *ogs_diam_s6a_cmd_pua; extern struct dict_object *ogs_diam_s6a_cmd_clr; extern struct dict_object *ogs_diam_s6a_cmd_cla; +extern struct dict_object *ogs_diam_s6a_cmd_idr; +extern struct dict_object *ogs_diam_s6a_cmd_ida; extern struct dict_object *ogs_diam_s6a_ulr_flags; extern struct dict_object *ogs_diam_s6a_ula_flags; extern struct dict_object *ogs_diam_s6a_clr_flags; +extern struct dict_object *ogs_diam_s6a_idr_flags; extern struct dict_object *ogs_diam_s6a_cancellation_type; extern struct dict_object *ogs_diam_s6a_subscription_data; extern struct dict_object *ogs_diam_s6a_req_eutran_auth_info; @@ -117,6 +120,11 @@ extern struct dict_object *ogs_diam_s6a_pre_emption_capability; extern struct dict_object *ogs_diam_s6a_pre_emption_vulnerability; extern struct dict_object *ogs_diam_s6a_pdn_gw_allocation_type; extern struct dict_object *ogs_diam_s6a_vplmn_dynamic_address_allowed; +extern struct dict_object *ogs_diam_s6a_eps_location_information; +extern struct dict_object *ogs_diam_s6a_mme_location_information; +extern struct dict_object *ogs_diam_s6a_e_utran_cell_global_identity; +extern struct dict_object *ogs_diam_s6a_tracking_area_identity; +extern struct dict_object *ogs_diam_s6a_age_of_location_information; extern struct dict_object *ogs_diam_s6a_terminal_information; extern struct dict_object *ogs_diam_s6a_imei; @@ -150,10 +158,27 @@ typedef struct ogs_diam_s6a_clr_message_s { uint32_t clr_flags; } ogs_diam_s6a_clr_message_t; +typedef struct ogs_diam_s6a_idr_message_s { +#define OGS_DIAM_S6A_IDR_FLAGS_UE_REACHABILITY (1) +#define OGS_DIAM_S6A_IDR_FLAGS_TADS_DATA (1 << 1) +#define OGS_DIAM_S6A_IDR_FLAGS_EPS_USER_STATE (1 << 2) +#define OGS_DIAM_S6A_IDR_FLAGS_EPS_LOCATION_INFO (1 << 3) +#define OGS_DIAM_S6A_IDR_FLAGS_CURRENT_LOCATION (1 << 4) +#define OGS_DIAM_S6A_IDR_FLAGS_LOCAL_TZ (1 << 5) +#define OGS_DIAM_S6A_IDR_FLAGS_REMOVE_SMS_REG (1 << 6) +#define OGS_DIAM_S6A_IDR_FLAGS_RAT_TYPE (1 << 7) +#define OGS_DIAM_S6A_IDR_FLAGS_PCSCF_Restoration (1 << 8) + + uint32_t idr_flags; + ogs_subscription_data_t subscription_data; +} ogs_diam_s6a_idr_message_t; + typedef struct ogs_diam_s6a_message_s { #define OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION 316 #define OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION 317 #define OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION 318 +#define OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA 319 +#define OGS_DIAM_S6A_CMD_CODE_PURGE_UE 321 uint16_t cmd_code; /* Experimental Result Code */ @@ -168,6 +193,7 @@ typedef struct ogs_diam_s6a_message_s { uint32_t *err; uint32_t *exp_err; + ogs_diam_s6a_idr_message_t idr_message; ogs_diam_s6a_clr_message_t clr_message; ogs_diam_s6a_aia_message_t aia_message; ogs_diam_s6a_ula_message_t ula_message; diff --git a/src/mme/emm-handler.c b/src/mme/emm-handler.c index 9ed359185..9838db80b 100644 --- a/src/mme/emm-handler.c +++ b/src/mme/emm-handler.c @@ -121,6 +121,7 @@ int emm_handle_attach_request(mme_ue_t *mme_ue, mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); /* Check TAI */ served_tai_index = mme_find_served_tai(&mme_ue->tai); @@ -538,6 +539,7 @@ int emm_handle_tau_request(mme_ue_t *mme_ue, mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); /* Check TAI */ served_tai_index = mme_find_served_tai(&mme_ue->tai); @@ -655,6 +657,7 @@ int emm_handle_extended_service_request(mme_ue_t *mme_ue, mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); /* Check TAI */ served_tai_index = mme_find_served_tai(&mme_ue->tai); diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index c8fa72430..d407e77e6 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -368,6 +368,7 @@ struct mme_ue_s { uint16_t enb_ostream_id; ogs_eps_tai_t tai; ogs_e_cgi_t e_cgi; + ogs_time_t ue_location_timestamp; ogs_plmn_id_t last_visited_plmn_id; #define SECURITY_CONTEXT_IS_VALID(__mME) \ diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 8f5ff5299..cbbefcd13 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -23,6 +23,9 @@ /* handler for Cancel-Location-Request cb */ static struct disp_hdl *hdl_s6a_clr = NULL; +/* handler for Insert-Subscriber-Data-Request cb */ +static struct disp_hdl *hdl_s6a_idr = NULL; + static struct session_handler *mme_s6a_reg = NULL; struct sess_state { @@ -1541,6 +1544,219 @@ out: return 0; } +/* Callback for incoming Insert-Subscriber-Data-Request messages 29.272 5.2.2.1.2 */ +static int mme_ogs_diam_s6a_idr_cb( struct msg **msg, struct avp *avp, + struct session *session, void *opaque, enum disp_action *act) +{ + int ret; + + mme_ue_t *mme_ue = NULL; + + struct msg *ans, *qry; + ogs_diam_s6a_idr_message_t *idr_message = NULL; + + struct avp_hdr *hdr; + union avp_value val; + + char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; + + uint32_t result_code = 0; + + ogs_assert(msg); + + ogs_diam_s6a_message_t *s6a_message = NULL; + + ogs_debug("Insert-Subscriber-Data-Request"); + + s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); + ogs_assert(s6a_message); + s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA; + idr_message = &s6a_message->idr_message; + ogs_assert(idr_message); + + /* Create answer header */ + qry = *msg; + ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0); + ogs_assert(ret == 0); + ans = *msg; + + ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + + ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data, + ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1); + + mme_ue = mme_ue_find_by_imsi_bcd(imsi_bcd); + + if (!mme_ue) { + ogs_error("Insert Subscriber Data for Unknown IMSI[%s]", imsi_bcd); + result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN; + goto out; + } + + /* AVP: 'Subscription-Data'(1400) + * The Subscription-Data AVP contains the information related to the user + * profile relevant for EPS and GERAN/UTRAN. + * Reference: 3GPP TS 29.272-f70 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_s6a_subscription_data, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + if (hdr->avp_value->os.len) { + ogs_debug("WIP: Process New Subscription Data"); + } else { + ogs_debug("No Sub Data, ok to check IDR Flags"); + } + } + + ret = fd_msg_search_avp(qry, ogs_diam_s6a_idr_flags, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + idr_message->idr_flags = hdr->avp_value->i32; + } else { + ogs_error("Insert Subscriber Data does not contain any IDR Flags for IMSI[%s]", imsi_bcd); + /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_UNABLE_TO_COMPLY", NULL, NULL, 1); + ogs_assert(ret == 0); + goto outnoexp; + } + + if (idr_message->idr_flags & OGS_DIAM_S6A_IDR_FLAGS_EPS_LOCATION_INFO) { + char buf[8]; + + uint8_t ida_ecgi[7]; + uint8_t ida_tai[5]; + ogs_time_t ida_age; + + ogs_nas_plmn_id_t ida_plmn_buf; + char ida_cell_id_hex[9]; + char ida_tac_hex[5]; + + uint32_t ida_cell_id = mme_ue->e_cgi.cell_id; + uint16_t ida_tac = mme_ue->tai.tac; + + sprintf(ida_cell_id_hex, "%08x", ida_cell_id); + memcpy(ida_ecgi, ogs_nas_from_plmn_id(&ida_plmn_buf, &mme_ue->e_cgi.plmn_id), 3); + memcpy(ida_ecgi + 3, OGS_HEX(ida_cell_id_hex,sizeof(ida_cell_id_hex),buf), 5); + + sprintf(ida_tac_hex, "%04x", ida_tac); + memcpy(ida_tai, ogs_nas_from_plmn_id(&ida_plmn_buf, &mme_ue->tai.plmn_id), 3); + memcpy(ida_tai + 3, OGS_HEX(ida_tac_hex,sizeof(ida_tac_hex),buf), 2); + + ida_age = (ogs_time_now() - mme_ue->ue_location_timestamp) / 1000000 / 60; + + struct avp *avp_mme_location_information; + struct avp *avp_e_utran_cell_global_identity; + struct avp *avp_tracking_area_identity; + struct avp *avp_age_of_location_information; + + /* Set the EPS-Location-Information AVP */ + ret = fd_msg_avp_new(ogs_diam_s6a_eps_location_information, 0, &avp); + ogs_assert(ret == 0); + ret = fd_msg_avp_new(ogs_diam_s6a_mme_location_information, 0, &avp_mme_location_information); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_e_utran_cell_global_identity, 0, &avp_e_utran_cell_global_identity); + ogs_assert(ret == 0); + val.os.data = ida_ecgi; + val.os.len = 7; + ret = fd_msg_avp_setvalue(avp_e_utran_cell_global_identity, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_mme_location_information, MSG_BRW_LAST_CHILD, avp_e_utran_cell_global_identity); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_tracking_area_identity, 0, &avp_tracking_area_identity); + ogs_assert(ret == 0); + val.os.data = ida_tai; + val.os.len = 5; + ret = fd_msg_avp_setvalue(avp_tracking_area_identity, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_mme_location_information, MSG_BRW_LAST_CHILD, avp_tracking_area_identity); + ogs_assert(ret == 0); + + ret = fd_msg_avp_new(ogs_diam_s6a_age_of_location_information, 0, &avp_age_of_location_information); + ogs_assert(ret == 0); + val.i32 = ida_age; + ret = fd_msg_avp_setvalue(avp_age_of_location_information, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(avp_mme_location_information, MSG_BRW_LAST_CHILD, avp_age_of_location_information); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, avp_mme_location_information); + ogs_assert(ret == 0); + + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + } else { + ogs_error("Insert Subscriber Data with unsupported IDR Flags for IMSI[%s]", imsi_bcd); + /* Set the Origin-Host, Origin-Realm, and Result-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_UNABLE_TO_COMPLY", NULL, NULL, 1); + ogs_assert(ret == 0); + goto outnoexp; + } + + /* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */ + ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1); + ogs_assert(ret == 0); + + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + ogs_debug("Insert-Subscriber-Data-Answer"); + + /* Add this value to the stats */ + ogs_assert( pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_echoed++; + ogs_assert( pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + return 0; + +out: + ret = ogs_diam_message_experimental_rescode_set(ans, result_code); + ogs_assert(ret == 0); +outnoexp: + /* Set the Auth-Session-State AVP */ + ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp); + ogs_assert(ret == 0); + val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED; + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + ans, OGS_DIAM_S6A_APPLICATION_ID); + ogs_assert(ret == 0); + + /* Send the answer */ + ret = fd_msg_send(msg, NULL, NULL); + ogs_assert(ret == 0); + + return 0; +} + int mme_fd_init(void) { int ret; @@ -1562,6 +1778,12 @@ int mme_fd_init(void) data.command = ogs_diam_s6a_cmd_clr; ret = fd_disp_register(mme_ogs_diam_s6a_clr_cb, DISP_HOW_CC, &data, NULL, &hdl_s6a_clr); + ogs_assert(ret == 0); + + /* Specific handler for Insert-Subscriber-Data-Request */ + data.command = ogs_diam_s6a_cmd_idr; + ret = fd_disp_register(mme_ogs_diam_s6a_idr_cb, DISP_HOW_CC, &data, NULL, + &hdl_s6a_idr); ogs_assert(ret == 0); /* Advertise the support for the application in the peer */ @@ -1584,5 +1806,8 @@ void mme_fd_final(void) if (hdl_s6a_clr) (void) fd_disp_unregister(&hdl_s6a_clr, NULL); + if (hdl_s6a_idr) + (void) fd_disp_unregister(&hdl_s6a_idr, NULL); + ogs_diam_final(); } diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index 5ebc666bb..13fbb1227 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -434,6 +434,8 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) case OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION: mme_s6a_handle_clr(mme_ue, &s6a_message->clr_message); break; + case OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA: + break; default: ogs_error("Invalid Type[%d]", s6a_message->cmd_code); break; diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index 6cce02a4b..683159340 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -511,6 +511,7 @@ void s1ap_handle_uplink_nas_transport( memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); } else { ogs_fatal("No UE Context in UplinkNASTransport"); ogs_assert_if_reached(); @@ -1897,6 +1898,7 @@ void s1ap_handle_path_switch_request( mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); ogs_assert(UESecurityCapabilities); encryptionAlgorithms = @@ -2939,6 +2941,7 @@ void s1ap_handle_handover_notification( mme_ue->enb_ostream_id = target_ue->enb_ostream_id; memcpy(&mme_ue->tai, &target_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &target_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); + mme_ue->ue_location_timestamp = ogs_time_now(); ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(source_ue,