2017-03-26 05:57:33 +00:00
|
|
|
#define TRACE_MODULE _s1ap_handler
|
|
|
|
|
|
|
|
#include "core_debug.h"
|
2017-03-26 06:34:34 +00:00
|
|
|
|
2017-04-04 01:49:19 +00:00
|
|
|
#include "mme_event.h"
|
2017-03-26 06:34:34 +00:00
|
|
|
|
2017-09-12 01:41:00 +00:00
|
|
|
#include "mme_kdf.h"
|
2017-03-26 05:57:33 +00:00
|
|
|
#include "s1ap_conv.h"
|
|
|
|
#include "s1ap_path.h"
|
2017-09-06 15:37:16 +00:00
|
|
|
#include "nas_path.h"
|
2017-08-31 02:05:00 +00:00
|
|
|
#include "mme_gtp_path.h"
|
2017-04-13 10:58:58 +00:00
|
|
|
|
2017-09-11 14:58:16 +00:00
|
|
|
#include "mme_s11_build.h"
|
2017-09-10 14:03:24 +00:00
|
|
|
#include "s1ap_build.h"
|
2017-04-13 10:58:58 +00:00
|
|
|
#include "s1ap_handler.h"
|
|
|
|
|
2018-02-02 06:59:21 +00:00
|
|
|
#include "mme_path.h"
|
2017-11-30 11:13:15 +00:00
|
|
|
#include "mme_sm.h"
|
|
|
|
|
2017-04-06 11:10:00 +00:00
|
|
|
void s1ap_handle_s1_setup_request(mme_enb_t *enb, s1ap_message_t *message)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-10 13:52:21 +00:00
|
|
|
int i, j;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_S1SetupRequest_t *S1SetupRequest = NULL;
|
|
|
|
|
|
|
|
S1AP_S1SetupRequestIEs_t *ie = NULL;
|
|
|
|
S1AP_Global_ENB_ID_t *Global_ENB_ID = NULL;
|
|
|
|
S1AP_SupportedTAs_t *SupportedTAs = NULL;
|
|
|
|
S1AP_PagingDRX_t *PagingDRX = NULL;
|
|
|
|
|
2017-04-13 14:30:56 +00:00
|
|
|
pkbuf_t *s1apbuf = NULL;
|
2017-03-26 05:57:33 +00:00
|
|
|
c_uint32_t enb_id;
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_Cause_PR group = S1AP_Cause_PR_NOTHING;
|
2018-02-22 13:23:16 +00:00
|
|
|
long cause = 0;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
S1SetupRequest = &initiatingMessage->value.choice.S1SetupRequest;
|
|
|
|
d_assert(S1SetupRequest, return,);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] S1-Setup request\n");
|
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
for (i = 0; i < S1SetupRequest->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = S1SetupRequest->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_Global_ENB_ID:
|
|
|
|
Global_ENB_ID = &ie->value.choice.Global_ENB_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_SupportedTAs:
|
|
|
|
SupportedTAs = &ie->value.choice.SupportedTAs;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_DefaultPagingDRX:
|
|
|
|
PagingDRX = &ie->value.choice.PagingDRX;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(Global_ENB_ID, return,);
|
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
s1ap_ENB_ID_to_uint32(&Global_ENB_ID->eNB_ID, &enb_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n", CORE_ADDR(enb->addr, buf), enb_id);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-12 11:38:21 +00:00
|
|
|
if (PagingDRX)
|
|
|
|
d_trace(5, " PagingDRX[%ld]\n", *PagingDRX);
|
|
|
|
|
2018-02-22 13:23:16 +00:00
|
|
|
mme_enb_set_enb_id(enb, enb_id);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(SupportedTAs, return,);
|
2017-08-04 21:34:52 +00:00
|
|
|
/* Parse Supported TA */
|
2017-12-11 07:55:11 +00:00
|
|
|
enb->num_of_supported_ta_list = 0;
|
2018-03-10 03:21:02 +00:00
|
|
|
for (i = 0; i < SupportedTAs->list.count; i++)
|
2017-08-04 21:34:52 +00:00
|
|
|
{
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_SupportedTAs_Item_t *SupportedTAs_Item = NULL;
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_TAC_t *tAC = NULL;
|
2017-08-04 21:34:52 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
SupportedTAs_Item =
|
|
|
|
(S1AP_SupportedTAs_Item_t *)SupportedTAs->list.array[i];
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(SupportedTAs_Item, return,);
|
|
|
|
tAC = &SupportedTAs_Item->tAC;
|
|
|
|
d_assert(tAC, return,);
|
2017-08-04 21:34:52 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
for (j = 0; j < SupportedTAs_Item->broadcastPLMNs.list.count; j++)
|
2017-08-04 21:34:52 +00:00
|
|
|
{
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_PLMNidentity_t *pLMNidentity = NULL;
|
|
|
|
pLMNidentity = (S1AP_PLMNidentity_t *)
|
2018-03-10 03:21:02 +00:00
|
|
|
SupportedTAs_Item->broadcastPLMNs.list.array[j];
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(pLMNidentity, return,);
|
2017-08-04 21:34:52 +00:00
|
|
|
|
2017-12-11 07:55:11 +00:00
|
|
|
memcpy(&enb->supported_ta_list[enb->num_of_supported_ta_list].tac,
|
2018-03-10 13:52:21 +00:00
|
|
|
tAC->buf, sizeof(c_uint16_t));
|
2017-12-11 07:55:11 +00:00
|
|
|
enb->supported_ta_list[enb->num_of_supported_ta_list].tac =
|
|
|
|
ntohs(enb->supported_ta_list
|
|
|
|
[enb->num_of_supported_ta_list].tac);
|
|
|
|
memcpy(&enb->supported_ta_list
|
|
|
|
[enb->num_of_supported_ta_list].plmn_id,
|
2018-03-10 13:52:21 +00:00
|
|
|
pLMNidentity->buf, sizeof(plmn_id_t));
|
2018-02-22 13:23:16 +00:00
|
|
|
d_trace(5, " PLMN_ID[MCC:%d MNC:%d] TAC[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
plmn_id_mcc(&enb->supported_ta_list
|
|
|
|
[enb->num_of_supported_ta_list].plmn_id),
|
|
|
|
plmn_id_mnc(&enb->supported_ta_list
|
2018-02-22 13:23:16 +00:00
|
|
|
[enb->num_of_supported_ta_list].plmn_id),
|
|
|
|
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
|
2017-12-11 07:55:11 +00:00
|
|
|
enb->num_of_supported_ta_list++;
|
2017-08-04 21:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-11 07:55:11 +00:00
|
|
|
if (enb->num_of_supported_ta_list == 0)
|
2017-08-04 21:34:52 +00:00
|
|
|
{
|
2018-02-22 13:23:16 +00:00
|
|
|
d_warn("S1-Setup failure:");
|
|
|
|
d_warn(" No supported TA exist in S1-Setup request");
|
2018-03-10 03:21:02 +00:00
|
|
|
group = S1AP_Cause_PR_misc;
|
|
|
|
cause = S1AP_CauseMisc_unspecified;
|
2017-08-04 21:34:52 +00:00
|
|
|
}
|
2018-02-22 13:23:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int served_tai_index = -1;
|
|
|
|
for (i = 0; i < enb->num_of_supported_ta_list; i++)
|
|
|
|
{
|
|
|
|
served_tai_index =
|
|
|
|
mme_find_served_tai(&enb->supported_ta_list[i]);
|
|
|
|
if (served_tai_index >= 0 &&
|
|
|
|
served_tai_index < MAX_NUM_OF_SERVED_TAI)
|
|
|
|
{
|
|
|
|
d_trace(5, " SERVED_TAI_INDEX[%d]\n", served_tai_index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-08-04 21:34:52 +00:00
|
|
|
|
2018-02-22 13:23:16 +00:00
|
|
|
if (served_tai_index < 0)
|
|
|
|
{
|
|
|
|
d_warn("S1-Setup failure:");
|
|
|
|
d_warn(" Cannot find Served TAI. Check 'mme.tai' configuration");
|
2018-03-10 03:21:02 +00:00
|
|
|
group = S1AP_Cause_PR_misc;
|
|
|
|
cause = S1AP_CauseMisc_unknown_PLMN;
|
2018-02-22 13:23:16 +00:00
|
|
|
}
|
|
|
|
}
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
if (group == S1AP_Cause_PR_NOTHING)
|
2018-02-22 13:23:16 +00:00
|
|
|
{
|
|
|
|
d_trace(3, "[MME] S1-Setup response\n");
|
|
|
|
d_assert(s1ap_build_setup_rsp(&s1apbuf) == CORE_OK,
|
|
|
|
return, "s1ap_build_setup_rsp() failed");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d_trace(3, "[MME] S1-Setup failure\n");
|
|
|
|
d_assert(s1ap_build_setup_failure(
|
2018-03-10 03:21:02 +00:00
|
|
|
&s1apbuf, group, cause, S1AP_TimeToWait_v10s) == CORE_OK,
|
2018-02-22 13:23:16 +00:00
|
|
|
return, "s1ap_build_setup_failure() failed");
|
|
|
|
}
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-02-22 13:23:16 +00:00
|
|
|
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,,
|
|
|
|
"s1ap_send_to_enb() failed");
|
2017-03-26 05:57:33 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 11:10:00 +00:00
|
|
|
void s1ap_handle_initial_ue_message(mme_enb_t *enb, s1ap_message_t *message)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
2018-01-30 13:10:28 +00:00
|
|
|
status_t rv;
|
2018-03-10 13:52:21 +00:00
|
|
|
int i;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_InitialUEMessage_t *InitialUEMessage = NULL;
|
|
|
|
|
|
|
|
S1AP_InitialUEMessage_IEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_NAS_PDU_t *NAS_PDU = NULL;
|
|
|
|
S1AP_TAI_t *TAI = NULL;
|
|
|
|
S1AP_EUTRAN_CGI_t *EUTRAN_CGI = NULL;
|
|
|
|
S1AP_S_TMSI_t *S_TMSI = NULL;
|
|
|
|
|
|
|
|
S1AP_PLMNidentity_t *pLMNidentity = NULL;
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_TAC_t *tAC = NULL;
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_CellIdentity_t *cell_ID = NULL;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
InitialUEMessage = &initiatingMessage->value.choice.InitialUEMessage;
|
|
|
|
d_assert(InitialUEMessage, return,);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Initial UE Message\n");
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < InitialUEMessage->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = InitialUEMessage->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_NAS_PDU:
|
|
|
|
NAS_PDU = &ie->value.choice.NAS_PDU;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_TAI:
|
|
|
|
TAI = &ie->value.choice.TAI;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_EUTRAN_CGI:
|
|
|
|
EUTRAN_CGI = &ie->value.choice.EUTRAN_CGI;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_S_TMSI:
|
|
|
|
S_TMSI = &ie->value.choice.S_TMSI;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2017-04-28 07:11:45 +00:00
|
|
|
if (!enb_ue)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
2017-04-28 07:11:45 +00:00
|
|
|
enb_ue = enb_ue_add(enb);
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID;
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
/* Find MME_UE if S_TMSI included */
|
|
|
|
if (S_TMSI)
|
2017-07-25 00:03:20 +00:00
|
|
|
{
|
|
|
|
served_gummei_t *served_gummei = &mme_self()->served_gummei[0];
|
|
|
|
guti_t guti;
|
2017-07-26 02:28:43 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
2017-07-25 00:03:20 +00:00
|
|
|
|
|
|
|
memset(&guti, 0, sizeof(guti_t));
|
|
|
|
|
2018-01-31 03:54:59 +00:00
|
|
|
/* Use the first configured plmn_id and mme group id */
|
2017-07-25 00:03:20 +00:00
|
|
|
memcpy(&guti.plmn_id, &served_gummei->plmn_id[0], PLMN_ID_LEN);
|
|
|
|
guti.mme_gid = served_gummei->mme_gid[0];
|
|
|
|
|
|
|
|
/* size must be 1 */
|
2018-03-10 13:52:21 +00:00
|
|
|
memcpy(&guti.mme_code, S_TMSI->mMEC.buf, S_TMSI->mMEC.size);
|
2017-07-25 00:03:20 +00:00
|
|
|
/* size must be 4 */
|
2018-03-10 13:52:21 +00:00
|
|
|
memcpy(&guti.m_tmsi, S_TMSI->m_TMSI.buf, S_TMSI->m_TMSI.size);
|
2017-07-25 14:29:02 +00:00
|
|
|
guti.m_tmsi = ntohl(guti.m_tmsi);
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2017-07-26 02:28:43 +00:00
|
|
|
mme_ue = mme_ue_find_by_guti(&guti);
|
|
|
|
if (!mme_ue)
|
2017-07-25 00:03:20 +00:00
|
|
|
{
|
2018-01-09 08:38:06 +00:00
|
|
|
d_warn("Unknown UE by S_TMSI[G:%d,C:%d,M_TMSI:0x%x]",
|
|
|
|
guti.mme_gid, guti.mme_code, guti.m_tmsi);
|
2017-07-26 02:28:43 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-28 06:08:52 +00:00
|
|
|
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");
|
2018-01-29 10:10:54 +00:00
|
|
|
|
2018-01-30 13:10:28 +00:00
|
|
|
/* If NAS(mme_ue_t) has already been associated with
|
2018-02-02 10:37:36 +00:00
|
|
|
* older S1(enb_ue_t) context */
|
2018-02-03 14:23:50 +00:00
|
|
|
if (ECM_CONNECTED(mme_ue))
|
2018-01-30 13:10:28 +00:00
|
|
|
{
|
2018-02-03 14:23:50 +00:00
|
|
|
#if IMPLICIT_S1_RELEASE
|
2018-02-02 10:37:36 +00:00
|
|
|
/* Implcit S1 release */
|
2018-02-01 19:26:01 +00:00
|
|
|
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,,);
|
2018-02-02 10:37:36 +00:00
|
|
|
|
2018-02-02 11:32:13 +00:00
|
|
|
#else /* S1_HOLDING_TIMER */
|
2018-02-02 10:37:36 +00:00
|
|
|
|
|
|
|
/* 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);
|
2018-02-01 19:26:01 +00:00
|
|
|
#endif
|
2018-01-30 13:10:28 +00:00
|
|
|
}
|
2018-02-02 10:37:36 +00:00
|
|
|
tm_stop(enb_ue->holding_timer);
|
2017-09-14 09:01:26 +00:00
|
|
|
mme_ue_associate_enb_ue(mme_ue, enb_ue);
|
2017-07-25 00:03:20 +00:00
|
|
|
}
|
|
|
|
}
|
2017-03-26 05:57:33 +00:00
|
|
|
}
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(TAI, return,);
|
|
|
|
pLMNidentity = &TAI->pLMNidentity;
|
|
|
|
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
|
|
|
|
tAC = &TAI->tAC;
|
2017-12-11 07:55:11 +00:00
|
|
|
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
memcpy(&enb_ue->nas.tai.plmn_id, pLMNidentity->buf,
|
2017-09-14 08:40:01 +00:00
|
|
|
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);
|
2017-12-11 07:55:11 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
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;
|
2017-12-11 07:55:11 +00:00
|
|
|
d_assert(cell_ID, return,);
|
2018-03-10 13:52:21 +00:00
|
|
|
memcpy(&enb_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
|
2017-09-14 08:40:01 +00:00
|
|
|
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);
|
2017-04-11 11:44:38 +00:00
|
|
|
|
2018-01-28 06:08:52 +00:00
|
|
|
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);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-02-03 13:55:05 +00:00
|
|
|
d_assert(s1ap_send_to_nas(enb_ue,
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_ProcedureCode_id_initialUEMessage, NAS_PDU) == CORE_OK,,
|
2018-02-03 13:55:05 +00:00
|
|
|
"s1ap_send_to_nas failed");
|
2017-03-26 05:57:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void s1ap_handle_uplink_nas_transport(
|
2017-04-06 11:10:00 +00:00
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-10 13:52:21 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_UplinkNASTransport_t *UplinkNASTransport = NULL;
|
|
|
|
|
|
|
|
S1AP_UplinkNASTransport_IEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_NAS_PDU_t *NAS_PDU = NULL;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
UplinkNASTransport = &initiatingMessage->value.choice.UplinkNASTransport;
|
|
|
|
d_assert(UplinkNASTransport, return,);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Uplink NAS transport\n");
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < UplinkNASTransport->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = UplinkNASTransport->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_NAS_PDU:
|
|
|
|
NAS_PDU = &ie->value.choice.NAS_PDU;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2018-02-07 05:12:40 +00:00
|
|
|
d_assert(enb_ue, return, "No UE Context[ENB_UE_S1AP_ID:%d]",
|
2018-03-10 13:52:21 +00:00
|
|
|
*ENB_UE_S1AP_ID);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2018-02-03 13:55:05 +00:00
|
|
|
d_assert(s1ap_send_to_nas(enb_ue,
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_ProcedureCode_id_uplinkNASTransport, NAS_PDU) == CORE_OK,,
|
2018-02-03 13:55:05 +00:00
|
|
|
"s1ap_send_to_nas failed");
|
2017-03-26 05:57:33 +00:00
|
|
|
}
|
|
|
|
|
2017-04-13 14:14:59 +00:00
|
|
|
void s1ap_handle_ue_capability_info_indication(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-10 13:52:21 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_UECapabilityInfoIndication_t *UECapabilityInfoIndication = NULL;
|
|
|
|
|
|
|
|
S1AP_UECapabilityInfoIndicationIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_UERadioCapability_t *UERadioCapability = NULL;
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
UECapabilityInfoIndication =
|
|
|
|
&initiatingMessage->value.choice.UECapabilityInfoIndication;
|
|
|
|
d_assert(UECapabilityInfoIndication, return,);
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] UE capability info indication\n");
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < UECapabilityInfoIndication->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = UECapabilityInfoIndication->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_UERadioCapability:
|
|
|
|
UERadioCapability = &ie->value.choice.UERadioCapability;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
|
|
|
d_assert(enb_ue, return, "No UE Context[%d]", *ENB_UE_S1AP_ID);
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-08-08 19:01:08 +00:00
|
|
|
if (enb_ue->mme_ue)
|
|
|
|
{
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_UERadioCapability_t *radio_capa = NULL;
|
2017-08-08 19:01:08 +00:00
|
|
|
mme_ue_t *mme_ue = enb_ue->mme_ue;
|
|
|
|
|
2017-08-08 21:45:52 +00:00
|
|
|
/* Release the previous one */
|
|
|
|
if (mme_ue->radio_capa)
|
|
|
|
{
|
2018-03-10 03:21:02 +00:00
|
|
|
radio_capa = (S1AP_UERadioCapability_t *)mme_ue->radio_capa;
|
2017-08-08 21:45:52 +00:00
|
|
|
|
|
|
|
if (radio_capa->buf)
|
2018-01-13 13:03:30 +00:00
|
|
|
CORE_FREE(radio_capa->buf);
|
|
|
|
CORE_FREE(mme_ue->radio_capa);
|
2017-08-08 21:45:52 +00:00
|
|
|
}
|
|
|
|
/* Save UE radio capability */
|
2018-03-10 03:21:02 +00:00
|
|
|
mme_ue->radio_capa = core_calloc(1, sizeof(S1AP_UERadioCapability_t));
|
|
|
|
radio_capa = (S1AP_UERadioCapability_t *)mme_ue->radio_capa;
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(radio_capa, return,);
|
2017-08-08 21:45:52 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(UERadioCapability, return,);
|
|
|
|
radio_capa->size = UERadioCapability->size;
|
|
|
|
radio_capa->buf = core_calloc(radio_capa->size, sizeof(c_uint8_t));
|
|
|
|
d_assert(radio_capa->buf, return, "core_calloc error(size=%d)",
|
2017-08-08 19:01:08 +00:00
|
|
|
radio_capa->size);
|
2018-03-10 13:52:21 +00:00
|
|
|
memcpy(radio_capa->buf, UERadioCapability->buf, radio_capa->size);
|
2017-08-08 19:01:08 +00:00
|
|
|
}
|
2017-04-13 14:14:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void s1ap_handle_initial_context_setup_response(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-14 02:12:02 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-10 13:52:21 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
|
|
|
S1AP_InitialContextSetupResponse_t *InitialContextSetupResponse = NULL;
|
|
|
|
|
|
|
|
S1AP_InitialContextSetupResponseIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_E_RABSetupListCtxtSURes_t *E_RABSetupListCtxtSURes = NULL;
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2017-09-11 15:49:15 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
2017-04-28 07:11:45 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
successfulOutcome = message->choice.successfulOutcome;
|
|
|
|
d_assert(successfulOutcome, return,);
|
|
|
|
InitialContextSetupResponse =
|
|
|
|
&successfulOutcome->value.choice.InitialContextSetupResponse;
|
|
|
|
d_assert(InitialContextSetupResponse, return,);
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Initial context setup response\n");
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < InitialContextSetupResponse->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = InitialContextSetupResponse->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_E_RABSetupListCtxtSURes:
|
|
|
|
E_RABSetupListCtxtSURes =
|
|
|
|
&ie->value.choice.E_RABSetupListCtxtSURes;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
|
|
|
d_assert(enb_ue, return, "No UE Context[%d]", *ENB_UE_S1AP_ID);
|
2017-09-11 15:49:15 +00:00
|
|
|
mme_ue = enb_ue->mme_ue;
|
|
|
|
d_assert(mme_ue, return,);
|
2017-04-13 14:14:59 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2017-04-13 16:26:50 +00:00
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
for (i = 0; i < E_RABSetupListCtxtSURes->list.count; i++)
|
2017-04-13 16:26:50 +00:00
|
|
|
{
|
2018-03-10 13:52:21 +00:00
|
|
|
S1AP_E_RABSetupItemCtxtSUResIEs_t *item = NULL;
|
|
|
|
S1AP_E_RABSetupItemCtxtSURes_t *e_rab = NULL;
|
|
|
|
|
2017-08-09 15:41:09 +00:00
|
|
|
mme_sess_t *sess = NULL;
|
2017-04-13 16:26:50 +00:00
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
item = (S1AP_E_RABSetupItemCtxtSUResIEs_t *)
|
|
|
|
E_RABSetupListCtxtSURes->list.array[i];
|
|
|
|
d_assert(item, return,);
|
|
|
|
|
|
|
|
e_rab = &item->value.choice.E_RABSetupItemCtxtSURes;
|
2017-04-13 16:26:50 +00:00
|
|
|
d_assert(e_rab, return, "Null param");
|
|
|
|
|
2017-08-26 09:52:06 +00:00
|
|
|
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);
|
2017-04-13 16:26:50 +00:00
|
|
|
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);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
|
|
|
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
|
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-08 03:11:44 +00:00
|
|
|
|
2018-02-01 05:07:01 +00:00
|
|
|
d_trace(5, " EBI[%d] ENB-S1U-TEID[%d]\n",
|
|
|
|
bearer->ebi, bearer->enb_s1u_teid);
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2017-09-08 03:11:44 +00:00
|
|
|
if (FSM_CHECK(&bearer->sm, esm_state_active))
|
|
|
|
{
|
2018-02-04 07:58:56 +00:00
|
|
|
d_trace(5, " NAS_EPS Type[%d]\n", mme_ue->nas_eps.type);
|
2017-09-14 08:29:34 +00:00
|
|
|
int uli_presence = 0;
|
|
|
|
if (mme_ue->nas_eps.type != MME_EPS_TYPE_ATTACH_REQUEST)
|
2017-09-14 02:12:02 +00:00
|
|
|
{
|
2018-02-04 07:58:56 +00:00
|
|
|
d_trace(5, " ### ULI PRESENT ###\n");
|
2017-09-14 08:29:34 +00:00
|
|
|
uli_presence = 1;
|
2017-09-14 02:12:02 +00:00
|
|
|
}
|
2017-09-14 08:29:34 +00:00
|
|
|
rv = mme_gtp_send_modify_bearer_request(bearer, uli_presence);
|
2017-09-11 14:58:16 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
2017-09-08 03:11:44 +00:00
|
|
|
}
|
2017-04-13 16:26:50 +00:00
|
|
|
}
|
2017-04-13 14:14:59 +00:00
|
|
|
}
|
|
|
|
|
2018-01-02 09:30:17 +00:00
|
|
|
void s1ap_handle_initial_context_setup_failure(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2018-01-11 23:32:33 +00:00
|
|
|
status_t rv;
|
2018-01-02 09:30:17 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-10 13:52:21 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL;
|
|
|
|
S1AP_InitialContextSetupFailure_t *InitialContextSetupFailure = NULL;
|
|
|
|
|
|
|
|
S1AP_InitialContextSetupFailureIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_Cause_t *Cause = NULL;
|
2018-01-02 09:30:17 +00:00
|
|
|
|
|
|
|
mme_ue_t *mme_ue = NULL;
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
2018-03-10 13:52:21 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
unsuccessfulOutcome = message->choice.unsuccessfulOutcome;
|
|
|
|
d_assert(unsuccessfulOutcome, return,);
|
|
|
|
InitialContextSetupFailure =
|
|
|
|
&unsuccessfulOutcome->value.choice.InitialContextSetupFailure;
|
|
|
|
d_assert(InitialContextSetupFailure, return,);
|
2018-01-02 09:30:17 +00:00
|
|
|
|
2018-01-28 13:08:53 +00:00
|
|
|
d_trace(3, "[MME] Initial context setup failure\n");
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < InitialContextSetupFailure->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = InitialContextSetupFailure->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_Cause:
|
|
|
|
Cause = &ie->value.choice.Cause;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-28 13:08:53 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-02 09:30:17 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2018-03-10 13:52:21 +00:00
|
|
|
|
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(Cause, return,);
|
|
|
|
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
|
|
|
d_assert(enb_ue, return, "No UE Context[%d]", *ENB_UE_S1AP_ID);
|
|
|
|
mme_ue = enb_ue->mme_ue;
|
|
|
|
|
2018-01-28 13:08:53 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-28 04:50:21 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2018-01-28 13:08:53 +00:00
|
|
|
d_trace(5, " Cause[Group:%d Cause:%d]\n",
|
2018-03-10 13:52:21 +00:00
|
|
|
Cause->present, Cause->choice.radioNetwork);
|
2018-01-28 13:08:53 +00:00
|
|
|
|
2018-01-29 13:44:25 +00:00
|
|
|
d_assert(mme_ue,,);
|
2018-01-29 13:38:53 +00:00
|
|
|
if (mme_ue && FSM_CHECK(&mme_ue->sm, emm_state_registered))
|
2018-01-11 23:32:33 +00:00
|
|
|
{
|
2018-02-02 06:59:21 +00:00
|
|
|
d_trace(5, " EMM-Registered\n");
|
2018-01-29 05:48:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2018-02-01 07:39:42 +00:00
|
|
|
#if 0 /* NOTHING TO DO */
|
|
|
|
|
2018-01-29 05:48:51 +00:00
|
|
|
#if 0 /* FIXME : Does it needed? */
|
2018-01-28 13:08:53 +00:00
|
|
|
rv = nas_send_service_reject(mme_ue,
|
|
|
|
EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
|
|
|
|
d_assert(rv == CORE_OK,,
|
|
|
|
"nas_send_service_reject() failed");
|
2018-01-29 05:48:51 +00:00
|
|
|
#endif
|
|
|
|
|
2018-01-31 06:24:23 +00:00
|
|
|
#if 1 /* Explicit Release */
|
2018-01-28 13:08:53 +00:00
|
|
|
|
2018-01-29 05:48:51 +00:00
|
|
|
d_trace(5, " Explicit Release\n");
|
2018-01-28 13:08:53 +00:00
|
|
|
rv = s1ap_send_ue_context_release_command(enb_ue,
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_Cause_PR_nas,
|
2018-01-31 06:24:23 +00:00
|
|
|
#if 1 /* NAS Cause: Normal Relase */
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_CauseNas_normal_release,
|
2018-01-31 06:24:23 +00:00
|
|
|
#else /* NAS Cause : Detach */
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_CauseNas_detach,
|
2018-01-31 06:24:23 +00:00
|
|
|
#endif
|
2018-02-01 17:48:55 +00:00
|
|
|
S1AP_UE_CTX_REL_UNLINK_MME_UE_CONTEXT, 0);
|
2018-01-29 05:48:51 +00:00
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2018-01-31 06:24:23 +00:00
|
|
|
|
|
|
|
#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");
|
2018-01-29 05:48:51 +00:00
|
|
|
|
2018-02-01 07:39:42 +00:00
|
|
|
#endif
|
|
|
|
|
2018-01-29 05:48:51 +00:00
|
|
|
#endif
|
2018-01-11 23:32:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-02 06:59:21 +00:00
|
|
|
d_trace(5, " NOT EMM-Registered\n");
|
2018-01-29 13:44:25 +00:00
|
|
|
d_assert(mme_ue,,);
|
2018-02-03 13:55:05 +00:00
|
|
|
rv = mme_send_delete_session_or_ue_context_release(mme_ue, enb_ue);
|
2018-02-02 06:59:21 +00:00
|
|
|
d_assert(rv == CORE_OK,,
|
2018-02-03 13:55:05 +00:00
|
|
|
"mme_send_delete_session_or_ue_context_release() failed");
|
2018-01-11 23:32:33 +00:00
|
|
|
}
|
2018-01-02 09:30:17 +00:00
|
|
|
}
|
|
|
|
|
2017-09-04 16:17:24 +00:00
|
|
|
void s1ap_handle_e_rab_setup_response(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-12-07 08:23:45 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2017-09-04 16:17:24 +00:00
|
|
|
int i;
|
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
|
|
|
S1AP_E_RABSetupResponse_t *E_RABSetupResponse = NULL;
|
|
|
|
|
|
|
|
S1AP_E_RABSetupResponseIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_E_RABSetupListBearerSURes_t *E_RABSetupListBearerSURes = NULL;
|
|
|
|
|
2017-09-04 16:17:24 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-09-11 15:49:15 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
successfulOutcome = message->choice.successfulOutcome;
|
|
|
|
d_assert(successfulOutcome, return,);
|
|
|
|
E_RABSetupResponse = &successfulOutcome->value.choice.E_RABSetupResponse;
|
|
|
|
d_assert(E_RABSetupResponse, return,);
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] E-RAB setup response\n");
|
2018-03-11 11:41:37 +00:00
|
|
|
|
|
|
|
for (i = 0; i < E_RABSetupResponse->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = E_RABSetupResponse->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_E_RABSetupListBearerSURes:
|
|
|
|
E_RABSetupListBearerSURes =
|
|
|
|
&ie->value.choice.E_RABSetupListBearerSURes;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
|
|
|
d_assert(enb_ue, return, "No UE Context[%d]", *ENB_UE_S1AP_ID);
|
2017-09-11 15:49:15 +00:00
|
|
|
mme_ue = enb_ue->mme_ue;
|
|
|
|
d_assert(mme_ue, return,);
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
for (i = 0; i < E_RABSetupListBearerSURes->list.count; i++)
|
2017-09-04 16:17:24 +00:00
|
|
|
{
|
2018-03-11 11:41:37 +00:00
|
|
|
S1AP_E_RABSetupItemBearerSUResIEs_t *item = NULL;
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_E_RABSetupItemBearerSURes_t *e_rab = NULL;
|
2017-09-04 16:17:24 +00:00
|
|
|
|
2018-03-11 11:41:37 +00:00
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
item = (S1AP_E_RABSetupItemBearerSUResIEs_t *)
|
|
|
|
E_RABSetupListBearerSURes->list.array[i];
|
|
|
|
d_assert(item, return,);
|
|
|
|
|
|
|
|
e_rab = &item->value.choice.E_RABSetupItemBearerSURes;
|
2017-09-04 16:17:24 +00:00
|
|
|
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);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
|
|
|
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
|
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-08 03:11:44 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " EBI[%d]\n", bearer->ebi);
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2017-09-08 03:11:44 +00:00
|
|
|
if (FSM_CHECK(&bearer->sm, esm_state_active))
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
|
|
|
|
mme_bearer_t *linked_bearer = mme_linked_bearer(bearer);
|
2018-01-22 14:14:20 +00:00
|
|
|
d_assert(linked_bearer, return, "Null param");
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Linked-EBI[%d]\n", linked_bearer->ebi);
|
2017-09-08 03:11:44 +00:00
|
|
|
|
|
|
|
if (bearer->ebi == linked_bearer->ebi)
|
|
|
|
{
|
2017-09-14 08:29:34 +00:00
|
|
|
rv = mme_gtp_send_modify_bearer_request(bearer, 0);
|
2017-09-11 14:58:16 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
2017-09-08 03:11:44 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rv = mme_gtp_send_create_bearer_response(bearer);
|
2017-09-11 14:58:16 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
2017-09-08 03:11:44 +00:00
|
|
|
}
|
|
|
|
}
|
2017-09-04 16:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-25 00:03:20 +00:00
|
|
|
void s1ap_handle_ue_context_release_request(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-08 07:46:37 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-11 05:38:35 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_UEContextReleaseRequest_t *UEContextReleaseRequest = NULL;
|
|
|
|
|
|
|
|
S1AP_UEContextReleaseRequest_IEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
2018-03-12 14:06:14 +00:00
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
2018-03-11 05:38:35 +00:00
|
|
|
S1AP_Cause_t *Cause = NULL;
|
2017-07-25 00:03:20 +00:00
|
|
|
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
2018-01-29 13:38:53 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
|
|
|
|
2018-02-03 02:48:15 +00:00
|
|
|
d_assert(enb, return,);
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2018-02-03 02:48:15 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
UEContextReleaseRequest =
|
|
|
|
&initiatingMessage->value.choice.UEContextReleaseRequest;
|
|
|
|
d_assert(UEContextReleaseRequest, return,);
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] UE Context release request\n");
|
2018-03-11 05:38:35 +00:00
|
|
|
|
|
|
|
for (i = 0; i < UEContextReleaseRequest->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = UEContextReleaseRequest->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
2018-03-12 14:06:14 +00:00
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
2018-03-11 05:38:35 +00:00
|
|
|
case S1AP_ProtocolIE_ID_id_Cause:
|
|
|
|
Cause = &ie->value.choice.Cause;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
|
2018-02-03 02:48:15 +00:00
|
|
|
if (!enb_ue)
|
|
|
|
{
|
2018-03-11 05:38:35 +00:00
|
|
|
d_warn("No ENB UE Context : MME_UE_S1AP_ID[%d]", *MME_UE_S1AP_ID);
|
2018-02-03 02:48:15 +00:00
|
|
|
rv = s1ap_send_error_indication(enb,
|
2018-03-12 14:06:14 +00:00
|
|
|
MME_UE_S1AP_ID, ENB_UE_S1AP_ID, Cause);
|
2018-02-03 02:48:15 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "s1ap send error");
|
|
|
|
return;
|
|
|
|
}
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2018-03-11 05:38:35 +00:00
|
|
|
|
|
|
|
d_assert(Cause, return,);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Cause[Group:%d Cause:%d]\n",
|
2018-03-11 05:38:35 +00:00
|
|
|
Cause->present, Cause->choice.radioNetwork);
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
switch(Cause->present)
|
2017-07-25 12:15:25 +00:00
|
|
|
{
|
2018-03-10 03:21:02 +00:00
|
|
|
case S1AP_Cause_PR_radioNetwork:
|
|
|
|
case S1AP_Cause_PR_transport:
|
|
|
|
case S1AP_Cause_PR_protocol:
|
|
|
|
case S1AP_Cause_PR_misc:
|
2017-07-25 12:15:25 +00:00
|
|
|
break;
|
2018-03-10 03:21:02 +00:00
|
|
|
case S1AP_Cause_PR_nas:
|
2018-03-11 05:38:35 +00:00
|
|
|
d_warn("NAS-Cause[%d]", Cause->choice.nas);
|
2017-07-25 12:15:25 +00:00
|
|
|
default:
|
2018-03-11 05:38:35 +00:00
|
|
|
d_warn("Invalid cause group[%d]", Cause->present);
|
2017-07-25 12:15:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-01-29 13:38:53 +00:00
|
|
|
|
2018-02-02 10:37:36 +00:00
|
|
|
mme_ue = enb_ue->mme_ue;
|
|
|
|
if (mme_ue)
|
2018-01-29 13:38:53 +00:00
|
|
|
{
|
2018-02-02 10:37:36 +00:00
|
|
|
if (FSM_CHECK(&mme_ue->sm, emm_state_registered))
|
2018-01-31 03:54:59 +00:00
|
|
|
{
|
2018-02-02 10:37:36 +00:00
|
|
|
d_trace(5, " EMM-Registered\n");
|
2018-02-03 13:55:05 +00:00
|
|
|
rv = mme_send_release_access_bearer_or_ue_context_release(
|
|
|
|
mme_ue, enb_ue);
|
|
|
|
d_assert(rv == CORE_OK,, "mme_send_release_access_bearer_or_"
|
|
|
|
"ue_context_release() failed");
|
2018-01-31 03:54:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-02 10:37:36 +00:00
|
|
|
d_trace(5, " NOT EMM-Registered\n");
|
2018-02-03 13:55:05 +00:00
|
|
|
rv = mme_send_delete_session_or_ue_context_release(mme_ue, enb_ue);
|
2018-02-02 10:37:36 +00:00
|
|
|
d_assert(rv == CORE_OK,,
|
2018-02-03 13:55:05 +00:00
|
|
|
"mme_send_delete_session_or_ue_context_release() failed");
|
2018-01-31 03:54:59 +00:00
|
|
|
}
|
2018-01-29 13:38:53 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-02-02 10:37:36 +00:00
|
|
|
d_trace(5, " S1 Context Not Associated\n");
|
|
|
|
rv = s1ap_send_ue_context_release_command(enb_ue,
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release,
|
2018-02-02 10:37:36 +00:00
|
|
|
S1AP_UE_CTX_REL_NO_ACTION, 0);
|
2018-02-03 13:55:05 +00:00
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2018-01-29 13:38:53 +00:00
|
|
|
}
|
2017-07-25 12:15:25 +00:00
|
|
|
}
|
2017-07-25 00:03:20 +00:00
|
|
|
|
2017-04-28 04:46:16 +00:00
|
|
|
void s1ap_handle_ue_context_release_complete(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-18 10:30:03 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-11 05:38:35 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
|
|
|
S1AP_UEContextReleaseComplete_t *UEContextReleaseComplete = NULL;
|
|
|
|
|
|
|
|
S1AP_UEContextReleaseComplete_IEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2017-09-18 10:30:03 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
2018-03-11 05:38:35 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
successfulOutcome = message->choice.successfulOutcome;
|
|
|
|
d_assert(successfulOutcome, return,);
|
|
|
|
UEContextReleaseComplete =
|
|
|
|
&successfulOutcome->value.choice.UEContextReleaseComplete;
|
|
|
|
d_assert(UEContextReleaseComplete, return,);
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] UE Context release complete\n");
|
2018-03-11 05:38:35 +00:00
|
|
|
|
|
|
|
for (i = 0; i < UEContextReleaseComplete->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = UEContextReleaseComplete->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-11 05:38:35 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
|
|
|
|
d_assert(enb_ue, return, "No UE Context[%d]", *MME_UE_S1AP_ID);
|
2018-01-29 05:48:51 +00:00
|
|
|
mme_ue = enb_ue->mme_ue;
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2018-01-29 05:48:51 +00:00
|
|
|
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");
|
2018-02-01 17:48:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-02-04 08:05:30 +00:00
|
|
|
case S1AP_UE_CTX_REL_S1_NORMAL_RELEASE:
|
2018-02-01 17:48:55 +00:00
|
|
|
{
|
2018-02-04 08:05:30 +00:00
|
|
|
d_trace(5, " Action: S1 normal release\n");
|
2018-02-01 17:48:55 +00:00
|
|
|
rv = enb_ue_remove(enb_ue);
|
|
|
|
d_assert(rv == CORE_OK,, "enb_ue_remove() failed");
|
2018-01-29 10:10:54 +00:00
|
|
|
|
|
|
|
d_assert(mme_ue,,);
|
|
|
|
rv = mme_ue_deassociate(mme_ue);
|
2018-01-31 06:24:23 +00:00
|
|
|
d_assert(rv == CORE_OK,, "mme_ue_deassociate() failed");
|
2018-01-29 05:48:51 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-02-04 08:05:30 +00:00
|
|
|
case S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE:
|
2018-01-29 05:48:51 +00:00
|
|
|
{
|
2018-02-04 08:05:30 +00:00
|
|
|
d_trace(5, " Action: UE context remove()\n");
|
2018-01-29 05:48:51 +00:00
|
|
|
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:
|
2017-09-18 10:30:03 +00:00
|
|
|
{
|
2018-01-29 05:48:51 +00:00
|
|
|
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,,);
|
2018-03-07 13:32:31 +00:00
|
|
|
if (mme_ue_have_indirect_tunnel(mme_ue))
|
2018-02-02 06:30:25 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
|
{
|
2018-03-07 13:32:31 +00:00
|
|
|
d_warn("Check your eNodeB");
|
|
|
|
d_warn(" There is no INDIRECT TUNNEL");
|
|
|
|
d_warn(" Packet could be dropped during S1-Handover");
|
|
|
|
rv = mme_ue_clear_indirect_tunnel(mme_ue);
|
|
|
|
d_assert(rv == CORE_OK,,
|
|
|
|
"mme_ue_clear_indirect_tunnel() failed");
|
2018-02-02 06:30:25 +00:00
|
|
|
}
|
2018-01-29 05:48:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
d_assert(0,, "Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
|
|
|
|
break;
|
2017-09-18 12:58:33 +00:00
|
|
|
}
|
|
|
|
}
|
2017-04-28 04:46:16 +00:00
|
|
|
}
|
2017-08-07 22:58:13 +00:00
|
|
|
|
|
|
|
void s1ap_handle_paging(mme_ue_t *mme_ue)
|
|
|
|
{
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
2017-10-18 05:05:22 +00:00
|
|
|
hash_index_t *hi = NULL;
|
2017-08-07 22:58:13 +00:00
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
int i;
|
|
|
|
status_t rv;
|
|
|
|
|
|
|
|
/* Find enB with matched TAI */
|
2017-10-18 05:05:22 +00:00
|
|
|
for (hi = mme_enb_first(); hi; hi = mme_enb_next(hi))
|
2017-08-07 22:58:13 +00:00
|
|
|
{
|
2017-10-18 05:05:22 +00:00
|
|
|
enb = mme_enb_this(hi);
|
2017-12-11 07:55:11 +00:00
|
|
|
for (i = 0; i < enb->num_of_supported_ta_list; i++)
|
2017-08-07 22:58:13 +00:00
|
|
|
{
|
2017-12-11 07:55:11 +00:00
|
|
|
if (!memcmp(&enb->supported_ta_list[i],
|
|
|
|
&mme_ue->tai, sizeof(tai_t)))
|
2017-08-07 22:58:13 +00:00
|
|
|
{
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-11 12:14:55 +00:00
|
|
|
|
|
|
|
void s1ap_handle_path_switch_request(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2018-03-12 13:47:10 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2017-09-11 12:14:55 +00:00
|
|
|
int i;
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_PathSwitchRequest_t *PathSwitchRequest = NULL;
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
S1AP_PathSwitchRequestIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_E_RABToBeSwitchedDLList_t *E_RABToBeSwitchedDLList = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_EUTRAN_CGI_t *EUTRAN_CGI = NULL;
|
|
|
|
S1AP_TAI_t *TAI = NULL;
|
|
|
|
S1AP_UESecurityCapabilities_t *UESecurityCapabilities = NULL;
|
|
|
|
|
|
|
|
S1AP_PLMNidentity_t *pLMNidentity = NULL;
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_CellIdentity_t *cell_ID = NULL;
|
|
|
|
S1AP_TAC_t *tAC = NULL;
|
|
|
|
S1AP_EncryptionAlgorithms_t *encryptionAlgorithms = NULL;
|
|
|
|
S1AP_IntegrityProtectionAlgorithms_t *integrityProtectionAlgorithms = NULL;
|
2017-09-11 12:14:55 +00:00
|
|
|
c_uint16_t eea = 0, eia = 0;
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
|
|
|
mme_ue_t *mme_ue = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
PathSwitchRequest = &initiatingMessage->value.choice.PathSwitchRequest;
|
|
|
|
d_assert(PathSwitchRequest, return,);
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Path switch request\n");
|
2018-03-12 13:47:10 +00:00
|
|
|
|
|
|
|
for (i = 0; i < PathSwitchRequest->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = PathSwitchRequest->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_E_RABToBeSwitchedDLList:
|
|
|
|
E_RABToBeSwitchedDLList =
|
|
|
|
&ie->value.choice.E_RABToBeSwitchedDLList;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_SourceMME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_EUTRAN_CGI:
|
|
|
|
EUTRAN_CGI = &ie->value.choice.EUTRAN_CGI;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_TAI:
|
|
|
|
TAI = &ie->value.choice.TAI;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_UESecurityCapabilities:
|
|
|
|
UESecurityCapabilities = &ie->value.choice.UESecurityCapabilities;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
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;
|
2017-09-11 12:14:55 +00:00
|
|
|
d_assert(cell_ID, return,);
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(TAI, return,);
|
|
|
|
pLMNidentity = &TAI->pLMNidentity;
|
|
|
|
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
|
|
|
|
tAC = &TAI->tAC;
|
2017-09-11 12:14:55 +00:00
|
|
|
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(UESecurityCapabilities, return,);
|
2017-09-11 12:14:55 +00:00
|
|
|
encryptionAlgorithms =
|
2018-03-12 13:47:10 +00:00
|
|
|
&UESecurityCapabilities->encryptionAlgorithms;
|
2017-09-11 12:14:55 +00:00
|
|
|
integrityProtectionAlgorithms =
|
2018-03-12 13:47:10 +00:00
|
|
|
&UESecurityCapabilities->integrityProtectionAlgorithms;
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
|
2017-09-11 12:14:55 +00:00
|
|
|
if (!enb_ue)
|
|
|
|
{
|
|
|
|
d_error("Cannot find UE from sourceMME-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-12 13:47:10 +00:00
|
|
|
*MME_UE_S1AP_ID, CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
s1ap_send_path_switch_failure(enb,
|
|
|
|
*ENB_UE_S1AP_ID, *MME_UE_S1AP_ID,
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_Cause_PR_radioNetwork,
|
|
|
|
S1AP_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
|
2017-09-11 12:14:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-09-11 12:14:55 +00:00
|
|
|
mme_ue = enb_ue->mme_ue;
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
|
2017-09-12 01:48:42 +00:00
|
|
|
if (SECURITY_CONTEXT_IS_VALID(mme_ue))
|
|
|
|
{
|
|
|
|
mme_ue->nhcc++;
|
|
|
|
mme_kdf_nh(mme_ue->kasme, mme_ue->nh, mme_ue->nh);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-12 13:47:10 +00:00
|
|
|
s1ap_send_path_switch_failure(enb,
|
|
|
|
*ENB_UE_S1AP_ID, *MME_UE_S1AP_ID,
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_Cause_PR_nas, S1AP_CauseNas_authentication_failure);
|
2017-09-12 01:48:42 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
enb_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID;
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
memcpy(&enb_ue->nas.tai.plmn_id, pLMNidentity->buf,
|
2018-02-02 17:08:43 +00:00
|
|
|
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);
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
memcpy(&enb_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
|
2018-02-02 17:08:43 +00:00
|
|
|
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));
|
2017-09-11 12:14:55 +00:00
|
|
|
|
|
|
|
memcpy(&eea, encryptionAlgorithms->buf, sizeof(eea));
|
|
|
|
eea = ntohs(eea);
|
2017-09-12 14:07:55 +00:00
|
|
|
mme_ue->ue_network_capability.eea = eea >> 9;
|
|
|
|
mme_ue->ue_network_capability.eea0 = 1;
|
2017-09-11 12:14:55 +00:00
|
|
|
|
|
|
|
memcpy(&eia, integrityProtectionAlgorithms->buf, sizeof(eia));
|
|
|
|
eia = ntohs(eia);
|
2017-09-12 14:07:55 +00:00
|
|
|
mme_ue->ue_network_capability.eia = eia >> 9;
|
|
|
|
mme_ue->ue_network_capability.eia0 = 0;
|
2017-09-11 12:14:55 +00:00
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(E_RABToBeSwitchedDLList, return,);
|
|
|
|
for (i = 0; i < E_RABToBeSwitchedDLList->list.count; i++)
|
2017-09-11 12:14:55 +00:00
|
|
|
{
|
2018-03-12 13:47:10 +00:00
|
|
|
S1AP_E_RABToBeSwitchedDLItemIEs_t *item = NULL;
|
|
|
|
S1AP_E_RABToBeSwitchedDLItem_t *e_rab = NULL;
|
2017-09-11 14:58:16 +00:00
|
|
|
|
2017-09-11 12:14:55 +00:00
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
2018-03-12 13:47:10 +00:00
|
|
|
item = (S1AP_E_RABToBeSwitchedDLItemIEs_t *)
|
|
|
|
E_RABToBeSwitchedDLList->list.array[i];
|
|
|
|
d_assert(item, return,);
|
|
|
|
|
|
|
|
e_rab = &item->value.choice.E_RABToBeSwitchedDLItem;
|
2017-09-11 12:14:55 +00:00
|
|
|
d_assert(e_rab, return, "Null param");
|
|
|
|
|
|
|
|
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
|
2018-03-12 13:47:10 +00:00
|
|
|
d_assert(bearer, return, "Cannot find e_RAB_ID[%d]", e_rab->e_RAB_ID);
|
2017-09-11 12:14:55 +00:00
|
|
|
|
|
|
|
memcpy(&bearer->enb_s1u_teid, e_rab->gTP_TEID.buf,
|
|
|
|
sizeof(bearer->enb_s1u_teid));
|
|
|
|
bearer->enb_s1u_teid = ntohl(bearer->enb_s1u_teid);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
|
|
|
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
|
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-11 14:58:16 +00:00
|
|
|
|
2017-09-13 02:18:17 +00:00
|
|
|
GTP_COUNTER_INCREMENT(
|
|
|
|
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH);
|
|
|
|
|
2017-09-14 08:29:34 +00:00
|
|
|
rv = mme_gtp_send_modify_bearer_request(bearer, 1);
|
2017-09-11 14:58:16 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
2017-09-11 12:14:55 +00:00
|
|
|
}
|
|
|
|
|
2017-09-15 21:02:14 +00:00
|
|
|
/* Switch to enb */
|
|
|
|
enb_ue_switch_to_enb(enb_ue, enb);
|
2017-09-11 12:14:55 +00:00
|
|
|
}
|
2017-09-12 05:16:22 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
void s1ap_handle_enb_configuration_transfer(
|
|
|
|
mme_enb_t *enb, s1ap_message_t *message, pkbuf_t *pkbuf)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
char buf[CORE_ADDRSTRLEN];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_ENBConfigurationTransfer_t *ENBConfigurationTransfer = NULL;
|
|
|
|
|
|
|
|
S1AP_ENBConfigurationTransferIEs_t *ie = NULL;
|
|
|
|
S1AP_SONConfigurationTransfer_t *SONConfigurationTransfer = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return,);
|
|
|
|
d_assert(enb->sock, return,);
|
|
|
|
|
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
ENBConfigurationTransfer =
|
|
|
|
&initiatingMessage->value.choice.ENBConfigurationTransfer;
|
|
|
|
d_assert(ENBConfigurationTransfer, return,);
|
|
|
|
|
|
|
|
d_trace(3, "[MME] ENB configuration transfer\n");
|
|
|
|
for (i = 0; i < ENBConfigurationTransfer->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = ENBConfigurationTransfer->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_SONConfigurationTransferECT:
|
|
|
|
SONConfigurationTransfer =
|
|
|
|
&ie->value.choice.SONConfigurationTransfer;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
|
|
|
if (SONConfigurationTransfer)
|
|
|
|
{
|
|
|
|
S1AP_SONConfigurationTransfer_t *transfer = SONConfigurationTransfer;
|
|
|
|
mme_enb_t *target_enb = NULL;
|
|
|
|
c_uint32_t source_enb_id, target_enb_id;
|
|
|
|
c_uint16_t source_tac, target_tac;
|
|
|
|
|
|
|
|
d_assert(transfer, return,);
|
|
|
|
|
|
|
|
s1ap_ENB_ID_to_uint32(
|
|
|
|
&transfer->sourceeNB_ID.global_ENB_ID.eNB_ID,
|
|
|
|
&source_enb_id);
|
|
|
|
s1ap_ENB_ID_to_uint32(
|
|
|
|
&transfer->targeteNB_ID.global_ENB_ID.eNB_ID,
|
|
|
|
&target_enb_id);
|
|
|
|
|
|
|
|
memcpy(&source_tac, transfer->sourceeNB_ID.selected_TAI.tAC.buf,
|
|
|
|
sizeof(source_tac));
|
|
|
|
source_tac = ntohs(source_tac);
|
|
|
|
memcpy(&target_tac, transfer->targeteNB_ID.selected_TAI.tAC.buf,
|
|
|
|
sizeof(target_tac));
|
|
|
|
target_tac = ntohs(target_tac);
|
|
|
|
|
|
|
|
d_trace(5, " Source : ENB_ID[%s:%d], TAC[%d]\n",
|
|
|
|
transfer->sourceeNB_ID.global_ENB_ID.eNB_ID.present ==
|
|
|
|
S1AP_ENB_ID_PR_homeENB_ID ? "Home" :
|
|
|
|
transfer->sourceeNB_ID.global_ENB_ID.eNB_ID.present ==
|
|
|
|
S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others",
|
|
|
|
source_enb_id, source_tac);
|
|
|
|
d_trace(5, " Target : ENB_ID[%s:%d], TAC[%d]\n",
|
|
|
|
transfer->targeteNB_ID.global_ENB_ID.eNB_ID.present ==
|
|
|
|
S1AP_ENB_ID_PR_homeENB_ID ? "Home" :
|
|
|
|
transfer->targeteNB_ID.global_ENB_ID.eNB_ID.present ==
|
|
|
|
S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others",
|
|
|
|
target_enb_id, target_tac);
|
|
|
|
|
|
|
|
target_enb = mme_enb_find_by_enb_id(target_enb_id);
|
|
|
|
d_assert(target_enb, return,
|
|
|
|
"Cannot find target eNB = %d", target_enb_id);
|
|
|
|
|
|
|
|
rv = s1ap_send_mme_configuration_transfer(target_enb, pkbuf);
|
|
|
|
d_assert(rv == CORE_OK,,);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-12 05:16:22 +00:00
|
|
|
void s1ap_handle_handover_required(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-12 14:07:55 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-13 14:16:01 +00:00
|
|
|
int i;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_HandoverRequired_t *HandoverRequired = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_HandoverRequiredIEs_t *ie = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_HandoverType_t *HandoverType = NULL;
|
|
|
|
S1AP_Cause_t *Cause = NULL;
|
|
|
|
S1AP_TargetID_t *TargetID = NULL;
|
|
|
|
S1AP_Source_ToTarget_TransparentContainer_t
|
|
|
|
*Source_ToTarget_TransparentContainer = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
|
|
|
d_assert(enb, return,);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
HandoverRequired = &initiatingMessage->value.choice.HandoverRequired;
|
|
|
|
d_assert(HandoverRequired, return,);
|
|
|
|
|
|
|
|
enb_ue_t *source_ue = NULL;
|
|
|
|
mme_ue_t *mme_ue = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover required\n");
|
2018-03-13 14:16:01 +00:00
|
|
|
for (i = 0; i < HandoverRequired->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = HandoverRequired->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_HandoverType:
|
|
|
|
HandoverType = &ie->value.choice.HandoverType;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_Cause:
|
|
|
|
Cause = &ie->value.choice.Cause;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_TargetID:
|
|
|
|
TargetID = &ie->value.choice.TargetID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_Source_ToTarget_TransparentContainer:
|
|
|
|
Source_ToTarget_TransparentContainer =
|
|
|
|
&ie->value.choice.Source_ToTarget_TransparentContainer;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2017-09-14 09:01:26 +00:00
|
|
|
d_assert(source_ue, return,
|
2017-09-12 14:07:55 +00:00
|
|
|
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-13 14:16:01 +00:00
|
|
|
*ENB_UE_S1AP_ID,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID, return,
|
2017-09-12 14:07:55 +00:00
|
|
|
"Conflict MME-UE-S1AP-ID : %d != %d\n",
|
2018-03-13 14:16:01 +00:00
|
|
|
source_ue->mme_ue_s1ap_id, *MME_UE_S1AP_ID);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-09-14 09:01:26 +00:00
|
|
|
mme_ue = source_ue->mme_ue;
|
2017-09-12 14:07:55 +00:00
|
|
|
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
|
|
|
|
{
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(Cause, return,);
|
|
|
|
|
|
|
|
rv = s1ap_send_handover_preparation_failure(source_ue, Cause);
|
2017-09-15 04:28:07 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "s1ap send error");
|
|
|
|
|
|
|
|
return;
|
2017-09-12 14:07:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(HandoverType, return,);
|
|
|
|
source_ue->handover_type = *HandoverType;
|
2017-09-13 12:51:02 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
rv = s1ap_send_handover_request(mme_ue,
|
|
|
|
ENB_UE_S1AP_ID, MME_UE_S1AP_ID,
|
|
|
|
HandoverType, Cause, TargetID,
|
|
|
|
Source_ToTarget_TransparentContainer);
|
2017-09-12 14:07:55 +00:00
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2017-09-12 05:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void s1ap_handle_handover_request_ack(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-13 07:22:39 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2017-09-12 14:07:55 +00:00
|
|
|
int i;
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
|
|
|
|
S1AP_HandoverRequestAcknowledge_t *HandoverRequestAcknowledge = NULL;
|
|
|
|
|
|
|
|
S1AP_HandoverRequestAcknowledgeIEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_E_RABAdmittedList_t *E_RABAdmittedList = NULL;
|
|
|
|
S1AP_Target_ToSource_TransparentContainer_t
|
|
|
|
*Target_ToSource_TransparentContainer = NULL;
|
|
|
|
|
2017-09-15 03:06:26 +00:00
|
|
|
enb_ue_t *source_ue = NULL;
|
2017-09-14 09:01:26 +00:00
|
|
|
enb_ue_t *target_ue = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return,);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
successfulOutcome = message->choice.successfulOutcome;
|
|
|
|
d_assert(successfulOutcome, return,);
|
|
|
|
HandoverRequestAcknowledge =
|
|
|
|
&successfulOutcome->value.choice.HandoverRequestAcknowledge;
|
|
|
|
d_assert(HandoverRequestAcknowledge, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover request acknowledge\n");
|
2018-03-13 14:16:01 +00:00
|
|
|
for (i = 0; i < HandoverRequestAcknowledge->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = HandoverRequestAcknowledge->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_E_RABAdmittedList:
|
|
|
|
E_RABAdmittedList = &ie->value.choice.E_RABAdmittedList;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_Target_ToSource_TransparentContainer:
|
|
|
|
Target_ToSource_TransparentContainer =
|
|
|
|
&ie->value.choice.Target_ToSource_TransparentContainer;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(E_RABAdmittedList, return,);
|
|
|
|
d_assert(Target_ToSource_TransparentContainer, return,);
|
|
|
|
|
|
|
|
target_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
|
2017-09-14 09:01:26 +00:00
|
|
|
d_assert(target_ue, return,
|
2017-09-12 14:07:55 +00:00
|
|
|
"Cannot find UE for MME-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-13 14:16:01 +00:00
|
|
|
*MME_UE_S1AP_ID,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
target_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2017-09-15 03:06:26 +00:00
|
|
|
source_ue = target_ue->source_ue;
|
|
|
|
d_assert(source_ue, return,);
|
2017-09-18 12:30:04 +00:00
|
|
|
mme_ue = source_ue->mme_ue;
|
|
|
|
d_assert(mme_ue, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
for (i = 0; i < E_RABAdmittedList->list.count; i++)
|
2017-09-12 14:07:55 +00:00
|
|
|
{
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_E_RABAdmittedItemIEs_t *item = NULL;
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_E_RABAdmittedItem_t *e_rab = NULL;
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
item = (S1AP_E_RABAdmittedItemIEs_t *)E_RABAdmittedList->list.array[i];
|
|
|
|
d_assert(item, return,);
|
|
|
|
|
|
|
|
e_rab = &item->value.choice.E_RABAdmittedItem;
|
|
|
|
d_assert(e_rab, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
|
|
|
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(bearer, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
2017-09-14 02:12:02 +00:00
|
|
|
memcpy(&bearer->target_s1u_teid, e_rab->gTP_TEID.buf,
|
|
|
|
sizeof(bearer->target_s1u_teid));
|
|
|
|
bearer->target_s1u_teid = ntohl(bearer->target_s1u_teid);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
|
|
|
&e_rab->transportLayerAddress, &bearer->target_s1u_ip);
|
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
|
|
|
|
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);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
|
|
|
e_rab->dL_transportLayerAddress, &bearer->enb_dl_ip);
|
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
if (e_rab->uL_TransportLayerAddress && e_rab->uL_GTP_TEID)
|
2017-09-12 14:07:55 +00:00
|
|
|
{
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(e_rab->uL_GTP_TEID->buf, return,);
|
|
|
|
d_assert(e_rab->uL_TransportLayerAddress->buf, return,);
|
|
|
|
memcpy(&bearer->enb_ul_teid, e_rab->uL_GTP_TEID->buf,
|
2017-09-12 14:07:55 +00:00
|
|
|
sizeof(bearer->enb_ul_teid));
|
|
|
|
bearer->enb_ul_teid = ntohl(bearer->enb_ul_teid);
|
2017-12-07 08:23:45 +00:00
|
|
|
rv = s1ap_BIT_STRING_to_ip(
|
2018-03-13 14:16:01 +00:00
|
|
|
e_rab->uL_TransportLayerAddress, &bearer->enb_ul_ip);
|
2017-12-07 08:23:45 +00:00
|
|
|
d_assert(rv == CORE_OK, return,);
|
2017-09-12 14:07:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-13 02:57:17 +00:00
|
|
|
S1AP_STORE_DATA(
|
2018-03-13 14:16:01 +00:00
|
|
|
&mme_ue->container, Target_ToSource_TransparentContainer);
|
2017-09-13 02:57:17 +00:00
|
|
|
|
2018-03-07 13:32:31 +00:00
|
|
|
if (mme_ue_have_indirect_tunnel(mme_ue) == 1)
|
2017-09-13 14:49:31 +00:00
|
|
|
{
|
|
|
|
rv = mme_gtp_send_create_indirect_data_forwarding_tunnel_request(
|
|
|
|
mme_ue);
|
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-15 03:06:26 +00:00
|
|
|
rv = s1ap_send_handover_command(source_ue);
|
2017-09-13 14:49:31 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
|
|
|
}
|
2017-09-12 05:16:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
#if 0
|
2017-09-12 05:16:22 +00:00
|
|
|
void s1ap_handle_handover_failure(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-15 04:28:07 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2017-09-15 04:28:07 +00:00
|
|
|
|
2018-03-10 03:21:02 +00:00
|
|
|
S1AP_HandoverFailureIEs_t *ies = NULL;
|
2017-09-15 04:28:07 +00:00
|
|
|
enb_ue_t *target_ue = NULL;
|
|
|
|
enb_ue_t *source_ue = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return,);
|
|
|
|
|
|
|
|
ies = &message->s1ap_HandoverFailureIEs;
|
|
|
|
d_assert(ies, return,);
|
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover failure\n");
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2017-09-15 04:28:07 +00:00
|
|
|
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,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2017-09-15 04:28:07 +00:00
|
|
|
|
|
|
|
source_ue = target_ue->source_ue;
|
|
|
|
d_assert(source_ue, return,);
|
2018-01-22 14:14:20 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-09-15 04:28:07 +00:00
|
|
|
rv = s1ap_send_handover_preparation_failure(source_ue, &ies->cause);
|
|
|
|
d_assert(rv == CORE_OK, return, "s1ap send error");
|
|
|
|
|
2018-01-21 11:31:28 +00:00
|
|
|
rv = s1ap_send_ue_context_release_command(
|
2018-03-10 03:21:02 +00:00
|
|
|
target_ue, S1AP_Cause_PR_radioNetwork,
|
|
|
|
S1AP_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system,
|
2018-01-21 11:31:28 +00:00
|
|
|
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 0);
|
2017-09-15 04:28:07 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "s1ap send error");
|
2017-09-12 05:16:22 +00:00
|
|
|
}
|
2018-03-13 14:42:55 +00:00
|
|
|
#endif
|
2017-09-12 05:16:22 +00:00
|
|
|
|
2017-09-15 03:06:26 +00:00
|
|
|
void s1ap_handle_handover_cancel(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-13 14:42:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_HandoverCancel_t *HandoverCancel = NULL;
|
|
|
|
|
|
|
|
S1AP_HandoverCancelIEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_Cause_t *Cause = NULL;
|
2017-09-15 03:06:26 +00:00
|
|
|
|
|
|
|
enb_ue_t *source_ue = NULL;
|
2017-09-18 10:30:03 +00:00
|
|
|
enb_ue_t *target_ue = NULL;
|
2017-09-15 03:06:26 +00:00
|
|
|
|
|
|
|
d_assert(enb, return,);
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2017-09-15 03:06:26 +00:00
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
HandoverCancel = &initiatingMessage->value.choice.HandoverCancel;
|
|
|
|
d_assert(HandoverCancel, return,);
|
2017-09-15 03:06:26 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover cancel\n");
|
2018-03-13 14:42:55 +00:00
|
|
|
for (i = 0; i < HandoverCancel->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = HandoverCancel->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_Cause:
|
|
|
|
Cause = &ie->value.choice.Cause;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(Cause, return,);
|
|
|
|
|
|
|
|
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2017-09-15 03:06:26 +00:00
|
|
|
d_assert(source_ue, return,
|
|
|
|
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-13 14:42:55 +00:00
|
|
|
*ENB_UE_S1AP_ID,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID, return,
|
2017-09-15 03:06:26 +00:00
|
|
|
"Conflict MME-UE-S1AP-ID : %d != %d\n",
|
2018-03-13 14:42:55 +00:00
|
|
|
source_ue->mme_ue_s1ap_id, *MME_UE_S1AP_ID);
|
2017-09-15 03:06:26 +00:00
|
|
|
|
2017-09-18 10:30:03 +00:00
|
|
|
target_ue = source_ue->target_ue;
|
|
|
|
d_assert(target_ue, return,);
|
2017-09-15 03:06:26 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-09-18 10:30:03 +00:00
|
|
|
rv = s1ap_send_handover_cancel_ack(source_ue);
|
|
|
|
d_assert(rv == CORE_OK,, "s1ap send error");
|
2017-09-15 04:28:07 +00:00
|
|
|
|
2018-01-21 11:31:28 +00:00
|
|
|
rv = s1ap_send_ue_context_release_command(
|
2018-03-10 03:21:02 +00:00
|
|
|
target_ue, S1AP_Cause_PR_radioNetwork,
|
|
|
|
S1AP_CauseRadioNetwork_handover_cancelled,
|
2018-01-11 13:12:48 +00:00
|
|
|
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 300);
|
2017-09-18 10:30:03 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "s1ap send error");
|
2017-09-15 03:06:26 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover Cancel : "
|
2017-09-15 03:06:26 +00:00
|
|
|
"UE[eNB-UE-S1AP-ID(%d)] --> eNB[%s:%d]\n",
|
|
|
|
source_ue->enb_ue_s1ap_id,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2017-09-15 03:06:26 +00:00
|
|
|
}
|
|
|
|
|
2017-09-12 05:16:22 +00:00
|
|
|
void s1ap_handle_enb_status_transfer(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-14 02:12:02 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-13 14:16:01 +00:00
|
|
|
int i;
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_ENBStatusTransfer_t *ENBStatusTransfer = NULL;
|
|
|
|
|
|
|
|
S1AP_ENBStatusTransferIEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_ENB_StatusTransfer_TransparentContainer_t
|
|
|
|
*ENB_StatusTransfer_TransparentContainer = NULL;
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
enb_ue_t *source_ue = NULL, *target_ue = NULL;
|
2017-09-13 14:49:31 +00:00
|
|
|
|
|
|
|
d_assert(enb, return,);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
ENBStatusTransfer = &initiatingMessage->value.choice.ENBStatusTransfer;
|
|
|
|
d_assert(ENBStatusTransfer, return,);
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] ENB status transfer\n");
|
2018-03-13 14:16:01 +00:00
|
|
|
for (i = 0; i < ENBStatusTransfer->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = ENBStatusTransfer->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_StatusTransfer_TransparentContainer:
|
|
|
|
ENB_StatusTransfer_TransparentContainer =
|
|
|
|
&ie->value.choice.ENB_StatusTransfer_TransparentContainer;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(ENB_StatusTransfer_TransparentContainer, return,);
|
|
|
|
|
|
|
|
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2017-09-14 09:01:26 +00:00
|
|
|
d_assert(source_ue, return,
|
2017-09-13 14:49:31 +00:00
|
|
|
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-13 14:16:01 +00:00
|
|
|
*ENB_UE_S1AP_ID,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2018-03-13 14:16:01 +00:00
|
|
|
d_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID, return,
|
2017-09-13 14:49:31 +00:00
|
|
|
"Conflict MME-UE-S1AP-ID : %d != %d\n",
|
2018-03-13 14:16:01 +00:00
|
|
|
source_ue->mme_ue_s1ap_id, *MME_UE_S1AP_ID);
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2017-09-14 09:01:26 +00:00
|
|
|
target_ue = source_ue->target_ue;
|
|
|
|
d_assert(target_ue, return,);
|
2017-09-13 14:49:31 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
|
|
|
|
|
2018-03-13 14:16:01 +00:00
|
|
|
rv = s1ap_send_mme_status_transfer(target_ue,
|
|
|
|
ENB_StatusTransfer_TransparentContainer);
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(rv == CORE_OK,,);
|
2017-09-12 05:16:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void s1ap_handle_handover_notification(mme_enb_t *enb, s1ap_message_t *message)
|
|
|
|
{
|
2017-09-14 02:12:02 +00:00
|
|
|
status_t rv;
|
2017-11-23 10:44:49 +00:00
|
|
|
char buf[CORE_ADDRSTRLEN];
|
2018-03-13 14:42:55 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
|
|
|
|
S1AP_HandoverNotify_t *HandoverNotify = NULL;
|
|
|
|
|
|
|
|
S1AP_HandoverNotifyIEs_t *ie = NULL;
|
|
|
|
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
|
|
|
|
S1AP_EUTRAN_CGI_t *EUTRAN_CGI = NULL;
|
|
|
|
S1AP_TAI_t *TAI = NULL;
|
|
|
|
|
|
|
|
S1AP_PLMNidentity_t *pLMNidentity = NULL;
|
|
|
|
S1AP_CellIdentity_t *cell_ID = NULL;
|
|
|
|
S1AP_TAC_t *tAC = NULL;
|
2017-09-14 02:12:02 +00:00
|
|
|
|
2017-09-18 12:30:04 +00:00
|
|
|
enb_ue_t *source_ue = NULL;
|
2017-09-14 09:01:26 +00:00
|
|
|
enb_ue_t *target_ue = NULL;
|
2017-09-14 02:12:02 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
|
|
|
mme_sess_t *sess = NULL;
|
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
d_assert(enb, return,);
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(enb->sock, return,);
|
2017-09-14 02:12:02 +00:00
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(message, return,);
|
|
|
|
initiatingMessage = message->choice.initiatingMessage;
|
|
|
|
d_assert(initiatingMessage, return,);
|
|
|
|
HandoverNotify = &initiatingMessage->value.choice.HandoverNotify;
|
|
|
|
d_assert(HandoverNotify, return,);
|
2017-09-14 02:12:02 +00:00
|
|
|
|
2018-01-22 14:14:20 +00:00
|
|
|
d_trace(3, "[MME] Handover notification\n");
|
2018-03-13 14:42:55 +00:00
|
|
|
for (i = 0; i < HandoverNotify->protocolIEs.list.count; i++)
|
|
|
|
{
|
|
|
|
ie = HandoverNotify->protocolIEs.list.array[i];
|
|
|
|
switch(ie->id)
|
|
|
|
{
|
|
|
|
case S1AP_ProtocolIE_ID_id_MME_UE_S1AP_ID:
|
|
|
|
MME_UE_S1AP_ID = &ie->value.choice.MME_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_eNB_UE_S1AP_ID:
|
|
|
|
ENB_UE_S1AP_ID = &ie->value.choice.ENB_UE_S1AP_ID;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_EUTRAN_CGI:
|
|
|
|
EUTRAN_CGI = &ie->value.choice.EUTRAN_CGI;
|
|
|
|
break;
|
|
|
|
case S1AP_ProtocolIE_ID_id_TAI:
|
|
|
|
TAI = &ie->value.choice.TAI;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " IP[%s] ENB_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
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;
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(cell_ID, return,);
|
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(TAI, return,);
|
|
|
|
pLMNidentity = &TAI->pLMNidentity;
|
|
|
|
d_assert(pLMNidentity && pLMNidentity->size == sizeof(plmn_id_t), return,);
|
|
|
|
tAC = &TAI->tAC;
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(tAC && tAC->size == sizeof(c_uint16_t), return,);
|
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(ENB_UE_S1AP_ID, return,);
|
|
|
|
d_assert(MME_UE_S1AP_ID, return,);
|
|
|
|
target_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
|
2017-09-14 09:01:26 +00:00
|
|
|
d_assert(target_ue, return,
|
2017-09-14 02:12:02 +00:00
|
|
|
"Cannot find UE for eNB-UE-S1AP-ID[%d] and eNB[%s:%d]",
|
2018-03-13 14:42:55 +00:00
|
|
|
*ENB_UE_S1AP_ID,
|
2017-11-25 14:28:34 +00:00
|
|
|
CORE_ADDR(enb->addr, buf), enb->enb_id);
|
2018-03-13 14:42:55 +00:00
|
|
|
d_assert(target_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID, return,
|
2017-09-14 02:12:02 +00:00
|
|
|
"Conflict MME-UE-S1AP-ID : %d != %d\n",
|
2018-03-13 14:42:55 +00:00
|
|
|
target_ue->mme_ue_s1ap_id, *MME_UE_S1AP_ID);
|
2017-09-14 02:12:02 +00:00
|
|
|
|
2017-09-18 12:30:04 +00:00
|
|
|
source_ue = target_ue->source_ue;
|
|
|
|
d_assert(source_ue, return,);
|
|
|
|
mme_ue = source_ue->mme_ue;
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(mme_ue, return,);
|
2017-09-14 09:01:26 +00:00
|
|
|
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
|
2018-01-23 06:38:07 +00:00
|
|
|
d_trace(5, " Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]\n",
|
2018-01-22 14:14:20 +00:00
|
|
|
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
|
|
|
|
|
2017-09-14 09:01:26 +00:00
|
|
|
mme_ue_associate_enb_ue(mme_ue, target_ue);
|
2017-09-14 02:12:02 +00:00
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
memcpy(&target_ue->nas.tai.plmn_id, pLMNidentity->buf,
|
2018-02-02 17:00:38 +00:00
|
|
|
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);
|
|
|
|
|
2018-03-13 14:42:55 +00:00
|
|
|
memcpy(&target_ue->nas.e_cgi.plmn_id, pLMNidentity->buf,
|
2018-02-02 17:00:38 +00:00
|
|
|
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));
|
2017-09-14 02:12:02 +00:00
|
|
|
|
|
|
|
sess = mme_sess_first(mme_ue);
|
|
|
|
while(sess)
|
|
|
|
{
|
|
|
|
bearer = mme_bearer_first(sess);
|
|
|
|
while(bearer)
|
|
|
|
{
|
|
|
|
bearer->enb_s1u_teid = bearer->target_s1u_teid;
|
2017-12-07 08:23:45 +00:00
|
|
|
memcpy(&bearer->enb_s1u_ip, &bearer->target_s1u_ip, sizeof(ip_t));
|
2017-09-14 02:12:02 +00:00
|
|
|
|
|
|
|
GTP_COUNTER_INCREMENT(
|
|
|
|
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY);
|
|
|
|
|
2017-09-14 08:29:34 +00:00
|
|
|
rv = mme_gtp_send_modify_bearer_request(bearer, 1);
|
2017-09-14 02:12:02 +00:00
|
|
|
d_assert(rv == CORE_OK, return, "gtp send failed");
|
|
|
|
|
|
|
|
bearer = mme_bearer_next(bearer);
|
|
|
|
}
|
|
|
|
sess = mme_sess_next(sess);
|
|
|
|
}
|
2017-09-12 05:16:22 +00:00
|
|
|
}
|