implement detach process

- mme done including emm, esm, and s1ap
   - sgw/pgw are not finished
   - exception processing is further needed.
This commit is contained in:
Brandon 2017-04-28 13:46:16 +09:00
parent 707c4f4cad
commit 846f356322
14 changed files with 155 additions and 50 deletions

View File

@ -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 */
}
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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 = &gtp_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(&gtp_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;

View File

@ -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
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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, &gtp_message.delete_session_response);
sess, &gtp_message.delete_session_response);
break;
default:
d_warn("Not implmeneted(type:%d)", type);

View File

@ -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];

View File

@ -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

View File

@ -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);
}

View File

@ -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
}

View File

@ -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)",