Merge branch 'master' of https://github.com/acetcom/cellwire
Conflicts: src/mme/emm_handler.c src/mme/emm_handler.h
This commit is contained in:
commit
62935aac2c
|
@ -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(
|
||||
|
@ -156,7 +159,7 @@ void emm_handle_identity_request(mme_ue_t *mme_ue)
|
|||
ue = mme_ue->enb_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;
|
||||
|
@ -220,7 +223,7 @@ void emm_handle_authentication_request(mme_ue_t *mme_ue)
|
|||
ue = mme_ue->enb_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;
|
||||
|
@ -450,7 +453,8 @@ void emm_handle_detach_request(
|
|||
status_t rv;
|
||||
mme_enb_t *enb = NULL;
|
||||
enb_ue_t *enb_ue = 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;
|
||||
|
@ -466,24 +470,57 @@ void emm_handle_detach_request(
|
|||
enb = enb_ue->enb;
|
||||
d_assert(enb, return, "Null param");
|
||||
|
||||
/* Encode ue->s1ap.cause for later use */
|
||||
enb_ue->s1ap.cause.present = S1ap_Cause_PR_nas;
|
||||
enb_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_default_bearer_in_sess(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)
|
||||
{
|
||||
|
@ -509,7 +546,56 @@ 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;
|
||||
enb_ue_t *enb_ue = NULL;
|
||||
|
||||
d_assert(bearer, return, "Null param");
|
||||
ue = bearer->ue;
|
||||
d_assert(ue, return, "Null param");
|
||||
enb_ue = ue->enb_ue;
|
||||
d_assert(enb_ue, return, "Null param");
|
||||
enb = 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_default_bearer_in_sess(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, enb_ue, enb_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 */
|
||||
}
|
||||
}
|
||||
|
||||
mme_ue_t *emm_find_ue_by_message(enb_ue_t *enb_ue, nas_message_t *message)
|
||||
|
|
|
@ -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);
|
||||
CORE_DECLARE(mme_ue_t*) emm_find_ue_by_message(enb_ue_t *enb_ue, nas_message_t *message);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -355,6 +355,9 @@ status_t enb_ue_remove(enb_ue_t *ue)
|
|||
|
||||
index_free(&enb_ue_pool, ue);
|
||||
|
||||
if (ue->mme_ue)
|
||||
ue->mme_ue->enb_ue = NULL;
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "mme_sm.h"
|
||||
|
||||
/* S1AP */
|
||||
#include "S1ap-Cause.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
@ -114,15 +117,16 @@ struct _enb_ue_t {
|
|||
tai_t tai;
|
||||
e_cgi_t e_cgi;
|
||||
|
||||
/* S_TMSI */
|
||||
//s_tmsi_t s_smti;
|
||||
/* S1AP transactions */
|
||||
struct {
|
||||
S1ap_Cause_t cause;
|
||||
} s1ap;
|
||||
|
||||
/* mme_ue_context */
|
||||
mme_ue_t *mme_ue;
|
||||
|
||||
/* Connected enodeB */
|
||||
mme_enb_t *enb;
|
||||
|
||||
};
|
||||
|
||||
struct _mme_ue_t {
|
||||
|
@ -182,6 +186,7 @@ struct _mme_ue_t {
|
|||
c_uint8_t ebi; /* EPS Bearer ID generator */
|
||||
list_t sess_list;
|
||||
|
||||
|
||||
/* Timer Info */
|
||||
tm_block_id tm_t3; /**< T3 Timer */
|
||||
|
||||
|
|
|
@ -179,3 +179,33 @@ status_t mme_s11_build_modify_bearer_request(
|
|||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t mme_s11_build_delete_session_request(pkbuf_t **pkbuf, mme_sess_t *sess)
|
||||
{
|
||||
status_t rv;
|
||||
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 mme_s11_teid;
|
||||
|
||||
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));
|
||||
|
||||
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(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;
|
||||
|
||||
rv = gtp_build_msg(pkbuf, GTP_DELETE_SESSION_REQUEST_TYPE, >p_message);
|
||||
d_assert(rv == CORE_OK, return CORE_ERROR, "gtp build failed");
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -97,3 +97,30 @@ void mme_s11_handle_modify_bearer_response(
|
|||
event_set_param2(&e, (c_uintptr_t)GTP_MODIFY_BEARER_RESPONSE_TYPE);
|
||||
mme_event_send(&e);
|
||||
}
|
||||
|
||||
void mme_s11_handle_delete_session_response(
|
||||
mme_sess_t *sess, gtp_delete_session_response_t *rsp)
|
||||
{
|
||||
event_t e;
|
||||
|
||||
mme_bearer_t *bearer;
|
||||
|
||||
d_assert(sess, return, "Null param");
|
||||
d_assert(rsp, return, "Null param");
|
||||
bearer = mme_default_bearer_in_sess(sess);
|
||||
d_assert(bearer, return, "Null param");
|
||||
|
||||
if (rsp->cause.presence == 0)
|
||||
{
|
||||
d_error("No Cause");
|
||||
return;
|
||||
}
|
||||
|
||||
d_info("[GTP] Delete Session Response : "
|
||||
"MME[%d] <-- SGW[%d]", sess->mme_s11_teid, sess->sgw_s11_teid);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -295,6 +295,10 @@ void mme_state_operational(fsm_t *s, event_t *e)
|
|||
mme_s11_handle_modify_bearer_response(
|
||||
sess, >p_message.modify_bearer_response);
|
||||
break;
|
||||
case GTP_DELETE_SESSION_RESPONSE_TYPE:
|
||||
mme_s11_handle_delete_session_response(
|
||||
sess, >p_message.delete_session_response);
|
||||
break;
|
||||
default:
|
||||
d_warn("Not implmeneted(type:%d)", type);
|
||||
break;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "s1ap_build.h"
|
||||
#include "s1ap_conv.h"
|
||||
|
||||
|
||||
status_t s1ap_build_setup_rsp(pkbuf_t **pkbuf)
|
||||
{
|
||||
int erval;
|
||||
|
@ -260,3 +261,55 @@ status_t s1ap_build_initial_context_setup_request(
|
|||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
||||
status_t s1ap_build_ue_context_release_commmand(
|
||||
pkbuf_t **s1apbuf, enb_ue_t *ue, S1ap_Cause_t cause)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
|
||||
int encoded;
|
||||
s1ap_message_t message;
|
||||
S1ap_UEContextReleaseCommand_IEs_t *ies =
|
||||
&message.s1ap_UEContextReleaseCommand_IEs;
|
||||
|
||||
d_assert(ue, return CORE_ERROR, "Null param");
|
||||
|
||||
memset(&message, 0, sizeof(s1ap_message_t));
|
||||
|
||||
if (ue->mme_ue_s1ap_id == 0)
|
||||
{
|
||||
d_error("invalid mme ue s1ap id (idx: %d)", ue->index);
|
||||
return CORE_ERROR;
|
||||
}
|
||||
|
||||
if (ue->enb_ue_s1ap_id)
|
||||
{
|
||||
ies->uE_S1AP_IDs.present = S1ap_UE_S1AP_IDs_PR_uE_S1AP_ID_pair;
|
||||
ies->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID = ue->mme_ue_s1ap_id;
|
||||
ies->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID = ue->enb_ue_s1ap_id;
|
||||
ies->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.iE_Extensions = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ies->uE_S1AP_IDs.present = S1ap_UE_S1AP_IDs_PR_mME_UE_S1AP_ID;
|
||||
ies->uE_S1AP_IDs.choice.mME_UE_S1AP_ID = ue->mme_ue_s1ap_id;
|
||||
}
|
||||
|
||||
ies->cause = cause;
|
||||
|
||||
message.procedureCode = S1ap_ProcedureCode_id_UEContextRelease;
|
||||
message.direction = S1AP_PDU_PR_initiatingMessage;
|
||||
|
||||
encoded = s1ap_encode_pdu(s1apbuf, &message);
|
||||
s1ap_free_pdu(&message);
|
||||
|
||||
d_assert(s1apbuf && encoded >= 0,return CORE_ERROR,);
|
||||
|
||||
d_info("[S1AP] UE Context Release Command : "
|
||||
"UE[mME-UE-S1AP-ID(%d)] <-- eNB[%s:%d]",
|
||||
ue->mme_ue_s1ap_id,
|
||||
INET_NTOP(&ue->enb->s1ap_sock->remote.sin_addr.s_addr, buf),
|
||||
ue->enb->enb_id);
|
||||
|
||||
return CORE_OK;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ CORE_DECLARE(status_t) s1ap_build_downlink_nas_transport(
|
|||
pkbuf_t **s1apbuf, enb_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_commmand(
|
||||
pkbuf_t **s1apbuf, enb_ue_t *ue, S1ap_Cause_t cause);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -300,3 +300,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];
|
||||
|
||||
enb_ue_t *ue = NULL;
|
||||
S1ap_UEContextReleaseComplete_IEs_t *ies = NULL;
|
||||
|
||||
ies = &message->s1ap_UEContextReleaseComplete_IEs;
|
||||
d_assert(ies, return, "Null param");
|
||||
|
||||
ue = enb_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 */
|
||||
enb_ue_remove(ue);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)",
|
||||
|
|
Loading…
Reference in New Issue