open5gs/src/mme/s1ap-handler.c

2047 lines
67 KiB
C

/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "mme-event.h"
#include "s1ap-path.h"
#include "nas-path.h"
#include "mme-gtp-path.h"
#include "sgsap-types.h"
#include "sgsap-path.h"
#include "mme-s11-build.h"
#include "s1ap-build.h"
#include "s1ap-handler.h"
#include "mme-path.h"
#include "mme-sm.h"
static bool served_tai_is_found(mme_enb_t *enb)
{
int i;
int served_tai_index;
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 < OGS_MAX_NUM_OF_SERVED_TAI) {
ogs_debug(" SERVED_TAI_INDEX[%d]", served_tai_index);
return true;
}
}
return false;
}
static bool maximum_number_of_enbs_is_reached(void)
{
mme_enb_t *enb = NULL, *next_enb = NULL;
int number_of_enbs_online = 0;
ogs_list_for_each_safe(&mme_self()->enb_list, next_enb, enb) {
if (enb->state.s1_setup_success) {
number_of_enbs_online++;
}
}
return number_of_enbs_online >= ogs_app()->max.gnb;
}
void s1ap_handle_s1_setup_request(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i, j;
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;
uint32_t enb_id;
S1AP_Cause_PR group = S1AP_Cause_PR_NOTHING;
long cause = 0;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
S1SetupRequest = &initiatingMessage->value.choice.S1SetupRequest;
ogs_assert(S1SetupRequest);
ogs_debug("[MME] S1-Setup request");
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;
}
}
ogs_assert(Global_ENB_ID);
ogs_s1ap_ENB_ID_to_uint32(&Global_ENB_ID->eNB_ID, &enb_id);
ogs_debug(" IP[%s] ENB_ID[%d]", OGS_ADDR(enb->addr, buf), enb_id);
if (PagingDRX)
ogs_debug(" PagingDRX[%ld]", *PagingDRX);
mme_enb_set_enb_id(enb, enb_id);
ogs_assert(SupportedTAs);
/* Parse Supported TA */
enb->num_of_supported_ta_list = 0;
for (i = 0; i < SupportedTAs->list.count; i++) {
S1AP_SupportedTAs_Item_t *SupportedTAs_Item = NULL;
S1AP_TAC_t *tAC = NULL;
SupportedTAs_Item =
(S1AP_SupportedTAs_Item_t *)SupportedTAs->list.array[i];
ogs_assert(SupportedTAs_Item);
tAC = &SupportedTAs_Item->tAC;
ogs_assert(tAC);
for (j = 0; j < SupportedTAs_Item->broadcastPLMNs.list.count; j++) {
S1AP_PLMNidentity_t *pLMNidentity = NULL;
pLMNidentity = (S1AP_PLMNidentity_t *)
SupportedTAs_Item->broadcastPLMNs.list.array[j];
ogs_assert(pLMNidentity);
memcpy(&enb->supported_ta_list[enb->num_of_supported_ta_list].tac,
tAC->buf, sizeof(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);
memcpy(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id,
pLMNidentity->buf, sizeof(ogs_plmn_id_t));
ogs_debug(" PLMN_ID[MCC:%d MNC:%d] TAC[%d]",
ogs_plmn_id_mcc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
ogs_plmn_id_mnc(&enb->supported_ta_list
[enb->num_of_supported_ta_list].plmn_id),
enb->supported_ta_list[enb->num_of_supported_ta_list].tac);
enb->num_of_supported_ta_list++;
}
}
if (maximum_number_of_enbs_is_reached()) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Maximum number of eNBs reached");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unspecified;
s1ap_send_s1_setup_failure(enb, group, cause);
return;
}
if (enb->num_of_supported_ta_list == 0) {
ogs_warn("S1-Setup failure:");
ogs_warn(" No supported TA exist in S1-Setup request");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unspecified;
s1ap_send_s1_setup_failure(enb, group, cause);
return;
}
if (!served_tai_is_found(enb)) {
ogs_warn("S1-Setup failure:");
ogs_warn(" Cannot find Served TAI. Check 'mme.tai' configuration");
group = S1AP_Cause_PR_misc;
cause = S1AP_CauseMisc_unknown_PLMN;
s1ap_send_s1_setup_failure(enb, group, cause);
return;
}
enb->state.s1_setup_success = true;
s1ap_send_s1_setup_response(enb);
}
void s1ap_handle_initial_ue_message(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int i;
char buf[OGS_ADDRSTRLEN];
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;
S1AP_TAC_t *tAC = NULL;
S1AP_CellIdentity_t *cell_ID = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
InitialUEMessage = &initiatingMessage->value.choice.InitialUEMessage;
ogs_assert(InitialUEMessage);
ogs_debug("[MME] Initial UE Message");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
if (!enb_ue) {
enb_ue = enb_ue_add(enb, *ENB_UE_S1AP_ID);
ogs_assert(enb_ue);
/* Find MME_UE if S_TMSI included */
if (S_TMSI) {
served_gummei_t *served_gummei = &mme_self()->served_gummei[0];
ogs_nas_eps_guti_t nas_guti;
mme_ue_t *mme_ue = NULL;
memset(&nas_guti, 0, sizeof(ogs_nas_eps_guti_t));
/* Use the first configured plmn_id and mme group id */
ogs_nas_from_plmn_id(&nas_guti.nas_plmn_id,
&served_gummei->plmn_id[0]);
nas_guti.mme_gid = served_gummei->mme_gid[0];
/* size must be 1 */
memcpy(&nas_guti.mme_code, S_TMSI->mMEC.buf, S_TMSI->mMEC.size);
/* size must be 4 */
memcpy(&nas_guti.m_tmsi, S_TMSI->m_TMSI.buf, S_TMSI->m_TMSI.size);
nas_guti.m_tmsi = ntohl(nas_guti.m_tmsi);
mme_ue = mme_ue_find_by_guti(&nas_guti);
if (!mme_ue) {
ogs_warn("Unknown UE by S_TMSI[G:%d,C:%d,M_TMSI:0x%x]",
nas_guti.mme_gid, nas_guti.mme_code, nas_guti.m_tmsi);
} else {
ogs_debug(" S_TMSI[G:%d,C:%d,M_TMSI:0x%x] IMSI:[%s]",
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 (ECM_CONNECTED(mme_ue)) {
/* Implcit S1 release */
ogs_debug("Implicit S1 release");
ogs_debug(" 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);
enb_ue_remove(mme_ue->enb_ue);
}
mme_ue_associate_enb_ue(mme_ue, enb_ue);
}
}
}
ogs_assert(TAI);
pLMNidentity = &TAI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
tAC = &TAI->tAC;
ogs_assert(tAC && tAC->size == sizeof(uint16_t));
memcpy(&enb_ue->saved.tai.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->saved.tai.plmn_id));
memcpy(&enb_ue->saved.tai.tac, tAC->buf, sizeof(enb_ue->saved.tai.tac));
enb_ue->saved.tai.tac = ntohs(enb_ue->saved.tai.tac);
ogs_assert(EUTRAN_CGI);
pLMNidentity = &EUTRAN_CGI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
cell_ID = &EUTRAN_CGI->cell_ID;
ogs_assert(cell_ID);
memcpy(&enb_ue->saved.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->saved.e_cgi.plmn_id));
memcpy(&enb_ue->saved.e_cgi.cell_id, cell_ID->buf,
sizeof(enb_ue->saved.e_cgi.cell_id));
enb_ue->saved.e_cgi.cell_id = (ntohl(enb_ue->saved.e_cgi.cell_id) >> 4);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d] TAC[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id, enb_ue->saved.tai.tac);
s1ap_send_to_nas(enb_ue,
S1AP_ProcedureCode_id_initialUEMessage, NAS_PDU);
}
void s1ap_handle_uplink_nas_transport(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
UplinkNASTransport = &initiatingMessage->value.choice.UplinkNASTransport;
ogs_assert(UplinkNASTransport);
ogs_debug("[MME] Uplink NAS transport");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_expect_or_return(enb_ue);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
s1ap_send_to_nas(enb_ue,
S1AP_ProcedureCode_id_uplinkNASTransport, NAS_PDU);
}
void s1ap_handle_ue_capability_info_indication(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
UECapabilityInfoIndication =
&initiatingMessage->value.choice.UECapabilityInfoIndication;
ogs_assert(UECapabilityInfoIndication);
ogs_debug("[MME] UE capability info indication");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(enb_ue);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
if (enb_ue->mme_ue) {
ogs_assert(UERadioCapability);
OGS_ASN_STORE_DATA(&enb_ue->mme_ue->ueRadioCapability,
UERadioCapability);
}
}
void s1ap_handle_initial_context_setup_response(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int rv;
char buf[OGS_ADDRSTRLEN];
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;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
InitialContextSetupResponse =
&successfulOutcome->value.choice.InitialContextSetupResponse;
ogs_assert(InitialContextSetupResponse);
ogs_debug("[MME] Initial context setup response");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_expect_or_return(enb_ue);
mme_ue = enb_ue->mme_ue;
ogs_assert(mme_ue);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_assert(E_RABSetupListCtxtSURes);
for (i = 0; i < E_RABSetupListCtxtSURes->list.count; i++) {
S1AP_E_RABSetupItemCtxtSUResIEs_t *ie2 = NULL;
S1AP_E_RABSetupItemCtxtSURes_t *e_rab = NULL;
mme_bearer_t *bearer = NULL;
ie2 = (S1AP_E_RABSetupItemCtxtSUResIEs_t *)
E_RABSetupListCtxtSURes->list.array[i];
ogs_assert(ie2);
e_rab = &ie2->value.choice.E_RABSetupItemCtxtSURes;
ogs_assert(e_rab);
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
ogs_assert(bearer);
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 = ogs_asn_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
ogs_assert(rv == OGS_OK);
ogs_debug(" EBI[%d] ENB-S1U-TEID[%d]",
bearer->ebi, bearer->enb_s1u_teid);
if (OGS_FSM_CHECK(&bearer->sm, esm_state_active)) {
ogs_debug(" NAS_EPS Type[%d]", mme_ue->nas_eps.type);
int uli_presence = 0;
if (mme_ue->nas_eps.type != MME_EPS_TYPE_ATTACH_REQUEST) {
ogs_debug(" ### ULI PRESENT ###");
uli_presence = 1;
}
mme_gtp_send_modify_bearer_request(bearer, uli_presence);
}
}
if (SMS_SERVICE_INDICATOR(mme_ue)) {
sgsap_send_service_request(mme_ue, SGSAP_EMM_CONNECTED_MODE);
}
CLEAR_SERVICE_INDICATOR(mme_ue);
}
void s1ap_handle_initial_context_setup_failure(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
unsuccessfulOutcome = message->choice.unsuccessfulOutcome;
ogs_assert(unsuccessfulOutcome);
InitialContextSetupFailure =
&unsuccessfulOutcome->value.choice.InitialContextSetupFailure;
ogs_assert(InitialContextSetupFailure);
ogs_debug("[MME] Initial context setup failure");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(Cause);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
if (enb_ue == NULL) {
ogs_warn("Initial context setup failure : "
"cannot find eNB-UE-S1AP-ID[%d]", (int)*ENB_UE_S1AP_ID);
return;
}
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_debug(" Cause[Group:%d Cause:%d]",
Cause->present, (int)Cause->choice.radioNetwork);
if (mme_ue)
CLEAR_SERVICE_INDICATOR(mme_ue);
/*
* 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.
*/
mme_send_delete_session_or_enb_ue_context_release(enb_ue);
}
void s1ap_handle_ue_context_modification_response(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_UEContextModificationResponse_t *UEContextModificationResponse = NULL;
S1AP_UEContextModificationResponseIEs_t *ie = NULL;
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
UEContextModificationResponse =
&successfulOutcome->value.choice.UEContextModificationResponse;
ogs_assert(UEContextModificationResponse);
ogs_debug("[MME] UE context modification response");
for (i = 0; i < UEContextModificationResponse->protocolIEs.list.count; i++) {
ie = UEContextModificationResponse->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;
default:
break;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(enb_ue);
mme_ue = enb_ue->mme_ue;
ogs_assert(mme_ue);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
CLEAR_SERVICE_INDICATOR(mme_ue);
}
void s1ap_handle_ue_context_modification_failure(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL;
S1AP_UEContextModificationFailure_t *UEContextModificationFailure = NULL;
S1AP_UEContextModificationFailureIEs_t *ie = NULL;
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
S1AP_Cause_t *Cause = NULL;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
unsuccessfulOutcome = message->choice.unsuccessfulOutcome;
ogs_assert(unsuccessfulOutcome);
UEContextModificationFailure =
&unsuccessfulOutcome->value.choice.UEContextModificationFailure;
ogs_assert(UEContextModificationFailure);
ogs_warn("[MME] UE context modification failure");
for (i = 0; i < UEContextModificationFailure->protocolIEs.list.count; i++) {
ie = UEContextModificationFailure->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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(Cause);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
if (enb_ue == NULL) {
ogs_warn("Initial context setup failure : "
"cannot find eNB-UE-S1AP-ID[%d]", (int)*ENB_UE_S1AP_ID);
goto cleanup;
}
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_debug(" Cause[Group:%d Cause:%d]",
Cause->present, (int)Cause->choice.radioNetwork);
cleanup:
mme_ue = enb_ue->mme_ue;
ogs_assert(mme_ue);
CLEAR_SERVICE_INDICATOR(mme_ue);
}
void s1ap_handle_e_rab_setup_response(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int rv;
char buf[OGS_ADDRSTRLEN];
int i;
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;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
E_RABSetupResponse = &successfulOutcome->value.choice.E_RABSetupResponse;
ogs_assert(E_RABSetupResponse);
ogs_debug("[MME] E-RAB setup response");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(enb_ue);
mme_ue = enb_ue->mme_ue;
ogs_assert(mme_ue);
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_assert(E_RABSetupListBearerSURes);
for (i = 0; i < E_RABSetupListBearerSURes->list.count; i++) {
S1AP_E_RABSetupItemBearerSUResIEs_t *ie2 = NULL;
S1AP_E_RABSetupItemBearerSURes_t *e_rab = NULL;
mme_bearer_t *bearer = NULL;
ie2 = (S1AP_E_RABSetupItemBearerSUResIEs_t *)
E_RABSetupListBearerSURes->list.array[i];
ogs_assert(ie2);
e_rab = &ie2->value.choice.E_RABSetupItemBearerSURes;
ogs_assert(e_rab);
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
ogs_assert(bearer);
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 = ogs_asn_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
ogs_assert(rv == OGS_OK);
ogs_debug(" EBI[%d]", bearer->ebi);
if (OGS_FSM_CHECK(&bearer->sm, esm_state_active)) {
mme_bearer_t *linked_bearer = mme_linked_bearer(bearer);
ogs_assert(linked_bearer);
ogs_debug(" Linked-EBI[%d]", linked_bearer->ebi);
if (bearer->ebi == linked_bearer->ebi) {
mme_gtp_send_modify_bearer_request(bearer, 0);
} else {
mme_gtp_send_create_bearer_response(bearer);
}
}
}
}
void s1ap_handle_ue_context_release_request(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL;
S1AP_Cause_t *Cause = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
UEContextReleaseRequest =
&initiatingMessage->value.choice.UEContextReleaseRequest;
ogs_assert(UEContextReleaseRequest);
ogs_debug("[MME] UE Context release request");
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;
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
if (!enb_ue) {
ogs_warn("No ENB UE Context : MME_UE_S1AP_ID[%d]",
(int)*MME_UE_S1AP_ID);
s1ap_send_error_indication(enb,
MME_UE_S1AP_ID, ENB_UE_S1AP_ID,
S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
return;
}
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
ogs_assert(Cause);
ogs_debug(" Cause[Group:%d Cause:%d]",
Cause->present, (int)Cause->choice.radioNetwork);
switch (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:
ogs_warn("NAS-Cause[%d]", (int)Cause->choice.nas);
break;
default:
ogs_warn("Invalid cause group[%d]", Cause->present);
break;
}
mme_send_release_access_bearer_or_ue_context_release(enb_ue);
}
void s1ap_handle_ue_context_release_complete(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int rv;
char buf[OGS_ADDRSTRLEN];
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;
mme_ue_t *mme_ue = NULL;
enb_ue_t *enb_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
UEContextReleaseComplete =
&successfulOutcome->value.choice.UEContextReleaseComplete;
ogs_assert(UEContextReleaseComplete);
ogs_debug("[MME] UE Context release complete");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
if (!enb_ue) {
ogs_warn("No ENB UE Context : MME_UE_S1AP_ID[%d]",
(int)*MME_UE_S1AP_ID);
s1ap_send_error_indication(enb,
MME_UE_S1AP_ID, NULL,
S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
return;
}
mme_ue = enb_ue->mme_ue;
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
switch (enb_ue->ue_ctx_rel_action) {
case S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE:
ogs_debug(" No Action");
enb_ue_remove(enb_ue);
break;
case S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK:
ogs_debug(" Action: S1 normal release");
enb_ue_remove(enb_ue);
mme_ue_deassociate(mme_ue);
break;
case S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE:
ogs_debug(" Action: UE context remove()");
enb_ue_remove(enb_ue);
mme_ue_remove(mme_ue);
break;
case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL:
ogs_debug(" Action: Delete indirect tunnel");
source_ue_deassociate_target_ue(enb_ue);
enb_ue_remove(enb_ue);
ogs_assert(mme_ue);
if (mme_ue_have_indirect_tunnel(mme_ue)) {
mme_gtp_send_delete_indirect_data_forwarding_tunnel_request(
mme_ue);
} else {
ogs_warn("Check your eNodeB");
ogs_warn(" There is no INDIRECT TUNNEL");
ogs_warn(" Packet could be dropped during S1-Handover");
rv = mme_ue_clear_indirect_tunnel(mme_ue);
ogs_expect(rv == OGS_OK);
}
break;
default:
ogs_error("Invalid Action[%d]", enb_ue->ue_ctx_rel_action);
break;
}
}
void s1ap_handle_path_switch_request(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int rv;
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_PathSwitchRequest_t *PathSwitchRequest = NULL;
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;
S1AP_CellIdentity_t *cell_ID = NULL;
S1AP_TAC_t *tAC = NULL;
S1AP_EncryptionAlgorithms_t *encryptionAlgorithms = NULL;
S1AP_IntegrityProtectionAlgorithms_t *integrityProtectionAlgorithms = NULL;
uint16_t eea = 0, eia = 0;
enb_ue_t *enb_ue = NULL;
mme_ue_t *mme_ue = NULL;
ogs_pkbuf_t *s1apbuf = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
PathSwitchRequest = &initiatingMessage->value.choice.PathSwitchRequest;
ogs_assert(PathSwitchRequest);
ogs_debug("[MME] Path switch request");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(EUTRAN_CGI);
pLMNidentity = &EUTRAN_CGI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
cell_ID = &EUTRAN_CGI->cell_ID;
ogs_assert(cell_ID);
ogs_assert(TAI);
pLMNidentity = &TAI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
tAC = &TAI->tAC;
ogs_assert(tAC && tAC->size == sizeof(uint16_t));
ogs_assert(UESecurityCapabilities);
encryptionAlgorithms =
&UESecurityCapabilities->encryptionAlgorithms;
integrityProtectionAlgorithms =
&UESecurityCapabilities->integrityProtectionAlgorithms;
ogs_assert(MME_UE_S1AP_ID);
ogs_assert(ENB_UE_S1AP_ID);
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
if (!enb_ue) {
ogs_error("Cannot find UE from sourceMME-UE-S1AP-ID[%d] and eNB[%s:%d]",
(int)*MME_UE_S1AP_ID, OGS_ADDR(enb->addr, buf), enb->enb_id);
s1apbuf = s1ap_build_path_switch_failure(
*ENB_UE_S1AP_ID, *MME_UE_S1AP_ID,
S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_unknown_mme_ue_s1ap_id);
ogs_expect_or_return(s1apbuf);
ogs_expect(OGS_OK ==
s1ap_send_to_enb(enb, s1apbuf, S1AP_NON_UE_SIGNALLING));
return;
}
ogs_debug(" ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
enb_ue->enb_ue_s1ap_id, enb_ue->mme_ue_s1ap_id);
mme_ue = enb_ue->mme_ue;
ogs_assert(mme_ue);
if (SECURITY_CONTEXT_IS_VALID(mme_ue)) {
mme_ue->nhcc++;
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->nh, mme_ue->nh);
} else {
s1apbuf = s1ap_build_path_switch_failure(
*ENB_UE_S1AP_ID, *MME_UE_S1AP_ID,
S1AP_Cause_PR_nas, S1AP_CauseNas_authentication_failure);
ogs_expect_or_return(s1apbuf);
s1ap_send_to_enb_ue(enb_ue, s1apbuf);
return;
}
enb_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID;
memcpy(&enb_ue->saved.tai.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->saved.tai.plmn_id));
memcpy(&enb_ue->saved.tai.tac, tAC->buf, sizeof(enb_ue->saved.tai.tac));
enb_ue->saved.tai.tac = ntohs(enb_ue->saved.tai.tac);
memcpy(&enb_ue->saved.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(enb_ue->saved.e_cgi.plmn_id));
memcpy(&enb_ue->saved.e_cgi.cell_id, cell_ID->buf,
sizeof(enb_ue->saved.e_cgi.cell_id));
enb_ue->saved.e_cgi.cell_id = (ntohl(enb_ue->saved.e_cgi.cell_id) >> 4);
ogs_debug(" OLD TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&mme_ue->tai.plmn_id),
mme_ue->tai.tac);
ogs_debug(" OLD E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&mme_ue->e_cgi.plmn_id),
mme_ue->e_cgi.cell_id);
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&enb_ue->saved.tai.plmn_id),
enb_ue->saved.tai.tac);
ogs_debug(" E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&enb_ue->saved.e_cgi.plmn_id),
enb_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_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;
ogs_assert(E_RABToBeSwitchedDLList);
for (i = 0; i < E_RABToBeSwitchedDLList->list.count; i++) {
S1AP_E_RABToBeSwitchedDLItemIEs_t *ie2 = NULL;
S1AP_E_RABToBeSwitchedDLItem_t *e_rab = NULL;
mme_bearer_t *bearer = NULL;
ie2 = (S1AP_E_RABToBeSwitchedDLItemIEs_t *)
E_RABToBeSwitchedDLList->list.array[i];
ogs_assert(ie2);
e_rab = &ie2->value.choice.E_RABToBeSwitchedDLItem;
ogs_assert(e_rab);
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
ogs_assert(bearer);
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 = ogs_asn_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->enb_s1u_ip);
ogs_expect(rv == OGS_OK);
GTP_COUNTER_INCREMENT(
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_PATH_SWITCH);
mme_gtp_send_modify_bearer_request(bearer, 1);
}
/* Switch to enb */
enb_ue_switch_to_enb(enb_ue, enb);
}
void s1ap_handle_enb_configuration_transfer(
mme_enb_t *enb, ogs_s1ap_message_t *message, ogs_pkbuf_t *pkbuf)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_ENBConfigurationTransfer_t *ENBConfigurationTransfer = NULL;
S1AP_ENBConfigurationTransferIEs_t *ie = NULL;
S1AP_SONConfigurationTransfer_t *SONConfigurationTransfer = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
ENBConfigurationTransfer =
&initiatingMessage->value.choice.ENBConfigurationTransfer;
ogs_assert(ENBConfigurationTransfer);
ogs_debug("[MME] ENB configuration transfer");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
if (SONConfigurationTransfer) {
S1AP_TargeteNB_ID_t *targeteNB_ID =
&SONConfigurationTransfer->targeteNB_ID;
S1AP_SourceeNB_ID_t *sourceeNB_ID =
&SONConfigurationTransfer->sourceeNB_ID;
mme_enb_t *target_enb = NULL;
uint32_t source_enb_id, target_enb_id;
uint16_t source_tac, target_tac;
ogs_s1ap_ENB_ID_to_uint32(
&sourceeNB_ID->global_ENB_ID.eNB_ID, &source_enb_id);
ogs_s1ap_ENB_ID_to_uint32(
&targeteNB_ID->global_ENB_ID.eNB_ID, &target_enb_id);
memcpy(&source_tac, sourceeNB_ID->selected_TAI.tAC.buf,
sizeof(source_tac));
source_tac = ntohs(source_tac);
memcpy(&target_tac, targeteNB_ID->selected_TAI.tAC.buf,
sizeof(target_tac));
target_tac = ntohs(target_tac);
ogs_debug(" Source : ENB_ID[%s:%d], TAC[%d]",
sourceeNB_ID->global_ENB_ID.eNB_ID.present ==
S1AP_ENB_ID_PR_homeENB_ID ? "Home" :
sourceeNB_ID->global_ENB_ID.eNB_ID.present ==
S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others",
source_enb_id, source_tac);
ogs_debug(" Target : ENB_ID[%s:%d], TAC[%d]",
targeteNB_ID->global_ENB_ID.eNB_ID.present ==
S1AP_ENB_ID_PR_homeENB_ID ? "Home" :
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);
if (target_enb == NULL) {
ogs_warn("eNB configuration transfer : "
"cannot find target eNB-id[0x%x]", target_enb_id);
return;
}
s1ap_send_mme_configuration_transfer(
target_enb, SONConfigurationTransfer);
}
}
void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_HandoverRequired_t *HandoverRequired = NULL;
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;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
HandoverRequired = &initiatingMessage->value.choice.HandoverRequired;
ogs_assert(HandoverRequired);
enb_ue_t *source_ue = NULL;
mme_ue_t *mme_ue = NULL;
mme_enb_t *target_enb = NULL;
uint32_t target_enb_id = 0;
ogs_debug("[MME] Handover required");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(TargetID);
switch (TargetID->present) {
case S1AP_TargetID_PR_targeteNB_ID:
ogs_s1ap_ENB_ID_to_uint32(
&TargetID->choice.targeteNB_ID->global_ENB_ID.eNB_ID,
&target_enb_id);
break;
default:
ogs_error("Not implemented(%d)", TargetID->present);
return;
}
target_enb = mme_enb_find_by_enb_id(target_enb_id);
if (target_enb == NULL) {
ogs_warn("Handover required : cannot find target eNB-id[%d]",
target_enb_id);
return;
}
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(MME_UE_S1AP_ID);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(source_ue);
ogs_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
mme_ue = source_ue->mme_ue;
ogs_assert(mme_ue);
if (SECURITY_CONTEXT_IS_VALID(mme_ue)) {
mme_ue->nhcc++;
ogs_kdf_nh_enb(mme_ue->kasme, mme_ue->nh, mme_ue->nh);
} else {
ogs_assert(Cause);
s1ap_send_handover_preparation_failure(source_ue, Cause);
return;
}
ogs_assert(HandoverType);
source_ue->handover_type = *HandoverType;
s1ap_send_handover_request(mme_ue, target_enb,
ENB_UE_S1AP_ID, MME_UE_S1AP_ID,
HandoverType, Cause,
Source_ToTarget_TransparentContainer);
}
void s1ap_handle_handover_request_ack(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
int rv;
char buf[OGS_ADDRSTRLEN];
int i;
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;
enb_ue_t *source_ue = NULL;
enb_ue_t *target_ue = NULL;
mme_ue_t *mme_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
HandoverRequestAcknowledge =
&successfulOutcome->value.choice.HandoverRequestAcknowledge;
ogs_assert(HandoverRequestAcknowledge);
ogs_debug("[MME] Handover request acknowledge");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(E_RABAdmittedList);
ogs_assert(Target_ToSource_TransparentContainer);
target_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
ogs_assert(target_ue);
target_ue->enb_ue_s1ap_id = *ENB_UE_S1AP_ID;
source_ue = target_ue->source_ue;
ogs_assert(source_ue);
mme_ue = source_ue->mme_ue;
ogs_assert(mme_ue);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
ogs_debug(" Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
for (i = 0; i < E_RABAdmittedList->list.count; i++) {
S1AP_E_RABAdmittedItemIEs_t *ie2 = NULL;
S1AP_E_RABAdmittedItem_t *e_rab = NULL;
mme_bearer_t *bearer = NULL;
ie2 = (S1AP_E_RABAdmittedItemIEs_t *)E_RABAdmittedList->list.array[i];
ogs_assert(ie2);
e_rab = &ie2->value.choice.E_RABAdmittedItem;
ogs_assert(e_rab);
bearer = mme_bearer_find_by_ue_ebi(mme_ue, e_rab->e_RAB_ID);
ogs_assert(bearer);
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 = ogs_asn_BIT_STRING_to_ip(
&e_rab->transportLayerAddress, &bearer->target_s1u_ip);
ogs_assert(rv == OGS_OK);
if (e_rab->dL_transportLayerAddress && e_rab->dL_gTP_TEID) {
ogs_assert(e_rab->dL_gTP_TEID->buf);
ogs_assert(e_rab->dL_transportLayerAddress->buf);
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 = ogs_asn_BIT_STRING_to_ip(
e_rab->dL_transportLayerAddress, &bearer->enb_dl_ip);
ogs_assert(rv == OGS_OK);
}
if (e_rab->uL_TransportLayerAddress && e_rab->uL_GTP_TEID) {
ogs_assert(e_rab->uL_GTP_TEID->buf);
ogs_assert(e_rab->uL_TransportLayerAddress->buf);
memcpy(&bearer->enb_ul_teid, e_rab->uL_GTP_TEID->buf,
sizeof(bearer->enb_ul_teid));
bearer->enb_ul_teid = ntohl(bearer->enb_ul_teid);
rv = ogs_asn_BIT_STRING_to_ip(
e_rab->uL_TransportLayerAddress, &bearer->enb_ul_ip);
ogs_assert(rv == OGS_OK);
}
}
OGS_ASN_STORE_DATA(&mme_ue->container,
Target_ToSource_TransparentContainer);
if (mme_ue_have_indirect_tunnel(mme_ue) == 1) {
mme_gtp_send_create_indirect_data_forwarding_tunnel_request(
mme_ue);
} else {
s1ap_send_handover_command(source_ue);
}
}
void s1ap_handle_handover_failure(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL;
S1AP_HandoverFailure_t *HandoverFailure = NULL;
S1AP_HandoverFailureIEs_t *ie = NULL;
S1AP_MME_UE_S1AP_ID_t *MME_UE_S1AP_ID = NULL;
S1AP_Cause_t *Cause = NULL;
enb_ue_t *target_ue = NULL;
enb_ue_t *source_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
unsuccessfulOutcome = message->choice.unsuccessfulOutcome;
ogs_assert(unsuccessfulOutcome);
HandoverFailure = &unsuccessfulOutcome->value.choice.HandoverFailure;
ogs_assert(HandoverFailure);
ogs_debug("[MME] Handover failure");
for (i = 0; i < HandoverFailure->protocolIEs.list.count; i++) {
ie = HandoverFailure->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_Cause:
Cause = &ie->value.choice.Cause;
break;
default:
break;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
ogs_assert(Cause);
target_ue = enb_ue_find_by_mme_ue_s1ap_id(*MME_UE_S1AP_ID);
ogs_assert(target_ue);
source_ue = target_ue->source_ue;
ogs_assert(source_ue);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
ogs_debug(" Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
s1ap_send_handover_preparation_failure(source_ue, Cause);
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);
}
void s1ap_handle_handover_cancel(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
enb_ue_t *source_ue = NULL;
enb_ue_t *target_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
HandoverCancel = &initiatingMessage->value.choice.HandoverCancel;
ogs_assert(HandoverCancel);
ogs_debug("[MME] Handover cancel");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(Cause);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(source_ue);
ogs_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID);
target_ue = source_ue->target_ue;
ogs_assert(target_ue);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
ogs_debug(" Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
s1ap_send_handover_cancel_ack(source_ue);
s1ap_send_ue_context_release_command(
target_ue, S1AP_Cause_PR_radioNetwork,
S1AP_CauseRadioNetwork_handover_cancelled,
S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL,
ogs_time_from_msec(300));
ogs_debug("[MME] Handover Cancel : "
"UE[eNB-UE-S1AP-ID(%d)] --> eNB[%s:%d]",
source_ue->enb_ue_s1ap_id,
OGS_ADDR(enb->addr, buf), enb->enb_id);
}
void s1ap_handle_enb_status_transfer(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
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;
enb_ue_t *source_ue = NULL, *target_ue = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
ENBStatusTransfer = &initiatingMessage->value.choice.ENBStatusTransfer;
ogs_assert(ENBStatusTransfer);
ogs_debug("[MME] ENB status transfer");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(MME_UE_S1AP_ID);
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(ENB_StatusTransfer_TransparentContainer);
source_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(source_ue);
ogs_assert(source_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID);
target_ue = source_ue->target_ue;
ogs_assert(target_ue);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
ogs_debug(" Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
s1ap_send_mme_status_transfer(target_ue,
ENB_StatusTransfer_TransparentContainer);
}
void s1ap_handle_handover_notification(mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
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;
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;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
HandoverNotify = &initiatingMessage->value.choice.HandoverNotify;
ogs_assert(HandoverNotify);
ogs_debug("[MME] Handover notification");
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;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(EUTRAN_CGI);
pLMNidentity = &EUTRAN_CGI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
cell_ID = &EUTRAN_CGI->cell_ID;
ogs_assert(cell_ID);
ogs_assert(TAI);
pLMNidentity = &TAI->pLMNidentity;
ogs_assert(pLMNidentity && pLMNidentity->size == sizeof(ogs_plmn_id_t));
tAC = &TAI->tAC;
ogs_assert(tAC && tAC->size == sizeof(uint16_t));
ogs_assert(ENB_UE_S1AP_ID);
ogs_assert(MME_UE_S1AP_ID);
target_ue = enb_ue_find_by_enb_ue_s1ap_id(enb, *ENB_UE_S1AP_ID);
ogs_assert(target_ue);
ogs_assert(target_ue->mme_ue_s1ap_id == *MME_UE_S1AP_ID);
source_ue = target_ue->source_ue;
ogs_assert(source_ue);
mme_ue = source_ue->mme_ue;
ogs_assert(mme_ue);
ogs_debug(" Source : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
source_ue->enb_ue_s1ap_id, source_ue->mme_ue_s1ap_id);
ogs_debug(" Target : ENB_UE_S1AP_ID[%d] MME_UE_S1AP_ID[%d]",
target_ue->enb_ue_s1ap_id, target_ue->mme_ue_s1ap_id);
mme_ue_associate_enb_ue(mme_ue, target_ue);
memcpy(&target_ue->saved.tai.plmn_id, pLMNidentity->buf,
sizeof(target_ue->saved.tai.plmn_id));
memcpy(&target_ue->saved.tai.tac,
tAC->buf, sizeof(target_ue->saved.tai.tac));
target_ue->saved.tai.tac = ntohs(target_ue->saved.tai.tac);
memcpy(&target_ue->saved.e_cgi.plmn_id, pLMNidentity->buf,
sizeof(target_ue->saved.e_cgi.plmn_id));
memcpy(&target_ue->saved.e_cgi.cell_id, cell_ID->buf,
sizeof(target_ue->saved.e_cgi.cell_id));
target_ue->saved.e_cgi.cell_id =
(ntohl(target_ue->saved.e_cgi.cell_id) >> 4);
ogs_debug(" OLD TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&mme_ue->tai.plmn_id),
mme_ue->tai.tac);
ogs_debug(" OLD E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&mme_ue->e_cgi.plmn_id),
mme_ue->e_cgi.cell_id);
ogs_debug(" TAI[PLMN_ID:%06x,TAC:%d]",
ogs_plmn_id_hexdump(&target_ue->saved.tai.plmn_id),
target_ue->saved.tai.tac);
ogs_debug(" E_CGI[PLMN_ID:%06x,CELL_ID:%d]",
ogs_plmn_id_hexdump(&target_ue->saved.e_cgi.plmn_id),
target_ue->saved.e_cgi.cell_id);
/* Copy TAI and ECGI from enb_ue */
memcpy(&mme_ue->tai, &target_ue->saved.tai, sizeof(ogs_eps_tai_t));
memcpy(&mme_ue->e_cgi, &target_ue->saved.e_cgi, sizeof(ogs_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(ogs_ip_t));
GTP_COUNTER_INCREMENT(
mme_ue, GTP_COUNTER_MODIFY_BEARER_BY_HANDOVER_NOTIFY);
mme_gtp_send_modify_bearer_request(bearer, 1);
bearer = mme_bearer_next(bearer);
}
sess = mme_sess_next(sess);
}
}
void s1ap_handle_s1_reset(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
int i;
S1AP_InitiatingMessage_t *initiatingMessage = NULL;
S1AP_Reset_t *Reset = NULL;
S1AP_ResetIEs_t *ie = NULL;
S1AP_Cause_t *Cause = NULL;
S1AP_ResetType_t *ResetType = NULL;
S1AP_UE_associatedLogicalS1_ConnectionListRes_t *partOfS1_Interface = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
initiatingMessage = message->choice.initiatingMessage;
ogs_assert(initiatingMessage);
Reset = &initiatingMessage->value.choice.Reset;
ogs_assert(Reset);
ogs_debug("[MME] Reset");
for (i = 0; i < Reset->protocolIEs.list.count; i++) {
ie = Reset->protocolIEs.list.array[i];
switch (ie->id) {
case S1AP_ProtocolIE_ID_id_Cause:
Cause = &ie->value.choice.Cause;
break;
case S1AP_ProtocolIE_ID_id_ResetType:
ResetType = &ie->value.choice.ResetType;
break;
default:
break;
}
}
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
ogs_assert(Cause);
ogs_debug(" Cause[Group:%d Cause:%d]",
Cause->present, (int)Cause->choice.radioNetwork);
switch (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:
ogs_warn("NAS-Cause[%d]", (int)Cause->choice.nas);
break;
default:
ogs_warn("Invalid cause group[%d]", Cause->present);
break;
}
ogs_assert(ResetType);
switch (ResetType->present) {
case S1AP_ResetType_PR_s1_Interface:
ogs_debug(" S1AP_ResetType_PR_s1_Interface");
enb_ue_remove_in_enb(enb);
break;
case S1AP_ResetType_PR_partOfS1_Interface:
ogs_debug(" S1AP_ResetType_PR_partOfS1_Interface");
partOfS1_Interface = ResetType->choice.partOfS1_Interface;
ogs_assert(partOfS1_Interface);
for (i = 0; i < partOfS1_Interface->list.count; i++) {
S1AP_UE_associatedLogicalS1_ConnectionItemRes_t *ie2 = NULL;
S1AP_UE_associatedLogicalS1_ConnectionItem_t *item = NULL;
enb_ue_t *enb_ue = NULL;
ie2 = (S1AP_UE_associatedLogicalS1_ConnectionItemRes_t *)
partOfS1_Interface->list.array[i];
ogs_assert(ie2);
item = &ie2->value.choice.UE_associatedLogicalS1_ConnectionItem;
ogs_assert(item);
ogs_debug(" MME_UE_S1AP_ID[%d] ENB_UE_S1AP_ID[%d]",
item->mME_UE_S1AP_ID ? (int)*item->mME_UE_S1AP_ID : -1,
item->eNB_UE_S1AP_ID ? (int)*item->eNB_UE_S1AP_ID : -1);
if (item->mME_UE_S1AP_ID)
enb_ue = enb_ue_find_by_mme_ue_s1ap_id(
*item->mME_UE_S1AP_ID);
else if (item->eNB_UE_S1AP_ID)
enb_ue = enb_ue_find_by_enb_ue_s1ap_id(enb,
*item->eNB_UE_S1AP_ID);
if (enb_ue == NULL) {
ogs_warn("Cannot find S1 Context "
"(MME_UE_S1AP_ID[%d] ENB_UE_S1AP_ID[%d])",
item->mME_UE_S1AP_ID ? (int)*item->mME_UE_S1AP_ID : -1,
item->eNB_UE_S1AP_ID ? (int)*item->eNB_UE_S1AP_ID : -1);
continue;
}
enb_ue_remove(enb_ue);
}
break;
default:
ogs_warn("Invalid ResetType[%d]", ResetType->present);
break;
}
s1ap_send_s1_reset_ack(enb, partOfS1_Interface);
}
void s1ap_handle_write_replace_warning_response(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_WriteReplaceWarningResponse_t *WriteReplaceWarningResponse = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
WriteReplaceWarningResponse =
&successfulOutcome->value.choice.WriteReplaceWarningResponse;
ogs_assert(WriteReplaceWarningResponse);
ogs_debug("[MME] Write replace warning response");
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
}
void s1ap_handle_kill_response(
mme_enb_t *enb, ogs_s1ap_message_t *message)
{
char buf[OGS_ADDRSTRLEN];
S1AP_SuccessfulOutcome_t *successfulOutcome = NULL;
S1AP_KillResponse_t *KillResponse = NULL;
ogs_assert(enb);
ogs_assert(enb->sock);
ogs_assert(message);
successfulOutcome = message->choice.successfulOutcome;
ogs_assert(successfulOutcome);
KillResponse =
&successfulOutcome->value.choice.KillResponse;
ogs_assert(KillResponse);
ogs_debug("[MME] Kill response");
ogs_debug(" IP[%s] ENB_ID[%d]",
OGS_ADDR(enb->addr, buf), enb->enb_id);
}