From 5c3f10aa0eb4633db7ed1f032f3c57de1d5814b9 Mon Sep 17 00:00:00 2001 From: jmasterfunk84 <48972964+jmasterfunk84@users.noreply.github.com> Date: Wed, 18 Jan 2023 20:39:27 -0600 Subject: [PATCH] [MME] Introduce aging timers * Creating three new timers * mirroring work done by gstaa on the AMF * Implicit detach procedures added * Fix for detach from unknown UE --- configs/open5gs/mme.yaml.in | 13 ++++-- lib/app/ogs-context.c | 6 +++ src/mme/emm-sm.c | 84 ++++++++++++++++++++++++++++++++++++- src/mme/mme-context.c | 79 ++++++++++++++++++++++++++++++++++ src/mme/mme-context.h | 7 +++- src/mme/mme-path.c | 49 ++++++++++++++++++++-- src/mme/mme-path.h | 2 + src/mme/mme-s11-handler.c | 32 ++++++++++++-- src/mme/mme-s6a-handler.c | 2 +- src/mme/mme-sm.c | 3 ++ src/mme/mme-timer.c | 18 ++++++++ src/mme/mme-timer.h | 8 ++++ src/mme/s1ap-handler.c | 16 ++++++- src/mme/s1ap-path.c | 2 + src/mme/sgsap-handler.c | 17 ++++++-- 15 files changed, 317 insertions(+), 21 deletions(-) diff --git a/configs/open5gs/mme.yaml.in b/configs/open5gs/mme.yaml.in index 722648dd6..0dd137f7f 100644 --- a/configs/open5gs/mme.yaml.in +++ b/configs/open5gs/mme.yaml.in @@ -432,10 +432,15 @@ usrsctp: # # o Timers of EPS mobility/session management # t3402: -# value: 720 # 12 minutes * 60 = 720 seconds +# value: 720 # 12 minutes * 60 = 720 seconds # t3412: -# value: 3240 # 54 minutes * 60 = 3240 seconds +# value: 3240 # 54 minutes * 60 = 3240 seconds # t3423: -# value: 720 # 12 minutes * 60 = 720 seconds -# +# value: 720 # 12 minutes * 60 = 720 seconds +# mobile_reachable: +# value: 3480 # 54 minutes * 60 + 240 = 3480 seconds +# implicit_detach: +# value: 240 # 4 minutes * 60 = 240 seconds +# purge_ue: +# value: 86400 # 24 hours * 60 minutes * 60 = 86400 seconds time: diff --git a/lib/app/ogs-context.c b/lib/app/ogs-context.c index f315df558..87e4abe2f 100644 --- a/lib/app/ogs-context.c +++ b/lib/app/ogs-context.c @@ -525,6 +525,12 @@ int ogs_app_context_parse_config(void) /* handle config in mme */ } else if (!strcmp(time_key, "t3423")) { /* handle config in mme */ + } else if (!strcmp(time_key, "mobile_reachable")) { + /* handle config in mme */ + } else if (!strcmp(time_key, "implicit_detach")) { + /* handle config in mme */ + } else if (!strcmp(time_key, "purge_ue")) { + /* handle config in mme */ } else ogs_warn("unknown key `%s`", time_key); } diff --git a/src/mme/emm-sm.c b/src/mme/emm-sm.c index 4a5f70a10..a58efe6da 100644 --- a/src/mme/emm-sm.c +++ b/src/mme/emm-sm.c @@ -61,6 +61,8 @@ void emm_state_de_registered(ogs_fsm_t *s, mme_event_t *e) ogs_assert(e); + mme_sm_debug(e); + mme_ue = e->mme_ue; ogs_assert(mme_ue); @@ -68,6 +70,13 @@ void emm_state_de_registered(ogs_fsm_t *s, mme_event_t *e) case OGS_FSM_ENTRY_SIG: CLEAR_SERVICE_INDICATOR(mme_ue); CLEAR_MME_UE_ALL_TIMERS(mme_ue); + + if (mme_self()->time.purge_ue.value > 0) { + ogs_debug("DB Purge Timer started for IMSI[%s]", mme_ue->imsi_bcd); + ogs_timer_start(mme_ue->t_purge_ue.timer, + ogs_time_from_sec(mme_self()->time.purge_ue.value)); + } + break; case OGS_FSM_EXIT_SIG: break; @@ -96,6 +105,17 @@ void emm_state_de_registered(ogs_fsm_t *s, mme_event_t *e) } break; + case MME_TIMER_PURGE_UE: + ogs_info("[%s] Purge Timer expired, removing UE", mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); + if (mme_ue->location_updated_but_not_canceled_yet == true) { + mme_s6a_send_pur(mme_ue); + } else { + mme_ue_hash_remove(mme_ue); + mme_ue_remove(mme_ue); + } + break; + default: ogs_error("Unknown timer[%s:%d]", mme_timer_get_name(e->timer_id), e->timer_id); @@ -114,11 +134,14 @@ void emm_state_registered(ogs_fsm_t *s, mme_event_t *e) ogs_assert(e); + mme_sm_debug(e); + mme_ue = e->mme_ue; ogs_assert(mme_ue); switch (e->id) { case OGS_FSM_ENTRY_SIG: + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); break; case OGS_FSM_EXIT_SIG: break; @@ -186,6 +209,39 @@ void emm_state_registered(ogs_fsm_t *s, mme_event_t *e) } break; + case MME_TIMER_MOBILE_REACHABLE: + ogs_info("[%s] Mobile Reachable timer expired", mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_mobile_reachable); + /* TS 24.301 5.3.5 + * Upon expiry of the mobile reachable timer the network shall + * start the implicit detach timer. + */ + if (mme_self()->time.implicit_detach.value > 0) { + ogs_debug("[%s] Starting Implicit Detach timer", + mme_ue->imsi_bcd); + ogs_timer_start(mme_ue->t_implicit_detach.timer, + ogs_time_from_sec(mme_self()->time.implicit_detach.value)); + } + break; + + case MME_TIMER_IMPLICIT_DETACH: + ogs_info("[%s] Implicit Detach timer expired, detaching UE", + mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_implicit_detach); + /* TS 24.301 5.3.5 + * If the implicit detach timer expires before the UE contacts + * the network, the network shall implicitly detach the UE. + */ + mme_ue->detach_type = MME_DETACH_TYPE_MME_IMPLICIT; + if (MME_P_TMSI_IS_AVAILABLE(mme_ue)) { + ogs_assert(OGS_OK == sgsap_send_detach_indication(mme_ue)); + } else { + mme_send_delete_session_or_detach(mme_ue); + } + + OGS_FSM_TRAN(s, &emm_state_de_registered); + break; + default: ogs_error("Unknown timer[%s:%d]", mme_timer_get_name(e->timer_id), e->timer_id); @@ -205,9 +261,11 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e) enb_ue_t *enb_ue = NULL; ogs_nas_eps_message_t *message = NULL; ogs_nas_security_header_type_t h; - + ogs_assert(e); - + + mme_sm_debug(e); + mme_ue = e->mme_ue; ogs_assert(mme_ue); @@ -632,6 +690,24 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e) break; } + if (!MME_UE_HAVE_IMSI(mme_ue)) { + ogs_warn("Detach request : Unknown UE"); + ogs_assert(OGS_OK == + nas_eps_send_service_reject(mme_ue, + OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK)); + OGS_FSM_TRAN(s, &emm_state_exception); + break; + } + + if (!SECURITY_CONTEXT_IS_VALID(mme_ue)) { + ogs_warn("No Security Context : IMSI[%s]", mme_ue->imsi_bcd); + ogs_assert(OGS_OK == + nas_eps_send_service_reject(mme_ue, + OGS_NAS_EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK)); + OGS_FSM_TRAN(s, &emm_state_exception); + break; + } + if (MME_P_TMSI_IS_AVAILABLE(mme_ue)) { ogs_assert(OGS_OK == sgsap_send_detach_indication(mme_ue)); } else { @@ -714,6 +790,7 @@ void emm_state_authentication(ogs_fsm_t *s, mme_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); break; case OGS_FSM_EXIT_SIG: break; @@ -883,6 +960,7 @@ void emm_state_security_mode(ogs_fsm_t *s, mme_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: CLEAR_MME_UE_TIMER(mme_ue->t3460); + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); ogs_assert(OGS_OK == nas_eps_send_security_mode_command(mme_ue)); break; @@ -1060,6 +1138,7 @@ void emm_state_initial_context_setup(ogs_fsm_t *s, mme_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); break; case OGS_FSM_EXIT_SIG: break; @@ -1272,6 +1351,7 @@ void emm_state_exception(ogs_fsm_t *s, mme_event_t *e) case OGS_FSM_ENTRY_SIG: CLEAR_SERVICE_INDICATOR(mme_ue); CLEAR_MME_UE_ALL_TIMERS(mme_ue); + CLEAR_MME_UE_TIMER(mme_ue->t_purge_ue); break; case OGS_FSM_EXIT_SIG: break; diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 090d5bcda..292a11808 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -173,6 +173,10 @@ static int mme_context_prepare(void) self.diam_config->cnf_port = DIAMETER_PORT; self.diam_config->cnf_port_tls = DIAMETER_SECURE_PORT; + self.time.mobile_reachable.value = (54 * 60) + 240; + self.time.implicit_detach.value = 4 * 60; + self.time.purge_ue.value = 60 * 60 * 24; + return OGS_OK; } @@ -1615,6 +1619,54 @@ int mme_context_parse_config() } else ogs_warn("unknown key `%s`", t3423_key); } + } else if (!strcmp(time_key, "mobile_reachable")) { + ogs_yaml_iter_t mobile_reachable_iter; + ogs_yaml_iter_recurse(&time_iter, &mobile_reachable_iter); + + while (ogs_yaml_iter_next(&mobile_reachable_iter)) { + const char *mobile_reachable_key = + ogs_yaml_iter_key(&mobile_reachable_iter); + ogs_assert(mobile_reachable_key); + + if (!strcmp(mobile_reachable_key, "value")) { + const char *v = ogs_yaml_iter_value(&mobile_reachable_iter); + if (v) + self.time.mobile_reachable.value = atoll(v); + } else + ogs_warn("unknown key `%s`", mobile_reachable_key); + } + } else if (!strcmp(time_key, "implicit_detach")) { + ogs_yaml_iter_t implicit_detach_iter; + ogs_yaml_iter_recurse(&time_iter, &implicit_detach_iter); + + while (ogs_yaml_iter_next(&implicit_detach_iter)) { + const char *implicit_detach_key = + ogs_yaml_iter_key(&implicit_detach_iter); + ogs_assert(implicit_detach_key); + + if (!strcmp(implicit_detach_key, "value")) { + const char *v = ogs_yaml_iter_value(&implicit_detach_iter); + if (v) + self.time.implicit_detach.value = atoll(v); + } else + ogs_warn("unknown key `%s`", implicit_detach_key); + } + } else if (!strcmp(time_key, "purge_ue")) { + ogs_yaml_iter_t purge_ue_iter; + ogs_yaml_iter_recurse(&time_iter, &purge_ue_iter); + + while (ogs_yaml_iter_next(&purge_ue_iter)) { + const char *purge_ue_key = + ogs_yaml_iter_key(&purge_ue_iter); + ogs_assert(purge_ue_key); + + if (!strcmp(purge_ue_key, "value")) { + const char *v = ogs_yaml_iter_value(&purge_ue_iter); + if (v) + self.time.purge_ue.value = atoll(v); + } else + ogs_warn("unknown key `%s`", purge_ue_key); + } } else if (!strcmp(time_key, "t3512")) { /* handle config in amf */ } else if (!strcmp(time_key, "nf_instance")) { @@ -2402,6 +2454,30 @@ mme_ue_t *mme_ue_add(enb_ue_t *enb_ue) return NULL; } mme_ue->t3470.pkbuf = NULL; + mme_ue->t_mobile_reachable.timer = ogs_timer_add( + ogs_app()->timer_mgr, mme_timer_mobile_reachable_expire, mme_ue); + if (!mme_ue->t_mobile_reachable.timer) { + ogs_error("ogs_timer_add() failed"); + ogs_pool_free(&mme_ue_pool, mme_ue); + return NULL; + } + mme_ue->t_mobile_reachable.pkbuf = NULL; + mme_ue->t_implicit_detach.timer = ogs_timer_add( + ogs_app()->timer_mgr, mme_timer_implicit_detach_expire, mme_ue); + if (!mme_ue->t_implicit_detach.timer) { + ogs_error("ogs_timer_add() failed"); + ogs_pool_free(&mme_ue_pool, mme_ue); + return NULL; + } + mme_ue->t_implicit_detach.pkbuf = NULL; + mme_ue->t_purge_ue.timer = ogs_timer_add( + ogs_app()->timer_mgr, mme_timer_purge_ue_expire, mme_ue); + if (!mme_ue->t_purge_ue.timer) { + ogs_error("ogs_timer_add() failed"); + ogs_pool_free(&mme_ue_pool, mme_ue); + return NULL; + } + mme_ue->t_purge_ue.pkbuf = NULL; mme_ebi_pool_init(mme_ue); @@ -2493,6 +2569,9 @@ void mme_ue_remove(mme_ue_t *mme_ue) ogs_timer_delete(mme_ue->t3450.timer); ogs_timer_delete(mme_ue->t3460.timer); ogs_timer_delete(mme_ue->t3470.timer); + ogs_timer_delete(mme_ue->t_mobile_reachable.timer); + ogs_timer_delete(mme_ue->t_implicit_detach.timer); + ogs_timer_delete(mme_ue->t_purge_ue.timer); enb_ue_unlink(mme_ue); diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 8e98e8413..78a23d735 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -149,7 +149,7 @@ typedef struct mme_context_s { struct { struct { ogs_time_t value; /* Timer Value(Seconds) */ - } t3402, t3412, t3423; + } t3402, t3412, t3423, mobile_reachable, implicit_detach, purge_ue; } time; } mme_context_t; @@ -517,6 +517,8 @@ struct mme_ue_s { CLEAR_MME_UE_TIMER((__mME)->t3450); \ CLEAR_MME_UE_TIMER((__mME)->t3460); \ CLEAR_MME_UE_TIMER((__mME)->t3470); \ + CLEAR_MME_UE_TIMER((__mME)->t_mobile_reachable); \ + CLEAR_MME_UE_TIMER((__mME)->t_implicit_detach); \ \ ogs_list_for_each(&mme_ue->sess_list, sess) { \ ogs_list_for_each(&sess->bearer_list, bearer) { \ @@ -537,7 +539,8 @@ struct mme_ue_s { ogs_pkbuf_t *pkbuf; ogs_timer_t *timer; uint32_t retry_count;; - } t3413, t3422, t3450, t3460, t3470; + } t3413, t3422, t3450, t3460, t3470, t_mobile_reachable, + t_implicit_detach, t_purge_ue; #define CLEAR_SERVICE_INDICATOR(__mME) \ do { \ diff --git a/src/mme/mme-path.c b/src/mme/mme-path.c index ea305769f..0950097fe 100644 --- a/src/mme/mme-path.c +++ b/src/mme/mme-path.c @@ -58,10 +58,30 @@ void mme_send_delete_session_or_detach(mme_ue_t *mme_ue) } break; - /* MME Implicit Detach, ie: Lost Communication */ + /* MME Implicit Detach, ie: Lost Communication + * TS23.401 - V16.10.0 + * Ch 5.3.8.3 MME-initiated Detach procedure (Without Step 1) + */ case MME_DETACH_TYPE_MME_IMPLICIT: - ogs_fatal("Not Implemented : MME_DETACH_TYPE_MME_IMPLICIT"); - ogs_assert_if_reached(); + ogs_debug("Implicit MME Detach"); + if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue)) { + if (ECM_IDLE(mme_ue)) { + mme_gtp_send_delete_all_sessions(mme_ue, + OGS_GTP_DELETE_NO_ACTION); + } else { + mme_gtp_send_delete_all_sessions(mme_ue, + OGS_GTP_DELETE_SEND_RELEASE_WITH_S1_REMOVE_AND_UNLINK); + } + } else { + enb_ue_t *enb_ue = enb_ue_cycle(mme_ue->enb_ue); + if (enb_ue) { + ogs_assert(OGS_OK == + s1ap_send_ue_context_release_command(enb_ue, + S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, + S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK, 0)); + } else + ogs_error("ENB-S1 Context has already been removed"); + } break; /* HSS Implicit Detach, ie: MME-UPDATE-PROCEDURE @@ -256,3 +276,26 @@ cleanup: CLEAR_SERVICE_INDICATOR(mme_ue); MME_CLEAR_PAGING_INFO(mme_ue); } + +int mme_s1ap_page_if_attached(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain) +{ + if (ogs_timer_running(mme_ue->t_implicit_detach.timer)) { + /* + * TS 24.301 5.3.7 + * If ISR is not activated, the network behaviour upon expiry of the + * mobile reachable timer is network dependent, but typically the + * network stops sending paging messages to the UE on the first + * expiry, and may take other appropriate actions + */ + ogs_debug("[%s] Paging ignored due to Mobile Reachable timer expiry", + mme_ue->imsi_bcd); + + MME_CLEAR_PAGING_INFO(mme_ue); + + return OGS_ERROR; + } else { + ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, cn_domain)); + } + + return OGS_OK; +} diff --git a/src/mme/mme-path.h b/src/mme/mme-path.h index afc6f13e8..8f4694cda 100644 --- a/src/mme/mme-path.h +++ b/src/mme/mme-path.h @@ -32,6 +32,8 @@ void mme_send_release_access_bearer_or_ue_context_release(enb_ue_t *enb_ue); void mme_send_after_paging(mme_ue_t *mme_ue, bool failed); +int mme_s1ap_page_if_attached(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain); + #ifdef __cplusplus } #endif diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index 50e784012..2f7bc8bb5 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -701,6 +701,7 @@ void mme_s11_handle_create_bearer_request( ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_create_bearer_request_t *req) { + int rv; uint8_t cause_value = OGS_GTP2_CAUSE_UNDEFINED_VALUE; mme_bearer_t *bearer = NULL, *default_bearer = NULL; mme_sess_t *sess = NULL; @@ -863,7 +864,12 @@ void mme_s11_handle_create_bearer_request( if (ECM_IDLE(mme_ue)) { MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_CREATE_BEARER, bearer); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + mme_gtp_send_create_bearer_response( + bearer, OGS_GTP2_CAUSE_UNABLE_TO_PAGE_UE)); + } } else { ogs_assert(OGS_OK == nas_eps_send_activate_dedicated_bearer_context_request(bearer)); @@ -880,6 +886,7 @@ void mme_s11_handle_update_bearer_request( ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_update_bearer_request_t *req) { + int rv; uint8_t cause_value = OGS_GTP2_CAUSE_UNDEFINED_VALUE; mme_bearer_t *bearer = NULL; mme_sess_t *sess = NULL; @@ -988,7 +995,12 @@ void mme_s11_handle_update_bearer_request( if (ECM_IDLE(mme_ue)) { MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_UPDATE_BEARER, bearer); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + mme_gtp_send_update_bearer_response( + bearer, OGS_GTP2_CAUSE_UNABLE_TO_PAGE_UE)); + } } else { ogs_assert(OGS_OK == nas_eps_send_modify_bearer_context_request(bearer, @@ -1017,6 +1029,7 @@ void mme_s11_handle_delete_bearer_request( ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_delete_bearer_request_t *req) { + int rv; uint8_t cause_value = OGS_GTP2_CAUSE_UNDEFINED_VALUE; mme_bearer_t *bearer = NULL; @@ -1121,7 +1134,12 @@ void mme_s11_handle_delete_bearer_request( if (ECM_IDLE(mme_ue)) { MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_DELETE_BEARER, bearer); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + mme_gtp_send_delete_bearer_response( + bearer, OGS_GTP2_CAUSE_UNABLE_TO_PAGE_UE)); + } } else { ogs_assert(OGS_OK == nas_eps_send_deactivate_bearer_context_request(bearer)); @@ -1283,6 +1301,7 @@ void mme_s11_handle_downlink_data_notification( ogs_gtp_xact_t *xact, mme_ue_t *mme_ue, ogs_gtp2_downlink_data_notification_t *noti) { + int rv; uint8_t cause_value = OGS_GTP2_CAUSE_UNDEFINED_VALUE; mme_bearer_t *bearer = NULL; @@ -1370,7 +1389,12 @@ void mme_s11_handle_downlink_data_notification( if (ECM_IDLE(mme_ue)) { MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_DOWNLINK_DATA_NOTIFICATION, bearer); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + mme_gtp_send_downlink_data_notification_ack( + bearer, OGS_GTP2_CAUSE_UNABLE_TO_PAGE_UE)); + } } else if (ECM_CONNECTED(mme_ue)) { if (cause_value == OGS_GTP2_CAUSE_ERROR_INDICATION_RECEIVED) { diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 8147d04a4..64c254ef6 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -260,7 +260,7 @@ void mme_s6a_handle_clr(mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) */ if (ECM_IDLE(mme_ue)) { MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_DETACH_TO_UE, NULL); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); } else { ogs_assert(OGS_OK == nas_eps_send_detach_request(mme_ue)); if (MME_P_TMSI_IS_AVAILABLE(mme_ue)) { diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index caa19ab47..dc306eed5 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -302,6 +302,9 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE, 0)); } enb_ue_associate_mme_ue(enb_ue, mme_ue); + ogs_debug("Mobile Reachable timer stopped for IMSI[%s]", + mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_mobile_reachable); } ogs_assert(mme_ue); diff --git a/src/mme/mme-timer.c b/src/mme/mme-timer.c index 1e3780e60..0a980d2fd 100644 --- a/src/mme/mme-timer.c +++ b/src/mme/mme-timer.c @@ -92,6 +92,12 @@ const char *mme_timer_get_name(mme_timer_e id) return "MME_TIMER_T3470"; case MME_TIMER_T3489: return "MME_TIMER_T3489"; + case MME_TIMER_MOBILE_REACHABLE: + return "MME_TIMER_MOBILE_REACHABLE"; + case MME_TIMER_IMPLICIT_DETACH: + return "MME_TIMER_IMPLICIT_DETACH"; + case MME_TIMER_PURGE_UE: + return "MME_TIMER_PURGE_UE"; case MME_TIMER_SGS_CLI_CONN_TO_SRV: return "MME_TIMER_SGS_CLI_CONN_TO_SRV"; case MME_TIMER_S1_HOLDING: @@ -160,6 +166,18 @@ void mme_timer_t3470_expire(void *data) { emm_timer_event_send(MME_TIMER_T3470, data); } +void mme_timer_mobile_reachable_expire(void *data) +{ + emm_timer_event_send(MME_TIMER_MOBILE_REACHABLE, data); +} +void mme_timer_implicit_detach_expire(void *data) +{ + emm_timer_event_send(MME_TIMER_IMPLICIT_DETACH, data); +} +void mme_timer_purge_ue_expire(void *data) +{ + emm_timer_event_send(MME_TIMER_PURGE_UE, data); +} static void esm_timer_event_send( mme_timer_e timer_id, mme_bearer_t *bearer) diff --git a/src/mme/mme-timer.h b/src/mme/mme-timer.h index 8356311f6..739117d3e 100644 --- a/src/mme/mme-timer.h +++ b/src/mme/mme-timer.h @@ -40,6 +40,10 @@ typedef enum { MME_TIMER_T3470, MME_TIMER_T3489, + MME_TIMER_MOBILE_REACHABLE, + MME_TIMER_IMPLICIT_DETACH, + MME_TIMER_PURGE_UE, + MME_TIMER_S11_HOLDING, MME_TIMER_SGS_CLI_CONN_TO_SRV, @@ -67,6 +71,10 @@ void mme_timer_t3460_expire(void *data); void mme_timer_t3470_expire(void *data); void mme_timer_t3489_expire(void *data); +void mme_timer_mobile_reachable_expire(void *data); +void mme_timer_implicit_detach_expire(void *data); +void mme_timer_purge_ue_expire(void *data); + void mme_timer_sgs_cli_conn_to_srv(void *data); void mme_timer_s1_holding_timer_expire(void *data); void mme_timer_s11_holding_timer_expire(void *data); diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index bbe57c4ad..6d291b3a9 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -319,6 +319,9 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message) S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE, 0)); } enb_ue_associate_mme_ue(enb_ue, mme_ue); + ogs_debug("Mobile Reachable timer stopped for IMSI[%s]", + mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_mobile_reachable); } } } @@ -1467,6 +1470,15 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) * to prevent retransmission of NAS messages. */ CLEAR_MME_UE_ALL_TIMERS(mme_ue); + + if (mme_self()->time.mobile_reachable.value > 0) { + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_registered)) { + ogs_debug("Mobile Reachable timer started for IMSI[%s]", + mme_ue->imsi_bcd); + ogs_timer_start(mme_ue->t_mobile_reachable.timer, + ogs_time_from_sec(mme_self()->time.mobile_reachable.value)); + } + } } switch (enb_ue->ue_ctx_rel_action) { @@ -1551,7 +1563,7 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) ogs_expect_or_return(mme_ue); enb_ue_unlink(mme_ue); - ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); break; default: ogs_error("Invalid Action[%d]", enb_ue->ue_ctx_rel_action); @@ -2916,6 +2928,8 @@ void s1ap_handle_handover_notification( target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id); enb_ue_associate_mme_ue(target_ue, mme_ue); + ogs_debug("Mobile Reachable timer stopped for IMSI[%s]", mme_ue->imsi_bcd); + CLEAR_MME_UE_TIMER(mme_ue->t_mobile_reachable); memcpy(&target_ue->saved.tai.plmn_id, pLMNidentity->buf, sizeof(target_ue->saved.tai.plmn_id)); diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 4e3a18d39..4015e7ca0 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -358,6 +358,8 @@ int s1ap_send_paging(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain) int i; int rv; + ogs_assert(ogs_timer_running(mme_ue->t_implicit_detach.timer) == false); + /* Find enB with matched TAI */ ogs_list_for_each(&mme_self()->enb_list, enb) { for (i = 0; i < enb->num_of_supported_ta_list; i++) { diff --git a/src/mme/sgsap-handler.c b/src/mme/sgsap-handler.c index 7a2010ae4..c7bbbb4f4 100644 --- a/src/mme/sgsap-handler.c +++ b/src/mme/sgsap-handler.c @@ -277,6 +277,7 @@ void sgsap_handle_detach_ack(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf) void sgsap_handle_paging_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf) { + int rv; ogs_tlv_t *root = NULL, *iter = NULL; mme_ue_t *mme_ue = NULL; @@ -354,15 +355,23 @@ void sgsap_handle_paging_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf) /* UE will respond Extended Service Request in PS CNDomain*/ MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_CS_CALL_SERVICE, NULL); - ogs_assert(OGS_OK == - s1ap_send_paging(mme_ue, S1AP_CNDomain_cs)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_cs); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + sgsap_send_paging_reject( + mme_ue, SGSAP_SGS_CAUSE_UE_UNREACHABLE)); + } } else if (SMS_SERVICE_INDICATOR(mme_ue)) { /* UE will respond Service Request in PS CNDomain*/ MME_STORE_PAGING_INFO(mme_ue, MME_PAGING_TYPE_SMS_SERVICE, NULL); - ogs_assert(OGS_OK == - s1ap_send_paging(mme_ue, S1AP_CNDomain_ps)); + rv = mme_s1ap_page_if_attached(mme_ue, S1AP_CNDomain_ps); + if (rv != OGS_OK) { + ogs_assert(OGS_OK == + sgsap_send_paging_reject( + mme_ue, SGSAP_SGS_CAUSE_UE_UNREACHABLE)); + } } else goto paging_reject;