open5gs/src/mme/s1ap_handler.c

1318 lines
45 KiB
C

#define TRACE_MODULE _s1ap_handler
#include "core_debug.h"
#include "mme_event.h"
#include "mme_kdf.h"
#include "s1ap_conv.h"
#include "s1ap_path.h"
#include "nas_path.h"
#include "mme_gtp_path.h"
#include "mme_s11_build.h"
#include "s1ap_build.h"
#include "s1ap_handler.h"
#include "mme_path.h"
#include "mme_sm.h"
void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
S1ap_S1SetupRequestIEs_t *ies = NULL;
pkbuf_t *s1apbuf = NULL;
c_uint32_t enb_id;
int i, j;
d_assert(enb, return, "Null param");
d_assert(enb->sock, return, "Null param");
d_assert(message, return, "Null param");
ies = &message->s1ap_S1SetupRequestIEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] S1-Setup request\n");
s1ap_ENB_ID_to_uint32(&ies->global_ENB_ID.eNB_ID, &enb_id);
d_trace(5, " IP[%s] ENB_ID[%d]\n", CORE_ADDR(enb->addr, buf), enb_id);
/* Parse Supported TA */
enb->num_of_supported_ta_list = 0;
for (i = 0; i < ies->supportedTAs.list.count; i++)
{
S1ap_SupportedTAs_Item_t *tai = NULL;
S1ap_TAC_t *tAC;
tai = (S1ap_SupportedTAs_Item_t *)ies->supportedTAs.list.array[i];
tAC = &tai->tAC;
for (j = 0; j < tai->broadcastPLMNs.list.count; j++)
{
S1ap_PLMNidentity_t *pLMNidentity = NULL;
pLMNidentity =
(S1ap_PLMNidentity_t *)tai->broadcastPLMNs.list.array[j];
memcpy(&enb->supported_ta_list[enb->num_of_supported_ta_list].tac,
tAC->buf, sizeof(c_uint16_t));
enb->supported_ta_list[enb->num_of_supported_ta_list].tac =
ntohs(enb->supported_ta_list
[enb->num_of_supported_ta_list].tac);
d_trace(5, " TAC[%d]\n",
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
memcpy(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id,
pLMNidentity->buf, sizeof(plmn_id_t));
d_trace(5, " PLMN_ID[MCC:%d MNC:%d]\n",
plmn_id_mcc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
plmn_id_mnc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id));
enb->num_of_supported_ta_list++;
}
}
if (enb->num_of_supported_ta_list == 0)
{
d_error("No supported TA exist in s1stup_req messages");
}
d_assert(enb->sock, return,);
d_trace(3, "[MME] S1-Setup response\n");
d_assert(mme_enb_set_enb_id(enb, enb_id) == CORE_OK,
return, "hash add error");
d_assert(s1ap_build_setup_rsp(&s1apbuf) == CORE_OK,
return, "build error");
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK, , "send error");
d_assert(enb->sock, return,);
}
void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
S1ap_InitialUEMessage_IEs_t *ies = NULL;
S1ap_TAI_t *tai = NULL;
S1ap_PLMNidentity_t *pLMNidentity = NULL;
S1ap_TAC_t *tAC = NULL;
S1ap_EUTRAN_CGI_t *eutran_cgi = NULL;
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");
d_trace(3, "[MME] Initial UE Message\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
if (!enb_ue)
{
enb_ue = enb_ue_add(enb);
d_assert(enb_ue, return, "Null param");
enb_ue->enb_ue_s1ap_id = ies->eNB_UE_S1AP_ID;
/* Find MME_UE if s_tmsi included */
if (ies->presenceMask & S1AP_INITIALUEMESSAGE_IES_S_TMSI_PRESENT)
{
S1ap_S_TMSI_t *s_tmsi = &ies->s_tmsi;
served_gummei_t *served_gummei = &mme_self()->served_gummei[0];
guti_t guti;
mme_ue_t *mme_ue = NULL;
memset(&guti, 0, sizeof(guti_t));
/* Use the first configured plmn_id and mme group id */
memcpy(&guti.plmn_id, &served_gummei->plmn_id[0], PLMN_ID_LEN);
guti.mme_gid = served_gummei->mme_gid[0];
/* size must be 1 */
memcpy(&guti.mme_code, s_tmsi->mMEC.buf, s_tmsi->mMEC.size);
/* size must be 4 */
memcpy(&guti.m_tmsi, s_tmsi->m_TMSI.buf, s_tmsi->m_TMSI.size);
guti.m_tmsi = ntohl(guti.m_tmsi);
mme_ue = mme_ue_find_by_guti(&guti);
if (!mme_ue)
{
d_warn("Unknown UE by S_TMSI[G:%d,C:%d,M_TMSI:0x%x]",
guti.mme_gid, guti.mme_code, guti.m_tmsi);
}
else
{
d_trace(5, " S_TMSI[G:%d,C:%d,M_TMSI:0x%x] IMSI:[%s]\n",
mme_ue->guti.mme_gid,
mme_ue->guti.mme_code,
mme_ue->guti.m_tmsi,
MME_UE_HAVE_IMSI(mme_ue)
? mme_ue->imsi_bcd : "Unknown");
/* If NAS(mme_ue_t) has already been associated with
* older S1(enb_ue_t) context */
if (mme_ue->enb_ue)
{
#if SEND_UE_CTX_REL_CMD_IMMEDIATELY
/* Send UE context release command to
* older S1 context immediately. */
d_trace(5, "OLD ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = s1ap_send_ue_context_release_command(mme_ue->enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_NO_ACTION, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
#elif IMPLICIT_S1_RELEASE
/* Implcit S1 release */
d_warn("Implicit S1 release");
d_warn(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
rv = enb_ue_remove(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
#else /* S1_HOLDING_TIMER */
/* Previous S1(enb_ue_t) context the holding timer(30secs)
* is started.
* Newly associated S1(enb_ue_t) context holding timer
* is stopped. */
d_trace(5, "Start S1 Holding Timer\n");
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
mme_ue->enb_ue->enb_ue_s1ap_id,
mme_ue->enb_ue->mme_ue_s1ap_id);
/* De-associate S1 with NAS/EMM */
rv = enb_ue_deassociate(mme_ue->enb_ue);
d_assert(rv == CORE_OK,,);
tm_start(mme_ue->enb_ue->holding_timer);
#endif
}
tm_stop(enb_ue->holding_timer);
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
}
}
tai = &ies->tai;
d_assert(tai, return,);
pLMNidentity = &tai->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
tAC = &tai->tAC;
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
memcpy(&enb_ue->nas.tai.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.tai.plmn_id));
memcpy(&enb_ue->nas.tai.tac, tAC->buf, sizeof(enb_ue->nas.tai.tac));
enb_ue->nas.tai.tac = ntohs(enb_ue->nas.tai.tac);
eutran_cgi = &ies->eutran_cgi;
d_assert(eutran_cgi, return,);
pLMNidentity = &eutran_cgi->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
cell_ID = &eutran_cgi->cell_ID;
d_assert(cell_ID, return,);
memcpy(&enb_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.e_cgi.plmn_id));
memcpy(&enb_ue->nas.e_cgi.cell_id, cell_ID->buf,
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_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);
d_assert(s1ap_send_to_nas(enb_ue, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
}
void s1ap_handle_uplink_nas_transport(
mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
S1ap_UplinkNASTransport_IEs_t *ies = NULL;
ies = &message->s1ap_UplinkNASTransport_IEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] Uplink NAS transport\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
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);
d_assert(s1ap_send_to_nas(enb_ue, &ies->nas_pdu) == CORE_OK,,
"s1ap_send_to_nas failed");
}
void s1ap_handle_ue_capability_info_indication(
mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
S1ap_UECapabilityInfoIndicationIEs_t *ies = NULL;
ies = &message->s1ap_UECapabilityInfoIndicationIEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] UE capability info indication\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
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);
if (enb_ue->mme_ue)
{
S1ap_UERadioCapability_t *ue_radio_capa = NULL;
S1ap_UERadioCapability_t *radio_capa = NULL;
mme_ue_t *mme_ue = enb_ue->mme_ue;
ue_radio_capa = &ies->ueRadioCapability;
/* Release the previous one */
if (mme_ue->radio_capa)
{
radio_capa = (S1ap_UERadioCapability_t *)mme_ue->radio_capa;
if (radio_capa->buf)
CORE_FREE(radio_capa->buf);
CORE_FREE(mme_ue->radio_capa);
}
/* Save UE radio capability */
mme_ue->radio_capa = core_calloc(1, sizeof(S1ap_UERadioCapability_t));
radio_capa = (S1ap_UERadioCapability_t *)mme_ue->radio_capa;
d_assert(radio_capa,return,"core_calloc Error");
radio_capa->size = ue_radio_capa->size;
radio_capa->buf =
core_calloc(radio_capa->size, sizeof(c_uint8_t));
d_assert(radio_capa->buf,return,"core_calloc Error(size=%d)",
radio_capa->size);
memcpy(radio_capa->buf, ue_radio_capa->buf, radio_capa->size);
}
}
void s1ap_handle_initial_context_setup_response(
mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
int i = 0;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
S1ap_InitialContextSetupResponseIEs_t *ies = NULL;
ies = &message->s1ap_InitialContextSetupResponseIEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] Initial context setup response\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
mme_ue = enb_ue->mme_ue;
d_assert(mme_ue, return,);
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);
for (i = 0; i < ies->e_RABSetupListCtxtSURes.
s1ap_E_RABSetupItemCtxtSURes.count; i++)
{
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
S1ap_E_RABSetupItemCtxtSURes_t *e_rab = NULL;
e_rab = (S1ap_E_RABSetupItemCtxtSURes_t *)
ies->e_RABSetupListCtxtSURes.s1ap_E_RABSetupItemCtxtSURes.array[i];
d_assert(e_rab, return, "Null param");
sess = mme_sess_find_by_ebi(mme_ue, e_rab->e_RAB_ID);
d_assert(sess, return, "Null param");
bearer = mme_default_bearer_in_sess(sess);
d_assert(bearer, return, "Null param");
memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf,
sizeof(bearer->enb_s1u_teid));
bearer->enb_s1u_teid = ntohl(bearer->enb_s1u_teid);
rv = s1ap_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
d_assert(rv == CORE_OK, return,);
d_trace(5, " EBI[%d] ENB-S1U-TEID[%d]\n",
bearer->ebi, bearer->enb_s1u_teid);
if (FSM_CHECK(&bearer->sm, esm_state_active))
{
int uli_presence = 0;
if (mme_ue->nas_eps.type != MME_EPS_TYPE_ATTACH_REQUEST)
{
uli_presence = 1;
}
rv = mme_gtp_send_modify_bearer_request(bearer, uli_presence);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
}
}
void s1ap_handle_initial_context_setup_failure(
mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
S1ap_InitialContextSetupFailureIEs_t *ies = NULL;
ies = &message->s1ap_InitialContextSetupFailureIEs;
d_assert(ies, return, "Null param");
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
mme_ue = enb_ue->mme_ue;
d_trace(3, "[MME] Initial context setup failure\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
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);
d_trace(5, " Cause[Group:%d Cause:%d]\n",
ies->cause.present, ies->cause.choice.radioNetwork);
d_assert(mme_ue,,);
if (mme_ue && FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
d_trace(5, " EMM-Registered\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 /* NOTHING TO DO */
#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 /* Explicit Release */
d_trace(5, " Explicit Release\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas,
#if 1 /* NAS Cause: Normal Relase */
S1ap_CauseNas_normal_release,
#else /* NAS Cause : Detach */
S1ap_CauseNas_detach,
#endif
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK,, "s1ap send error");
#else /* Implicit Release */
d_trace(5, " Implicit Release\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
rv = mme_ue_deassociate(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate() failed");
#endif
#endif
}
else
{
d_trace(5, " NOT EMM-Registered\n");
d_assert(mme_ue,,);
rv = mme_send_ue_context_release_command(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_ue_context_release_command failed");
}
}
void s1ap_handle_e_rab_setup_response(
mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
int i;
enb_ue_t *enb_ue = NULL;
S1ap_E_RABSetupResponseIEs_t *ies = NULL;
mme_ue_t *mme_ue = NULL;
d_assert(enb, return, "Null param");
d_assert(message, return, "Null param");
ies = &message->s1ap_E_RABSetupResponseIEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] E-RAB setup response\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(enb_ue, return, "No UE Context[%d]", ies->eNB_UE_S1AP_ID);
mme_ue = enb_ue->mme_ue;
d_assert(mme_ue, return,);
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);
for (i = 0; i < ies->e_RABSetupListBearerSURes.
s1ap_E_RABSetupItemBearerSURes.count; i++)
{
mme_bearer_t *bearer = NULL;
S1ap_E_RABSetupItemBearerSURes_t *e_rab = NULL;
e_rab = (S1ap_E_RABSetupItemBearerSURes_t *)ies->
e_RABSetupListBearerSURes.s1ap_E_RABSetupItemBearerSURes.array[i];
d_assert(e_rab, return, "Null param");
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
d_assert(bearer, return, "Null param");
memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf,
sizeof(bearer->enb_s1u_teid));
bearer->enb_s1u_teid = ntohl(bearer->enb_s1u_teid);
rv = s1ap_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
d_assert(rv == CORE_OK, return,);
d_trace(5, " EBI[%d]\n", bearer->ebi);
if (FSM_CHECK(&bearer->sm, esm_state_active))
{
status_t rv;
mme_bearer_t *linked_bearer = mme_linked_bearer(bearer);
d_assert(linked_bearer, return, "Null param");
d_trace(5, " Linked-EBI[%d]\n", linked_bearer->ebi);
if (bearer->ebi == linked_bearer->ebi)
{
rv = mme_gtp_send_modify_bearer_request(bearer, 0);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
else
{
rv = mme_gtp_send_create_bearer_response(bearer);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
}
}
}
void s1ap_handle_ue_context_release_request(
mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_UEContextReleaseRequest_IEs_t *ies = NULL;
d_assert(enb, return,);
d_assert(message, return,);
ies = &message->s1ap_UEContextReleaseRequest_IEs;
d_assert(ies, return,);
d_trace(3, "[MME] UE Context release request\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
if (!enb_ue)
{
d_assert(0,,);
d_warn("No ENB UE Context : MME_UE_S1AP_ID[%d]", ies->mme_ue_s1ap_id);
rv = s1ap_send_error_indication(enb,
S1AP_ERRORINDICATIONIES_MME_UE_S1AP_ID_PRESENT |
S1AP_ERRORINDICATIONIES_ENB_UE_S1AP_ID_PRESENT |
S1AP_ERRORINDICATIONIES_CAUSE_PRESENT,
ies->eNB_UE_S1AP_ID,
ies->mme_ue_s1ap_id,
S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
d_assert(rv == CORE_OK, return, "s1ap send error");
return;
}
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);
d_trace(5, " Cause[Group:%d Cause:%d]\n",
ies->cause.present, ies->cause.choice.radioNetwork);
switch(ies->cause.present)
{
case S1ap_Cause_PR_radioNetwork:
case S1ap_Cause_PR_transport:
case S1ap_Cause_PR_protocol:
case S1ap_Cause_PR_misc:
break;
case S1ap_Cause_PR_nas:
d_warn("NAS-Cause[%d]", ies->cause.choice.nas);
default:
d_warn("Invalid cause group[%d]", ies->cause.present);
break;
}
mme_ue = enb_ue->mme_ue;
if (mme_ue)
{
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
{
d_trace(5, " EMM-Registered\n");
if (MME_BEARER_ACTIVE(mme_ue))
{
d_trace(5, " Bearer-Active\n");
rv = mme_gtp_send_release_access_bearers_request(mme_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
else
{
d_trace(5, " Bearer-Inactive\n");
rv = s1ap_send_ue_context_release_command(enb_ue,
S1ap_Cause_PR_nas, S1ap_CauseNas_normal_release,
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
}
else
{
d_trace(5, " NOT EMM-Registered\n");
rv = mme_send_ue_context_release_command(mme_ue, enb_ue);
d_assert(rv == CORE_OK,,
"mme_send_ue_context_release_command failed");
}
}
else
{
d_trace(5, " S1 Context Not Associated\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, return, "s1ap send error");
}
}
void s1ap_handle_ue_context_release_complete(
mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_UEContextReleaseComplete_IEs_t *ies = NULL;
ies = &message->s1ap_UEContextReleaseComplete_IEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] UE Context release complete\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
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);
switch (enb_ue->ue_ctx_rel_action)
{
case S1AP_UE_CTX_REL_NO_ACTION:
{
d_trace(5, " No Action\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
break;
}
case S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT:
{
d_trace(5, " Action: Unlink UE(mme) context\n");
rv = enb_ue_remove(enb_ue);
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
d_assert(mme_ue,,);
rv = mme_ue_deassociate(mme_ue);
d_assert(rv == CORE_OK,, "mme_ue_deassociate() failed");
break;
}
case S1AP_UE_CTX_REL_REMOVE_MME_UE_CONTEXT:
{
d_trace(5, " Action: Remove UE(mme) context\n");
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,,);
if (SESSION_CONTEXT_IS_VALID(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");
}
else
{
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
d_warn("GTP-C(S11) has already been deleted");
sess = mme_sess_first(mme_ue);
while(sess)
{
bearer = mme_bearer_first(sess);
while(bearer)
{
CLEAR_INDIRECT_TUNNEL(bearer);
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
}
break;
}
default:
{
d_assert(0,, "Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
break;
}
}
}
void s1ap_handle_paging(mme_ue_t *mme_ue)
{
pkbuf_t *s1apbuf = NULL;
hash_index_t *hi = NULL;
mme_enb_t *enb = NULL;
int i;
status_t rv;
/* Find enB with matched TAI */
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
{
enb = mme_enb_this(hi);
for (i = 0; i < enb->num_of_supported_ta_list; i++)
{
if (!memcmp(&enb->supported_ta_list[i],
&mme_ue->tai, sizeof(tai_t)))
{
if (mme_ue->last_paging_msg)
s1apbuf = mme_ue->last_paging_msg;
else
{
/* Buidl S1Ap Paging message */
rv = s1ap_build_paging(&s1apbuf, mme_ue);
d_assert(rv == CORE_OK && s1apbuf, return,
"s1ap build error");
/* Save it for later use */
mme_ue->last_paging_msg = pkbuf_copy(s1apbuf);
}
/* Send to enb */
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK, return,
"s1ap send error");
}
}
}
}
void s1ap_handle_path_switch_request(
mme_enb_t *enb, s1ap_message_t *message)
{
char buf[CORE_ADDRSTRLEN];
int i;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_PathSwitchRequestIEs_t *ies = NULL;
S1ap_EUTRAN_CGI_t *eutran_cgi;
S1ap_PLMNidentity_t *pLMNidentity = NULL;
S1ap_CellIdentity_t *cell_ID = NULL;
S1ap_TAI_t *tai;
S1ap_TAC_t *tAC = NULL;
S1ap_UESecurityCapabilities_t *ueSecurityCapabilities = NULL;
S1ap_EncryptionAlgorithms_t *encryptionAlgorithms = NULL;
S1ap_IntegrityProtectionAlgorithms_t *integrityProtectionAlgorithms = NULL;
c_uint16_t eea = 0, eia = 0;
d_assert(enb, return, "Null param");
ies = &message->s1ap_PathSwitchRequestIEs;
d_assert(ies, return, "Null param");
d_trace(3, "[MME] Path switch request\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
eutran_cgi = &ies->eutran_cgi;
d_assert(eutran_cgi, return,);
pLMNidentity = &eutran_cgi->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
cell_ID = &eutran_cgi->cell_ID;
d_assert(cell_ID, return,);
tai = &ies->tai;
d_assert(tai, return,);
pLMNidentity = &tai->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
tAC = &tai->tAC;
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
ueSecurityCapabilities = &ies->ueSecurityCapabilities;
d_assert(ueSecurityCapabilities, return,);
encryptionAlgorithms =
&ueSecurityCapabilities->encryptionAlgorithms;
integrityProtectionAlgorithms =
&ueSecurityCapabilities->integrityProtectionAlgorithms;
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->sourceMME_UE_S1AP_ID);
if (!enb_ue)
{
d_error("Cannot find UE from sourceMME-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->sourceMME_UE_S1AP_ID,
CORE_ADDR(enb->addr, buf), enb->enb_id);
s1ap_send_path_switch_failure(enb, ies->eNB_UE_S1AP_ID,
ies->sourceMME_UE_S1AP_ID,
S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
return;
}
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);
mme_ue = enb_ue->mme_ue;
d_assert(mme_ue, return, "Null param");
if (SECURITY_CONTEXT_IS_VALID(mme_ue))
{
mme_ue->nhcc++;
mme_kdf_nh(mme_ue->kasme, mme_ue->nh, mme_ue->nh);
}
else
{
s1ap_send_path_switch_failure(enb, ies->eNB_UE_S1AP_ID,
ies->sourceMME_UE_S1AP_ID,
S1ap_Cause_PR_nas, S1ap_CauseNas_authentication_failure);
return;
}
enb_ue->enb_ue_s1ap_id = ies->eNB_UE_S1AP_ID;
memcpy(&enb_ue->nas.tai.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.tai.plmn_id));
memcpy(&enb_ue->nas.tai.tac, tAC->buf, sizeof(enb_ue->nas.tai.tac));
enb_ue->nas.tai.tac = ntohs(enb_ue->nas.tai.tac);
memcpy(&enb_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->nas.e_cgi.plmn_id));
memcpy(&enb_ue->nas.e_cgi.cell_id, cell_ID->buf,
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_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
enb_ue->nas.tai.plmn_id, enb_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
enb_ue->nas.e_cgi.plmn_id, enb_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->nas.tai, sizeof(tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->nas.e_cgi, sizeof(e_cgi_t));
memcpy(&eea, encryptionAlgorithms->buf, sizeof(eea));
eea = ntohs(eea);
mme_ue->ue_network_capability.eea = eea >> 9;
mme_ue->ue_network_capability.eea0 = 1;
memcpy(&eia, integrityProtectionAlgorithms->buf, sizeof(eia));
eia = ntohs(eia);
mme_ue->ue_network_capability.eia = eia >> 9;
mme_ue->ue_network_capability.eia0 = 0;
for (i = 0; i < ies->e_RABToBeSwitchedDLList.
s1ap_E_RABToBeSwitchedDLItem.count; i++)
{
status_t rv;
mme_bearer_t *bearer = NULL;
S1ap_E_RABToBeSwitchedDLItem_t *e_rab = NULL;
e_rab = (S1ap_E_RABToBeSwitchedDLItem_t *)ies->e_RABToBeSwitchedDLList.
s1ap_E_RABToBeSwitchedDLItem.array[i];
d_assert(e_rab, return, "Null param");
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
d_assert(bearer, return, "Null param");
memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf,
sizeof(bearer->enb_s1u_teid));
bearer->enb_s1u_teid = ntohl(bearer->enb_s1u_teid);
rv = s1ap_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
d_assert(rv == CORE_OK, return,);
GTP_COUNTER_INCREMENT(
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH);
rv = mme_gtp_send_modify_bearer_request(bearer, 1);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
/* Switch to enb */
enb_ue_switch_to_enb(enb_ue, enb);
}
void s1ap_handle_handover_required(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *source_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_HandoverRequiredIEs_t *ies = NULL;
d_assert(enb, return,);
ies = &message->s1ap_HandoverRequiredIEs;
d_assert(ies, return,);
d_trace(3, "[MME] Handover required\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(source_ue, return,
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->eNB_UE_S1AP_ID,
CORE_ADDR(enb->addr, buf), enb->enb_id);
d_assert(source_ue->mme_ue_s1ap_id == ies->mme_ue_s1ap_id, return,
"Conflict MME-UE-S1AP-ID : %d != %d\n",
source_ue->mme_ue_s1ap_id, ies->mme_ue_s1ap_id);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
mme_ue = source_ue->mme_ue;
d_assert(mme_ue, return,);
if (SECURITY_CONTEXT_IS_VALID(mme_ue))
{
mme_ue->nhcc++;
mme_kdf_nh(mme_ue->kasme, mme_ue->nh, mme_ue->nh);
}
else
{
rv = s1ap_send_handover_preparation_failure(source_ue, &ies->cause);
d_assert(rv == CORE_OK, return, "s1ap send error");
return;
}
source_ue->handover_type = ies->handoverType;
rv = s1ap_send_handover_request(mme_ue, ies);
d_assert(rv == CORE_OK,, "s1ap send error");
}
void s1ap_handle_handover_request_ack(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
int i;
enb_ue_t *source_ue = NULL;
enb_ue_t *target_ue = NULL;
mme_ue_t *mme_ue = NULL;
S1ap_HandoverRequestAcknowledgeIEs_t *ies = NULL;
d_assert(enb, return,);
ies = &message->s1ap_HandoverRequestAcknowledgeIEs;
d_assert(ies, return,);
d_trace(3, "[MME] Handover request acknowledge\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
target_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(target_ue, return,
"Cannot find UE for MME-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->mme_ue_s1ap_id,
CORE_ADDR(enb->addr, buf), enb->enb_id);
target_ue->enb_ue_s1ap_id = ies->eNB_UE_S1AP_ID;
source_ue = target_ue->source_ue;
d_assert(source_ue, return,);
mme_ue = source_ue->mme_ue;
d_assert(mme_ue, return,);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
for (i = 0; i < ies->e_RABAdmittedList.s1ap_E_RABAdmittedItem.count; i++)
{
mme_bearer_t *bearer = NULL;
S1ap_E_RABAdmittedItem_t *e_rab = NULL;
e_rab = (S1ap_E_RABAdmittedItem_t *)ies->e_RABAdmittedList.
s1ap_E_RABAdmittedItem.array[i];
d_assert(e_rab, return, "Null param");
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
d_assert(bearer, return, "Null param");
memcpy(&bearer->target_s1u_teid, e_rab->gTP_TEID.buf,
sizeof(bearer->target_s1u_teid));
bearer->target_s1u_teid = ntohl(bearer->target_s1u_teid);
rv = s1ap_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->target_s1u_ip);
d_assert(rv == CORE_OK, return,);
if (e_rab->dL_transportLayerAddress && e_rab->dL_gTP_TEID)
{
d_assert(e_rab->dL_gTP_TEID->buf, return,);
d_assert(e_rab->dL_transportLayerAddress->buf, return,);
memcpy(&bearer->enb_dl_teid, e_rab->dL_gTP_TEID->buf,
sizeof(bearer->enb_dl_teid));
bearer->enb_dl_teid = ntohl(bearer->enb_dl_teid);
rv = s1ap_BIT_STRING_to_ip(
e_rab->dL_transportLayerAddress, &bearer->enb_dl_ip);
d_assert(rv == CORE_OK, return,);
}
if (e_rab->uL_S1ap_TransportLayerAddress && e_rab->uL_S1ap_GTP_TEID)
{
d_assert(e_rab->uL_S1ap_GTP_TEID->buf, return,);
d_assert(e_rab->uL_S1ap_TransportLayerAddress->buf, return,);
memcpy(&bearer->enb_ul_teid, e_rab->uL_S1ap_GTP_TEID->buf,
sizeof(bearer->enb_ul_teid));
bearer->enb_ul_teid = ntohl(bearer->enb_ul_teid);
rv = s1ap_BIT_STRING_to_ip(
e_rab->uL_S1ap_TransportLayerAddress, &bearer->enb_ul_ip);
d_assert(rv == CORE_OK, return,);
}
}
S1AP_STORE_DATA(
&mme_ue->container, &ies->target_ToSource_TransparentContainer);
if (i > 0)
{
rv = mme_gtp_send_create_indirect_data_forwarding_tunnel_request(
mme_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
else
{
rv = s1ap_send_handover_command(source_ue);
d_assert(rv == CORE_OK, return, "gtp send failed");
}
}
void s1ap_handle_handover_failure(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
S1ap_HandoverFailureIEs_t *ies = NULL;
enb_ue_t *target_ue = NULL;
enb_ue_t *source_ue = NULL;
d_assert(enb, return,);
ies = &message->s1ap_HandoverFailureIEs;
d_assert(ies, return,);
d_trace(3, "[MME] Handover failure\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
target_ue = enb_ue_find_by_mme_ue_s1ap_id(ies->mme_ue_s1ap_id);
d_assert(target_ue, return,
"Cannot find UE for MME-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->mme_ue_s1ap_id,
CORE_ADDR(enb->addr, buf), enb->enb_id);
source_ue = target_ue->source_ue;
d_assert(source_ue, return,);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
rv = s1ap_send_handover_preparation_failure(source_ue, &ies->cause);
d_assert(rv == CORE_OK, return, "s1ap send error");
rv = s1ap_send_ue_context_release_command(
target_ue, S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system,
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 0);
d_assert(rv == CORE_OK, return, "s1ap send error");
}
void s1ap_handle_handover_cancel(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *source_ue = NULL;
enb_ue_t *target_ue = NULL;
S1ap_HandoverCancelIEs_t *ies = NULL;
d_assert(enb, return,);
ies = &message->s1ap_HandoverCancelIEs;
d_assert(ies, return,);
d_trace(3, "[MME] Handover cancel\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(source_ue, return,
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->eNB_UE_S1AP_ID,
CORE_ADDR(enb->addr, buf), enb->enb_id);
d_assert(source_ue->mme_ue_s1ap_id == ies->mme_ue_s1ap_id, return,
"Conflict MME-UE-S1AP-ID : %d != %d\n",
source_ue->mme_ue_s1ap_id, ies->mme_ue_s1ap_id);
target_ue = source_ue->target_ue;
d_assert(target_ue, return,);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
rv = s1ap_send_handover_cancel_ack(source_ue);
d_assert(rv == CORE_OK,, "s1ap send error");
rv = s1ap_send_ue_context_release_command(
target_ue, S1ap_Cause_PR_radioNetwork,
S1ap_CauseRadioNetwork_handover_cancelled,
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 300);
d_assert(rv == CORE_OK, return, "s1ap send error");
d_trace(3, "[MME] Handover Cancel : "
"UE[eNB-UE-S1AP-ID(%d)] --> eNB[%s:%d]\n",
source_ue->enb_ue_s1ap_id,
CORE_ADDR(enb->addr, buf), enb->enb_id);
}
void s1ap_handle_enb_status_transfer(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *source_ue = NULL, *target_ue = NULL;
S1ap_ENBStatusTransferIEs_t *ies = NULL;
d_assert(enb, return,);
ies = &message->s1ap_ENBStatusTransferIEs;
d_assert(ies, return,);
d_trace(3, "[MME] ENB status transfer\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(source_ue, return,
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->eNB_UE_S1AP_ID,
CORE_ADDR(enb->addr, buf), enb->enb_id);
d_assert(source_ue->mme_ue_s1ap_id == ies->mme_ue_s1ap_id, return,
"Conflict MME-UE-S1AP-ID : %d != %d\n",
source_ue->mme_ue_s1ap_id, ies->mme_ue_s1ap_id);
target_ue = source_ue->target_ue;
d_assert(target_ue, return,);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
rv = s1ap_send_mme_status_transfer(target_ue, ies);
d_assert(rv == CORE_OK,,);
}
void s1ap_handle_handover_notification(mme_enb_t *enb, s1ap_message_t *message)
{
status_t rv;
char buf[CORE_ADDRSTRLEN];
enb_ue_t *source_ue = NULL;
enb_ue_t *target_ue = NULL;
mme_ue_t *mme_ue = NULL;
mme_sess_t *sess = NULL;
mme_bearer_t *bearer = NULL;
S1ap_HandoverNotifyIEs_t *ies = NULL;
S1ap_EUTRAN_CGI_t *eutran_cgi;
S1ap_PLMNidentity_t *pLMNidentity = NULL;
S1ap_CellIdentity_t *cell_ID = NULL;
S1ap_TAI_t *tai;
S1ap_TAC_t *tAC = NULL;
d_assert(enb, return,);
ies = &message->s1ap_HandoverNotifyIEs;
d_assert(ies, return,);
d_trace(3, "[MME] Handover notification\n");
d_trace(5, " IP[%s] ENB_ID[%d]\n",
CORE_ADDR(enb->addr, buf), enb->enb_id);
eutran_cgi = &ies->eutran_cgi;
d_assert(eutran_cgi, return,);
pLMNidentity = &eutran_cgi->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
cell_ID = &eutran_cgi->cell_ID;
d_assert(cell_ID, return,);
tai = &ies->tai;
d_assert(tai, return,);
pLMNidentity = &tai->pLMNidentity;
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
tAC = &tai->tAC;
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
target_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, ies->eNB_UE_S1AP_ID);
d_assert(target_ue, return,
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
ies->eNB_UE_S1AP_ID,
CORE_ADDR(enb->addr, buf), enb->enb_id);
d_assert(target_ue->mme_ue_s1ap_id == ies->mme_ue_s1ap_id, return,
"Conflict MME-UE-S1AP-ID : %d != %d\n",
target_ue->mme_ue_s1ap_id, ies->mme_ue_s1ap_id);
source_ue = target_ue->source_ue;
d_assert(source_ue, return,);
mme_ue = source_ue->mme_ue;
d_assert(mme_ue, return,);
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
mme_ue_associate_enb_ue(mme_ue, target_ue);
memcpy(&target_ue->nas.tai.plmn_id, pLMNidentity->buf,
sizeof(target_ue->nas.tai.plmn_id));
memcpy(&target_ue->nas.tai.tac, tAC->buf, sizeof(target_ue->nas.tai.tac));
target_ue->nas.tai.tac = ntohs(target_ue->nas.tai.tac);
memcpy(&target_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(target_ue->nas.e_cgi.plmn_id));
memcpy(&target_ue->nas.e_cgi.cell_id, cell_ID->buf,
sizeof(target_ue->nas.e_cgi.cell_id));
target_ue->nas.e_cgi.cell_id = (ntohl(target_ue->nas.e_cgi.cell_id) >> 4);
d_trace(5, " OLD TAI[PLMN_ID:0x%x,TAC:%d]\n",
mme_ue->tai.plmn_id, mme_ue->tai.tac);
d_trace(5, " OLD E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
mme_ue->e_cgi.plmn_id, mme_ue->e_cgi.cell_id);
d_trace(5, " TAI[PLMN_ID:0x%x,TAC:%d]\n",
target_ue->nas.tai.plmn_id, target_ue->nas.tai.tac);
d_trace(5, " E_CGI[PLMN_ID:0x%x,CELL_ID:%d]\n",
target_ue->nas.e_cgi.plmn_id, target_ue->nas.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &target_ue->nas.tai, sizeof(tai_t));
memcpy(&mme_ue->e_cgi, &target_ue->nas.e_cgi, sizeof(e_cgi_t));
sess = mme_sess_first(mme_ue);
while(sess)
{
bearer = mme_bearer_first(sess);
while(bearer)
{
bearer->enb_s1u_teid = bearer->target_s1u_teid;
memcpy(&bearer->enb_s1u_ip, &bearer->target_s1u_ip, sizeof(ip_t));
GTP_COUNTER_INCREMENT(
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY);
rv = mme_gtp_send_modify_bearer_request(bearer, 1);
d_assert(rv == CORE_OK, return, "gtp send failed");
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
}