diff --git a/src/mme/emm_build.c b/src/mme/emm_build.c index 689b627669..02b997e672 100644 --- a/src/mme/emm_build.c +++ b/src/mme/emm_build.c @@ -107,3 +107,94 @@ status_t emm_build_attach_reject( return CORE_OK; } +status_t emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue) +{ + nas_message_t message; + nas_tracking_area_update_accept_t *tau_accept = + &message.emm.tracking_area_update_accept; + + memset(&message, 0, sizeof(message)); + message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM; + message.emm.h.message_type = NAS_TRACKING_AREA_UPDATE_ACCEPT; + + tau_accept->eps_update_result.result = NAS_EPS_UPDATE_RESULT_TA_UPDATED; + + /* Set T3412 */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT ; + + /* FIXME: Use the value from configuration */ + tau_accept->t3412_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH; + tau_accept->t3412_value.value = 9; + + /* Set TAI */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT; + + tau_accept->tai_list.length = 6; + tau_accept->tai_list.type = 2; + tau_accept->tai_list.num = 0; /* +1 = 1 elements */ + + memcpy(&tau_accept->tai_list.type2.tai[0], &mme_ue->tai, sizeof(tai_t)); + + /* Set EPS bearer context status */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT; + + tau_accept->eps_bearer_context_status.length = 2; + tau_accept->eps_bearer_context_status.ebi5 = + (mme_sess_find_by_ebi(mme_ue, 5) ? 1 : 0); + tau_accept->eps_bearer_context_status.ebi6 = + (mme_sess_find_by_ebi(mme_ue, 6) ? 1 : 0); + tau_accept->eps_bearer_context_status.ebi7 = + (mme_sess_find_by_ebi(mme_ue, 7) ? 1 : 0); + /* FIXME : Need to set other ebi */ + + /* Set T3402 */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT; + + /* FIXME: Use the value from configuration */ + tau_accept->t3402_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_1_MM; + tau_accept->t3402_value.value = 12; + + /* Set T3423 */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT; + + /* FIXME: Use the value from configuration */ + tau_accept->t3423_value.unit = NAS_GRPS_TIMER_UNIT_MULTIPLES_OF_DECI_HH; + tau_accept->t3423_value.value = 9; + + /* Set EPS network feature support */ + tau_accept->presencemask |= + NAS_TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT; + + tau_accept->eps_network_feature_support.length = 1; + tau_accept->eps_network_feature_support.esr_ps = 1; + tau_accept->eps_network_feature_support.epc_lcs = 1; + tau_accept->eps_network_feature_support.ims_vops = 1; + + d_assert(nas_security_encode(emmbuf, mme_ue, &message) == CORE_OK && + *emmbuf,,); + + return CORE_OK; +} + +status_t emm_build_tau_reject(pkbuf_t **emmbuf, nas_emm_cause_t emm_cause, + mme_ue_t *mme_ue) +{ + nas_message_t message; + nas_tracking_area_update_reject_t *tau_reject = + &message.emm.tracking_area_update_reject; + + memset(&message, 0, sizeof(message)); + message.emm.h.protocol_discriminator = NAS_PROTOCOL_DISCRIMINATOR_EMM; + message.emm.h.message_type = NAS_TRACKING_AREA_UPDATE_REJECT; + + tau_reject->emm_cause = emm_cause; + + d_assert(nas_plain_encode(emmbuf, &message) == CORE_OK && *emmbuf,,); + + return CORE_OK; +} diff --git a/src/mme/emm_build.h b/src/mme/emm_build.h index 3237de7aff..290a57cd4b 100644 --- a/src/mme/emm_build.h +++ b/src/mme/emm_build.h @@ -11,6 +11,9 @@ CORE_DECLARE(status_t) emm_build_attach_accept( pkbuf_t **emmbuf, mme_ue_t *mme_ue, pkbuf_t *esmbuf); CORE_DECLARE(status_t) emm_build_attach_reject( pkbuf_t **emmbuf, nas_emm_cause_t emm_cause, pkbuf_t *esmbuf); +CORE_DECLARE(status_t) emm_build_tau_accept(pkbuf_t **emmbuf, mme_ue_t *mme_ue); +CORE_DECLARE(status_t) emm_build_tau_reject(pkbuf_t **emmbuf, + nas_emm_cause_t emm_cause,mme_ue_t *mme_ue); #ifdef __cplusplus } diff --git a/src/mme/emm_handler.c b/src/mme/emm_handler.c index dd5217b7bb..cf7c30a2c6 100644 --- a/src/mme/emm_handler.c +++ b/src/mme/emm_handler.c @@ -606,6 +606,191 @@ void emm_handle_emm_status(mme_ue_t *mme_ue, nas_emm_status_t *emm_status) emm_status->emm_cause, mme_ue->imsi_bcd); } +void emm_handle_tau_request( + mme_ue_t *mme_ue, nas_tracking_area_update_request_t *tau_request) +{ + nas_eps_mobile_identity_t *eps_mobile_identity = + &tau_request->old_guti; + 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"); + + /* Store UE specific information */ + if (tau_request->presencemask & + NAS_TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) + { + nas_tracking_area_identity_t *last_visited_registered_tai = + &tau_request->last_visited_registered_tai; + + memcpy(&mme_ue->visited_plmn_id, + &last_visited_registered_tai->plmn_id, + PLMN_ID_LEN); + } + 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); + } + + if (tau_request->presencemask & + NAS_TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT) + { + memcpy(&mme_ue->ue_network_capability, + &tau_request->ue_network_capability, + sizeof(tau_request->ue_network_capability)); + } + + if (tau_request->presencemask & + NAS_TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT) + { + memcpy(&mme_ue->ms_network_capability, + &tau_request->ms_network_capability, + sizeof(tau_request->ms_network_capability)); + } + + /* 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)); + + /* TODO: + * 1) Consider if MME is changed or not. + * 2) Consider if SGW is changed or not. + */ + switch(eps_mobile_identity->imsi.type) + { + case NAS_EPS_MOBILE_IDENTITY_GUTI: + { + 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; + + d_trace(3, "[NAS] TAU request : GUTI[G:%d,C:%d,M_TMSI:0x%x]-" + "IMSI:[%s] --> EMM\n", + guti.mme_gid, + guti.mme_code, + guti.m_tmsi, + MME_UE_HAVE_IMSI(mme_ue) + ? mme_ue->imsi_bcd : "Unknown"); + + if (!MME_UE_HAVE_IMSI(mme_ue)) + { + /* Unknown GUTI */ + + /* FIXME : Need to check if GUTI is allocated to old MME. + * if so , transmit context request to get the context of ue. + */ + + /* Send TAU reject */ + emm_handle_tau_reject(mme_ue, + EMM_CAUSE_UE_IDENTITY_CANNOT_BE_DERIVED_BY_THE_NETWORK); + } + else if (!SECURITY_CONTEXT_IS_VALID(mme_ue)) + { + /* Need Authencation */ + d_warn("Need Authenticatoin"); + } + else + { + /* Send TAU accept */ + emm_handle_tau_accept(mme_ue); + } + + break; + } + default: + { + d_warn("Not implemented(type:%d)", + eps_mobile_identity->imsi.type); + + return; + } + } + + //event_emm_to_esm(mme_ue, &attach_request->esm_message_container); +} + +void emm_handle_tau_accept(mme_ue_t *mme_ue) +{ + status_t rv; + mme_enb_t *enb = NULL; + enb_ue_t *enb_ue = NULL; + pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; + S1ap_Cause_t cause; + + 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"); + + /* Build TAU accept */ + if (emm_build_tau_accept(&emmbuf, mme_ue) != CORE_OK) + { + d_error("emm_build_tau_accept error"); + pkbuf_free(emmbuf); + return; + } + + /* Send Dl NAS to UE */ + d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); + + + /* FIXME : delay required before sending UE context release to make sure + * that UE receive DL NAS ? */ + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + + 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"); +} + +void emm_handle_tau_reject(mme_ue_t *mme_ue, nas_emm_cause_t emm_cause) +{ + status_t rv; + mme_enb_t *enb = NULL; + enb_ue_t *enb_ue = NULL; + pkbuf_t *emmbuf = NULL, *s1apbuf = NULL; + S1ap_Cause_t cause; + + 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"); + + /* Build TAU reject */ + if (emm_build_tau_reject(&emmbuf, emm_cause, mme_ue) != CORE_OK) + { + d_error("emm_build_tau_accept error"); + pkbuf_free(emmbuf); + return; + } + + /* Send Dl NAS to UE */ + d_assert(nas_send_to_downlink_nas_transport(mme_ue, emmbuf) == CORE_OK,,); + + + /* FIXME : delay required before sending UE context release to make sure + * that UE receive DL NAS ? */ + cause.present = S1ap_Cause_PR_nas; + cause.choice.nas = S1ap_CauseNas_normal_release; + + 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"); +} + /*********************************************************************** * S11 Layer in EMM Handler */ diff --git a/src/mme/emm_handler.h b/src/mme/emm_handler.h index 81ab215576..fa1474edf4 100644 --- a/src/mme/emm_handler.h +++ b/src/mme/emm_handler.h @@ -34,6 +34,11 @@ CORE_DECLARE(void) emm_handle_service_request( CORE_DECLARE(void) emm_handle_emm_status( mme_ue_t *mme_ue, nas_emm_status_t *emm_status); +CORE_DECLARE(void) emm_handle_tau_request( + mme_ue_t *mme_ue, nas_tracking_area_update_request_t *tau_request); +CORE_DECLARE(void) emm_handle_tau_accept(mme_ue_t *mme_ue); +CORE_DECLARE(void) emm_handle_tau_reject(mme_ue_t *mme_ue, + nas_esm_cause_t emm_cause); /** S11 Layer in EMM handler */ CORE_DECLARE(void) emm_handle_s11_delete_session_request(mme_ue_t *mme_ue); diff --git a/src/mme/emm_sm.c b/src/mme/emm_sm.c index dc1f47c010..e74a9d959f 100644 --- a/src/mme/emm_sm.c +++ b/src/mme/emm_sm.c @@ -186,6 +186,8 @@ void emm_state_operational(fsm_t *s, event_t *e) case NAS_TRACKING_AREA_UPDATE_REQUEST: { mme_ue_paged(mme_ue); + emm_handle_tau_request( + mme_ue, &message->emm.tracking_area_update_request); break; } default: diff --git a/src/mme/mme_context.c b/src/mme/mme_context.c index dc9459a4f9..e60f74ce38 100644 --- a/src/mme/mme_context.c +++ b/src/mme/mme_context.c @@ -1280,7 +1280,49 @@ mme_ue_t* mme_ue_find_by_message(nas_message_t *message) } case NAS_TRACKING_AREA_UPDATE_REQUEST: { - /* TODO */ + nas_tracking_area_update_request_t *tau_request = + &message->emm.tracking_area_update_request; + + nas_eps_mobile_identity_t *eps_mobile_identity = + &tau_request->old_guti; + + switch(eps_mobile_identity->imsi.type) + { + case NAS_EPS_MOBILE_IDENTITY_GUTI: + { + 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; + + mme_ue = mme_ue_find_by_guti(&guti); + if (mme_ue) + { + d_trace(3, "Known UE by GUTI[G:%d,C:%d,M_TMSI:0x%x]\n", + guti.mme_gid, + guti.mme_code, + guti.m_tmsi); + } + else + { + d_warn("Unknown UE by GUTI[G:%d,C:%d,M_TMSI:0x%x]", + guti.mme_gid, + guti.mme_code, + guti.m_tmsi); + } + break; + } + default: + { + d_error("Uknown message imsi type =%d\n", + eps_mobile_identity->imsi.type); + break; + } + } break; } default: diff --git a/support/linux_netconfig.sh b/support/linux_netconfig.sh index 4dc3b1cf98..b79f275e25 100755 --- a/support/linux_netconfig.sh +++ b/support/linux_netconfig.sh @@ -4,7 +4,7 @@ ifconfig eth1:hss 10.1.35.214/24 up ifconfig eth1:mme 10.1.35.215/24 up ifconfig eth1:sgw_s5 10.1.35.216/24 up ifconfig eth1:sgw_s11 10.1.35.217/24 up -ifconfig eth1:pcrf 10.1.35.218/24 up +ifconfig eth1:pcrf 10.1.35.213/24 up ifconfig eth1:pgw 10.1.35.219/24 up ifconfig pgwtun 45.45.0.1/16 up