diff --git a/src/mme/emm_handler.c b/src/mme/emm_handler.c index 581840dd5..dc2d10306 100644 --- a/src/mme/emm_handler.c +++ b/src/mme/emm_handler.c @@ -15,6 +15,7 @@ #include "s1ap_build.h" #include "s1ap_path.h" #include "nas_path.h" +#include "mme_fd_path.h" #include "mme_s11_build.h" #include "mme_gtp_path.h" @@ -24,7 +25,11 @@ void emm_handle_attach_request( mme_ue_t *mme_ue, nas_attach_request_t *attach_request) { + status_t rv; + enb_ue_t *enb_ue = NULL; + nas_eps_attach_type_t *eps_attach_type = + &attach_request->eps_attach_type; nas_eps_mobile_identity_t *eps_mobile_identity = &attach_request->eps_mobile_identity; nas_esm_message_container_t *esm_message_container = @@ -37,6 +42,18 @@ void emm_handle_attach_request( d_assert(esm_message_container, return, "Null param"); d_assert(esm_message_container->length, return, "Null param"); + if (SECURITY_CONTEXT_IS_VALID(mme_ue)) + mme_kdf_enb(mme_ue->kasme, mme_ue->ul_count.i32, + mme_ue->kenb); + + CLEAR_EPS_BEARER_ID(mme_ue); + CLEAR_PAGING_INFO(mme_ue); + + /* Set EPS Attach Type */ + memcpy(&mme_ue->nas_eps.attach, eps_attach_type, + sizeof(nas_eps_attach_type_t)); + mme_ue->nas_eps.type = MME_UE_EPS_ATTACH_TYPE; + /* Store UE specific information */ if (attach_request->presencemask & NAS_ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) @@ -112,6 +129,35 @@ void emm_handle_attach_request( } NAS_STORE_DATA(&mme_ue->pdn_connectivity_request, esm_message_container); + + if (!MME_UE_HAVE_IMSI(mme_ue)) + { + /* Unknown GUTI */ + FSM_TRAN(&mme_ue->sm, &emm_state_identity); + } + else + { + if (SECURITY_CONTEXT_IS_VALID(mme_ue)) + { + rv = nas_send_emm_to_esm(mme_ue, &mme_ue->pdn_connectivity_request); + d_assert(rv == CORE_OK,, "nas_send_emm_to_esm failed"); + FSM_TRAN(&mme_ue->sm, &emm_state_default_esm); + } + else + { + if (MME_HAVE_SGW_S11_PATH(mme_ue)) + { + rv = mme_gtp_send_delete_all_sessions(mme_ue); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_delete_all_sessions failed"); + } + else + { + mme_s6a_send_air(mme_ue); + } + FSM_TRAN(&mme_ue->sm, &emm_state_authentication); + } + } } void emm_handle_attach_complete( @@ -177,6 +223,8 @@ void emm_handle_attach_complete( void emm_handle_identity_response( mme_ue_t *mme_ue, nas_identity_response_t *identity_response) { + status_t rv; + nas_mobile_identity_t *mobile_identity = NULL; enb_ue_t *enb_ue = NULL; @@ -204,6 +252,29 @@ void emm_handle_identity_response( { d_warn("Not supported Identity type(%d)", mobile_identity->imsi.type); } + + d_assert(MME_UE_HAVE_IMSI(mme_ue), return, "No IMSI in IDENTITY_RESPONSE"); + + if (SECURITY_CONTEXT_IS_VALID(mme_ue)) + { + rv = nas_send_emm_to_esm(mme_ue, &mme_ue->pdn_connectivity_request); + d_assert(rv == CORE_OK, return, "nas_send_emm_to_esm failed"); + FSM_TRAN(&mme_ue->sm, &emm_state_default_esm); + } + else + { + if (MME_HAVE_SGW_S11_PATH(mme_ue)) + { + rv = mme_gtp_send_delete_all_sessions(mme_ue); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_delete_all_sessions failed"); + } + else + { + mme_s6a_send_air(mme_ue); + } + FSM_TRAN(&mme_ue->sm, &emm_state_authentication); + } } void emm_handle_authentication_response(mme_ue_t *mme_ue, @@ -229,6 +300,7 @@ void emm_handle_authentication_response(mme_ue_t *mme_ue, void emm_handle_detach_request( mme_ue_t *mme_ue, nas_detach_request_from_ue_t *detach_request) { + status_t rv; enb_ue_t *enb_ue = NULL; d_assert(detach_request, return, "Null param"); @@ -260,22 +332,30 @@ void emm_handle_detach_request( /* Save detach type */ mme_ue->detach_type = detach_request->detach_type; + + if (MME_HAVE_SGW_S11_PATH(mme_ue)) + { + rv = mme_gtp_send_delete_all_sessions(mme_ue); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_delete_all_sessions failed"); + } + else + { + emm_handle_detach_accept(mme_ue); + } } void emm_handle_detach_accept(mme_ue_t *mme_ue) { status_t rv; - mme_enb_t *enb = NULL; enb_ue_t *enb_ue = NULL; nas_message_t message; - pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; + pkbuf_t *emmbuf = NULL; S1ap_Cause_t cause; d_assert(mme_ue, return, "Null param"); enb_ue = mme_ue->enb_ue; d_assert(enb_ue, return, "Null param"); - enb = enb_ue->enb; - d_assert(enb, return, "Null param"); /* reply with detach accept */ if ((mme_ue->detach_type.switch_off & 0x1) == 0) @@ -296,13 +376,11 @@ void emm_handle_detach_accept(mme_ue_t *mme_ue) d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); } + /* FIXME : delay is needed */ cause.present = S1ap_Cause_PR_nas; cause.choice.nas = S1ap_CauseNas_detach; - - rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause); - d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); - - d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, , "s1ap send error"); } void emm_handle_service_request( @@ -319,6 +397,12 @@ void emm_handle_service_request( sess = mme_sess_first(mme_ue); d_assert(sess, return, "Null param"); + /* Update Kenb */ + if (SECURITY_CONTEXT_IS_VALID(mme_ue)) + mme_kdf_enb(mme_ue->kasme, mme_ue->ul_count.i32, mme_ue->kenb); + + CLEAR_PAGING_INFO(mme_ue); + rv = s1ap_build_initial_context_setup_request(&s1apbuf, sess, NULL); d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); @@ -336,6 +420,10 @@ void emm_handle_emm_status(mme_ue_t *mme_ue, nas_emm_status_t *emm_status) void emm_handle_tau_request( mme_ue_t *mme_ue, nas_tracking_area_update_request_t *tau_request) { + status_t rv; + + nas_eps_update_type_t *eps_update_type = + &tau_request->eps_update_type; nas_eps_mobile_identity_t *eps_mobile_identity = &tau_request->old_guti; enb_ue_t *enb_ue = NULL; @@ -344,6 +432,13 @@ void emm_handle_tau_request( enb_ue = mme_ue->enb_ue; d_assert(enb_ue, return, "Null param"); + CLEAR_PAGING_INFO(mme_ue); + + /* Set EPS Attach Type */ + memcpy(&mme_ue->nas_eps.update, eps_update_type, + sizeof(nas_eps_update_type_t)); + mme_ue->nas_eps.type = MME_UE_EPS_UPDATE_TYPE; + /* Store UE specific information */ if (tau_request->presencemask & NAS_TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) @@ -407,6 +502,7 @@ void emm_handle_tau_request( MME_UE_HAVE_IMSI(mme_ue) ? mme_ue->imsi_bcd : "Unknown"); +#if 0 if (!MME_UE_HAVE_IMSI(mme_ue)) { /* Unknown GUTI */ @@ -416,7 +512,7 @@ void emm_handle_tau_request( */ /* Send TAU reject */ - emm_handle_tau_reject(mme_ue, + nas_send_tau_reject(mme_ue, EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK); } else if (!SECURITY_CONTEXT_IS_VALID(mme_ue)) @@ -427,9 +523,9 @@ void emm_handle_tau_request( else { /* Send TAU accept */ - emm_handle_tau_accept(mme_ue); + nas_send_tau_accept(mme_ue); } - +#endif break; } default: @@ -440,78 +536,33 @@ void emm_handle_tau_request( return; } } -} -void emm_handle_tau_accept(mme_ue_t *mme_ue) -{ - status_t rv; - mme_enb_t *enb = NULL; - enb_ue_t *enb_ue = NULL; - pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; - S1ap_Cause_t cause; - - d_assert(mme_ue, return, "Null param"); - enb_ue = mme_ue->enb_ue; - d_assert(enb_ue, return, "Null param"); - enb = enb_ue->enb; - d_assert(enb, return, "Null param"); - - /* Build TAU accept */ - if (emm_build_tau_accept(&emmbuf, mme_ue) != CORE_OK) + if (!MME_UE_HAVE_IMSI(mme_ue)) { - d_error("emm_build_tau_accept error"); - pkbuf_free(emmbuf); - return; + /* Unknown GUTI */ + FSM_TRAN(&mme_ue->sm, &emm_state_identity); } - - /* Send Dl NAS to UE */ - d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); - - - /* FIXME : delay required before sending UE context release to make sure - * that UE receive DL NAS ? */ - cause.present = S1ap_Cause_PR_nas; - cause.choice.nas = S1ap_CauseNas_normal_release; - - rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause); - d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); - - d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); -} - -void emm_handle_tau_reject(mme_ue_t *mme_ue, nas_emm_cause_t emm_cause) -{ - status_t rv; - mme_enb_t *enb = NULL; - enb_ue_t *enb_ue = NULL; - pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; - S1ap_Cause_t cause; - - d_assert(mme_ue, return, "Null param"); - enb_ue = mme_ue->enb_ue; - d_assert(enb_ue, return, "Null param"); - enb = enb_ue->enb; - d_assert(enb, return, "Null param"); - - /* Build TAU reject */ - if (emm_build_tau_reject(&emmbuf, emm_cause, mme_ue) != CORE_OK) + else { - d_error("emm_build_tau_accept error"); - pkbuf_free(emmbuf); - return; + if (SECURITY_CONTEXT_IS_VALID(mme_ue)) + { + /* Send TAU accept */ + rv = nas_send_tau_accept(mme_ue); + d_assert(rv == CORE_OK, return, "nas_send_tau_accept failed"); + } + else + { + if (MME_HAVE_SGW_S11_PATH(mme_ue)) + { + rv = mme_gtp_send_delete_all_sessions(mme_ue); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_delete_all_sessions failed"); + } + else + { + mme_s6a_send_air(mme_ue); + } + FSM_TRAN(&mme_ue->sm, &emm_state_authentication); + } } - - /* Send Dl NAS to UE */ - d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); - - - /* FIXME : delay required before sending UE context release to make sure - * that UE receive DL NAS ? */ - cause.present = S1ap_Cause_PR_nas; - cause.choice.nas = S1ap_CauseNas_normal_release; - - rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause); - d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); - - d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); } diff --git a/src/mme/emm_handler.h b/src/mme/emm_handler.h index 03efe9651..0ec1cdfa7 100644 --- a/src/mme/emm_handler.h +++ b/src/mme/emm_handler.h @@ -30,9 +30,6 @@ CORE_DECLARE(void) emm_handle_emm_status( mme_ue_t *mme_ue, nas_emm_status_t *emm_status); CORE_DECLARE(void) emm_handle_tau_request( mme_ue_t *mme_ue, nas_tracking_area_update_request_t *tau_request); -CORE_DECLARE(void) emm_handle_tau_accept(mme_ue_t *mme_ue); -CORE_DECLARE(void) emm_handle_tau_reject(mme_ue_t *mme_ue, - nas_esm_cause_t emm_cause); #ifdef __cplusplus } diff --git a/src/mme/emm_sm.c b/src/mme/emm_sm.c index 1e94ec43f..64ed2d80c 100644 --- a/src/mme/emm_sm.c +++ b/src/mme/emm_sm.c @@ -14,11 +14,9 @@ #include "emm_build.h" #include "esm_handler.h" #include "nas_path.h" +#include "s1ap_path.h" #include "mme_gtp_path.h" -static void emm_state_attach_request(fsm_t *s, event_t *e, - mme_ue_t *mme_ue, nas_message_t *message); - void emm_state_initial(fsm_t *s, event_t *e) { d_assert(s, return, "Null param"); @@ -66,7 +64,8 @@ void emm_state_detached(fsm_t *s, event_t *e) { case NAS_ATTACH_REQUEST: { - emm_state_attach_request(s, e, mme_ue, message); + emm_handle_attach_request( + mme_ue, &message->emm.attach_request); break; } } @@ -122,33 +121,6 @@ void emm_state_identity(fsm_t *s, event_t *e) { emm_handle_identity_response(mme_ue, &message->emm.identity_response); - - d_assert(MME_UE_HAVE_IMSI(mme_ue), break, - "No IMSI in IDENTITY_RESPONSE"); - - if (SECURITY_CONTEXT_IS_VALID(mme_ue)) - { - status_t rv; - rv = nas_send_emm_to_esm(mme_ue, - &mme_ue->pdn_connectivity_request); - d_assert(rv == CORE_OK,, - "nas_send_emm_to_esm failed"); - FSM_TRAN(s, &emm_state_default_esm); - } - else - { - if (MME_HAVE_SGW_S11_PATH(mme_ue)) - { - rv = mme_gtp_send_delete_all_sessions(mme_ue); - d_assert(rv == CORE_OK, break, - "mme_gtp_send_delete_all_sessions failed"); - } - else - { - mme_s6a_send_air(mme_ue); - } - FSM_TRAN(s, &emm_state_authentication); - } break; } case NAS_EMM_STATUS: @@ -401,15 +373,8 @@ void emm_state_attached(fsm_t *s, event_t *e) if (message->emm.h.security_header_type == NAS_SECURITY_HEADER_FOR_SERVICE_REQUEST_MESSAGE) { - /* Update Kenb */ - if (SECURITY_CONTEXT_IS_VALID(mme_ue)) - mme_kdf_enb(mme_ue->kasme, mme_ue->ul_count.i32, - mme_ue->kenb); - - mme_ue_paged(mme_ue); emm_handle_service_request( mme_ue, &message->emm.service_request); - break; } @@ -417,7 +382,8 @@ void emm_state_attached(fsm_t *s, event_t *e) { case NAS_ATTACH_REQUEST: { - emm_state_attach_request(s, e, mme_ue, message); + emm_handle_attach_request( + mme_ue, &message->emm.attach_request); break; } case NAS_EMM_STATUS: @@ -430,29 +396,30 @@ void emm_state_attached(fsm_t *s, event_t *e) { emm_handle_detach_request( mme_ue, &message->emm.detach_request_from_ue); - - if (MME_HAVE_SGW_S11_PATH(mme_ue)) - { - status_t rv; - rv = mme_gtp_send_delete_all_sessions(mme_ue); - d_assert(rv == CORE_OK, break, - "mme_gtp_send_delete_all_sessions failed"); - } - else - { - emm_handle_detach_accept(mme_ue); - } - FSM_TRAN(s, &emm_state_detached); break; } case NAS_TRACKING_AREA_UPDATE_REQUEST: { - mme_ue_paged(mme_ue); emm_handle_tau_request( mme_ue, &message->emm.tracking_area_update_request); break; } + case NAS_TRACKING_AREA_UPDATE_COMPLETE: + { + status_t rv; + S1ap_Cause_t cause; + enb_ue_t *enb_ue = mme_ue->enb_ue; + + d_assert(enb_ue, return, "Null param"); + + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, return, "s1ap send error"); + break; + } default: { d_warn("Unknown message(type:%d)", @@ -527,53 +494,3 @@ void emm_state_exception(fsm_t *s, event_t *e) } } } - -static void emm_state_attach_request(fsm_t *s, event_t *e, - mme_ue_t *mme_ue, nas_message_t *message) -{ - status_t rv; - - d_assert(s, return, "Null param"); - d_assert(e, return, "Null param"); - d_assert(mme_ue, return, "Null param"); - d_assert(message, return, "Null param"); - - /* Update Kenb */ - if (SECURITY_CONTEXT_IS_VALID(mme_ue)) - mme_kdf_enb(mme_ue->kasme, mme_ue->ul_count.i32, - mme_ue->kenb); - - CLEAR_EPS_BEARER_ID(mme_ue); - mme_ue_paged(mme_ue); - - emm_handle_attach_request(mme_ue, &message->emm.attach_request); - - if (!MME_UE_HAVE_IMSI(mme_ue)) - { - /* Unknown GUTI */ - FSM_TRAN(s, &emm_state_identity); - } - else - { - if (SECURITY_CONTEXT_IS_VALID(mme_ue)) - { - rv = nas_send_emm_to_esm(mme_ue, &mme_ue->pdn_connectivity_request); - d_assert(rv == CORE_OK,, "nas_send_emm_to_esm failed"); - FSM_TRAN(s, &emm_state_default_esm); - } - else - { - if (MME_HAVE_SGW_S11_PATH(mme_ue)) - { - rv = mme_gtp_send_delete_all_sessions(mme_ue); - d_assert(rv == CORE_OK, return, - "mme_gtp_send_delete_all_sessions failed"); - } - else - { - mme_s6a_send_air(mme_ue); - } - FSM_TRAN(s, &emm_state_authentication); - } - } -} diff --git a/src/mme/esm_handler.c b/src/mme/esm_handler.c index 7b7c360e2..4aab6a639 100644 --- a/src/mme/esm_handler.c +++ b/src/mme/esm_handler.c @@ -10,15 +10,24 @@ #include "esm_build.h" -void esm_handle_pdn_connectivity_request(mme_sess_t *sess, +void esm_handle_pdn_connectivity_request(mme_bearer_t *bearer, nas_pdn_connectivity_request_t *pdn_connectivity_request) { + status_t rv; mme_ue_t *mme_ue = NULL; + mme_sess_t *sess = NULL; + d_assert(bearer, return, "Null param"); + sess = bearer->sess; d_assert(sess, return, "Null param"); mme_ue = sess->mme_ue; d_assert(mme_ue, return, "Null param"); + d_assert(MME_UE_HAVE_IMSI(mme_ue), return, + "No IMSI in PDN_CPNNECTIVITY_REQUEST"); + d_assert(SECURITY_CONTEXT_IS_VALID(mme_ue), return, + "No Security Context in PDN_CPNNECTIVITY_REQUEST"); + if (pdn_connectivity_request->presencemask & NAS_PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) { @@ -36,11 +45,53 @@ void esm_handle_pdn_connectivity_request(mme_sess_t *sess, NAS_STORE_DATA(&sess->ue_pco, protocol_configuration_options); } + + if (MME_UE_HAVE_APN(mme_ue)) + { + if (FSM_CHECK(&mme_ue->sm, emm_state_attached)) + { + rv = mme_gtp_send_create_session_request(sess); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_create_session_request failed"); + } + else + { + if (MME_HAVE_SGW_S11_PATH(mme_ue)) + { + if (mme_ue->nas_eps.type == MME_UE_EPS_ATTACH_TYPE) + { + rv = nas_send_attach_accept(mme_ue); + d_assert(rv == CORE_OK, return, + "nas_send_attach_accept failed"); + } + else if (mme_ue->nas_eps.type == MME_UE_EPS_UPDATE_TYPE) + { + rv = nas_send_tau_accept(mme_ue); + d_assert(rv == CORE_OK, return, + "nas_send_tau_accept failed"); + } + else + d_assert(0, return, "Invalid EPS type(%d)", + mme_ue->nas_eps.type); + } + else + { + rv = mme_gtp_send_create_session_request(sess); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_create_session_request failed"); + } + } + } + else + { + FSM_TRAN(&bearer->sm, esm_state_information); + } } void esm_handle_information_response(mme_sess_t *sess, nas_esm_information_response_t *esm_information_response) { + status_t rv; mme_ue_t *mme_ue = NULL; d_assert(sess, return, "Null param"); @@ -63,6 +114,10 @@ void esm_handle_information_response(mme_sess_t *sess, &esm_information_response->protocol_configuration_options; NAS_STORE_DATA(&sess->ue_pco, protocol_configuration_options); } + + rv = mme_gtp_send_create_session_request(sess); + d_assert(rv == CORE_OK, return, + "mme_gtp_send_create_session_request failed"); } void esm_handle_activate_default_bearer_accept(mme_bearer_t *bearer) diff --git a/src/mme/esm_handler.h b/src/mme/esm_handler.h index a52ab78fa..feb463e53 100644 --- a/src/mme/esm_handler.h +++ b/src/mme/esm_handler.h @@ -9,7 +9,7 @@ extern "C" { #endif /* __cplusplus */ -CORE_DECLARE(void) esm_handle_pdn_connectivity_request(mme_sess_t *sess, +CORE_DECLARE(void) esm_handle_pdn_connectivity_request(mme_bearer_t *bearer, nas_pdn_connectivity_request_t *pdn_connectivity_request); CORE_DECLARE(void) esm_handle_information_response(mme_sess_t *sess, nas_esm_information_response_t *bearer_information_response); diff --git a/src/mme/esm_sm.c b/src/mme/esm_sm.c index 8a17dd857..1d6f2d371 100644 --- a/src/mme/esm_sm.c +++ b/src/mme/esm_sm.c @@ -13,10 +13,6 @@ #include "nas_path.h" #include "mme_gtp_path.h" -static void esm_state_pdn_connectivity_request( - fsm_t *s, event_t *e, mme_ue_t *mme_ue, mme_sess_t *sess, - mme_bearer_t *bearer, nas_message_t *message); - void esm_state_initial(fsm_t *s, event_t *e) { d_assert(s, return, "Null param"); @@ -71,8 +67,8 @@ void esm_state_inactive(fsm_t *s, event_t *e) { case NAS_PDN_CONNECTIVITY_REQUEST: { - esm_state_pdn_connectivity_request(s, e, - mme_ue, sess, bearer, message); + esm_handle_pdn_connectivity_request( + bearer, &message->esm.pdn_connectivity_request); break; } case NAS_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: @@ -176,8 +172,6 @@ void esm_state_information(fsm_t *s, event_t *e) mme_ue->imsi_bcd, sess->pti); esm_handle_information_response( sess, &message->esm.esm_information_response); - - mme_s11_handle_create_session_request(sess); FSM_TRAN(s, esm_state_inactive); break; } @@ -237,8 +231,8 @@ void esm_state_active(fsm_t *s, event_t *e) { case NAS_PDN_CONNECTIVITY_REQUEST: { - esm_state_pdn_connectivity_request(s, e, - mme_ue, sess, bearer, message); + esm_handle_pdn_connectivity_request( + bearer, &message->esm.pdn_connectivity_request); FSM_TRAN(s, esm_state_inactive); break; } @@ -366,53 +360,3 @@ void esm_state_bearer_exception(fsm_t *s, event_t *e) } } } - -static void esm_state_pdn_connectivity_request( - fsm_t *s, event_t *e, mme_ue_t *mme_ue, mme_sess_t *sess, - mme_bearer_t *bearer, nas_message_t *message) -{ - d_assert(s, return, "Null param"); - d_assert(e, return, "Null param"); - d_assert(mme_ue, return, "Null param"); - d_assert(sess, return, "Null param"); - d_assert(bearer, return, "Null param"); - d_assert(message, return, "Null param"); - - d_trace(3, "[NAS] PDN connectivity request : UE[%s] --> ESM[%d]\n", - mme_ue->imsi_bcd, sess->pti); - - d_assert(MME_UE_HAVE_IMSI(mme_ue), return, - "No IMSI in PDN_CPNNECTIVITY_REQUEST"); - d_assert(SECURITY_CONTEXT_IS_VALID(mme_ue), return, - "No Security Context in PDN_CPNNECTIVITY_REQUEST"); - - esm_handle_pdn_connectivity_request( - sess, &message->esm.pdn_connectivity_request); - - if (MME_UE_HAVE_APN(mme_ue)) - { - if (FSM_CHECK(&mme_ue->sm, emm_state_attached)) - { - mme_s11_handle_create_session_request(sess); - } - else - { - if (MME_HAVE_SGW_S11_PATH(mme_ue)) - { - status_t rv; - rv = nas_send_attach_accept(mme_ue); - d_assert(rv == CORE_OK, return, - "nas_send_attach_accept failed"); - } - else - { - mme_s11_handle_create_session_request(sess); - } - } - } - else - { - FSM_TRAN(s, esm_state_information); - } -} - diff --git a/src/mme/mme_context.c b/src/mme/mme_context.c index 96f3fb977..8a55a3d89 100644 --- a/src/mme/mme_context.c +++ b/src/mme/mme_context.c @@ -1164,15 +1164,11 @@ status_t mme_ue_remove(mme_ue_t *mme_ue) if (mme_ue->imsi_len != 0) hash_set(self.imsi_ue_hash, mme_ue->imsi, mme_ue->imsi_len, NULL); - /* Delete t3413 timer */ - tm_delete(mme_ue->t3413); - - /* Free the saved PDN Connectivity Request */ + /* Clear the saved PDN Connectivity Request */ NAS_CLEAR_DATA(&mme_ue->pdn_connectivity_request); - /* Free the saved paging msg */ - if (mme_ue->last_paging_msg) - pkbuf_free(mme_ue->last_paging_msg); + /* Clear Paging info : t3413, last_paing_msg */ + CLEAR_PAGING_INFO(mme_ue); /* Free UeRadioCapability */ if (mme_ue->radio_capa) @@ -1738,16 +1734,3 @@ pdn_t* mme_pdn_find_by_apn(mme_ue_t *mme_ue, c_int8_t *apn) return NULL; } - -void mme_ue_paged(mme_ue_t *mme_ue) -{ - d_assert(mme_ue, return , "Null param"); - - tm_stop(mme_ue->t3413); - if (mme_ue->last_paging_msg) - { - pkbuf_free(mme_ue->last_paging_msg); - mme_ue->last_paging_msg = NULL; - } - mme_ue->max_paging_retry = 0; -} diff --git a/src/mme/mme_context.h b/src/mme/mme_context.h index 84b48265a..78a8b12c7 100644 --- a/src/mme/mme_context.h +++ b/src/mme/mme_context.h @@ -143,6 +143,16 @@ struct _mme_ue_t { index_t index; /* An index of this node */ fsm_t sm; /* A state machine */ + struct { +#define MME_UE_EPS_ATTACH_TYPE 1 +#define MME_UE_EPS_UPDATE_TYPE 2 + c_uint8_t type; + union { + nas_eps_attach_type_t attach; + nas_eps_update_type_t update; + }; + } nas_eps; + /* UE identity */ #define MME_UE_HAVE_IMSI(__mME) \ ((__mME) && ((__mME)->imsi_len)) @@ -230,6 +240,18 @@ struct _mme_ue_t { nas_esm_message_container_t pdn_connectivity_request; /* Paging */ +#define CLEAR_PAGING_INFO(__mME) \ + do { \ + d_assert((__mME), break, "Null param"); \ + \ + tm_stop((__mME)->t3413); \ + if ((__mME)->last_paging_msg) \ + { \ + pkbuf_free((__mME)->last_paging_msg); \ + (__mME)->last_paging_msg = NULL; \ + } \ + (__mME)->max_paging_retry = 0; \ + } while(0); pkbuf_t *last_paging_msg; tm_block_id t3413; #define MAX_NUM_OF_PAGING 2 @@ -268,10 +290,10 @@ typedef struct _mme_sess_t { /* Related Context */ #define CONNECT_SGW_GTP_NODE(__sESS) \ do { \ - d_assert((__sESS), return, "Null param"); \ + d_assert((__sESS), break, "Null param"); \ (__sESS)->sgw = mme_sgw_next((__sESS)->sgw); \ if (!(__sESS)->sgw) (__sESS)->sgw = mme_sgw_first(); \ - d_assert((__sESS)->sgw, return, "Null param"); \ + d_assert((__sESS)->sgw, break, "Null param"); \ } while(0) mme_sgw_t *sgw; mme_ue_t *mme_ue; @@ -400,7 +422,6 @@ CORE_DECLARE(enb_ue_t*) enb_ue_find_by_mme_ue_s1ap_id(c_uint32_t mme_ue_s1ap CORE_DECLARE(enb_ue_t*) enb_ue_first_in_enb(mme_enb_t *enb); CORE_DECLARE(enb_ue_t*) enb_ue_next_in_enb(enb_ue_t *enb_ue); -CORE_DECLARE(void) mme_ue_paged(mme_ue_t *mme_ue); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/mme/mme_gtp_path.c b/src/mme/mme_gtp_path.c index 1ee1b7a26..7cc8f35c5 100644 --- a/src/mme/mme_gtp_path.c +++ b/src/mme/mme_gtp_path.c @@ -91,6 +91,38 @@ status_t mme_gtp_close() return CORE_OK; } +status_t mme_gtp_send_create_session_request(mme_sess_t *sess) +{ + status_t rv; + gtp_header_t h; + pkbuf_t *pkbuf = NULL; + gtp_xact_t *xact = NULL; + mme_ue_t *mme_ue = NULL; + + /* Use round-robin for selecting SGW */ + CONNECT_SGW_GTP_NODE(sess); + + mme_ue = sess->mme_ue; + d_assert(mme_ue, return CORE_ERROR, "Null param"); + + memset(&h, 0, sizeof(gtp_header_t)); + h.type = GTP_CREATE_SESSION_REQUEST_TYPE; + h.teid = mme_ue->sgw_s11_teid; + + rv = mme_s11_build_create_session_request(&pkbuf, h.type, sess); + d_assert(rv == CORE_OK, return CORE_ERROR, + "S11 build error"); + + xact = gtp_xact_local_create(sess->sgw, &h, pkbuf); + d_assert(xact, return CORE_ERROR, "Null param"); + + rv = gtp_xact_commit(xact); + d_assert(rv == CORE_OK, return CORE_ERROR, "xact_commit error"); + + return CORE_OK; +} + + status_t mme_gtp_send_modify_bearer_request(mme_bearer_t *bearer) { status_t rv; diff --git a/src/mme/mme_gtp_path.h b/src/mme/mme_gtp_path.h index ac6346a98..9748e4d49 100644 --- a/src/mme/mme_gtp_path.h +++ b/src/mme/mme_gtp_path.h @@ -12,6 +12,7 @@ extern "C" { CORE_DECLARE(status_t) mme_gtp_open(); CORE_DECLARE(status_t) mme_gtp_close(); +CORE_DECLARE(status_t) mme_gtp_send_create_session_request(mme_sess_t *sess); CORE_DECLARE(status_t) mme_gtp_send_modify_bearer_request( mme_bearer_t *bearer); CORE_DECLARE(status_t) mme_gtp_send_delete_session_request( diff --git a/src/mme/mme_s11_handler.c b/src/mme/mme_s11_handler.c index 582f00a73..90fc58d81 100644 --- a/src/mme/mme_s11_handler.c +++ b/src/mme/mme_s11_handler.c @@ -15,35 +15,6 @@ #include "esm_build.h" #include "nas_path.h" -void mme_s11_handle_create_session_request(mme_sess_t *sess) -{ - status_t rv; - gtp_header_t h; - pkbuf_t *pkbuf = NULL; - gtp_xact_t *xact = NULL; - mme_ue_t *mme_ue = NULL; - - /* Use round-robin for selecting SGW */ - CONNECT_SGW_GTP_NODE(sess); - - mme_ue = sess->mme_ue; - d_assert(mme_ue, return, "Null param"); - - memset(&h, 0, sizeof(gtp_header_t)); - h.type = GTP_CREATE_SESSION_REQUEST_TYPE; - h.teid = mme_ue->sgw_s11_teid; - - rv = mme_s11_build_create_session_request(&pkbuf, h.type, sess); - d_assert(rv == CORE_OK, return, - "S11 build error"); - - xact = gtp_xact_local_create(sess->sgw, &h, pkbuf); - d_assert(xact, return, "Null param"); - - rv = gtp_xact_commit(xact); - d_assert(rv == CORE_OK, return, "xact_commit error"); -} - void mme_s11_handle_create_session_response(gtp_xact_t *xact, mme_bearer_t *bearer, gtp_create_session_response_t *rsp) { diff --git a/src/mme/mme_s11_handler.h b/src/mme/mme_s11_handler.h index 831e7cc6f..69c628e45 100644 --- a/src/mme/mme_s11_handler.h +++ b/src/mme/mme_s11_handler.h @@ -9,7 +9,6 @@ extern "C" { #endif /* __cplusplus */ -CORE_DECLARE(void) mme_s11_handle_create_session_request(mme_sess_t *sess); CORE_DECLARE(void) mme_s11_handle_create_session_response( gtp_xact_t *xact, mme_bearer_t *bearer, gtp_create_session_response_t *rsp); diff --git a/src/mme/mme_sm.c b/src/mme/mme_sm.c index 1a95fe656..adb4aa076 100644 --- a/src/mme/mme_sm.c +++ b/src/mme/mme_sm.c @@ -386,9 +386,21 @@ void mme_state_operational(fsm_t *s, event_t *e) if (FSM_CHECK(&mme_ue->sm, emm_state_default_esm)) { - rv = nas_send_attach_accept(mme_ue); - d_assert(rv == CORE_OK, return, - "nas_send_attach_accept failed"); + if (mme_ue->nas_eps.type == MME_UE_EPS_ATTACH_TYPE) + { + rv = nas_send_attach_accept(mme_ue); + d_assert(rv == CORE_OK, return, + "nas_send_attach_accept failed"); + } + else if (mme_ue->nas_eps.type == MME_UE_EPS_UPDATE_TYPE) + { + rv = nas_send_tau_accept(mme_ue); + d_assert(rv == CORE_OK, return, + "nas_send_tau_accept failed"); + } + else + d_assert(0, return, "Invalid EPS type(%d)", + mme_ue->nas_eps.type); } else if (FSM_CHECK(&mme_ue->sm, emm_state_attached)) { @@ -495,10 +507,15 @@ void mme_state_operational(fsm_t *s, event_t *e) break; case GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE: { + S1ap_Cause_t cause; + mme_s11_handle_release_access_bearers_response( xact, mme_ue, &message.release_access_bearers_response); - s1ap_handle_release_access_bearers_response(enb_ue); + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK,, "s1ap send error"); break; } diff --git a/src/mme/nas_path.c b/src/mme/nas_path.c index 592b6f3d3..3f4d4bfe1 100644 --- a/src/mme/nas_path.c +++ b/src/mme/nas_path.c @@ -100,7 +100,7 @@ status_t nas_send_attach_reject(mme_ue_t *mme_ue, mme_enb_t *enb = NULL; enb_ue_t *enb_ue = NULL; mme_sess_t *sess = NULL; - pkbuf_t *s1apbuf = NULL, *esmbuf = NULL, *emmbuf = NULL; + pkbuf_t *esmbuf = NULL, *emmbuf = NULL; S1ap_Cause_t cause; d_assert(mme_ue, return CORE_ERROR, "Null param"); @@ -126,14 +126,11 @@ status_t nas_send_attach_reject(mme_ue_t *mme_ue, d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); d_trace(3, "[NAS] Attach reject : UE[%s] <-- EMM\n", mme_ue->imsi_bcd); + /* FIXME : delay is needed */ cause.present = S1ap_Cause_PR_nas; cause.choice.nas = s1ap_cause_nas;; - - rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause); - d_assert(rv == CORE_OK && s1apbuf, - return CORE_ERROR, "s1ap build error"); - d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK, - return CORE_ERROR, "s1ap send error"); + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error"); return CORE_OK; } @@ -188,3 +185,81 @@ status_t nas_send_deactivate_bearer_context_request( return CORE_OK; } + +status_t nas_send_tau_accept(mme_ue_t *mme_ue) +{ + status_t rv; + enb_ue_t *enb_ue = NULL; + pkbuf_t *s1apbuf = NULL, *emmbuf = NULL; + S1ap_Cause_t cause; + + d_assert(mme_ue, return CORE_ERROR, "Null param"); + enb_ue = mme_ue->enb_ue; + d_assert(enb_ue, return CORE_ERROR, "Null param"); + + if (FSM_CHECK(&mme_ue->sm, emm_state_attached)) + { + /* Build TAU accept */ + rv = emm_build_tau_accept(&emmbuf, mme_ue); + d_assert(rv == CORE_OK, return CORE_ERROR, "emm build error"); + + /* Send Dl NAS to UE */ + d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); + + /* FIXME : delay required before sending UE context release to make sure + * that UE receive DL NAS ? */ + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error"); + } + else + { + mme_sess_t *sess = mme_sess_first(mme_ue); + d_assert(sess, return CORE_ERROR, "Null param"); + + rv = emm_build_tau_accept(&emmbuf, mme_ue); + d_assert(rv == CORE_OK, return CORE_ERROR, "emm build error"); + + rv = s1ap_build_initial_context_setup_request(&s1apbuf, sess, emmbuf); + d_assert(rv == CORE_OK && s1apbuf, + pkbuf_free(emmbuf); return CORE_ERROR, "s1ap build error"); + + d_assert(nas_send_to_enb(enb_ue, s1apbuf) == CORE_OK,,); + } + + return CORE_OK; +} + +status_t nas_send_tau_reject(mme_ue_t *mme_ue, nas_emm_cause_t emm_cause) +{ + status_t rv; + enb_ue_t *enb_ue = NULL; + pkbuf_t *emmbuf = NULL; + S1ap_Cause_t cause; + + d_assert(mme_ue, return CORE_ERROR, "Null param"); + enb_ue = mme_ue->enb_ue; + d_assert(enb_ue, return CORE_ERROR, "Null param"); + + /* Build TAU reject */ + if (emm_build_tau_reject(&emmbuf, emm_cause, mme_ue) != CORE_OK) + { + d_error("emm_build_tau_accept error"); + pkbuf_free(emmbuf); + return CORE_ERROR; + } + + /* Send Dl NAS to UE */ + d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); + + + /* FIXME : delay required before sending UE context release to make sure + * that UE receive DL NAS ? */ + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, return CORE_ERROR, "s1ap send error"); + + return CORE_OK; +} diff --git a/src/mme/nas_path.h b/src/mme/nas_path.h index 0dc6e139a..912647ef2 100644 --- a/src/mme/nas_path.h +++ b/src/mme/nas_path.h @@ -22,6 +22,9 @@ CORE_DECLARE(status_t) nas_send_activate_dedicated_bearer_context_request( enb_ue_t *enb_ue, mme_bearer_t *bearer); CORE_DECLARE(status_t) nas_send_deactivate_bearer_context_request( enb_ue_t *enb_ue, mme_bearer_t *bearer); +CORE_DECLARE(status_t) nas_send_tau_accept(mme_ue_t *mme_ue); +CORE_DECLARE(status_t) nas_send_tau_reject(mme_ue_t *mme_ue, + nas_esm_cause_t emm_cause); #ifdef __cplusplus } diff --git a/src/mme/s1ap_handler.c b/src/mme/s1ap_handler.c index 19a77a99d..aecede6a0 100644 --- a/src/mme/s1ap_handler.c +++ b/src/mme/s1ap_handler.c @@ -400,6 +400,7 @@ void s1ap_handle_e_rab_setup_response( void s1ap_handle_ue_context_release_request( mme_enb_t *enb, s1ap_message_t *message) { + status_t rv; char buf[INET_ADDRSTRLEN]; enb_ue_t *enb_ue = NULL; @@ -425,7 +426,6 @@ void s1ap_handle_ue_context_release_request( if (cause == S1ap_CauseRadioNetwork_user_inactivity) { mme_ue_t *mme_ue = enb_ue->mme_ue; - status_t rv; if (MME_HAVE_SGW_S11_PATH(mme_ue)) { @@ -441,7 +441,12 @@ void s1ap_handle_ue_context_release_request( } else { - s1ap_handle_release_access_bearers_response(enb_ue); + S1ap_Cause_t cause; + + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + rv = s1ap_send_ue_context_release_commmand(enb_ue, &cause); + d_assert(rv == CORE_OK, return, "s1ap send error"); } } else @@ -471,26 +476,6 @@ void s1ap_handle_ue_context_release_request( } } -void s1ap_handle_release_access_bearers_response(enb_ue_t *enb_ue) -{ - status_t rv; - mme_enb_t *enb = NULL; - pkbuf_t *s1apbuf; - S1ap_Cause_t cause; - - d_assert(enb_ue, return, "Null param"); - enb = enb_ue->enb; - d_assert(enb, return, "Null param"); - - cause.present = S1ap_Cause_PR_nas; - cause.choice.nas = S1ap_CauseNas_normal_release; - - rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause); - d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); - - d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); -} - void s1ap_handle_ue_context_release_complete( mme_enb_t *enb, s1ap_message_t *message) { diff --git a/src/mme/s1ap_handler.h b/src/mme/s1ap_handler.h index a77990f5b..a62800481 100644 --- a/src/mme/s1ap_handler.h +++ b/src/mme/s1ap_handler.h @@ -26,9 +26,6 @@ CORE_DECLARE(void) s1ap_handle_ue_context_release_request( CORE_DECLARE(void) s1ap_handle_ue_context_release_complete( mme_enb_t *enb, s1ap_message_t *message); -CORE_DECLARE(void) s1ap_handle_release_access_bearers_response( - enb_ue_t *enb_ue); - /* FIXME : Can I move the function to EMM handler? */ CORE_DECLARE(void) s1ap_handle_paging(mme_ue_t *mme_ue); diff --git a/src/mme/s1ap_path.c b/src/mme/s1ap_path.c index 0a7402a62..eb931364e 100644 --- a/src/mme/s1ap_path.c +++ b/src/mme/s1ap_path.c @@ -4,8 +4,9 @@ #include "mme_event.h" -#include "s1ap_path.h" +#include "s1ap_build.h" #include "nas_security.h" +#include "s1ap_path.h" static int _s1ap_accept_cb(net_sock_t *net_sock, void *data); @@ -350,3 +351,23 @@ status_t s1ap_send_to_nas(enb_ue_t *enb_ue, S1ap_NAS_PDU_t *nasPdu) } +status_t s1ap_send_ue_context_release_commmand( + enb_ue_t *enb_ue, S1ap_Cause_t *cause) +{ + status_t rv; + mme_enb_t *enb = NULL; + pkbuf_t *s1apbuf = NULL; + + d_assert(enb_ue, return CORE_ERROR, "Null param"); + d_assert(cause, return CORE_ERROR, "Null param"); + enb = enb_ue->enb; + d_assert(enb, return CORE_ERROR, "Null param"); + + rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, cause); + d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error"); + + d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK, + return CORE_ERROR, "s1ap send error"); + + return CORE_OK; +} diff --git a/src/mme/s1ap_path.h b/src/mme/s1ap_path.h index 41ce60124..6031dac3d 100644 --- a/src/mme/s1ap_path.h +++ b/src/mme/s1ap_path.h @@ -19,6 +19,8 @@ CORE_DECLARE(status_t) s1ap_send_to_enb(mme_enb_t *enb, pkbuf_t *pkb); CORE_DECLARE(status_t) s1ap_send_to_nas( enb_ue_t *enb_ue, S1ap_NAS_PDU_t *nasPdu); CORE_DECLARE(status_t) s1ap_send_to_esm(mme_ue_t *mme_ue, pkbuf_t *esmbuf); +CORE_DECLARE(status_t) s1ap_send_ue_context_release_commmand( + enb_ue_t *enb_ue, S1ap_Cause_t *cause); int _s1ap_recv_cb(net_sock_t *net_sock, void *data);