diff --git a/lib/core/ogs-epoll.c b/lib/core/ogs-epoll.c index 2b3399fef..cc9569a68 100644 --- a/lib/core/ogs-epoll.c +++ b/lib/core/ogs-epoll.c @@ -74,7 +74,11 @@ static void epoll_init(ogs_pollset_t *pollset) ogs_assert(context->map_hash); context->epfd = epoll_create(pollset->capacity); - ogs_assert(context->epfd >= 0); + if (context->epfd < 0) { + ogs_log_message(OGS_LOG_FATAL, ogs_errno, "epoll_create() failed"); + ogs_assert_if_reached(); + return; + } ogs_notify_init(pollset); } diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index 57ecc854f..7e059d913 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -3764,6 +3764,7 @@ int mme_ue_set_imsi(mme_ue_t *mme_ue, char *imsi_bcd) ogs_assert(mme_ue->sgw_ue); mme_ue->sgw_ue->sgw_s11_teid = old_mme_ue->sgw_ue->sgw_s11_teid; + MME_UE_CHECK(OGS_LOG_WARN, old_mme_ue); mme_ue_remove(old_mme_ue); } } diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 5e5671dd2..566c57382 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -146,6 +146,15 @@ typedef struct mme_context_s { /* Generator for unique identification */ uint32_t mme_ue_s1ap_id; /* mme_ue_s1ap_id generator */ +#define MME_UE_CHECK(level, __mME) \ + do { \ + ogs_log_message(level, 0, "IMSI [%s] NAS-EPS Type[%d]", \ + (__mME) ? (__mME)->imsi_bcd : "No MME_UE", \ + (__mME) ? (__mME)->nas_eps.type : 0); \ + ogs_log_message(level, 0, "mme_ue[%p:%p]", \ + (__mME), mme_ue_cycle((__mME))); \ + } while(0) + #define MME_UE_LIST_CHECK \ if (ogs_log_get_domain_level(OGS_LOG_DOMAIN) >= OGS_LOG_TRACE) { \ mme_ue_t *mme_ue = NULL; \ @@ -154,8 +163,9 @@ typedef struct mme_context_s { mme_sess_t *sess = NULL; \ mme_bearer_t *bearer = NULL; \ ogs_list_for_each(&mme_self()->mme_ue_list, mme_ue) { \ - ogs_trace("MME_UE(%p) [%s] MME_S11_TEID[%d]", \ - mme_ue, mme_ue->imsi_bcd, mme_ue->mme_s11_teid); \ + ogs_trace("MME_UE(%p:%p) [%s] MME_S11_TEID[%d]", \ + mme_ue, mme_ue_cycle(mme_ue), \ + mme_ue->imsi_bcd, mme_ue->mme_s11_teid); \ if (mme_ue->sgw_ue) { \ sgw_ue = mme_ue->sgw_ue; \ ogs_trace("SGW_UE(%p) MME_UE(%p) SGW_S11_TEID[%d]", \ diff --git a/src/mme/mme-path.c b/src/mme/mme-path.c index c076fd212..420ec8b67 100644 --- a/src/mme/mme-path.c +++ b/src/mme/mme-path.c @@ -86,6 +86,7 @@ void mme_send_delete_session_or_detach(mme_ue_t *mme_ue) if (mme_ue->location_updated_but_not_canceled_yet == true) { mme_s6a_send_pur(mme_ue); } else { + MME_UE_CHECK(OGS_LOG_WARN, mme_ue); mme_ue_remove(mme_ue); } } diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index c4945d8ac..306056eda 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -707,6 +707,7 @@ void mme_s11_handle_delete_session_response( if (mme_ue->location_updated_but_not_canceled_yet == true) { mme_s6a_send_pur(mme_ue); } else { + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); mme_ue_remove(mme_ue); } } else { diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 780f9c015..2c138091b 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -143,6 +143,7 @@ uint8_t mme_s6a_handle_pua( 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_CHECK(OGS_LOG_ERROR, mme_ue); mme_ue_remove(mme_ue); return OGS_ERROR; } @@ -150,6 +151,7 @@ uint8_t mme_s6a_handle_pua( if (pua_message->pua_flags & OGS_DIAM_S6A_PUA_FLAGS_FREEZE_MTMSI) ogs_debug("Freeze M-TMSI requested but not implemented."); + MME_UE_CHECK(OGS_LOG_DEBUG, mme_ue); mme_ue_remove(mme_ue); return OGS_OK; @@ -224,6 +226,7 @@ void mme_s6a_handle_clr(mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) */ if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_de_registered)) { ogs_warn("UE has already been de-registered"); + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); mme_ue_remove(mme_ue); return; } diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index ea006cc24..637e92e3d 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -255,6 +255,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) mme_ue = mme_ue_find_by_message(&nas_message); if (!mme_ue) { mme_ue = mme_ue_add(enb_ue); + MME_UE_CHECK(OGS_LOG_DEBUG, mme_ue); if (mme_ue == NULL) { r = s1ap_send_ue_context_release_command(enb_ue, S1AP_Cause_PR_misc, @@ -319,6 +320,17 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) } ogs_assert(mme_ue); + if (!OGS_FSM_STATE(&mme_ue->sm)) { + ogs_fatal("MESSAGE[%d]", nas_message.emm.h.message_type); + ogs_fatal("ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]", + enb_ue ? enb_ue->enb_ue_s1ap_id : 0, + enb_ue ? enb_ue->mme_ue_s1ap_id : 0); + ogs_fatal("context [%p:%p]", enb_ue, mme_ue); + ogs_fatal("cycle [%p:%p]", + enb_ue_cycle(enb_ue), mme_ue_cycle(mme_ue)); + ogs_fatal("IMSI [%s]", mme_ue ? mme_ue->imsi_bcd : "No MME_UE"); + ogs_assert_if_reached(); + } ogs_assert(OGS_FSM_STATE(&mme_ue->sm)); e->mme_ue = mme_ue; @@ -351,6 +363,103 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) break; } +#define ESM_MESSAGE_CHECK \ + do { \ + ogs_error("emm_state_exception"); \ + ogs_error("nas_type:%d, create_action:%d", \ + e->nas_type, e->create_action); \ + ogs_error("esm.message[EBI:%d,PTI:%d,TYPE:%d]", \ + nas_message.esm.h.eps_bearer_identity, \ + nas_message.esm.h.procedure_transaction_identity, \ + nas_message.esm.h.message_type); \ + } while(0) + + /* + * Because a race condition can occur between S6A Diameter and S1AP message, + * the following error handling code has been added. + * + * 1. InitialUEMessage + Attach Request + PDN Connectivity request + * 2. Authentication-Information-Request/Authentication-Information-Answer + * 3. Authentication Request/Response + * 4. Security-mode command/complete + * 5. Update-Location-Request/Update-Location-Answer + * 6. Detach request/accept + * + * In the ULR/ULA process in step 6, the PDN Connectivity request is + * pushed to the queue as an ESM_MESSAGE because the NAS-Type is still + * an Attach Request. + * + * See the code below in 'mme-s6a-handler.c' for where the queue is pushed. + * + * if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) { + * rv = nas_eps_send_emm_to_esm(mme_ue, + * &mme_ue->pdn_connectivity_request); + * if (rv != OGS_OK) { + * ogs_error("nas_eps_send_emm_to_esm() failed"); + * return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED; + * } + * } else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) { + * r = nas_eps_send_tau_accept(mme_ue, + * S1AP_ProcedureCode_id_InitialContextSetup); + * ogs_expect(r == OGS_OK); + * ogs_assert(r != OGS_ERROR); + * } else { + * ogs_error("Invalid Type[%d]", mme_ue->nas_eps.type); + * return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED; + * } + * + * If you perform step 7 Detach request/accept here, + * the NAS-Type becomes Detach Request and the EMM state changes + * to emm_state_de_registered(). + * + * Since the PDN, which is an ESM message that was previously queued, + * should not be processed in de_registered, the message is ignored + * through error handling below. + * + * Otherwise, MME will crash because there is no active bearer + * in the initial_context_setup_request build process. + * + * See the code below in 's1ap-build.c' for where the crash occurs. + * ogs_list_for_each(&mme_ue->sess_list, sess) { + * ogs_list_for_each(&sess->bearer_list, bearer) { + * ... + * if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) { + * } else if (OGS_FSM_CHECK(&bearer->sm, esm_state_inactive)) { + * ogs_warn("No active EPS bearer [%d]", bearer->ebi); + * ogs_warn(" IMSI[%s] NAS-EPS Type[%d] " + * "ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]", + * mme_ue->imsi_bcd, mme_ue->nas_eps.type, + * enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id); + * continue; + * } + * ... + * } + * } + */ + if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_de_registered)) { + ESM_MESSAGE_CHECK; + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); + ogs_pkbuf_free(pkbuf); + break; + } else if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_authentication)) { + ESM_MESSAGE_CHECK; + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); + ogs_pkbuf_free(pkbuf); + break; + } else if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_security_mode)) { + ESM_MESSAGE_CHECK; + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); + ogs_pkbuf_free(pkbuf); + break; + } else if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_initial_context_setup)) { + } else if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_registered)) { + } else if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_exception)) { + ESM_MESSAGE_CHECK; + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); + ogs_pkbuf_free(pkbuf); + break; + } + bearer = mme_bearer_find_or_add_by_message( mme_ue, &nas_message, e->create_action); if (!bearer) { @@ -459,6 +568,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) switch (s6a_message->cmd_code) { case OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION: + ogs_debug("OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION"); emm_cause = mme_s6a_handle_aia(mme_ue, s6a_message); if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) { ogs_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]", @@ -481,6 +591,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) } break; case OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION: + ogs_debug("OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION"); emm_cause = mme_s6a_handle_ula(mme_ue, s6a_message); if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) { ogs_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]", @@ -505,13 +616,16 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) mme_ue->location_updated_but_not_canceled_yet = true; break; case OGS_DIAM_S6A_CMD_CODE_PURGE_UE: + ogs_debug("OGS_DIAM_S6A_CMD_CODE_PURGE_UE"); mme_s6a_handle_pua(mme_ue, s6a_message); break; case OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION: + ogs_debug("OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION"); mme_ue->location_updated_but_not_canceled_yet = false; mme_s6a_handle_clr(mme_ue, s6a_message); break; case OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA: + ogs_debug("OGS_DIAM_S6A_CMD_CODE_INSERT_SUBSCRIBER_DATA"); mme_s6a_handle_idr(mme_ue, s6a_message); break; default: diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index d4dde8eaa..245d70a08 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -575,10 +575,7 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request( } if (!E_RABToBeSetupListCtxtSUReq->list.count) { - ogs_error(" IMSI[%s] NAS-EPS Type[%d] " - "ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]", - mme_ue->imsi_bcd, mme_ue->nas_eps.type, - enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id); + MME_UE_CHECK(OGS_LOG_ERROR, mme_ue); ogs_list_for_each(&mme_ue->sess_list, sess) { ogs_error(" APN[%s]", sess->session ? sess->session->name : "Unknown"); diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index 2c0b58f93..367f241b5 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -1949,6 +1949,7 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) if (mme_ue->location_updated_but_not_canceled_yet == true) { mme_s6a_send_pur(mme_ue); } else { + MME_UE_CHECK(OGS_LOG_DEBUG, mme_ue); mme_ue_remove(mme_ue); } break;