ECM_IDLE/CONNECTED is introduced

This commit is contained in:
Sukchan Lee 2018-01-29 14:48:51 +09:00
parent 60cfbed747
commit ae6e747e52
5 changed files with 159 additions and 70 deletions

View File

@ -1737,7 +1737,6 @@ unsigned int enb_ue_count()
status_t enb_ue_remove(enb_ue_t *enb_ue)
{
status_t rv;
d_assert(self.mme_ue_s1ap_id_hash, return CORE_ERROR, "Null param");
d_assert(enb_ue, return CORE_ERROR, "Null param");
d_assert(enb_ue->enb, return CORE_ERROR, "Null param");
@ -1746,9 +1745,6 @@ status_t enb_ue_remove(enb_ue_t *enb_ue)
hash_set(self.mme_ue_s1ap_id_hash, &enb_ue->mme_ue_s1ap_id,
sizeof(enb_ue->mme_ue_s1ap_id), NULL);
rv = source_ue_deassociate_target_ue(enb_ue);
d_assert(rv == CORE_OK, return CORE_ERROR, "Null param");
index_free(&enb_ue_pool, enb_ue);
return CORE_OK;
@ -1906,8 +1902,6 @@ status_t mme_ue_remove(mme_ue_t *mme_ue)
mme_sess_remove_all(mme_ue);
mme_pdn_remove_all(mme_ue);
mme_ue_deassociate_enb_ue(mme_ue->enb_ue);
index_free(&mme_ue_pool, mme_ue);
return CORE_OK;
@ -2171,12 +2165,6 @@ status_t mme_ue_set_imsi(mme_ue_t *mme_ue, c_int8_t *imsi_bcd)
return CORE_OK;
}
/*
* S1AP Initial UE-Message : S-TMSI
* NAS ATTACH_REQUEST : IMSI, GUTI
* NAS TAU_REQUEST : GUTI
* S1AP Handover Notification
*/
status_t mme_ue_associate_enb_ue(mme_ue_t *mme_ue, enb_ue_t *enb_ue)
{
d_assert(mme_ue, return CORE_ERROR, "Null param");
@ -2188,15 +2176,6 @@ status_t mme_ue_associate_enb_ue(mme_ue_t *mme_ue, enb_ue_t *enb_ue)
return CORE_OK;
}
/*
* mme_ue_remove()
*
* Note : should not call in enb_ue_remove()
*
* When mme_ue is removed, enb_ue->mme_ue must be NULL.
* However, when enb_ue is removed, mme_ue->enb_ue need not be NULL.
* mme_ue->enb_ue will be updated again when enb_ue is added.
*/
status_t mme_ue_deassociate_enb_ue(enb_ue_t *enb_ue)
{
mme_ue_t *mme_ue = NULL;
@ -2211,9 +2190,6 @@ status_t mme_ue_deassociate_enb_ue(enb_ue_t *enb_ue)
return CORE_OK;
}
/*
* S1AP Handover Required
*/
status_t source_ue_associate_target_ue(
enb_ue_t *source_ue, enb_ue_t *target_ue)
{
@ -2231,13 +2207,6 @@ status_t source_ue_associate_target_ue(
return CORE_OK;
}
/*
* enb_ue_remove()
*
* enb_ue->mme_ue->enb_ue should not be set to NULL.
* This is because enb_ue is not known as source_ue or target_ue.
* Therefore, when enb_ue is removed, leave enb_ue->mme_ue->enb_ue as is.
*/
status_t source_ue_deassociate_target_ue(enb_ue_t *enb_ue)
{
enb_ue_t *source_ue = NULL;

View File

@ -285,7 +285,11 @@ struct _mme_ue_t {
c_uint8_t ebi; /* EPS Bearer ID generator */
list_t sess_list;
/* eNB UE context */
#define MME_UE_ECM_IDLE(__mME) \
((__mME) && ((__mME)->enb_ue == NULL))
#define MME_UE_ECM_CONNECTED(__mME) \
((__mME) && ((__mME)->enb_ue != NULL))
/* S1 UE context */
enb_ue_t *enb_ue;
/* Save PDN Connectivity Request */
@ -495,6 +499,58 @@ CORE_DECLARE(mme_ue_t*) mme_ue_find_by_teid(c_uint32_t teid);
CORE_DECLARE(mme_ue_t*) mme_ue_find_by_message(nas_message_t *message);
CORE_DECLARE(status_t) mme_ue_set_imsi(
mme_ue_t *mme_ue, c_int8_t *imsi_bcd);
/*
* o RECV Initial UE-Message : S-TMSI
* o RECV Attach Request : IMSI, GUTI
* o RECV TAU Request : GUTI
* ### MME_UE_ASSOCIATE_ENB_UE() ###
* ### MME_UE_ECM_CONNECTED() ###
*
* o RECV Initial Context Setup Failure in EMM Registered State
* ### MME_UE_DEASSOCIATE_ENB_UE() ###
* ### MME_UE_ECM_IDLE() ###
* ### ENB_UE_REMOVE() ###
*
* o SEND UE Context Release Command with NO_ACTION
* - RECV UE Context Release Complete
* ### MME_UE_DEASSOCIATE_ENB_UE() ###
* ### MME_UE_ECM_IDLE() ###
* ### ENB_UE_REMOVE() ###
*
* o SEND UE Context Release Command with REMOVE_MME_UE_CONTEXT
* - RECV UE Context Release Complete
* ### MME_UE_DEASSOCIATE_ENB_UE() ###
* ### MME_UE_ECM_IDLE() ###
* ### ENB_UE_REMOVE() ###
* ### MME_UE_REMOVE() ###
*
*
* o RECV Handover Required
* ### SOURCE_UE_ASSOCIATE_TARGET_UE() ####
* - SEND Handover Request
*
* o RECV Handover Notify
* ### MME_UE_ASSOCIATE_ENB_UE(TARGET) ###
* ### MME_UE_ECM_CONNECTED(TARGET) ###
* - Modify Bearer Request/Response
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*
* o RECV Handover Cancel
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*
* o RECV Handover Failure
* - UE Context Release Command/Complete
* ### SOURCE_UE_DEASSOCIATE_TARGET_UE() ####
* ### ENB_UE_REMOVE() ####
* - Delete Indirect Data Forwarding Tunnel Request/Response
*/
CORE_DECLARE(status_t) mme_ue_associate_enb_ue(
mme_ue_t *mme_ue, enb_ue_t *enb_ue);
CORE_DECLARE(status_t) mme_ue_deassociate_enb_ue(enb_ue_t *enb_ue);

View File

@ -269,6 +269,7 @@ void mme_state_operational(fsm_t *s, event_t *e)
#endif
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
else
d_assert(mme_ue, pkbuf_free(pkbuf); break, "No MME UE context");
d_assert(FSM_STATE(&mme_ue->sm), pkbuf_free(pkbuf); break,
@ -478,7 +479,21 @@ void mme_state_operational(fsm_t *s, event_t *e)
mme_s11_handle_downlink_data_notification(
xact, mme_ue, &message.downlink_data_notification);
if (mme_ue->enb_ue == NULL)
/*
* 5.3.4.2 in Spec 23.401
* Under certain conditions, the current UE triggered Service Request
* procedure can cause unnecessary Downlink Packet Notification messages
* which increase the load of the MME.
*
* This can occur when uplink data sent in step 6 causes a response
* on the downlink which arrives at the Serving GW before the Modify Bearer
* Request message, step 8. This data cannot be forwarded from the Serving GW
* to the eNodeB and hence it triggers a Downlink Data Notification message.
*
* If the MME receives a Downlink Data Notification after step 2 and
* before step 9, the MME shall not send S1 interface paging messages
*/
if (MME_UE_ECM_IDLE(mme_ue))
{
s1ap_handle_paging(mme_ue);
/* Start T3413 */

View File

@ -105,6 +105,7 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
S1ap_CellIdentity_t *cell_ID = NULL;
d_assert(enb, return, "Null param");
d_assert(enb->sock, return, "Null param");
ies = &message->s1ap_InitialUEMessage_IEs;
d_assert(ies, return, "Null param");
@ -194,7 +195,6 @@ void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
sizeof(enb_ue->nas.e_cgi.cell_id));
enb_ue->nas.e_cgi.cell_id = (ntohl(enb_ue->nas.e_cgi.cell_id) >> 4);
d_assert(enb->sock, enb_ue_remove(enb_ue); return,);
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] TAC[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id, enb_ue->nas.tai.tac);
@ -371,16 +371,51 @@ void s1ap_handle_initial_context_setup_failure(
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
d_trace(5, " Registered State\n");
/*
* 19.2.2.3 in Spec 36.300
*
* In case of failure, eNB and MME behaviours are not mandated.
*
* Both implicit release (local release at each node) and
* explicit release (MME-initiated UE Context Release procedure)
* may in principle be adopted. The eNB should ensure
* that no hanging resources remain at the eNB.
*/
#if 0 /* FIXME : Does it needed? */
rv = nas_send_service_reject(mme_ue,
EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
d_assert(rv == CORE_OK,,
"nas_send_service_reject() failed");
#endif
#if 1 /* Implicitly Detach */
d_trace(5, " Implicit Release\n");
rv = mme_ue_deassociate_enb_ue(enb_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate_enb_ue() failed");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
#else /* Explicitly Detach */
d_trace(5, " Explicit Release\n");
#if 1 /* NAS Cause : Detach */
d_trace(5, " NAS-CAUSE: DETACH\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_detach,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
#else /* NAS Cause : Normal Release */
d_trace(5, " NAS-CAUSE: Normal Release\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
#endif
#endif
}
else
{
@ -611,7 +646,6 @@ void s1ap_handle_ue_context_release_complete(
status_t rv;
char buf[CORE_ADDRSTRLEN];
c_uint8_t ue_ctx_rel_action = 0;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_UEContextReleaseComplete_IEs_t *ies = NULL;
@ -625,44 +659,60 @@ void s1ap_handle_ue_context_release_complete(
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(enb_ue, return, "No UE Context[%d]", ies->mme_ue_s1ap_id);
mme_ue = enb_ue->mme_ue;
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ue_ctx_rel_action = enb_ue->ue_ctx_rel_action;
enb_ue->ue_ctx_rel_action = S1AP_UE_CTX_REL_INVALID_ACTION;
mme_ue = enb_ue->mme_ue;
enb_ue_remove(enb_ue);
if (mme_ue)
switch (enb_ue->ue_ctx_rel_action)
{
switch (ue_ctx_rel_action)
case S1AP_UE_CTX_REL_NO_ACTION:
{
case S1AP_UE_CTX_REL_NO_ACTION:
{
d_trace(5, " No Action\n");
break;
}
case S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT:
{
d_trace(5, " Action: UE(mme) context\n");
mme_ue_remove(mme_ue);
break;
}
case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL:
{
d_trace(5, " Action: Delete indirect tunnel\n");
rv = mme_gtp_send_delete_indirect_data_forwarding_tunnel_request(
mme_ue);
d_assert(rv == CORE_OK, return, "gtp send error");
break;
}
default:
{
d_assert(0, return, "Invalid action[%d]", ue_ctx_rel_action);
break;
}
d_trace(5, " No Action\n");
rv = mme_ue_deassociate_enb_ue(enb_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate_enb_ue() failed");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
break;
}
case S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT:
{
d_trace(5, " Action: UE(mme) context\n");
rv = mme_ue_deassociate_enb_ue(enb_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate_enb_ue() failed");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_removeI() failed");
d_assert(mme_ue,,);
rv = mme_ue_remove(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_remove() failed");
break;
}
case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL:
{
d_trace(5, " Action: Delete indirect tunnel\n");
rv = source_ue_deassociate_target_ue(enb_ue);
d_assert(rv == CORE_OK,,
"source_ue_deassociate_target_ue() failed");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_removeI() failed");
d_assert(mme_ue,,);
rv = mme_gtp_send_delete_indirect_data_forwarding_tunnel_request(
mme_ue);
d_assert(rv == CORE_OK,,
"mme_gtp_send_delete_indirect_data_forwarding_tunnel_request()"
"failed");
break;
}
default:
{
d_assert(0,, "Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
break;
}
}
}

View File

@ -424,11 +424,10 @@ status_t s1ap_send_handover_request(
d_assert(rv == CORE_OK, return CORE_ERROR,);
rv = s1ap_build_handover_request(&s1apbuf, mme_ue, target_ue, ies);
d_assert(rv == CORE_OK && s1apbuf,
enb_ue_remove(target_ue); return CORE_ERROR, "s1ap build error");
d_assert(rv == CORE_OK && s1apbuf, return CORE_ERROR, "s1ap build error");
rv = s1ap_send_to_enb(target_enb, s1apbuf);
d_assert(rv == CORE_OK, enb_ue_remove(target_ue), "s1ap send error");
d_assert(rv == CORE_OK,, "s1ap send error");
return rv;
}