[#220] Timer for UE Context Release

This commit is contained in:
Sukchan Lee 2019-07-21 01:03:19 +09:00
parent 5ce04bcc6f
commit ae3e59053d
11 changed files with 150 additions and 34 deletions

View File

@ -1844,6 +1844,9 @@ enb_ue_t *enb_ue_add(mme_enb_t *enb)
enb_ue->enb = enb;
enb_ue->t_ue_context_release.timer = ogs_timer_add(
self.timer_mgr, mme_timer_ue_context_release, enb_ue);
ogs_hash_set(self.mme_ue_s1ap_id_hash, &enb_ue->mme_ue_s1ap_id,
sizeof(enb_ue->mme_ue_s1ap_id), enb_ue);
ogs_list_add(&enb->enb_ue_list, enb_ue);
@ -1863,6 +1866,9 @@ void enb_ue_remove(enb_ue_t *enb_ue)
ogs_assert(enb_ue);
ogs_assert(enb_ue->enb);
CLEAR_ENB_UE_ALL_TIMERS(enb_ue);
ogs_timer_delete(enb_ue->t_ue_context_release.timer);
/* De-associate S1 with NAS/EMM */
enb_ue_deassociate(enb_ue);
@ -2547,6 +2553,7 @@ void mme_bearer_remove(mme_bearer_t *bearer)
ogs_fsm_fini(&bearer->sm, &e);
ogs_fsm_delete(&bearer->sm);
CLEAR_BEARER_ALL_TIMERS(bearer);
ogs_timer_delete(bearer->t3489.timer);
ogs_list_remove(&bearer->sess->bearer_list, bearer);

View File

@ -265,6 +265,26 @@ struct enb_ue_s {
#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4
uint8_t ue_ctx_rel_action;
#define CLEAR_ENB_UE_ALL_TIMERS(__eNB) \
do { \
CLEAR_ENB_UE_TIMER((__eNB)->t_ue_context_release); \
} while(0);
#define CLEAR_ENB_UE_TIMER(__eNB_UE_TIMER) \
do { \
ogs_timer_stop((__eNB_UE_TIMER).timer); \
if ((__eNB_UE_TIMER).pkbuf) \
{ \
ogs_pkbuf_free((__eNB_UE_TIMER).pkbuf); \
(__eNB_UE_TIMER).pkbuf = NULL; \
} \
(__eNB_UE_TIMER).retry_count = 0; \
} while(0);
struct {
ogs_pkbuf_t *pkbuf;
ogs_timer_t *timer;
uint32_t retry_count;;
} t_ue_context_release;
/* Related Context */
mme_enb_t *enb;
mme_ue_t *mme_ue;

View File

@ -50,6 +50,7 @@ int mme_send_delete_session_or_ue_context_release(
rv = mme_gtp_send_delete_all_sessions(mme_ue);
ogs_assert(rv == OGS_OK);
} else {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
@ -70,6 +71,7 @@ int mme_send_release_access_bearer_or_ue_context_release(
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
ogs_assert(rv == OGS_OK);
} else {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);

View File

@ -154,6 +154,7 @@ void mme_s11_handle_modify_bearer_response(
source_ue = target_ue->source_ue;
ogs_assert(source_ue);
CLEAR_ENB_UE_TIMER(source_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(source_ue,
S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_successful_handover,
@ -227,6 +228,7 @@ void mme_s11_handle_delete_session_response(
enb_ue = mme_ue->enb_ue;
if (enb_ue) {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
@ -244,6 +246,7 @@ void mme_s11_handle_delete_session_response(
enb_ue = mme_ue->enb_ue;
if (enb_ue) {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
@ -509,6 +512,7 @@ void mme_s11_handle_release_access_bearers_response(
ogs_assert(rv == OGS_OK);
if (enb_ue) {
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);

View File

@ -219,9 +219,9 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
ogs_assert(enb);
ogs_assert(OGS_FSM_STATE(&enb->sm));
ogs_fsm_dispatch(&enb->sm, e);
ogs_timer_delete(e->timer);
if (enb_ue_find_by_mme_ue_s1ap_id(enb_ue->mme_ue_s1ap_id)) {
ogs_fsm_dispatch(&enb->sm, e);
}
break;
case MME_EVT_EMM_MESSAGE:
@ -363,6 +363,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
enb_ue = mme_ue->enb_ue;
ogs_assert(enb_ue);
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);

View File

@ -22,6 +22,8 @@
#include "mme-context.h"
static mme_timer_cfg_t g_mme_timer_cfg[MAX_NUM_OF_MME_TIMER] = {
[MME_TIMER_UE_CONTEXT_RELEASE] =
{ .max_count = 2, .duration = ogs_time_from_sec(1) },
[MME_TIMER_T3413] =
{ .max_count = 2, .duration = ogs_time_from_sec(2) },
[MME_TIMER_T3422] =
@ -54,6 +56,8 @@ const char *mme_timer_get_name(mme_timer_e id)
switch (id) {
case MME_TIMER_S1_DELAYED_SEND:
return "MME_TIMER_S1_DELAYED_SEND";
case MME_TIMER_UE_CONTEXT_RELEASE:
return "MME_TIMER_UE_CONTEXT_RELEASE";
case MME_TIMER_T3413:
return "MME_TIMER_T3413";
case MME_TIMER_T3422:
@ -91,6 +95,49 @@ void mme_timer_s1_delayed_send(void *data)
}
}
static void s1_timer_event_send(
mme_timer_e timer_id, enb_ue_t *enb_ue)
{
int rv;
mme_event_t *e = NULL;
ogs_assert(enb_ue);
e = mme_event_new(MME_EVT_S1AP_TIMER);
e->timer_id = timer_id;
e->enb_ue = enb_ue;
e->enb = enb_ue->enb;
rv = ogs_queue_push(mme_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
mme_event_free(e);
}
}
void mme_timer_ue_context_release(void *data)
{
s1_timer_event_send(MME_TIMER_UE_CONTEXT_RELEASE, data);
}
static void emm_timer_event_send(
mme_timer_e timer_id, mme_ue_t *mme_ue)
{
int rv;
mme_event_t *e = NULL;
ogs_assert(mme_ue);
e = mme_event_new(MME_EVT_EMM_TIMER);
e->timer_id = timer_id;
e->mme_ue = mme_ue;
rv = ogs_queue_push(mme_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
mme_event_free(e);
}
}
void mme_timer_t3413_expire(void *data)
{
emm_timer_event_send(MME_TIMER_T3413, data);
@ -111,28 +158,6 @@ void mme_timer_t3470_expire(void *data)
{
emm_timer_event_send(MME_TIMER_T3470, data);
}
void mme_timer_t3489_expire(void *data)
{
esm_timer_event_send(MME_TIMER_T3489, data);
}
static void emm_timer_event_send(
mme_timer_e timer_id, mme_ue_t *mme_ue)
{
int rv;
mme_event_t *e = NULL;
ogs_assert(mme_ue);
e = mme_event_new(MME_EVT_EMM_TIMER);
e->timer_id = timer_id;
e->mme_ue = mme_ue;
rv = ogs_queue_push(mme_self()->queue, e);
if (rv != OGS_OK) {
ogs_warn("ogs_queue_push() failed:%d", (int)rv);
mme_event_free(e);
}
}
static void esm_timer_event_send(
mme_timer_e timer_id, mme_bearer_t *bearer)
@ -156,6 +181,11 @@ static void esm_timer_event_send(
}
}
void mme_timer_t3489_expire(void *data)
{
esm_timer_event_send(MME_TIMER_T3489, data);
}
void mme_timer_sgs_cli_conn_to_srv(void *data)
{
int rv;

View File

@ -32,6 +32,8 @@ typedef enum {
MME_TIMER_S1_DELAYED_SEND,
MME_TIMER_UE_CONTEXT_RELEASE,
/* Paging procedure for EPS services initiated */
MME_TIMER_T3413,
@ -70,6 +72,7 @@ mme_timer_cfg_t *mme_timer_cfg(mme_timer_e id);
const char *mme_timer_get_name(mme_timer_e id);
void mme_timer_s1_delayed_send(void *data);
void mme_timer_ue_context_release(void *data);
void mme_timer_t3413_expire(void *data);
void mme_timer_t3422_expire(void *data);

View File

@ -271,6 +271,7 @@ int nas_send_detach_accept(mme_ue_t *mme_ue)
ogs_assert(rv == OGS_OK);
}
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_detach,
S1AP_UE_CTX_REL_S1_NORMAL_RELEASE, 0);

View File

@ -928,6 +928,7 @@ void s1ap_handle_ue_context_release_request(
}
} else {
ogs_debug(" S1 Context Not Associated");
CLEAR_ENB_UE_TIMER(enb_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
@ -989,6 +990,7 @@ void s1ap_handle_ue_context_release_complete(
ogs_assert(rv == OGS_OK);
return;
}
mme_ue = enb_ue->mme_ue;
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
@ -1630,6 +1632,7 @@ void s1ap_handle_handover_failure(mme_enb_t *enb, s1ap_message_t *message)
rv = s1ap_send_handover_preparation_failure(source_ue, Cause);
ogs_assert(rv == OGS_OK);
CLEAR_ENB_UE_TIMER(target_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(
target_ue, S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system,
@ -1702,6 +1705,7 @@ void s1ap_handle_handover_cancel(mme_enb_t *enb, s1ap_message_t *message)
rv = s1ap_send_handover_cancel_ack(source_ue);
ogs_assert(rv == OGS_OK);
CLEAR_ENB_UE_TIMER(target_ue->t_ue_context_release);
rv = s1ap_send_ue_context_release_command(
target_ue, S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_handover_cancelled,

View File

@ -283,22 +283,47 @@ int s1ap_send_ue_context_release_command(
int rv;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_assert(action != S1AP_UE_CTX_REL_INVALID_ACTION);
ogs_assert(enb_ue);
enb_ue->ue_ctx_rel_action = action;
ogs_debug("[MME] UE Context release command");
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]",
group, (int)cause, action, delay);
rv = s1ap_build_ue_context_release_command(&s1apbuf, enb_ue, group, cause);
ogs_assert(rv == OGS_OK && s1apbuf);
if (delay) {
ogs_assert(action != S1AP_UE_CTX_REL_INVALID_ACTION);
enb_ue->ue_ctx_rel_action = action;
rv = s1ap_delayed_send_to_enb_ue(enb_ue, s1apbuf, delay);
ogs_assert(rv == OGS_OK);
ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]",
group, (int)cause, action, delay);
rv = s1ap_build_ue_context_release_command(
&s1apbuf, enb_ue, group, cause);
ogs_assert(rv == OGS_OK && s1apbuf);
rv = s1ap_delayed_send_to_enb_ue(enb_ue, s1apbuf, delay);
ogs_assert(rv == OGS_OK);
} else {
if (enb_ue->t_ue_context_release.pkbuf) {
s1apbuf = enb_ue->t_ue_context_release.pkbuf;
} else {
ogs_assert(action != S1AP_UE_CTX_REL_INVALID_ACTION);
enb_ue->ue_ctx_rel_action = action;
ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]",
group, (int)cause, action, delay);
rv = s1ap_build_ue_context_release_command(
&s1apbuf, enb_ue, group, cause);
ogs_assert(rv == OGS_OK && s1apbuf);
}
enb_ue->t_ue_context_release.pkbuf = ogs_pkbuf_copy(s1apbuf);
ogs_timer_start(enb_ue->t_ue_context_release.timer,
mme_timer_cfg(MME_TIMER_UE_CONTEXT_RELEASE)->duration);
rv = s1ap_delayed_send_to_enb_ue(enb_ue, s1apbuf, 0);
ogs_assert(rv == OGS_OK);
}
return OGS_OK;
}

View File

@ -192,6 +192,25 @@ void s1ap_state_operational(ogs_fsm_t *s, mme_event_t *e)
ogs_assert(e->pkbuf);
ogs_assert(OGS_OK == s1ap_send_to_enb_ue(e->enb_ue, e->pkbuf));
ogs_timer_delete(e->timer);
break;
case MME_TIMER_UE_CONTEXT_RELEASE:
ogs_assert(e->enb_ue);
if (e->enb_ue->t_ue_context_release.retry_count >=
mme_timer_cfg(MME_TIMER_UE_CONTEXT_RELEASE)->max_count) {
/* Paging failed */
ogs_warn("[S1AP] UE Context Release failed. Stop Releasing");
CLEAR_ENB_UE_TIMER(e->enb_ue->t_ue_context_release);
} else {
e->enb_ue->t_ue_context_release.retry_count++;
/*
* If timeout, the saved pkbuf is used.
* We don't have to set function parameter.
* So, we just set all parameters to 0
*/
s1ap_send_ue_context_release_command(e->enb_ue, 0, 0, 0, 0);
}
break;
default:
ogs_error("Unknown timer[%s:%d]",