From 3fd7ecc9a23675a96df80d9348d0866ad395928c Mon Sep 17 00:00:00 2001 From: jmasterfunk84 <48972964+jmasterfunk84@users.noreply.github.com> Date: Fri, 13 Jan 2023 18:13:48 -0600 Subject: [PATCH] [MME] Add Purge-UE Capability (#1991) * [MME] Add Purge-UE Capability * Add OGS_GTP_..._PURGE_AND_REMOVE to split CLR case --- lib/diameter/s6a/message.h | 18 ++- lib/gtp/xact.h | 19 +-- src/mme/esm-sm.c | 4 +- src/mme/mme-context.h | 9 +- src/mme/mme-fd-path.c | 284 +++++++++++++++++++++++++++++++++++++ src/mme/mme-fd-path.h | 2 + src/mme/mme-gtp-path.c | 2 +- src/mme/mme-path.c | 2 +- src/mme/mme-s11-handler.c | 14 ++ src/mme/mme-s6a-handler.c | 27 ++++ src/mme/mme-s6a-handler.h | 2 + src/mme/mme-sm.c | 5 +- src/mme/nas-path.c | 2 +- src/mme/s1ap-handler.c | 8 ++ 14 files changed, 372 insertions(+), 26 deletions(-) diff --git a/lib/diameter/s6a/message.h b/lib/diameter/s6a/message.h index a347365d3..6708282e3 100644 --- a/lib/diameter/s6a/message.h +++ b/lib/diameter/s6a/message.h @@ -59,9 +59,6 @@ extern "C" { #define OGS_DIAM_S6A_ULR_INITIAL_ATTACH_IND (1 << 5) #define OGS_DIAM_S6A_ULR_PS_LCS_SUPPORTED_BY_UE (1 << 6) -#define OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI (1) -#define OGS_DIAM_S6A_PUA_FLAGS_FREEZE_PTMSI (1 << 1) - #define OGS_DIAM_S6A_UE_SRVCC_NOT_SUPPORTED (0) #define OGS_DIAM_S6A_UE_SRVCC_SUPPORTED (1) @@ -169,15 +166,21 @@ typedef struct ogs_diam_s6a_aia_message_s { } ogs_diam_s6a_aia_message_t; typedef struct ogs_diam_s6a_ula_message_s { -#define OGS_DIAM_S6A_ULA_FLAGS_SEPARATION_INDICATION (0) -#define OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS (1) +#define OGS_DIAM_S6A_ULA_FLAGS_SEPARATION_INDICATION (0) +#define OGS_DIAM_S6A_ULA_FLAGS_MME_REGISTERED_FOR_SMS (1) uint32_t ula_flags; ogs_subscription_data_t subscription_data; } ogs_diam_s6a_ula_message_t; +typedef struct ogs_diam_s6a_pua_message_s { +#define OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI (1) +#define OGS_DIAM_S6A_PUA_FLAGS_FREEZE_PTMSI (1 << 1) + uint32_t pua_flags; +} ogs_diam_s6a_pua_message_t; + typedef struct ogs_diam_s6a_clr_message_s { -#define OGS_DIAM_S6A_CLR_FLAGS_S6A_S6D_INDICATOR (1) -#define OGS_DIAM_S6A_CLR_FLAGS_REATTACH_REQUIRED (1 << 1) +#define OGS_DIAM_S6A_CLR_FLAGS_S6A_S6D_INDICATOR (1) +#define OGS_DIAM_S6A_CLR_FLAGS_REATTACH_REQUIRED (1 << 1) uint32_t clr_flags; uint32_t cancellation_type; } ogs_diam_s6a_clr_message_t; @@ -221,6 +224,7 @@ typedef struct ogs_diam_s6a_message_s { ogs_diam_s6a_clr_message_t clr_message; ogs_diam_s6a_aia_message_t aia_message; ogs_diam_s6a_ula_message_t ula_message; + ogs_diam_s6a_pua_message_t pua_message; } ogs_diam_s6a_message_t; int ogs_diam_s6a_init(void); diff --git a/lib/gtp/xact.h b/lib/gtp/xact.h index 91c840f2c..01b4c43be 100644 --- a/lib/gtp/xact.h +++ b/lib/gtp/xact.h @@ -96,15 +96,16 @@ typedef struct ogs_gtp_xact_s { #define OGS_GTP_MODIFY_QOS_UPDATE ((uint64_t)1<<1) uint64_t update_flags; -#define OGS_GTP_DELETE_NO_ACTION 1 -#define OGS_GTP_DELETE_SEND_AUTHENTICATION_REQUEST 2 -#define OGS_GTP_DELETE_SEND_DETACH_ACCEPT 3 -#define OGS_GTP_DELETE_SEND_DEACTIVATE_BEARER_CONTEXT_REQUEST 4 -#define OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_REMOVE 5 -#define OGS_GTP_DELETE_SEND_RELEASE_WITH_S1_REMOVE_AND_UNLINK 6 -#define OGS_GTP_DELETE_HANDLE_PDN_CONNECTIVITY_REQUEST 7 -#define OGS_GTP_DELETE_UE_CONTEXT_REMOVE_PARTIAL 8 -#define OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST 9 +#define OGS_GTP_DELETE_NO_ACTION 1 +#define OGS_GTP_DELETE_SEND_AUTHENTICATION_REQUEST 2 +#define OGS_GTP_DELETE_SEND_DETACH_ACCEPT 3 +#define OGS_GTP_DELETE_SEND_DEACTIVATE_BEARER_CONTEXT_REQUEST 4 +#define OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_REMOVE 5 +#define OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_PURGE_AND_REMOVE 6 +#define OGS_GTP_DELETE_SEND_RELEASE_WITH_S1_REMOVE_AND_UNLINK 7 +#define OGS_GTP_DELETE_HANDLE_PDN_CONNECTIVITY_REQUEST 8 +#define OGS_GTP_DELETE_UE_CONTEXT_REMOVE_PARTIAL 9 +#define OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST 10 int delete_action; diff --git a/src/mme/esm-sm.c b/src/mme/esm-sm.c index 4cb31ac89..642c04df4 100644 --- a/src/mme/esm-sm.c +++ b/src/mme/esm-sm.c @@ -145,7 +145,7 @@ void esm_state_inactive(ogs_fsm_t *s, mme_event_t *e) ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(mme_ue->enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, - S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); OGS_FSM_TRAN(s, &esm_state_exception); break; } @@ -160,7 +160,7 @@ void esm_state_inactive(ogs_fsm_t *s, mme_event_t *e) ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(mme_ue->enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, - S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); OGS_FSM_TRAN(s, &esm_state_exception); break; } diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 55205e34b..ff6977f4b 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -262,10 +262,11 @@ struct enb_ue_s { #define S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE 1 #define S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK 2 #define S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE 3 -#define S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE 4 -#define S1AP_UE_CTX_REL_S1_HANDOVER_CANCEL 5 -#define S1AP_UE_CTX_REL_S1_HANDOVER_FAILURE 6 -#define S1AP_UE_CTX_REL_S1_PAGING 7 +#define S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE 4 +#define S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE 5 +#define S1AP_UE_CTX_REL_S1_HANDOVER_CANCEL 6 +#define S1AP_UE_CTX_REL_S1_HANDOVER_FAILURE 7 +#define S1AP_UE_CTX_REL_S1_PAGING 8 uint8_t ue_ctx_rel_action; bool part_of_s1_reset_requested; diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 2e74668f4..0d11d4f70 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -40,6 +40,7 @@ struct sess_state { static void mme_s6a_aia_cb(void *data, struct msg **msg); static void mme_s6a_ula_cb(void *data, struct msg **msg); +static void mme_s6a_pua_cb(void *data, struct msg **msg); static void state_cleanup(struct sess_state *sess_data, os0_t sid, void *opaque) { @@ -1218,6 +1219,98 @@ void mme_s6a_send_ulr(mme_ue_t *mme_ue) ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); } +/* MME Sends Purge UE Request to HSS */ +void mme_s6a_send_pur(mme_ue_t *mme_ue) +{ + int ret; + + struct msg *req = NULL; + struct avp *avp; + union avp_value val; + struct sess_state *sess_data = NULL, *svg; + struct session *session = NULL; + + ogs_assert(mme_ue); + + ogs_debug("[MME] Purge-UE-Request"); + + /* Create the random value to store with the session */ + sess_data = ogs_calloc(1, sizeof(*sess_data)); + ogs_assert(sess_data); + sess_data->mme_ue = mme_ue; + + /* Create the request */ + ret = fd_msg_new(ogs_diam_s6a_cmd_pur, MSGFL_ALLOC_ETEID, &req); + ogs_assert(ret == 0); + + /* Create a new session */ + #define OGS_DIAM_S6A_APP_SID_OPT "app_s6a" + ret = fd_msg_new_session(req, (os0_t)OGS_DIAM_S6A_APP_SID_OPT, + CONSTSTRLEN(OGS_DIAM_S6A_APP_SID_OPT)); + ogs_assert(ret == 0); + ret = fd_msg_sess_get(fd_g_config->cnf_dict, req, &session, NULL); + 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(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Origin-Host & Origin-Realm */ + ret = fd_msg_add_origin(req, 0); + ogs_assert(ret == 0); + + /* Set the Destination-Realm AVP */ + ret = fd_msg_avp_new(ogs_diam_destination_realm, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (unsigned char *)(fd_g_config->cnf_diamrlm); + val.os.len = strlen(fd_g_config->cnf_diamrlm); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set the User-Name AVP */ + ret = fd_msg_avp_new(ogs_diam_user_name, 0, &avp); + ogs_assert(ret == 0); + val.os.data = (uint8_t *)mme_ue->imsi_bcd; + val.os.len = strlen(mme_ue->imsi_bcd); + ret = fd_msg_avp_setvalue(avp, &val); + ogs_assert(ret == 0); + ret = fd_msg_avp_add(req, MSG_BRW_LAST_CHILD, avp); + ogs_assert(ret == 0); + + /* Set Vendor-Specific-Application-Id AVP */ + ret = ogs_diam_message_vendor_specific_appid_set( + req, OGS_DIAM_S6A_APPLICATION_ID); + ogs_assert(ret == 0); + + ret = clock_gettime(CLOCK_REALTIME, &sess_data->ts); + ogs_assert(ret == 0); + + /* Keep a pointer to the session data for debug purpose, + * in real life we would not need it */ + svg = sess_data; + + /* Store this value in the session */ + ret = fd_sess_state_store(mme_s6a_reg, session, &sess_data); + ogs_assert(ret == 0); + ogs_assert(sess_data == 0); + + /* Send the request */ + ret = fd_msg_send(&req, mme_s6a_pua_cb, svg); + ogs_assert(ret == 0); + + /* Increment the counter */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + ogs_diam_logger_self()->stats.nb_sent++; + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); +} + /* MME received Update Location Answer from HSS */ static void mme_s6a_ula_cb(void *data, struct msg **msg) { @@ -1456,6 +1549,197 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) return; } +/* MME received Purge UE Answer from HSS */ +static void mme_s6a_pua_cb(void *data, struct msg **msg) +{ + int ret; + + struct sess_state *sess_data = NULL; + struct timespec ts; + struct session *session; + struct avp *avp, *avpch; + struct avp_hdr *hdr; + unsigned long dur; + int error = 0; + int new; + + mme_event_t *e = NULL; + mme_ue_t *mme_ue = NULL; + ogs_diam_s6a_message_t *s6a_message = NULL; + ogs_diam_s6a_pua_message_t *pua_message = NULL; + + ogs_debug("[MME] Purge-UE-Answer"); + + ret = clock_gettime(CLOCK_REALTIME, &ts); + ogs_assert(ret == 0); + + /* Search the session, retrieve its data */ + ret = fd_msg_sess_get(fd_g_config->cnf_dict, *msg, &session, &new); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(new == 0); + + ret = fd_sess_state_retrieve(mme_s6a_reg, session, &sess_data); + ogs_expect_or_return(ret == 0); + ogs_expect_or_return(sess_data); + ogs_expect_or_return((void *)sess_data == data); + + mme_ue = sess_data->mme_ue; + ogs_assert(mme_ue); + + /* Set Purge-UE Command */ + s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); + ogs_assert(s6a_message); + s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_PURGE_UE; + pua_message = &s6a_message->pua_message; + ogs_assert(pua_message); + + /* AVP: 'Result-Code'(268) + * The Result-Code AVP indicates whether a particular request was completed + * successfully or whether an error occurred. The Result-Code data field + * contains an IANA-managed 32-bit address space representing errors. + * Reference: RFC 6733 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_result_code, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + s6a_message->result_code = hdr->avp_value->i32; + s6a_message->err = &s6a_message->result_code; + ogs_debug(" Result Code: %d", hdr->avp_value->i32); + } else { + ret = fd_msg_search_avp(*msg, ogs_diam_experimental_result, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_avp_search_avp(avp, + ogs_diam_experimental_result_code, &avpch); + ogs_assert(ret == 0); + if (avpch) { + ret = fd_msg_avp_hdr(avpch, &hdr); + ogs_assert(ret == 0); + s6a_message->result_code = hdr->avp_value->i32; + s6a_message->exp_err = &s6a_message->result_code; + ogs_debug(" Experimental Result Code: %d", + s6a_message->result_code); + } + } else { + ogs_error("no Result-Code"); + error++; + } + } + + /* AVP: 'Origin-Host'(264) + * The Origin-Host AVP identifies the endpoint that originated the Diameter + * message. Relay agents MUST NOT modify this AVP. The value of the + * Origin-Host AVP is guaranteed to be unique within a single host. + * Reference: RFC 6733 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_host, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug(" From '%.*s'", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Host"); + error++; + } + + /* AVP: 'Origin-Realm'(296) + * This AVP contains the Realm of the originator of any Diameter message + * and MUST be present in all messages. This AVP SHOULD be placed as close + * to the Diameter header as possible. + * Reference: RFC 6733 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_origin_realm, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + ogs_debug(" ('%.*s')", + (int)hdr->avp_value->os.len, hdr->avp_value->os.data); + } else { + ogs_error("no_Origin-Realm"); + error++; + } + + /* AVP: 'PUA-Flags'(1406) + * The PUA-Flags AVP contains a bit mask, whose meanings are defined in + * table in 29.272 7.3.8/1. + * Reference: 3GPP TS 29.272-f70 + */ + ret = fd_msg_search_avp(*msg, ogs_diam_s6a_pua_flags, &avp); + ogs_assert(ret == 0); + if (avp) { + ret = fd_msg_avp_hdr(avp, &hdr); + ogs_assert(ret == 0); + pua_message->pua_flags = hdr->avp_value->i32; + } + + if (!error) { + int rv; + e = mme_event_new(MME_EVENT_S6A_MESSAGE); + ogs_assert(e); + e->mme_ue = mme_ue; + e->s6a_message = s6a_message; + rv = ogs_queue_push(ogs_app()->queue, e); + if (rv != OGS_OK) { + ogs_error("ogs_queue_push() failed:%d", (int)rv); + ogs_free(s6a_message); + mme_event_free(e); + } else { + ogs_pollset_notify(ogs_app()->pollset); + } + } else { + ogs_free(s6a_message); + } + + /* Free the message */ + ogs_assert(pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0); + dur = ((ts.tv_sec - sess_data->ts.tv_sec) * 1000000) + + ((ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + if (ogs_diam_logger_self()->stats.nb_recv) { + /* Ponderate in the avg */ + ogs_diam_logger_self()->stats.avg = + (ogs_diam_logger_self()->stats.avg * + ogs_diam_logger_self()->stats.nb_recv + dur) / + (ogs_diam_logger_self()->stats.nb_recv + 1); + /* Min, max */ + if (dur < ogs_diam_logger_self()->stats.shortest) + ogs_diam_logger_self()->stats.shortest = dur; + if (dur > ogs_diam_logger_self()->stats.longest) + ogs_diam_logger_self()->stats.longest = dur; + } else { + ogs_diam_logger_self()->stats.shortest = dur; + ogs_diam_logger_self()->stats.longest = dur; + ogs_diam_logger_self()->stats.avg = dur; + } + if (error) + ogs_diam_logger_self()->stats.nb_errs++; + else + ogs_diam_logger_self()->stats.nb_recv++; + + ogs_assert(pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0); + + /* Display how long it took */ + if (ts.tv_nsec > sess_data->ts.tv_nsec) + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec - sess_data->ts.tv_sec), + (long)(ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + else + ogs_trace("in %d.%06ld sec", + (int)(ts.tv_sec + 1 - sess_data->ts.tv_sec), + (long)(1000000000 + ts.tv_nsec - sess_data->ts.tv_nsec) / 1000); + + ret = fd_msg_free(*msg); + ogs_assert(ret == 0); + *msg = NULL; + + state_cleanup(sess_data, NULL, NULL); + return; +} + /* Callback for incoming Cancel-Location-Request messages */ static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, struct session *session, void *opaque, enum disp_action *act) diff --git a/src/mme/mme-fd-path.h b/src/mme/mme-fd-path.h index a746ffd3e..4b455afcc 100644 --- a/src/mme/mme-fd-path.h +++ b/src/mme/mme-fd-path.h @@ -35,6 +35,8 @@ void mme_s6a_send_air(mme_ue_t *mme_ue, *authentication_failure_parameter); /* MME Sends Update Location Request to HSS */ void mme_s6a_send_ulr(mme_ue_t *mme_ue); +/* MME Sends Purge UE Request to HSS */ +void mme_s6a_send_pur(mme_ue_t *mme_ue); #ifdef __cplusplus } diff --git a/src/mme/mme-gtp-path.c b/src/mme/mme-gtp-path.c index 1d601d9e9..9e6156371 100644 --- a/src/mme/mme-gtp-path.c +++ b/src/mme/mme-gtp-path.c @@ -134,7 +134,7 @@ static void timeout(ogs_gtp_xact_t *xact, void *data) ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, - S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); } else { ogs_warn("No S1 Context"); } diff --git a/src/mme/mme-path.c b/src/mme/mme-path.c index ea305769f..e0e88eba1 100644 --- a/src/mme/mme-path.c +++ b/src/mme/mme-path.c @@ -98,7 +98,7 @@ void mme_send_delete_session_or_mme_ue_context_release(mme_ue_t *mme_ue) if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue)) { mme_gtp_send_delete_all_sessions(mme_ue, - OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_REMOVE); + OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_PURGE_AND_REMOVE); } else { enb_ue_t *enb_ue = enb_ue_cycle(mme_ue->enb_ue); if (enb_ue) { diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 9b53cb50a..b191dccac 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -634,6 +634,20 @@ void mme_s11_handle_delete_session_response( } } + } else if (action == + OGS_GTP_DELETE_SEND_RELEASE_WITH_UE_CONTEXT_PURGE_AND_REMOVE) { + if (mme_sess_count(mme_ue) == 1) /* Last Session */ { + if (ECM_IDLE(mme_ue)) { + mme_s6a_send_pur(mme_ue); + } else { + ogs_assert(mme_ue->enb_ue); + ogs_assert(OGS_OK == + s1ap_send_ue_context_release_command(mme_ue->enb_ue, + S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); + } + } + } else if (action == OGS_GTP_DELETE_SEND_RELEASE_WITH_S1_REMOVE_AND_UNLINK) { if (mme_sess_count(mme_ue) == 1) /* Last Session */ { diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 5285d8d83..8147d04a4 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -126,6 +126,33 @@ uint8_t mme_s6a_handle_ula( return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED; } +uint8_t mme_s6a_handle_pua( + mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) +{ + ogs_diam_s6a_pua_message_t *pua_message = NULL; + + ogs_assert(mme_ue); + ogs_assert(s6a_message); + pua_message = &s6a_message->pua_message; + ogs_assert(pua_message); + + if (s6a_message->result_code != ER_DIAMETER_SUCCESS) { + ogs_error("Purge UE failed for IMSI[%s] [%d]", mme_ue->imsi_bcd, + s6a_message->result_code); + mme_ue_hash_remove(mme_ue); + mme_ue_remove(mme_ue); + return OGS_ERROR; + } + + if (pua_message->pua_flags & OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI) + ogs_debug("Freeze M-TMSI requested but not implemented."); + + mme_ue_hash_remove(mme_ue); + mme_ue_remove(mme_ue); + + return OGS_OK; +} + uint8_t mme_s6a_handle_idr( mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) { diff --git a/src/mme/mme-s6a-handler.h b/src/mme/mme-s6a-handler.h index 3cf0a3463..703be9ddb 100644 --- a/src/mme/mme-s6a-handler.h +++ b/src/mme/mme-s6a-handler.h @@ -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_pua( + 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( diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index c725a4dfd..6e631a034 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -436,9 +436,12 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, - S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); } break; + case OGS_DIAM_S6A_CMD_CODE_PURGE_UE: + mme_s6a_handle_pua(mme_ue, s6a_message); + break; case OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION: mme_s6a_handle_clr(mme_ue, s6a_message); break; diff --git a/src/mme/nas-path.c b/src/mme/nas-path.c index 5989f2822..6ffb35e66 100644 --- a/src/mme/nas-path.c +++ b/src/mme/nas-path.c @@ -346,7 +346,7 @@ int nas_eps_send_pdn_connectivity_reject( ogs_assert(OGS_OK == s1ap_send_ue_context_release_command(mme_ue->enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, - S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); + S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE, 0)); } } else { esmbuf = esm_build_pdn_connectivity_reject( diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index 0eaa3d1dd..48990b08b 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -22,6 +22,7 @@ #include "s1ap-path.h" #include "nas-path.h" +#include "mme-fd-path.h" #include "mme-gtp-path.h" #include "sgsap-types.h" #include "sgsap-path.h" @@ -1487,6 +1488,13 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) mme_ue_hash_remove(mme_ue); mme_ue_remove(mme_ue); break; + case S1AP_UE_CTX_REL_UE_CONTEXT_PURGE_AND_REMOVE: + ogs_debug(" Action: UE context remove"); + enb_ue_remove(enb_ue); + ogs_expect_or_return(mme_ue); + + mme_s6a_send_pur(mme_ue); + break; case S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE: ogs_debug(" Action: S1 handover complete");