ue context release implemented for idle-mode

This commit is contained in:
Sukchan Lee 2017-07-25 21:15:25 +09:00
parent b96f06b63a
commit b302928bf3
20 changed files with 363 additions and 27 deletions

View File

@ -313,6 +313,10 @@ ED2(c_uint8_t spare:6;,
#define GTP_SELECTION_MODE_MS_PROVIDED_APN 1
#define GTP_SELECTION_MODE_NETWORK_PROVIDED_APN 2
/* 8.65 Node Type */
#define GTP_NODE_TYPE_MME 0
#define GTP_NODE_TYPE_SGSN 1
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -551,12 +551,7 @@ void emm_handle_detach_request(
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 */
}
d_assert(rv == CORE_OK, return, "S11 send error");
}
sess = mme_sess_next(sess);
}
@ -628,8 +623,8 @@ void emm_handle_delete_session_response(mme_bearer_t *bearer)
{
d_info("[NAS] Detach done : UE[%s] <-- EMM", mme_ue->imsi_bcd);
rv = s1ap_build_ue_context_release_commmand(&
s1apbuf, enb_ue, enb_ue->s1ap.cause);
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");

View File

@ -22,6 +22,8 @@ char* mme_event_get_name(event_t *e)
return "MME_EVT_S1AP_ENB_LO_ACCEPT";
case MME_EVT_S1AP_ENB_LO_CONNREFUSED:
return"MME_EVT_S1AP_ENB_LO_CONNREFUSED";
case MME_EVT_S1AP_UE_FROM_S11:
return "MME_EVT_S1AP_UE_FROM_S11";
case MME_EVT_EMM_UE_MSG:
return "MME_EVT_EMM_UE_MSG";

View File

@ -18,6 +18,7 @@ typedef enum {
MME_EVT_S1AP_ENB_MSG,
MME_EVT_S1AP_ENB_LO_ACCEPT,
MME_EVT_S1AP_ENB_LO_CONNREFUSED,
MME_EVT_S1AP_UE_FROM_S11,
MME_EVT_EMM_UE_MSG,
MME_EVT_EMM_UE_FROM_S6A,

View File

@ -226,3 +226,22 @@ status_t mme_s11_build_delete_session_request(pkbuf_t **pkbuf, mme_sess_t *sess)
return CORE_OK;
}
status_t mme_s11_build_release_access_bearers_request(pkbuf_t **pkbuf)
{
status_t rv;
gtp_message_t gtp_message;
gtp_release_access_bearers_request_t *req =
&gtp_message.release_access_bearers_request;
memset(&gtp_message, 0, sizeof(gtp_message_t));
req->originating_node.presence = 1;
req->originating_node.u8 = GTP_NODE_TYPE_MME;
rv = gtp_build_msg(pkbuf,
GTP_RELEASE_ACCESS_BEARERS_REQUEST_TYPE, &gtp_message);
d_assert(rv == CORE_OK, return CORE_ERROR, "gtp build failed");
return CORE_OK;
}

View File

@ -13,6 +13,8 @@ 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);
CORE_DECLARE(status_t) mme_s11_build_release_access_bearers_request(
pkbuf_t **pkbuf);
#ifdef __cplusplus
}

View File

@ -124,3 +124,37 @@ void mme_s11_handle_delete_session_response(
event_set_param2(&e, (c_uintptr_t)GTP_DELETE_SESSION_RESPONSE_TYPE);
mme_event_send(&e);
}
void mme_s11_handle_release_access_bearers_response(
mme_sess_t *sess, gtp_release_access_bearers_response_t *rsp)
{
event_t e;
mme_ue_t *mme_ue;
enb_ue_t *enb_ue;
mme_enb_t *enb;
d_assert(rsp, return, "Null param");
d_assert(sess, return, "Null param");
mme_ue = sess->mme_ue;
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");
if (rsp->cause.presence == 0)
{
d_error("No Cause");
return;
}
d_info("[GTP] Release Access Bearers Response : "
"MME[%d] <-- SGW[%d]", sess->mme_s11_teid, sess->sgw_s11_teid);
event_set(&e, MME_EVT_S1AP_UE_FROM_S11);
event_set_param1(&e, (c_uintptr_t)enb->index);
event_set_param2(&e, (c_uintptr_t)enb_ue->index);
event_set_param3(&e, (c_uintptr_t)GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE);
mme_event_send(&e);
}

View File

@ -15,6 +15,8 @@ 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);
CORE_DECLARE(void) mme_s11_handle_release_access_bearers_response(
mme_sess_t *sess, gtp_release_access_bearers_response_t *rsp);
#ifdef __cplusplus
}

View File

@ -123,6 +123,7 @@ void mme_state_operational(fsm_t *s, event_t *e)
break;
}
case MME_EVT_S1AP_ENB_MSG:
case MME_EVT_S1AP_UE_FROM_S11:
{
s1ap_message_t message;
index_t index = event_get_param1(e);
@ -133,16 +134,22 @@ void mme_state_operational(fsm_t *s, event_t *e)
d_assert(enb = mme_enb_find(index), break, "No eNB context");
d_assert(FSM_STATE(&enb->sm), break, "No S1AP State Machine");
pkbuf = (pkbuf_t *)event_get_param2(e);
d_assert(pkbuf, break, "Null param");
d_assert(s1ap_decode_pdu(&message, pkbuf) == CORE_OK,
pkbuf_free(pkbuf); break, "Can't decode S1AP_PDU");
if (event_get(e) == MME_EVT_S1AP_ENB_MSG)
{
pkbuf = (pkbuf_t *)event_get_param2(e);
d_assert(pkbuf, break, "Null param");
d_assert(s1ap_decode_pdu(&message, pkbuf) == CORE_OK,
pkbuf_free(pkbuf); break, "Can't decode S1AP_PDU");
event_set_param3(e, (c_uintptr_t)&message);
}
event_set_param3(e, (c_uintptr_t)&message);
fsm_dispatch(&enb->sm, (fsm_event_t*)e);
s1ap_free_pdu(&message);
pkbuf_free(pkbuf);
if (event_get(e) == MME_EVT_S1AP_ENB_MSG)
{
s1ap_free_pdu(&message);
pkbuf_free(pkbuf);
}
break;
}
case MME_EVT_EMM_UE_MSG:
@ -305,6 +312,10 @@ void mme_state_operational(fsm_t *s, event_t *e)
mme_s11_handle_delete_session_response(
sess, &gtp_message.delete_session_response);
break;
case GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE:
mme_s11_handle_release_access_bearers_response(
sess, &gtp_message.release_access_bearers_response);
break;
default:
d_warn("Not implmeneted(type:%d)", type);
break;

View File

@ -261,7 +261,7 @@ status_t s1ap_build_initial_context_setup_request(
}
status_t s1ap_build_ue_context_release_commmand(
pkbuf_t **s1apbuf, enb_ue_t *enb_ue, S1ap_Cause_t cause)
pkbuf_t **s1apbuf, enb_ue_t *enb_ue, S1ap_Cause_t *cause)
{
char buf[INET_ADDRSTRLEN];
@ -271,6 +271,7 @@ status_t s1ap_build_ue_context_release_commmand(
&message.s1ap_UEContextReleaseCommand_IEs;
d_assert(enb_ue, return CORE_ERROR, "Null param");
d_assert(cause, return CORE_ERROR, "Null param");
memset(&message, 0, sizeof(s1ap_message_t));
@ -295,7 +296,28 @@ status_t s1ap_build_ue_context_release_commmand(
ies->uE_S1AP_IDs.choice.mME_UE_S1AP_ID = enb_ue->mme_ue_s1ap_id;
}
ies->cause = cause;
ies->cause.present = cause->present;
switch(ies->cause.present)
{
case S1ap_Cause_PR_radioNetwork:
ies->cause.choice.radioNetwork = cause->choice.radioNetwork;
break;
case S1ap_Cause_PR_transport:
ies->cause.choice.transport = cause->choice.transport;
break;
case S1ap_Cause_PR_nas:
ies->cause.choice.nas = cause->choice.nas;
break;
case S1ap_Cause_PR_protocol:
ies->cause.choice.protocol = cause->choice.protocol;
break;
case S1ap_Cause_PR_misc:
ies->cause.choice.misc = cause->choice.misc;
break;
default:
d_error("Invalid cause type : %d", ies->cause.present);
break;
}
message.procedureCode = S1ap_ProcedureCode_id_UEContextRelease;
message.direction = S1AP_PDU_PR_initiatingMessage;
@ -303,7 +325,7 @@ status_t s1ap_build_ue_context_release_commmand(
encoded = s1ap_encode_pdu(s1apbuf, &message);
s1ap_free_pdu(&message);
d_assert(s1apbuf && encoded >= 0,return CORE_ERROR,);
d_assert(s1apbuf && encoded >= 0, return CORE_ERROR,);
d_info("[S1AP] UE Context Release Command : "
"UE[mME-UE-S1AP-ID(%d)] <-- eNB[%s:%d]",

View File

@ -16,7 +16,7 @@ CORE_DECLARE(status_t) s1ap_build_downlink_nas_transport(
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 *enb_ue, S1ap_Cause_t cause);
pkbuf_t **s1apbuf, enb_ue_t *enb_ue, S1ap_Cause_t *cause);
#ifdef __cplusplus
}

View File

@ -9,6 +9,8 @@
#include "s1ap_path.h"
#include "nas_message.h"
#include "nas_security.h"
#include "mme_s11_build.h"
#include "mme_s11_path.h"
#include "s1ap_handler.h"
@ -334,6 +336,7 @@ void s1ap_handle_ue_context_release_request(
enb_ue_t *enb_ue = NULL;
S1ap_UEContextReleaseRequest_IEs_t *ies = NULL;
long cause;
ies = &message->s1ap_UEContextReleaseRequest_IEs;
d_assert(ies, return, "Null param");
@ -347,11 +350,90 @@ void s1ap_handle_ue_context_release_request(
INET_NTOP(&enb->s1ap_sock->remote.sin_addr.s_addr, buf),
enb->enb_id);
/* FIXME :
* 1) Check if cause == user_inactivity
* 2) Send Release_access_bearer_request
*/
switch(ies->cause.present)
{
case S1ap_Cause_PR_radioNetwork:
cause = ies->cause.choice.radioNetwork;
if (cause == S1ap_CauseRadioNetwork_user_inactivity)
{
int release_access_bearer_needed = 0;
pkbuf_t *pkbuf = NULL;
mme_ue_t *mme_ue = enb_ue->mme_ue;
status_t rv;
if (mme_ue)
{
mme_sess_t *sess = mme_sess_first(mme_ue);
while (sess != NULL)
{
mme_bearer_t *bearer = mme_default_bearer_in_sess(sess);
if (bearer != NULL)
{
rv = mme_s11_build_release_access_bearers_request(
&pkbuf);
d_assert(rv == CORE_OK, return, "S11 build error");
rv = mme_s11_send_to_sgw(bearer->sgw,
GTP_RELEASE_ACCESS_BEARERS_REQUEST_TYPE,
sess->sgw_s11_teid, pkbuf);
d_assert(rv == CORE_OK, return, "S11 send error");
release_access_bearer_needed = 1;
}
sess = mme_sess_next(sess);
}
}
if (!release_access_bearer_needed)
{
s1ap_handle_release_access_bearers_response(enb, enb_ue);
}
}
else
{
d_warn("Not implmented (radioNetwork cause : %d)", cause);
}
break;
case S1ap_Cause_PR_transport:
cause = ies->cause.choice.transport;
d_warn("Not implmented (transport cause : %d)", cause);
break;
case S1ap_Cause_PR_nas:
cause = ies->cause.choice.nas;
d_warn("Not implmented (nas cause : %d)", cause);
break;
case S1ap_Cause_PR_protocol:
cause = ies->cause.choice.protocol;
d_warn("Not implmented (protocol cause : %d)", cause);
break;
case S1ap_Cause_PR_misc:
cause = ies->cause.choice.misc;
d_warn("Not implmented (misc cause : %d)", cause);
break;
default:
d_warn("Invalid cause type : %d", ies->cause.present);
break;
}
}
void s1ap_handle_release_access_bearers_response(
mme_enb_t *enb, enb_ue_t *enb_ue)
{
status_t rv;
pkbuf_t *s1apbuf;
S1ap_Cause_t cause;
d_assert(enb, return, "Null param");
d_assert(enb_ue, 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(
@ -374,7 +456,6 @@ void s1ap_handle_ue_context_release_complete(
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(enb_ue);
}

View File

@ -18,10 +18,14 @@ 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);
CORE_DECLARE(void) s1ap_handle_ue_context_release_request(
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);
CORE_DECLARE(void) s1ap_handle_release_access_bearers_response(
mme_enb_t *enb, enb_ue_t *enb_ue);
#ifdef __cplusplus
}

View File

@ -132,6 +132,33 @@ void s1ap_state_operational(fsm_t *s, event_t *e)
break;
}
case MME_EVT_S1AP_UE_FROM_S11:
{
index_t enb_index = event_get_param1(e);
index_t enb_ue_index = event_get_param2(e);
mme_enb_t *enb = NULL;
enb_ue_t *enb_ue = NULL;
d_assert(enb_index, return, "Null param");
d_assert(enb_ue_index, return, "Null param");
enb = mme_enb_find(enb_index);
d_assert(enb, return, "Null param");
enb_ue = enb_ue_find(enb_ue_index);
d_assert(enb_ue, return, "Null param");
switch(event_get_param3(e))
{
case GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE:
{
s1ap_handle_release_access_bearers_response(enb, enb_ue);
break;
}
}
break;
}
default:
{

View File

@ -283,3 +283,39 @@ void sgw_handle_delete_session_request(gtp_xact_t *xact,
d_info("[GTP] Delete Session Reqeust : "
"SGW[%d] --> PGW[%d]", sess->sgw_s5c_teid, sess->pgw_s5c_teid);
}
void sgw_handle_release_access_bearers_request(gtp_xact_t *xact,
sgw_sess_t *sess, gtp_release_access_bearers_request_t *req)
{
status_t rv;
gtp_release_access_bearers_response_t *rsp = NULL;
pkbuf_t *pkbuf = NULL;
gtp_message_t gtp_message;
gtp_cause_t cause;
d_assert(sess, return, "Null param");
d_assert(xact, return, "Null param");
rsp = &gtp_message.release_access_bearers_response;
memset(&gtp_message, 0, sizeof(gtp_message_t));
memset(&cause, 0, sizeof(cause));
cause.value = GTP_CAUSE_REQUEST_ACCEPTED;
rsp->cause.presence = 1;
rsp->cause.data = &cause;
rsp->cause.len = sizeof(cause);
rv = gtp_build_msg(&pkbuf,
GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE, &gtp_message);
d_assert(rv == CORE_OK, return, "gtp build failed");
d_assert(sgw_s11_send_to_mme(xact,
GTP_RELEASE_ACCESS_BEARERS_RESPONSE_TYPE,
sess->mme_s11_teid, pkbuf) == CORE_OK, return,
"failed to send message");
d_info("[GTP] Release Access Bearers Reqeust : "
"MME[%d] --> SGW[%d]", sess->mme_s11_teid, sess->sgw_s11_teid);
}

View File

@ -21,6 +21,9 @@ CORE_DECLARE(void) sgw_handle_modify_bearer_request(gtp_xact_t *xact,
CORE_DECLARE(void) sgw_handle_delete_session_request(gtp_xact_t *xact,
sgw_sess_t *sess, gtp_message_t *gtp_message);
CORE_DECLARE(void) sgw_handle_release_access_bearers_request(gtp_xact_t *xact,
sgw_sess_t *sess, gtp_release_access_bearers_request_t *req);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View File

@ -105,6 +105,12 @@ void sgw_state_operational(fsm_t *s, event_t *e)
sgw_handle_delete_session_response(
xact, sess, &gtp_message);
#endif
break;
case GTP_RELEASE_ACCESS_BEARERS_REQUEST_TYPE:
sgw_handle_release_access_bearers_request(
xact, sess,
&gtp_message.release_access_bearers_request);
break;
default:
d_warn("Not implmeneted(type:%d)", type);

View File

@ -458,6 +458,10 @@ static void nas_sm_test3(abts_case *tc, void *data)
"402a000003000000 05c0020000c80008 00020002001a0014 1327dc833e850307"
"6147717042911120 8a490100";
char *_ue_context_release_command =
"0017"
"0013000002006300 070c020000c80002 0002400120";
mongoc_collection_t *collection = NULL;
bson_error_t error;
const char *json =
@ -628,6 +632,28 @@ static void nas_sm_test3(abts_case *tc, void *data)
ABTS_TRUE(tc, memcmp(recvbuf->payload+43, tmp+43, 3) == 0);
pkbuf_free(recvbuf);
/* Send UE Release Request */
rv = tests1ap_build_ue_context_release_request(&sendbuf, msgindex);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = tests1ap_enb_send(sock, sendbuf);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
/* Receive UE Release Command */
recvbuf = pkbuf_alloc(0, MAX_SDU_LEN);
rc = tests1ap_enb_read(sock, recvbuf);
recvbuf->len = 23;
ABTS_TRUE(tc, memcmp(recvbuf->payload,
CORE_HEX(_ue_context_release_command,
strlen(_ue_context_release_command), tmp),
recvbuf->len) == 0);
pkbuf_free(recvbuf);
/* Send UE Release Complete */
rv = tests1ap_build_ue_context_release_complete(&sendbuf, msgindex);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
rv = tests1ap_enb_send(sock, sendbuf);
ABTS_INT_EQUAL(tc, CORE_OK, rv);
/* eNB disonncect from MME */
rv = tests1ap_enb_close(sock);
ABTS_INT_EQUAL(tc, CORE_OK, rv);

View File

@ -349,10 +349,67 @@ status_t tests1ap_build_emm_status(pkbuf_t **pkbuf, int i)
"000d403300000500 0000020001000800 02001f001a000a09 27574292cc020760"
"65006440080000f1 10002343d0004340 060000f1103039",
"",
};
c_uint16_t len[TESTS1AP_MAX_MESSAGE] = {
0,
55,
0,
};
char hexbuf[MAX_SDU_LEN];
*pkbuf = pkbuf_alloc(0, MAX_SDU_LEN);
if (!(*pkbuf)) return CORE_ERROR;
(*pkbuf)->len = len[i];
memcpy((*pkbuf)->payload, CORE_HEX(payload[i], strlen(payload[i]), hexbuf),
(*pkbuf)->len);
return CORE_OK;
}
status_t tests1ap_build_ue_context_release_request(pkbuf_t **pkbuf, int i)
{
char *payload[TESTS1AP_MAX_MESSAGE] = {
"",
"",
"0012"
"4018000003000000 05c0020000c80008 0002000200024002 0280",
};
c_uint16_t len[TESTS1AP_MAX_MESSAGE] = {
0,
0,
28,
};
char hexbuf[MAX_SDU_LEN];
*pkbuf = pkbuf_alloc(0, MAX_SDU_LEN);
if (!(*pkbuf)) return CORE_ERROR;
(*pkbuf)->len = len[i];
memcpy((*pkbuf)->payload, CORE_HEX(payload[i], strlen(payload[i]), hexbuf),
(*pkbuf)->len);
return CORE_OK;
}
status_t tests1ap_build_ue_context_release_complete(pkbuf_t **pkbuf, int i)
{
char *payload[TESTS1AP_MAX_MESSAGE] = {
"",
"",
"2017"
"0012000002000040 05c0020000c80008 40020002",
};
c_uint16_t len[TESTS1AP_MAX_MESSAGE] = {
0,
0,
22,
};
char hexbuf[MAX_SDU_LEN];

View File

@ -27,6 +27,10 @@ CORE_DECLARE(status_t) tests1ap_build_initial_context_setup_response(
pkbuf_t **pkbuf, int i);
CORE_DECLARE(status_t) tests1ap_build_attach_complete(pkbuf_t **pkbuf, int i);
CORE_DECLARE(status_t) tests1ap_build_emm_status(pkbuf_t **pkbuf, int i);
CORE_DECLARE(status_t) tests1ap_build_ue_context_release_request(
pkbuf_t **pkbuf, int i);
CORE_DECLARE(status_t) tests1ap_build_ue_context_release_complete(
pkbuf_t **pkbuf, int i);
#ifdef __cplusplus
}