diff --git a/src/mme/emm_handler.c b/src/mme/emm_handler.c index 6155b30980..7f38e029d0 100644 --- a/src/mme/emm_handler.c +++ b/src/mme/emm_handler.c @@ -16,6 +16,9 @@ #include "s1ap_build.h" #include "s1ap_path.h" +#include "mme_s11_build.h" +#include "mme_s11_path.h" + void emm_handle_identity_request(mme_ue_t *ue); void emm_handle_esm_message_container( @@ -153,7 +156,7 @@ void emm_handle_identity_request(mme_ue_t *ue) d_assert(ue, return, "Null param"); enb = ue->enb; - d_assert(ue->enb, return, "Null param"); + d_assert(enb, return, "Null param"); memset(&message, 0, sizeof(message)); message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM; @@ -214,7 +217,7 @@ void emm_handle_authentication_request(mme_ue_t *ue) d_assert(ue, return, "Null param"); enb = ue->enb; - d_assert(ue->enb, return, "Null param"); + d_assert(enb, return, "Null param"); memset(&message, 0, sizeof(message)); message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM; @@ -258,7 +261,7 @@ void emm_handle_authentication_response( d_assert(ue, return, "Null param"); enb = ue->enb; - d_assert(ue->enb, return, "Null param"); + d_assert(enb, return, "Null param"); if (authentication_response_parameter->length != ue->xres_len || memcmp(authentication_response_parameter->res, @@ -331,7 +334,7 @@ void emm_handle_create_session_response(mme_bearer_t *bearer) ue = bearer->ue; d_assert(ue, return, "Null param"); enb = ue->enb; - d_assert(ue->enb, return, "Null param"); + d_assert(enb, return, "Null param"); rv = esm_build_activate_default_bearer_context(&esmbuf, bearer); d_assert(rv == CORE_OK && esmbuf, @@ -434,7 +437,8 @@ void emm_handle_detach_request( { status_t rv; mme_enb_t *enb = NULL; - pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; + pkbuf_t *emmbuf = NULL, *s11buf = NULL, *s1apbuf = NULL; + mme_sess_t *sess; nas_message_t message; nas_detach_type_t *detach_type = &detach_request->detach_type; @@ -448,24 +452,56 @@ void emm_handle_detach_request( enb = ue->enb; d_assert(enb, return, "Null param"); + /* Encode ue->s1ap.cause for later use */ + ue->s1ap.cause.present = S1ap_Cause_PR_nas; + ue->s1ap.cause.choice.nas = S1ap_CauseNas_detach; + switch (detach_type->detach_type) { /* 0 0 1 : EPS detach */ case NAS_DETACH_TYPE_FROM_UE_EPS_DETACH: + d_info("[NAS] (EPS) Detach request : UE_IMSI[%s] --> EMM", + ue->imsi_bcd); break; /* 0 1 0 : IMSI detach */ case NAS_DETACH_TYPE_FROM_UE_IMSI_DETACH: + d_info("[NAS] (IMSI) Detach request : UE_IMSI[%s] --> EMM", + ue->imsi_bcd); break; case 6: /* 1 1 0 : reserved */ case 7: /* 1 1 1 : reserved */ + d_info("[NAS] (Unknown) Detach request : UE_IMSI[%s] --> EMM", + ue->imsi_bcd); break; /* 0 1 1 : combined EPS/IMSI detach */ case NAS_DETACH_TYPE_FROM_UE_COMBINED_EPS_IMSI_DETACH: default: /* all other values */ + d_info("[NAS] (EPS+IMSI) Detach request : UE_IMSI[%s] --> EMM", + ue->imsi_bcd); break; } - /* TODO: ESM session delete */ + sess = mme_sess_first(ue); + while (sess != NULL) + { + mme_bearer_t *bearer = mme_bearer_first(sess); + + if (bearer != NULL) + { + rv = mme_s11_build_delete_session_request(&s11buf, sess); + d_assert(rv == CORE_OK, return, "S11 build error"); + + rv = mme_s11_send_to_sgw(bearer->sgw, + GTP_DELETE_SESSION_REQUEST_TYPE, sess->sgw_s11_teid, s11buf); + if (rv != CORE_OK) + { + d_error("S11 send error rv %d", rv); + pkbuf_free(s11buf); + /* continue to send */ + } + } + sess = mme_sess_next(sess); + } if ((detach_type->switch_off & 0x1) == 0) { @@ -491,5 +527,51 @@ void emm_handle_detach_request( d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); } - /* initiate s1 ue context release */ + /* TODO: initiate s1 ue context release with a timeout value */ +} + +void emm_handle_delete_session_response(mme_bearer_t *bearer) +{ + status_t rv; + mme_ue_t *ue = NULL; + mme_enb_t *enb = NULL; + pkbuf_t *s1apbuf = NULL; + mme_sess_t *sess; + int b_wait = 0; + + d_assert(bearer, return, "Null param"); + ue = bearer->ue; + d_assert(ue, return, "Null param"); + enb = ue->enb; + d_assert(enb, return, "Null param"); + + sess = mme_sess_find_by_ebi(ue, bearer->ebi); + mme_sess_remove(sess); + + /* sess and bearer are not valid from here */ + + sess = mme_sess_first(ue); + while (sess != NULL) + { + mme_bearer_t *temp_bearer = mme_bearer_first(sess); + + if (temp_bearer != NULL) + { + b_wait = 1; + break; + } + sess = mme_sess_next(sess); + } + + if (!b_wait) + { + d_info("[NAS] Detach done : UE[%s] <-- EMM", ue->imsi_bcd); + + rv = s1ap_build_ue_context_release_commmand(&s1apbuf, ue, ue->s1ap.cause); + d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error"); + + d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error"); + + /* TODO: launch a timer */ + } } diff --git a/src/mme/emm_handler.h b/src/mme/emm_handler.h index 9a361602d7..c38be19345 100644 --- a/src/mme/emm_handler.h +++ b/src/mme/emm_handler.h @@ -22,6 +22,7 @@ CORE_DECLARE(void) emm_handle_identity_response( mme_ue_t *ue, nas_identity_response_t *identity_response); CORE_DECLARE(void) emm_handle_detach_request( mme_ue_t *ue, nas_detach_request_from_ue_t *detach_request); +CORE_DECLARE(void) emm_handle_delete_session_response(mme_bearer_t *bearer); #ifdef __cplusplus } diff --git a/src/mme/emm_sm.c b/src/mme/emm_sm.c index c12904a4d8..d6fa9fb979 100644 --- a/src/mme/emm_sm.c +++ b/src/mme/emm_sm.c @@ -56,6 +56,9 @@ void emm_state_operational(fsm_t *s, event_t *e) case GTP_CREATE_SESSION_RESPONSE_TYPE: emm_handle_create_session_response(bearer); break; + case GTP_DELETE_SESSION_RESPONSE_TYPE: + emm_handle_delete_session_response(bearer); + break; } break; @@ -107,23 +110,6 @@ void emm_state_operational(fsm_t *s, event_t *e) "MME <-- SGW"); break; } - case GTP_DELETE_SESSION_RESPONSE_TYPE: - { - mme_bearer_t *bearer = mme_bearer_first(ue); - - while(bearer) - { - event_t e; - event_set(&e, MME_EVT_ESM_BEARER_FROM_S6A); - event_set_param1(&e, (c_uintptr_t)bearer->index); - event_set_param2(&e, - (c_uintptr_t)S6A_CMD_UPDATE_LOCATION); - mme_event_send(&e); - - bearer = mme_bearer_next(bearer); - } - break; - } } break; } diff --git a/src/mme/mme_context.h b/src/mme/mme_context.h index 9765cb7b77..a6ae595bda 100644 --- a/src/mme/mme_context.h +++ b/src/mme/mme_context.h @@ -14,6 +14,9 @@ #include "mme_sm.h" +/* S1AP */ +#include "S1ap-Cause.h" + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -146,6 +149,11 @@ typedef struct _mme_ue_t { c_uint8_t ebi; /* EPS Bearer ID generator */ list_t sess_list; + /* S1AP transactions */ + struct { + S1ap_Cause_t cause; + } s1ap; + mme_enb_t *enb; } mme_ue_t; diff --git a/src/mme/mme_s11_build.c b/src/mme/mme_s11_build.c index 76da312a5c..40f295757d 100644 --- a/src/mme/mme_s11_build.c +++ b/src/mme/mme_s11_build.c @@ -179,23 +179,17 @@ status_t mme_s11_build_modify_bearer_request( return CORE_OK; } -status_t mme_s11_build_delete_session_request(pkbuf_t **pkbuf, mme_bearer_t *bearer) +status_t mme_s11_build_delete_session_request(pkbuf_t **pkbuf, mme_sess_t *sess) { status_t rv; - pdn_t *pdn = NULL; - mme_sgw_t *sgw = NULL; mme_ue_t *ue = NULL; gtp_message_t gtp_message; gtp_delete_session_request_t *req = >p_message.delete_session_request; - gtp_f_teid_t sender_cp_teid; + gtp_f_teid_t mme_s11_teid; - d_assert(bearer, return CORE_ERROR, "Null param"); - pdn = bearer->pdn; - d_assert(pdn, return CORE_ERROR, "Null param"); - sgw = bearer->sgw; - d_assert(sgw, return CORE_ERROR, "Null param"); - ue = bearer->ue; + d_assert(sess, return CORE_ERROR, "Null param"); + ue = sess->ue; d_assert(ue, return CORE_ERROR, "Null param"); memset(>p_message, 0, sizeof(gtp_message_t)); @@ -203,8 +197,8 @@ status_t mme_s11_build_delete_session_request(pkbuf_t **pkbuf, mme_bearer_t *bea memset(&mme_s11_teid, 0, sizeof(gtp_f_teid_t)); mme_s11_teid.ipv4 = 1; mme_s11_teid.interface_type = GTP_F_TEID_S11_MME_GTP_C; - mme_s11_teid.teid = htonl(ue->mme_s11_teid); - mme_s11_teid.ipv4_addr = ue->mme_s11_addr; + mme_s11_teid.teid = htonl(sess->mme_s11_teid); + mme_s11_teid.ipv4_addr = sess->mme_s11_addr; req->sender_f_teid_for_control_plane.presence = 1; req->sender_f_teid_for_control_plane.data = &mme_s11_teid; req->sender_f_teid_for_control_plane.len = GTP_F_TEID_IPV4_LEN; diff --git a/src/mme/mme_s11_build.h b/src/mme/mme_s11_build.h index 1e084d5998..5f1174f81b 100644 --- a/src/mme/mme_s11_build.h +++ b/src/mme/mme_s11_build.h @@ -11,6 +11,8 @@ CORE_DECLARE(status_t) mme_s11_build_create_session_request( pkbuf_t **pkbuf, mme_bearer_t *bearer); CORE_DECLARE(status_t) mme_s11_build_modify_bearer_request( pkbuf_t **pkbuf, mme_bearer_t *bearer); +CORE_DECLARE(status_t) mme_s11_build_delete_session_request( + pkbuf_t **pkbuf, mme_sess_t *sess); #ifdef __cplusplus } diff --git a/src/mme/mme_s11_handler.c b/src/mme/mme_s11_handler.c index 832086ab83..deabafe0c0 100644 --- a/src/mme/mme_s11_handler.c +++ b/src/mme/mme_s11_handler.c @@ -99,30 +99,28 @@ void mme_s11_handle_modify_bearer_response( } void mme_s11_handle_delete_session_response( - mme_ue_t *ue, gtp_delete_session_response_t *rsp) + mme_sess_t *sess, gtp_delete_session_response_t *rsp) { event_t e; - gtp_f_teid_t *sgw_s11_teid = NULL; - gtp_f_teid_t *sgw_s1u_teid = NULL; - - mme_bearer_t *bearer = NULL; - pdn_t *pdn = NULL; + mme_bearer_t *bearer; - d_assert(ue, return, "Null param"); + d_assert(sess, return, "Null param"); d_assert(rsp, return, "Null param"); + bearer = mme_bearer_first(sess); + d_assert(bearer, return, "Null param"); - if (rsp->cause == 0) + if (rsp->cause.presence == 0) { d_error("No Cause"); return; } d_info("[GTP] Delete Session Response : " - "MME[%d] <-- SGW[%d]", ue->mme_s11_teid, ue->sgw_s11_teid); + "MME[%d] <-- SGW[%d]", sess->mme_s11_teid, sess->sgw_s11_teid); - event_set(&e, MME_EVT_EMM_UE_FROM_S11); - event_set_param1(&e, (c_uintptr_t)ue->index); + event_set(&e, MME_EVT_EMM_BEARER_FROM_S11); + event_set_param1(&e, (c_uintptr_t)bearer->index); event_set_param2(&e, (c_uintptr_t)GTP_DELETE_SESSION_RESPONSE_TYPE); mme_event_send(&e); } diff --git a/src/mme/mme_s11_handler.h b/src/mme/mme_s11_handler.h index 8b0f2bad8f..3cd74cc0ea 100644 --- a/src/mme/mme_s11_handler.h +++ b/src/mme/mme_s11_handler.h @@ -13,6 +13,8 @@ CORE_DECLARE(void) mme_s11_handle_create_session_response( mme_sess_t *sess, gtp_create_session_response_t *rsp); CORE_DECLARE(void) mme_s11_handle_modify_bearer_response( mme_sess_t *sess, gtp_modify_bearer_response_t *rsp); +CORE_DECLARE(void) mme_s11_handle_delete_session_response( + mme_sess_t *sess, gtp_delete_session_response_t *rsp); #ifdef __cplusplus } diff --git a/src/mme/mme_sm.c b/src/mme/mme_sm.c index e13ebab7db..953ec4af4e 100644 --- a/src/mme/mme_sm.c +++ b/src/mme/mme_sm.c @@ -259,7 +259,7 @@ void mme_state_operational(fsm_t *s, event_t *e) break; case GTP_DELETE_SESSION_RESPONSE_TYPE: mme_s11_handle_delete_session_response( - ue, >p_message.delete_session_response); + sess, >p_message.delete_session_response); break; default: d_warn("Not implmeneted(type:%d)", type); diff --git a/src/mme/s1ap_build.c b/src/mme/s1ap_build.c index 49b8e2f7a2..b88d9eda2e 100644 --- a/src/mme/s1ap_build.c +++ b/src/mme/s1ap_build.c @@ -259,7 +259,7 @@ status_t s1ap_build_initial_context_setup_request( return CORE_OK; } -status_t s1ap_build_ue_context_release_commnad( +status_t s1ap_build_ue_context_release_commmand( pkbuf_t **s1apbuf, mme_ue_t *ue, S1ap_Cause_t cause) { char buf[INET_ADDRSTRLEN]; diff --git a/src/mme/s1ap_build.h b/src/mme/s1ap_build.h index fa5d31c0ba..049bd3e0a7 100644 --- a/src/mme/s1ap_build.h +++ b/src/mme/s1ap_build.h @@ -15,7 +15,7 @@ CORE_DECLARE(status_t) s1ap_build_downlink_nas_transport( pkbuf_t **s1apbuf, mme_ue_t *ue, pkbuf_t *emmbuf); CORE_DECLARE(status_t) s1ap_build_initial_context_setup_request( pkbuf_t **s1apbuf, mme_bearer_t *bearer, pkbuf_t *emmbuf); -CORE_DECLARE(status_t) s1ap_build_ue_context_release_commnad( +CORE_DECLARE(status_t) s1ap_build_ue_context_release_commmand( pkbuf_t **s1apbuf, mme_ue_t *ue, S1ap_Cause_t cause); #ifdef __cplusplus diff --git a/src/mme/s1ap_handler.c b/src/mme/s1ap_handler.c index bd16fd325f..a975298d7b 100644 --- a/src/mme/s1ap_handler.c +++ b/src/mme/s1ap_handler.c @@ -260,3 +260,27 @@ void s1ap_handle_initial_context_setup_response( } } +void s1ap_handle_ue_context_release_complete( + mme_enb_t *enb, s1ap_message_t *message) +{ + char buf[INET_ADDRSTRLEN]; + + mme_ue_t *ue = NULL; + S1ap_UEContextReleaseComplete_IEs_t *ies = NULL; + + ies = &message->s1ap_UEContextReleaseComplete_IEs; + d_assert(ies, return, "Null param"); + + ue = mme_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id); + d_assert(ue, return, "No UE Context[%d]", ies->mme_ue_s1ap_id); + + d_info("[S1AP] UE Context Release Complete : " + "UE[mME-UE-S1AP-ID(%d)] --> eNB[%s:%d]", + ue->mme_ue_s1ap_id, + INET_NTOP(&enb->s1ap_sock->remote.sin_addr.s_addr, buf), + enb->enb_id); + + /* BRANDON -> ACETCOM: "pass event to MME SM" or "process here?" */ + /* process here */ + mme_ue_remove(ue); +} diff --git a/src/mme/s1ap_handler.h b/src/mme/s1ap_handler.h index 7fa9846fcc..9f712fc137 100644 --- a/src/mme/s1ap_handler.h +++ b/src/mme/s1ap_handler.h @@ -18,6 +18,8 @@ CORE_DECLARE(void) s1ap_handle_ue_capability_info_indication( mme_enb_t *enb, s1ap_message_t *message); CORE_DECLARE(void) s1ap_handle_initial_context_setup_response( mme_enb_t *enb, s1ap_message_t *message); +CORE_DECLARE(void) s1ap_handle_ue_context_release_complete( + mme_enb_t *enb, s1ap_message_t *message); #ifdef __cplusplus } diff --git a/src/mme/s1ap_sm.c b/src/mme/s1ap_sm.c index e516d025ee..153b9a6c10 100644 --- a/src/mme/s1ap_sm.c +++ b/src/mme/s1ap_sm.c @@ -100,6 +100,12 @@ void s1ap_state_operational(fsm_t *s, event_t *e) enb, message); break; } + case S1ap_ProcedureCode_id_UEContextRelease : + { + s1ap_handle_ue_context_release_complete( + enb, message); + break; + } default: { d_warn("Not implemented(choice:%d, proc:%d)",