2017-03-26 05:57:33 +00:00
|
|
|
#define TRACE_MODULE _emm_handler
|
|
|
|
|
|
|
|
#include "core_debug.h"
|
2017-04-10 02:29:46 +00:00
|
|
|
#include "core_lib.h"
|
2017-03-26 05:57:33 +00:00
|
|
|
|
|
|
|
#include "nas_message.h"
|
|
|
|
|
2017-04-04 01:49:19 +00:00
|
|
|
#include "mme_event.h"
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-04-04 02:08:32 +00:00
|
|
|
#include "mme_kdf.h"
|
2017-03-26 05:57:33 +00:00
|
|
|
#include "nas_security.h"
|
|
|
|
#include "nas_conv.h"
|
2017-04-13 03:21:47 +00:00
|
|
|
#include "esm_build.h"
|
|
|
|
#include "emm_build.h"
|
|
|
|
#include "s1ap_build.h"
|
|
|
|
#include "s1ap_path.h"
|
2017-08-10 07:47:18 +00:00
|
|
|
#include "nas_path.h"
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-04-28 04:46:16 +00:00
|
|
|
#include "mme_s11_build.h"
|
|
|
|
#include "mme_s11_path.h"
|
|
|
|
|
2017-07-26 08:55:53 +00:00
|
|
|
#include "emm_handler.h"
|
2017-04-19 05:01:39 +00:00
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
static void event_emm_to_esm(
|
|
|
|
mme_ue_t *mme_ue, nas_esm_message_container_t *esm_message_container)
|
|
|
|
{
|
|
|
|
pkbuf_t *esmbuf = NULL;
|
|
|
|
event_t e;
|
|
|
|
|
|
|
|
nas_esm_header_t *h = NULL;
|
|
|
|
c_uint8_t pti = NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED;
|
|
|
|
c_uint8_t ebi = NAS_EPS_BEARER_IDENTITY_UNASSIGNED;
|
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
d_assert(esm_message_container, return, "Null param");
|
|
|
|
d_assert(esm_message_container->len, return, "Null param");
|
|
|
|
|
|
|
|
h = (nas_esm_header_t *)esm_message_container->data;
|
|
|
|
d_assert(h, return, "Null param");
|
|
|
|
|
|
|
|
pti = h->procedure_transaction_identity;
|
|
|
|
ebi = h->eps_bearer_identity;
|
|
|
|
if (pti == NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED && ebi)
|
|
|
|
bearer = mme_bearer_find_by_ue_ebi(mme_ue, ebi);
|
|
|
|
else if (ebi == NAS_EPS_BEARER_IDENTITY_UNASSIGNED && pti)
|
|
|
|
bearer = mme_bearer_find_by_ue_pti(mme_ue, pti);
|
|
|
|
|
|
|
|
if (!bearer)
|
|
|
|
bearer = mme_sess_add(mme_ue, pti);
|
|
|
|
d_assert(bearer, return, "No Bearer Context");
|
|
|
|
|
|
|
|
/* The Packet Buffer(pkbuf_t) for NAS message MUST make a HEADROOM.
|
|
|
|
* When calculating AES_CMAC, we need to use the headroom of the packet. */
|
|
|
|
esmbuf = pkbuf_alloc(NAS_HEADROOM, esm_message_container->len);
|
|
|
|
d_assert(esmbuf, return, "Null param");
|
|
|
|
memcpy(esmbuf->payload,
|
|
|
|
esm_message_container->data, esm_message_container->len);
|
|
|
|
|
|
|
|
event_set(&e, MME_EVT_ESM_BEARER_MSG);
|
|
|
|
event_set_param1(&e, (c_uintptr_t)bearer->index);
|
|
|
|
event_set_param3(&e, (c_uintptr_t)esmbuf);
|
|
|
|
mme_event_send(&e);
|
|
|
|
}
|
2017-04-08 02:38:09 +00:00
|
|
|
|
2017-03-26 05:57:33 +00:00
|
|
|
void emm_handle_attach_request(
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue_t *mme_ue, nas_attach_request_t *attach_request)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
|
|
|
nas_eps_mobile_identity_t *eps_mobile_identity =
|
2017-04-08 02:38:09 +00:00
|
|
|
&attach_request->eps_mobile_identity;
|
2017-07-26 12:58:14 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
2017-04-08 02:38:09 +00:00
|
|
|
|
2017-04-19 05:01:39 +00:00
|
|
|
/* Store UE specific information */
|
|
|
|
if (attach_request->presencemask &
|
|
|
|
NAS_ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT)
|
|
|
|
{
|
|
|
|
nas_tracking_area_identity_t *last_visited_registered_tai =
|
|
|
|
&attach_request->last_visited_registered_tai;
|
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
memcpy(&mme_ue->visited_plmn_id,
|
2017-04-19 05:01:39 +00:00
|
|
|
&last_visited_registered_tai->plmn_id,
|
|
|
|
PLMN_ID_LEN);
|
|
|
|
}
|
2017-07-14 15:27:22 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FIXME : what will do if we don't know last visited plmn_id */
|
|
|
|
memcpy(&mme_ue->visited_plmn_id,
|
|
|
|
&mme_self()->served_tai[0].plmn_id, PLMN_ID_LEN);
|
|
|
|
}
|
2017-04-19 05:01:39 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
memcpy(&mme_ue->ue_network_capability,
|
2017-04-19 05:01:39 +00:00
|
|
|
&attach_request->ue_network_capability,
|
|
|
|
sizeof(attach_request->ue_network_capability));
|
2017-04-28 07:11:45 +00:00
|
|
|
memcpy(&mme_ue->ms_network_capability,
|
2017-04-19 05:01:39 +00:00
|
|
|
&attach_request->ms_network_capability,
|
|
|
|
sizeof(attach_request->ms_network_capability));
|
|
|
|
|
2017-08-04 21:34:52 +00:00
|
|
|
/* Copy TAI and ECGI from enb_ue */
|
|
|
|
memcpy(&mme_ue->tai, &enb_ue->tai, sizeof(tai_t));
|
|
|
|
memcpy(&mme_ue->e_cgi, &enb_ue->e_cgi, sizeof(e_cgi_t));
|
|
|
|
|
2017-04-13 04:54:39 +00:00
|
|
|
switch(eps_mobile_identity->imsi.type)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
|
|
|
case NAS_EPS_MOBILE_IDENTITY_IMSI:
|
|
|
|
{
|
2017-07-23 07:26:40 +00:00
|
|
|
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
|
|
|
|
2017-04-09 15:27:19 +00:00
|
|
|
nas_imsi_to_bcd(
|
|
|
|
&eps_mobile_identity->imsi, eps_mobile_identity->length,
|
2017-07-23 07:26:40 +00:00
|
|
|
imsi_bcd);
|
|
|
|
mme_ue_set_imsi(mme_ue, imsi_bcd);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Attach request : IMSI[%s] --> EMM\n", imsi_bcd);
|
2017-04-13 13:30:56 +00:00
|
|
|
|
2017-03-26 05:57:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-04-19 05:01:39 +00:00
|
|
|
case NAS_EPS_MOBILE_IDENTITY_GUTI:
|
|
|
|
{
|
2017-07-23 07:26:40 +00:00
|
|
|
nas_eps_mobile_identity_guti_t *nas_guti = NULL;
|
|
|
|
nas_guti = &eps_mobile_identity->guti;
|
|
|
|
guti_t guti;
|
|
|
|
|
|
|
|
guti.plmn_id = nas_guti->plmn_id;
|
|
|
|
guti.mme_gid = nas_guti->mme_gid;
|
|
|
|
guti.mme_code = nas_guti->mme_code;
|
|
|
|
guti.m_tmsi = nas_guti->m_tmsi;
|
2017-04-19 05:01:39 +00:00
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Attach request : GUTI[G:%d,C:%d,M_TMSI:0x%x]-"
|
|
|
|
"IMSI:[%s] --> EMM\n",
|
2017-07-23 07:26:40 +00:00
|
|
|
guti.mme_gid,
|
|
|
|
guti.mme_code,
|
2017-07-28 03:48:49 +00:00
|
|
|
guti.m_tmsi,
|
|
|
|
MME_UE_HAVE_IMSI(mme_ue)
|
|
|
|
? mme_ue->imsi_bcd : "Unknown");
|
2017-07-23 07:26:40 +00:00
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
if (!MME_UE_HAVE_IMSI(mme_ue))
|
2017-07-23 07:35:01 +00:00
|
|
|
{
|
2017-07-27 12:50:55 +00:00
|
|
|
/* Unknown GUTI */
|
|
|
|
emm_handle_identity_request(mme_ue);
|
2017-07-23 07:35:01 +00:00
|
|
|
}
|
2017-07-27 12:50:55 +00:00
|
|
|
|
2017-04-19 05:01:39 +00:00
|
|
|
break;
|
|
|
|
}
|
2017-03-26 05:57:33 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
d_warn("Not implemented(type:%d)",
|
2017-04-13 04:54:39 +00:00
|
|
|
eps_mobile_identity->imsi.type);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2017-08-10 07:47:18 +00:00
|
|
|
|
|
|
|
event_emm_to_esm(mme_ue, &attach_request->esm_message_container);
|
2017-03-26 05:57:33 +00:00
|
|
|
}
|
|
|
|
|
2017-08-10 08:36:28 +00:00
|
|
|
void emm_handle_attach_accept(mme_sess_t *sess)
|
2017-08-09 15:41:09 +00:00
|
|
|
{
|
2017-08-10 07:47:18 +00:00
|
|
|
status_t rv;
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-08-10 08:36:28 +00:00
|
|
|
mme_ue_t *mme_ue = NULL;
|
2017-08-10 07:47:18 +00:00
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
pkbuf_t *esmbuf = NULL, *emmbuf = NULL, *s1apbuf = NULL;
|
2017-08-09 15:41:09 +00:00
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(sess, return, "Null param");
|
2017-08-10 08:36:28 +00:00
|
|
|
mme_ue = sess->mme_ue;
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-08-10 07:47:18 +00:00
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
|
|
|
bearer = mme_default_bearer_in_sess(sess);
|
|
|
|
d_assert(bearer, return, "Null param");
|
|
|
|
|
|
|
|
rv = esm_build_activate_default_bearer_context(&esmbuf, bearer);
|
2017-08-11 03:05:01 +00:00
|
|
|
d_assert(rv == CORE_OK && esmbuf, return, "esm build error");
|
2017-08-10 07:47:18 +00:00
|
|
|
|
|
|
|
d_trace(3, "[NAS] Activate default bearer context request : "
|
|
|
|
"EMM <-- ESM[%d]\n", bearer->ebi);
|
2017-08-09 15:41:09 +00:00
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
rv = emm_build_attach_accept(&emmbuf, mme_ue, esmbuf);
|
|
|
|
d_assert(rv == CORE_OK && emmbuf,
|
|
|
|
pkbuf_free(esmbuf); return, "emm build error");
|
|
|
|
|
|
|
|
d_trace(3, "[NAS] Attach accept : UE[%s] <-- EMM\n", mme_ue->imsi_bcd);
|
|
|
|
|
|
|
|
rv = s1ap_build_initial_context_setup_request(&s1apbuf, bearer, emmbuf);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf,
|
|
|
|
pkbuf_free(emmbuf); return, "s1ap build error");
|
|
|
|
|
|
|
|
d_assert(nas_send_to_enb(enb_ue, s1apbuf) == CORE_OK,,);
|
2017-08-09 15:41:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void emm_handle_attach_complete(
|
|
|
|
mme_ue_t *mme_ue, nas_attach_complete_t *attach_complete)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *emmbuf = NULL;
|
|
|
|
|
|
|
|
nas_message_t message;
|
|
|
|
nas_emm_information_t *emm_information = &message.emm.emm_information;
|
|
|
|
nas_time_zone_and_time_t *universal_time_and_local_time_zone =
|
|
|
|
&emm_information->universal_time_and_local_time_zone;
|
|
|
|
nas_daylight_saving_time_t *network_daylight_saving_time =
|
|
|
|
&emm_information->network_daylight_saving_time;
|
|
|
|
|
|
|
|
time_exp_t time_exp;
|
|
|
|
time_exp_lt(&time_exp, time_now());
|
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
event_emm_to_esm(mme_ue, &attach_complete->esm_message_container);
|
2017-08-09 15:41:09 +00:00
|
|
|
|
|
|
|
memset(&message, 0, sizeof(message));
|
|
|
|
message.h.security_header_type =
|
|
|
|
NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
|
|
|
|
message.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
|
|
|
|
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
message.emm.h.message_type = NAS_EMM_INFORMATION;
|
|
|
|
|
|
|
|
emm_information->presencemask |=
|
|
|
|
NAS_EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT;
|
|
|
|
universal_time_and_local_time_zone->year =
|
|
|
|
NAS_TIME_TO_BCD(time_exp.tm_year % 100);
|
|
|
|
universal_time_and_local_time_zone->mon = NAS_TIME_TO_BCD(time_exp.tm_mon);
|
|
|
|
universal_time_and_local_time_zone->mday =
|
|
|
|
NAS_TIME_TO_BCD(time_exp.tm_mday);
|
|
|
|
universal_time_and_local_time_zone->hour =
|
|
|
|
NAS_TIME_TO_BCD(time_exp.tm_hour);
|
|
|
|
universal_time_and_local_time_zone->min = NAS_TIME_TO_BCD(time_exp.tm_min);
|
|
|
|
universal_time_and_local_time_zone->sec = NAS_TIME_TO_BCD(time_exp.tm_sec);
|
|
|
|
if (time_exp.tm_gmtoff > 0)
|
|
|
|
universal_time_and_local_time_zone->sign = 0;
|
|
|
|
else
|
|
|
|
universal_time_and_local_time_zone->sign = 1;
|
|
|
|
/* quarters of an hour */
|
|
|
|
universal_time_and_local_time_zone->gmtoff =
|
|
|
|
NAS_TIME_TO_BCD(time_exp.tm_gmtoff / 900);
|
|
|
|
|
|
|
|
emm_information->presencemask |=
|
|
|
|
NAS_EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT;
|
|
|
|
network_daylight_saving_time->length = 1;
|
|
|
|
|
|
|
|
d_trace(3, "[NAS] EMM information : UE[%s] <-- EMM\n",
|
|
|
|
mme_ue->imsi_bcd);
|
|
|
|
|
|
|
|
rv = nas_security_encode(&emmbuf, mme_ue, &message);
|
|
|
|
d_assert(rv == CORE_OK && emmbuf, return, "emm build error");
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-08-09 15:41:09 +00:00
|
|
|
}
|
|
|
|
|
2017-08-11 03:05:01 +00:00
|
|
|
void emm_handle_attach_reject(mme_ue_t *mme_ue)
|
|
|
|
{
|
|
|
|
status_t rv;
|
2017-08-11 05:51:05 +00:00
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
|
|
|
pkbuf_t *s1apbuf = NULL, *esmbuf = NULL, *emmbuf = NULL;
|
2017-08-11 03:05:01 +00:00
|
|
|
nas_message_t *message = NULL;
|
2017-08-11 05:51:05 +00:00
|
|
|
S1ap_Cause_t cause;
|
2017-08-11 03:05:01 +00:00
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-08-11 05:51:05 +00:00
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
|
|
|
enb = enb_ue->enb;
|
|
|
|
d_assert(enb, return, "Null param");
|
|
|
|
|
2017-08-11 03:05:01 +00:00
|
|
|
message = &mme_ue->last_esm_message;
|
|
|
|
if (message)
|
|
|
|
{
|
|
|
|
switch(message->esm.h.message_type)
|
|
|
|
{
|
|
|
|
case NAS_PDN_CONNECTIVITY_REQUEST:
|
|
|
|
{
|
|
|
|
c_uint8_t pti = message->esm.h.procedure_transaction_identity;
|
|
|
|
rv = esm_build_pdn_connectivity_reject(&esmbuf, pti,
|
|
|
|
ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED);
|
|
|
|
d_assert(rv == CORE_OK && esmbuf, return, "esm build error");
|
|
|
|
d_trace(3, "[NAS] PDN Connectivity reject : "
|
|
|
|
"EMM <-- ESM[%d]\n", pti);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
d_warn("Not implemented(type:%d)", message->esm.h.message_type);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = emm_build_attach_reject(&emmbuf,
|
|
|
|
EMM_CAUSE_EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED, esmbuf);
|
|
|
|
d_assert(rv == CORE_OK && emmbuf,
|
|
|
|
pkbuf_free(esmbuf); return, "emm build error");
|
2017-08-11 05:51:05 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-08-11 03:05:01 +00:00
|
|
|
d_trace(3, "[NAS] Attach reject : UE[%s] <-- EMM\n", mme_ue->imsi_bcd);
|
|
|
|
|
2017-08-11 05:51:05 +00:00
|
|
|
cause.present = S1ap_Cause_PR_nas;
|
|
|
|
cause.choice.nas = S1ap_CauseNas_authentication_failure;
|
|
|
|
|
|
|
|
rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error");
|
|
|
|
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error");
|
2017-08-11 03:05:01 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 04:43:42 +00:00
|
|
|
void emm_handle_identity_request(mme_ue_t *mme_ue)
|
2017-04-19 05:01:39 +00:00
|
|
|
{
|
2017-08-09 11:49:18 +00:00
|
|
|
pkbuf_t *emmbuf = NULL;
|
2017-04-19 05:01:39 +00:00
|
|
|
|
|
|
|
nas_message_t message;
|
|
|
|
nas_identity_request_t *identity_request =
|
|
|
|
&message.emm.identity_request;
|
|
|
|
|
2017-04-28 04:43:42 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-04-19 05:01:39 +00:00
|
|
|
|
|
|
|
memset(&message, 0, sizeof(message));
|
|
|
|
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
message.emm.h.message_type = NAS_IDENTITY_REQUEST;
|
|
|
|
|
|
|
|
/* Request IMSI */
|
|
|
|
identity_request->identity_type.type = NAS_IDENTITY_TYPE_2_IMSI;
|
|
|
|
|
|
|
|
d_assert(nas_plain_encode(&emmbuf, &message) == CORE_OK && emmbuf,,);
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-04-19 05:01:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void emm_handle_identity_response(
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue_t *mme_ue, nas_identity_response_t *identity_response)
|
2017-04-19 05:01:39 +00:00
|
|
|
{
|
|
|
|
nas_mobile_identity_t *mobile_identity = NULL;
|
2017-07-26 14:27:03 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-04-19 05:01:39 +00:00
|
|
|
|
|
|
|
d_assert(identity_response, return, "Null param");
|
|
|
|
|
2017-07-26 14:27:03 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
|
|
|
|
2017-04-19 05:01:39 +00:00
|
|
|
mobile_identity = &identity_response->mobile_identity;
|
|
|
|
|
|
|
|
if (mobile_identity->imsi.type == NAS_IDENTITY_TYPE_2_IMSI)
|
|
|
|
{
|
2017-07-23 07:26:40 +00:00
|
|
|
c_int8_t imsi_bcd[MAX_IMSI_BCD_LEN+1];
|
|
|
|
|
2017-04-19 05:01:39 +00:00
|
|
|
nas_imsi_to_bcd(
|
|
|
|
&mobile_identity->imsi, mobile_identity->length,
|
2017-07-23 07:26:40 +00:00
|
|
|
imsi_bcd);
|
|
|
|
mme_ue_set_imsi(mme_ue, imsi_bcd);
|
2017-04-19 05:01:39 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
d_assert(mme_ue->imsi_len, return,
|
|
|
|
"Can't get IMSI(len:%d\n", mme_ue->imsi_len);
|
2017-04-19 05:01:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-28 07:11:45 +00:00
|
|
|
d_warn("Not supported Identity type(%d)", mobile_identity->imsi.type);
|
2017-07-26 14:27:03 +00:00
|
|
|
}
|
2017-04-19 05:01:39 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 04:43:42 +00:00
|
|
|
void emm_handle_authentication_request(mme_ue_t *mme_ue)
|
2017-04-11 02:54:00 +00:00
|
|
|
{
|
2017-08-09 11:49:18 +00:00
|
|
|
pkbuf_t *emmbuf = NULL;
|
2017-04-13 10:58:58 +00:00
|
|
|
|
2017-04-11 02:54:00 +00:00
|
|
|
nas_message_t message;
|
|
|
|
nas_authentication_request_t *authentication_request =
|
|
|
|
&message.emm.authentication_request;
|
|
|
|
|
2017-04-28 04:43:42 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-04-11 02:54:00 +00:00
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Authentication request : UE[%s] <-- EMM\n",
|
|
|
|
mme_ue->imsi_bcd);
|
|
|
|
|
2017-04-11 02:54:00 +00:00
|
|
|
memset(&message, 0, sizeof(message));
|
|
|
|
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
message.emm.h.message_type = NAS_AUTHENTICATION_REQUEST;
|
|
|
|
|
|
|
|
memcpy(authentication_request->authentication_parameter_rand.rand,
|
2017-04-28 04:43:42 +00:00
|
|
|
mme_ue->rand, RAND_LEN);
|
2017-04-11 02:54:00 +00:00
|
|
|
memcpy(authentication_request->authentication_parameter_autn.autn,
|
2017-04-28 04:43:42 +00:00
|
|
|
mme_ue->autn, AUTN_LEN);
|
2017-04-11 02:54:00 +00:00
|
|
|
authentication_request->authentication_parameter_autn.length =
|
|
|
|
AUTN_LEN;
|
|
|
|
|
2017-04-13 10:58:58 +00:00
|
|
|
d_assert(nas_plain_encode(&emmbuf, &message) == CORE_OK && emmbuf,,);
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-04-11 02:54:00 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
void emm_handle_authentication_response(mme_ue_t *mme_ue,
|
|
|
|
nas_authentication_response_t *authentication_response)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
2017-04-13 10:58:58 +00:00
|
|
|
status_t rv;
|
2017-08-09 11:49:18 +00:00
|
|
|
pkbuf_t *emmbuf = NULL;
|
2017-07-14 12:35:24 +00:00
|
|
|
int i;
|
2017-04-13 10:58:58 +00:00
|
|
|
|
2017-03-26 05:57:33 +00:00
|
|
|
nas_authentication_response_parameter_t *authentication_response_parameter =
|
|
|
|
&authentication_response->authentication_response_parameter;
|
|
|
|
|
|
|
|
nas_message_t message;
|
|
|
|
nas_security_mode_command_t *security_mode_command =
|
2017-04-07 13:23:38 +00:00
|
|
|
&message.emm.security_mode_command;
|
2017-03-26 05:57:33 +00:00
|
|
|
nas_security_algorithms_t *selected_nas_security_algorithms =
|
|
|
|
&security_mode_command->selected_nas_security_algorithms;
|
|
|
|
nas_key_set_identifier_t *nas_key_set_identifier =
|
|
|
|
&security_mode_command->nas_key_set_identifier;
|
|
|
|
nas_ue_security_capability_t *replayed_ue_security_capabilities =
|
|
|
|
&security_mode_command->replayed_ue_security_capabilities;
|
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
if (authentication_response_parameter->length != mme_ue->xres_len ||
|
2017-03-26 05:57:33 +00:00
|
|
|
memcmp(authentication_response_parameter->res,
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->xres, mme_ue->xres_len) != 0)
|
2017-03-26 05:57:33 +00:00
|
|
|
{
|
|
|
|
d_error("authentication failed");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Authentication response : UE[%s] --> EMM\n",
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->imsi_bcd);
|
2017-03-26 05:57:33 +00:00
|
|
|
|
|
|
|
memset(&message, 0, sizeof(message));
|
2017-04-07 13:23:38 +00:00
|
|
|
message.h.security_header_type =
|
|
|
|
NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_NEW_SECURITY_CONTEXT;
|
2017-03-26 05:57:33 +00:00
|
|
|
message.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
2017-04-07 13:23:38 +00:00
|
|
|
|
|
|
|
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
message.emm.h.message_type = NAS_SECURITY_MODE_COMMAND;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-07-14 12:35:24 +00:00
|
|
|
for (i = 0; i < mme_self()->num_of_integrity_order; i++)
|
|
|
|
{
|
|
|
|
if (mme_ue->ue_network_capability.eia &
|
|
|
|
(0x80 >> mme_self()->integrity_order[i]))
|
|
|
|
{
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_ue->selected_int_algorithm = mme_self()->integrity_order[i];
|
2017-07-14 12:35:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < mme_self()->num_of_ciphering_order; i++)
|
|
|
|
{
|
|
|
|
if (mme_ue->ue_network_capability.eea &
|
|
|
|
(0x80 >> mme_self()->ciphering_order[i]))
|
|
|
|
{
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_ue->selected_enc_algorithm = mme_self()->ciphering_order[i];
|
2017-07-14 12:35:24 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-26 05:57:33 +00:00
|
|
|
selected_nas_security_algorithms->type_of_integrity_protection_algorithm =
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_ue->selected_int_algorithm;
|
2017-07-14 12:35:24 +00:00
|
|
|
selected_nas_security_algorithms->type_of_ciphering_algorithm =
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_ue->selected_enc_algorithm;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
|
|
|
nas_key_set_identifier->tsc = 0;
|
|
|
|
nas_key_set_identifier->nas_key_set_identifier = 0;
|
|
|
|
|
|
|
|
replayed_ue_security_capabilities->length =
|
|
|
|
sizeof(replayed_ue_security_capabilities->eea) +
|
|
|
|
sizeof(replayed_ue_security_capabilities->eia) +
|
|
|
|
sizeof(replayed_ue_security_capabilities->uea) +
|
|
|
|
sizeof(replayed_ue_security_capabilities->uia) +
|
|
|
|
sizeof(replayed_ue_security_capabilities->gea);
|
2017-04-28 07:11:45 +00:00
|
|
|
replayed_ue_security_capabilities->eea = mme_ue->ue_network_capability.eea;
|
|
|
|
replayed_ue_security_capabilities->eia = mme_ue->ue_network_capability.eia;
|
|
|
|
replayed_ue_security_capabilities->uea = mme_ue->ue_network_capability.uea;
|
|
|
|
replayed_ue_security_capabilities->uia = mme_ue->ue_network_capability.uia;
|
2017-03-26 05:57:33 +00:00
|
|
|
replayed_ue_security_capabilities->gea =
|
2017-04-28 07:11:45 +00:00
|
|
|
(mme_ue->ms_network_capability.gea1 << 6) |
|
|
|
|
mme_ue->ms_network_capability.extended_gea;
|
2017-03-26 05:57:33 +00:00
|
|
|
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_kdf_nas(MME_KDF_NAS_INT_ALG, mme_ue->selected_int_algorithm,
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->kasme, mme_ue->knas_int);
|
2017-07-14 12:39:21 +00:00
|
|
|
mme_kdf_nas(MME_KDF_NAS_ENC_ALG, mme_ue->selected_enc_algorithm,
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->kasme, mme_ue->knas_enc);
|
2017-08-01 22:17:12 +00:00
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Security mode command : UE[%s] <-- EMM\n",
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->imsi_bcd);
|
2017-04-13 13:30:56 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
rv = nas_security_encode(&emmbuf, mme_ue, &message);
|
2017-04-13 10:58:58 +00:00
|
|
|
d_assert(rv == CORE_OK && emmbuf, return, "emm build error");
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-04-14 11:20:00 +00:00
|
|
|
}
|
2017-04-26 08:57:50 +00:00
|
|
|
|
|
|
|
void emm_handle_detach_request(
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue_t *mme_ue, nas_detach_request_from_ue_t *detach_request)
|
2017-04-26 08:57:50 +00:00
|
|
|
{
|
2017-04-28 04:43:42 +00:00
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-07-26 10:40:52 +00:00
|
|
|
nas_detach_type_t *detach_type = NULL;
|
2017-04-26 08:57:50 +00:00
|
|
|
|
2017-07-26 10:40:52 +00:00
|
|
|
d_assert(detach_request, return, "Null param");
|
|
|
|
detach_type = &detach_request->detach_type;
|
|
|
|
d_assert(detach_type, return, "Null param");
|
2017-04-26 08:57:50 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
enb_ue = mme_ue->enb_ue;
|
2017-04-28 04:43:42 +00:00
|
|
|
d_assert(enb_ue, return, "Null param");
|
2017-04-28 04:46:16 +00:00
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Detach request : UE_IMSI[%s] --> EMM\n",
|
|
|
|
mme_ue->imsi_bcd);
|
2017-07-31 14:27:14 +00:00
|
|
|
|
2017-04-26 08:57:50 +00:00
|
|
|
switch (detach_type->detach_type)
|
|
|
|
{
|
2017-04-27 03:38:03 +00:00
|
|
|
/* 0 0 1 : EPS detach */
|
|
|
|
case NAS_DETACH_TYPE_FROM_UE_EPS_DETACH:
|
2017-04-26 08:57:50 +00:00
|
|
|
break;
|
2017-04-27 03:38:03 +00:00
|
|
|
/* 0 1 0 : IMSI detach */
|
|
|
|
case NAS_DETACH_TYPE_FROM_UE_IMSI_DETACH:
|
2017-04-26 08:57:50 +00:00
|
|
|
break;
|
|
|
|
case 6: /* 1 1 0 : reserved */
|
|
|
|
case 7: /* 1 1 1 : reserved */
|
2017-07-31 14:27:14 +00:00
|
|
|
d_warn("[NAS] (Unknown) Detach request : UE_IMSI[%s] --> EMM",
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->imsi_bcd);
|
2017-04-26 08:57:50 +00:00
|
|
|
break;
|
2017-04-27 03:38:03 +00:00
|
|
|
/* 0 1 1 : combined EPS/IMSI detach */
|
|
|
|
case NAS_DETACH_TYPE_FROM_UE_COMBINED_EPS_IMSI_DETACH:
|
2017-04-26 08:57:50 +00:00
|
|
|
default: /* all other values */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:05:01 +00:00
|
|
|
if (MME_UE_HAVE_SESSION(mme_ue))
|
2017-07-28 02:37:19 +00:00
|
|
|
{
|
2017-08-09 11:49:18 +00:00
|
|
|
emm_handle_s11_delete_session_request(mme_ue);
|
2017-07-28 02:37:19 +00:00
|
|
|
}
|
|
|
|
else
|
2017-07-26 08:55:53 +00:00
|
|
|
{
|
2017-07-26 10:40:52 +00:00
|
|
|
emm_handle_detach_accept(mme_ue, detach_request);
|
2017-07-26 08:55:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-26 10:40:52 +00:00
|
|
|
void emm_handle_detach_accept(
|
|
|
|
mme_ue_t *mme_ue, nas_detach_request_from_ue_t *detach_request)
|
2017-07-26 08:55:53 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
mme_enb_t *enb = NULL;
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
2017-08-09 15:41:09 +00:00
|
|
|
nas_message_t message;
|
|
|
|
pkbuf_t *emmbuf = NULL, *s1apbuf = NULL;
|
2017-07-26 08:55:53 +00:00
|
|
|
nas_detach_type_t *detach_type = NULL;
|
2017-08-09 15:41:09 +00:00
|
|
|
S1ap_Cause_t cause;
|
2017-07-26 08:55:53 +00:00
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
|
|
|
enb = enb_ue->enb;
|
|
|
|
d_assert(enb, return, "Null param");
|
|
|
|
|
2017-07-26 10:40:52 +00:00
|
|
|
d_assert(detach_request, return, "Null param");
|
|
|
|
detach_type = &detach_request->detach_type;
|
2017-07-26 08:55:53 +00:00
|
|
|
d_assert(detach_type, return, "Null param");
|
|
|
|
|
|
|
|
/* reply with detach accept */
|
2017-04-26 08:57:50 +00:00
|
|
|
if ((detach_type->switch_off & 0x1) == 0)
|
|
|
|
{
|
|
|
|
memset(&message, 0, sizeof(message));
|
|
|
|
message.h.security_header_type =
|
|
|
|
NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
|
|
|
|
message.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
|
|
|
|
message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM;
|
|
|
|
message.emm.h.message_type = NAS_DETACH_ACCEPT;
|
|
|
|
|
2017-08-02 06:11:08 +00:00
|
|
|
d_trace(3, "[NAS] Detach accept : UE[%s] <-- EMM\n",
|
2017-04-28 07:11:45 +00:00
|
|
|
mme_ue->imsi_bcd);
|
2017-04-26 08:57:50 +00:00
|
|
|
|
2017-04-28 07:11:45 +00:00
|
|
|
rv = nas_security_encode(&emmbuf, mme_ue, &message);
|
2017-04-26 08:57:50 +00:00
|
|
|
d_assert(rv == CORE_OK && emmbuf, return, "emm build error");
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,);
|
2017-04-26 08:57:50 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 15:41:09 +00:00
|
|
|
cause.present = S1ap_Cause_PR_nas;
|
|
|
|
cause.choice.nas = S1ap_CauseNas_detach;
|
|
|
|
|
|
|
|
rv = s1ap_build_ue_context_release_commmand(&s1apbuf, enb_ue, &cause);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error");
|
|
|
|
|
|
|
|
d_assert(s1ap_send_to_enb(enb, s1apbuf) == CORE_OK,, "s1ap send error");
|
2017-04-28 04:46:16 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 11:49:18 +00:00
|
|
|
void emm_handle_service_request(
|
|
|
|
mme_ue_t *mme_ue, nas_service_request_t *service_request)
|
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s1apbuf = NULL;
|
|
|
|
enb_ue_t *enb_ue = NULL;
|
|
|
|
mme_sess_t *sess = NULL;
|
|
|
|
mme_bearer_t *bearer = NULL;
|
|
|
|
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
enb_ue = mme_ue->enb_ue;
|
|
|
|
d_assert(enb_ue, return, "Null param");
|
|
|
|
sess = mme_sess_first(mme_ue);
|
|
|
|
d_assert(sess, return, "Null param");
|
|
|
|
bearer = mme_default_bearer_in_sess(sess);
|
|
|
|
d_assert(bearer, return, "Null param");
|
|
|
|
|
|
|
|
rv = s1ap_build_initial_context_setup_request(&s1apbuf, bearer, NULL);
|
|
|
|
d_assert(rv == CORE_OK && s1apbuf, return, "s1ap build error");
|
|
|
|
|
2017-08-10 07:47:18 +00:00
|
|
|
d_assert(nas_send_to_enb(enb_ue, s1apbuf) == CORE_OK,, "s1ap send error");
|
2017-08-09 11:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void emm_handle_emm_status(mme_ue_t *mme_ue, nas_emm_status_t *emm_status)
|
|
|
|
{
|
|
|
|
d_assert(mme_ue, return, "Null param");
|
|
|
|
|
|
|
|
d_warn("[NAS] EMM status(%d) : UE[%s] --> EMM",
|
|
|
|
emm_status->emm_cause, mme_ue->imsi_bcd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* S11 Layer in EMM Handler
|
|
|
|
*/
|
|
|
|
void emm_handle_s11_delete_session_request(mme_ue_t *mme_ue)
|
2017-07-26 12:58:14 +00:00
|
|
|
{
|
|
|
|
status_t rv;
|
|
|
|
pkbuf_t *s11buf = NULL;
|
2017-08-09 15:41:09 +00:00
|
|
|
mme_sess_t *sess = NULL;
|
2017-07-26 12:58:14 +00:00
|
|
|
|
2017-08-09 15:41:09 +00:00
|
|
|
d_assert(mme_ue, return, "Null param");
|
2017-08-10 01:01:50 +00:00
|
|
|
sess = mme_sess_first(mme_ue);
|
|
|
|
while (sess != NULL)
|
|
|
|
{
|
|
|
|
mme_bearer_t *bearer = mme_default_bearer_in_sess(sess);
|
|
|
|
if (bearer != NULL)
|
|
|
|
{
|
|
|
|
rv = mme_s11_build_delete_session_request(&s11buf, sess);
|
|
|
|
d_assert(rv == CORE_OK, return, "S11 build error");
|
2017-08-09 15:41:09 +00:00
|
|
|
|
2017-08-10 01:01:50 +00:00
|
|
|
rv = mme_s11_send_to_sgw(bearer->sgw,
|
|
|
|
GTP_DELETE_SESSION_REQUEST_TYPE, sess->sgw_s11_teid,
|
|
|
|
s11buf);
|
|
|
|
d_assert(rv == CORE_OK, return, "S11 send error");
|
|
|
|
}
|
|
|
|
sess = mme_sess_next(sess);
|
|
|
|
}
|
2017-07-26 12:58:14 +00:00
|
|
|
}
|