diff --git a/lib/diameter/s6a/message.h b/lib/diameter/s6a/message.h index ae314dd10..707e0b085 100644 --- a/lib/diameter/s6a/message.h +++ b/lib/diameter/s6a/message.h @@ -168,8 +168,6 @@ typedef struct ogs_diam_s6a_message_s { uint32_t *err; uint32_t *exp_err; - bool during_attach; - ogs_diam_s6a_clr_message_t clr_message; ogs_diam_s6a_aia_message_t aia_message; ogs_diam_s6a_ula_message_t ula_message; diff --git a/lib/nas/eps/types.h b/lib/nas/eps/types.h index c59664325..83609b0fe 100644 --- a/lib/nas/eps/types.h +++ b/lib/nas/eps/types.h @@ -225,7 +225,7 @@ ED3(uint8_t cn_specific_drx_cycle_length_coefficient_and_drx_value_for_s1_mode:4 * O TV 2 */ /* REQUEST_ACCEPTED(16) cause is defined by Open5GS */ -#define EMM_CAUSE_REQUEST_ACCEPTED 16 +#define OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED 16 /* Annex A (informative) Cause values for EPS mobility management * A.1 Causes related to UE identification */ diff --git a/src/mme/mme-fd-path.c b/src/mme/mme-fd-path.c index 739409e8e..43f38c2b7 100644 --- a/src/mme/mme-fd-path.c +++ b/src/mme/mme-fd-path.c @@ -229,7 +229,6 @@ static void mme_s6a_aia_cb(void *data, struct msg **msg) s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); ogs_assert(s6a_message); s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION; - s6a_message->during_attach = true; aia_message = &s6a_message->aia_message; ogs_assert(aia_message); e_utran_vector = &aia_message->e_utran_vector; @@ -638,7 +637,6 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg) s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t)); ogs_assert(s6a_message); s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION; - s6a_message->during_attach = true; ula_message = &s6a_message->ula_message; ogs_assert(ula_message); subscription_data = &ula_message->subscription_data; @@ -1439,7 +1437,6 @@ static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp, s6a_message->cmd_code = OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION; clr_message = &s6a_message->clr_message; ogs_assert(clr_message); - /* Create answer header */ qry = *msg; diff --git a/src/mme/mme-s6a-handler.c b/src/mme/mme-s6a-handler.c index 4054045fd..8828efcc5 100644 --- a/src/mme/mme-s6a-handler.c +++ b/src/mme/mme-s6a-handler.c @@ -23,16 +23,33 @@ #include "mme-sm.h" #include "mme-s6a-handler.h" -void mme_s6a_handle_aia(mme_ue_t *mme_ue, - ogs_diam_s6a_aia_message_t *aia_message) +/* Unfortunately fd doesn't distinguish + * between result-code and experimental-result-code. + * + * However, e.g. 5004 has different meaning + * if used in result-code than in experimental-result-code */ +static uint8_t emm_cause_from_diameter( + const uint32_t *dia_err, const uint32_t *dia_exp_err); + +uint8_t mme_s6a_handle_aia( + mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) { + ogs_diam_s6a_aia_message_t *aia_message = NULL; ogs_diam_e_utran_vector_t *e_utran_vector = NULL; ogs_assert(mme_ue); + ogs_assert(s6a_message); + aia_message = &s6a_message->aia_message; ogs_assert(aia_message); e_utran_vector = &aia_message->e_utran_vector; ogs_assert(e_utran_vector); + if (s6a_message->result_code != ER_DIAMETER_SUCCESS) { + ogs_warn("Authentication Information failed [%d]", + s6a_message->result_code); + return emm_cause_from_diameter(s6a_message->err, s6a_message->exp_err); + } + mme_ue->xres_len = e_utran_vector->xres_len; memcpy(mme_ue->xres, e_utran_vector->xres, mme_ue->xres_len); memcpy(mme_ue->kasme, e_utran_vector->kasme, OGS_SHA256_DIGEST_SIZE); @@ -44,22 +61,31 @@ void mme_s6a_handle_aia(mme_ue_t *mme_ue, if (mme_ue->nas_eps.ksi == OGS_NAS_KSI_NO_KEY_IS_AVAILABLE) mme_ue->nas_eps.ksi = 0; - ogs_assert(OGS_OK == - nas_eps_send_authentication_request(mme_ue)); + ogs_assert(OGS_OK == nas_eps_send_authentication_request(mme_ue)); + + return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED; } -void mme_s6a_handle_ula(mme_ue_t *mme_ue, - ogs_diam_s6a_ula_message_t *ula_message) +uint8_t mme_s6a_handle_ula( + mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message) { + ogs_diam_s6a_ula_message_t *ula_message = NULL; ogs_subscription_data_t *subscription_data = NULL; ogs_slice_data_t *slice_data = NULL; - int i; + int i, rv; ogs_assert(mme_ue); + ogs_assert(s6a_message); + ula_message = &s6a_message->ula_message; ogs_assert(ula_message); subscription_data = &ula_message->subscription_data; ogs_assert(subscription_data); + if (s6a_message->result_code != ER_DIAMETER_SUCCESS) { + ogs_error("Update Location failed [%d]", s6a_message->result_code); + return emm_cause_from_diameter(s6a_message->err, s6a_message->exp_err); + } + ogs_assert(subscription_data->num_of_slice == 1); slice_data = &subscription_data->slice[0]; @@ -92,7 +118,8 @@ void mme_s6a_handle_ula(mme_ue_t *mme_ue, memcpy(&mme_ue->session[i].smf_ip, &slice_data->session[i].smf_ip, sizeof(mme_ue->session[i].smf_ip)); - memcpy(&mme_ue->session[i].charging_characteristics, &slice_data->session[i].charging_characteristics, + memcpy(&mme_ue->session[i].charging_characteristics, + &slice_data->session[i].charging_characteristics, sizeof(mme_ue->session[i].charging_characteristics)); mme_ue->session[i].charging_characteristics_presence = slice_data->session[i].charging_characteristics_presence; @@ -100,10 +127,35 @@ void mme_s6a_handle_ula(mme_ue_t *mme_ue, mme_ue->num_of_session = i; mme_ue->context_identifier = slice_data->context_identifier; + + if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) { + rv = nas_eps_send_emm_to_esm(mme_ue, + &mme_ue->pdn_connectivity_request); + if (rv != OGS_OK) { + ogs_error("nas_eps_send_emm_to_esm() failed"); + return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED; + } + } else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) { + ogs_assert(OGS_OK == + nas_eps_send_tau_accept(mme_ue, + S1AP_ProcedureCode_id_InitialContextSetup)); + } else if (mme_ue->nas_eps.type == MME_EPS_TYPE_SERVICE_REQUEST) { + ogs_error("[%s] Service request", mme_ue->imsi_bcd); + return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED; + } else if (mme_ue->nas_eps.type == + MME_EPS_TYPE_DETACH_REQUEST_FROM_UE) { + ogs_error("[%s] Detach request", mme_ue->imsi_bcd); + return OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED; + } else { + ogs_fatal("Invalid Type[%d]", mme_ue->nas_eps.type); + ogs_assert_if_reached(); + } + + return OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED; } -void mme_s6a_handle_clr(mme_ue_t *mme_ue, - ogs_diam_s6a_clr_message_t *clr_message) +void mme_s6a_handle_clr( + mme_ue_t *mme_ue, ogs_diam_s6a_clr_message_t *clr_message) { uint8_t detach_type = 0; @@ -131,3 +183,48 @@ void mme_s6a_handle_clr(mme_ue_t *mme_ue, ogs_assert(OGS_OK == nas_eps_send_detach_request(mme_ue, detach_type)); } } + +/* 3GPP TS 29.272 Annex A; Table !.a: + * Mapping from S6a error codes to NAS Cause Codes */ +static uint8_t emm_cause_from_diameter( + const uint32_t *dia_err, const uint32_t *dia_exp_err) +{ + if (dia_exp_err) { + switch (*dia_exp_err) { + case OGS_DIAM_S6A_ERROR_USER_UNKNOWN: /* 5001 */ + return OGS_NAS_EMM_CAUSE_PLMN_NOT_ALLOWED; + case OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION: /* 5420 */ + /* FIXME: Error diagnostic? */ + return OGS_NAS_EMM_CAUSE_NO_SUITABLE_CELLS_IN_TRACKING_AREA; + case OGS_DIAM_S6A_ERROR_RAT_NOT_ALLOWED: /* 5421 */ + return OGS_NAS_EMM_CAUSE_ROAMING_NOT_ALLOWED_IN_THIS_TRACKING_AREA; + case OGS_DIAM_S6A_ERROR_ROAMING_NOT_ALLOWED: /* 5004 */ + return OGS_NAS_EMM_CAUSE_PLMN_NOT_ALLOWED; + /* return OGS_NAS_EMM_CAUSE_EPS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN; + * (ODB_HPLMN_APN) */ + /* return OGS_NAS_EMM_CAUSE_ESM_FAILURE; (ODB_ALL_APN) */ + case OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE: /* 4181 */ + return OGS_NAS_EMM_CAUSE_NETWORK_FAILURE; + } + } + if (dia_err) { + switch (*dia_err) { + case ER_DIAMETER_AUTHORIZATION_REJECTED: /* 5003 */ + case ER_DIAMETER_UNABLE_TO_DELIVER: /* 3002 */ + case ER_DIAMETER_REALM_NOT_SERVED: /* 3003 */ + return OGS_NAS_EMM_CAUSE_NO_SUITABLE_CELLS_IN_TRACKING_AREA; + case ER_DIAMETER_UNABLE_TO_COMPLY: /* 5012 */ + case ER_DIAMETER_INVALID_AVP_VALUE: /* 5004 */ + case ER_DIAMETER_AVP_UNSUPPORTED: /* 5001 */ + case ER_DIAMETER_MISSING_AVP: /* 5005 */ + case ER_DIAMETER_RESOURCES_EXCEEDED: /* 5006 */ + case ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES: /* 5009 */ + return OGS_NAS_EMM_CAUSE_NETWORK_FAILURE; + } + } + + ogs_error("Unexpected Diameter Result Code %d/%d, defaulting to severe " + "network failure", + dia_err ? *dia_err : -1, dia_exp_err ? *dia_exp_err : -1); + return OGS_NAS_EMM_CAUSE_SEVERE_NETWORK_FAILURE; +} diff --git a/src/mme/mme-s6a-handler.h b/src/mme/mme-s6a-handler.h index 097d94ba1..5a0dc53db 100644 --- a/src/mme/mme-s6a-handler.h +++ b/src/mme/mme-s6a-handler.h @@ -26,12 +26,12 @@ extern "C" { #endif -void mme_s6a_handle_aia(mme_ue_t *mme_ue, - ogs_diam_s6a_aia_message_t *aia_message); -void mme_s6a_handle_ula(mme_ue_t *mme_ue, - ogs_diam_s6a_ula_message_t *ula_message); -void mme_s6a_handle_clr(mme_ue_t *mme_ue, - ogs_diam_s6a_clr_message_t *clr_message); +uint8_t mme_s6a_handle_aia( + mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message); +uint8_t mme_s6a_handle_ula( + mme_ue_t *mme_ue, ogs_diam_s6a_message_t *s6a_message); +void mme_s6a_handle_clr( + mme_ue_t *mme_ue, ogs_diam_s6a_clr_message_t *clr_message); #ifdef __cplusplus } diff --git a/src/mme/mme-sm.c b/src/mme/mme-sm.c index b76093bf2..58edee6ef 100644 --- a/src/mme/mme-sm.c +++ b/src/mme/mme-sm.c @@ -34,54 +34,6 @@ #include "mme-s6a-handler.h" #include "mme-path.h" -/* 3GPP TS 29.272 Annex A; Table !.a: - * Mapping from S6a error codes to NAS Cause Codes */ -static uint8_t emm_cause_from_diameter( - mme_ue_t *mme_ue, const uint32_t *dia_err, const uint32_t *dia_exp_err) -{ - ogs_assert(mme_ue); - - if (dia_exp_err) { - switch (*dia_exp_err) { - case OGS_DIAM_S6A_ERROR_USER_UNKNOWN: /* 5001 */ - ogs_info("[%s] User Unknown in HSS DB", mme_ue->imsi_bcd); - return OGS_NAS_EMM_CAUSE_PLMN_NOT_ALLOWED; - case OGS_DIAM_S6A_ERROR_UNKNOWN_EPS_SUBSCRIPTION: /* 5420 */ - /* FIXME: Error diagnostic? */ - return OGS_NAS_EMM_CAUSE_NO_SUITABLE_CELLS_IN_TRACKING_AREA; - case OGS_DIAM_S6A_ERROR_RAT_NOT_ALLOWED: /* 5421 */ - return OGS_NAS_EMM_CAUSE_ROAMING_NOT_ALLOWED_IN_THIS_TRACKING_AREA; - case OGS_DIAM_S6A_ERROR_ROAMING_NOT_ALLOWED: /* 5004 */ - return OGS_NAS_EMM_CAUSE_PLMN_NOT_ALLOWED; - /* return OGS_NAS_EMM_CAUSE_EPS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN; - * (ODB_HPLMN_APN) */ - /* return OGS_NAS_EMM_CAUSE_ESM_FAILURE; (ODB_ALL_APN) */ - case OGS_DIAM_S6A_AUTHENTICATION_DATA_UNAVAILABLE: /* 4181 */ - return OGS_NAS_EMM_CAUSE_NETWORK_FAILURE; - } - } - if (dia_err) { - switch (*dia_err) { - case ER_DIAMETER_AUTHORIZATION_REJECTED: /* 5003 */ - case ER_DIAMETER_UNABLE_TO_DELIVER: /* 3002 */ - case ER_DIAMETER_REALM_NOT_SERVED: /* 3003 */ - return OGS_NAS_EMM_CAUSE_NO_SUITABLE_CELLS_IN_TRACKING_AREA; - case ER_DIAMETER_UNABLE_TO_COMPLY: /* 5012 */ - case ER_DIAMETER_INVALID_AVP_VALUE: /* 5004 */ - case ER_DIAMETER_AVP_UNSUPPORTED: /* 5001 */ - case ER_DIAMETER_MISSING_AVP: /* 5005 */ - case ER_DIAMETER_RESOURCES_EXCEEDED: /* 5006 */ - case ER_DIAMETER_AVP_OCCURS_TOO_MANY_TIMES: /* 5009 */ - return OGS_NAS_EMM_CAUSE_NETWORK_FAILURE; - } - } - - ogs_error("Unexpected Diameter Result Code %d/%d, defaulting to severe " - "network failure", - dia_err ? *dia_err : -1, dia_exp_err ? *dia_exp_err : -1); - return OGS_NAS_EMM_CAUSE_SEVERE_NETWORK_FAILURE; -} - void mme_state_initial(ogs_fsm_t *s, mme_event_t *e) { mme_sm_debug(e); @@ -122,6 +74,7 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) mme_sess_t *sess = NULL; ogs_diam_s6a_message_t *s6a_message = NULL; + uint8_t emm_cause = 0; ogs_gtp_node_t *gnode = NULL; ogs_gtp_xact_t *xact = NULL; @@ -437,26 +390,20 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) s6a_message = e->s6a_message; ogs_assert(s6a_message); - if (s6a_message->during_attach) { - enb_ue = enb_ue_cycle(mme_ue->enb_ue); - if (!enb_ue) { - ogs_error("S1 context has already been removed"); + enb_ue = enb_ue_cycle(mme_ue->enb_ue); + if (!enb_ue) { + ogs_error("S1 context has already been removed"); - ogs_subscription_data_free( - &s6a_message->ula_message.subscription_data); - ogs_free(s6a_message); - break; - } - - if (s6a_message->result_code != ER_DIAMETER_SUCCESS) { - /* Unfortunately fd doesn't distinguish - * between result-code and experimental-result-code. - * - * However, e.g. 5004 has different meaning - * if used in result-code than in experimental-result-code */ - uint8_t emm_cause = emm_cause_from_diameter( - mme_ue, s6a_message->err, s6a_message->exp_err); + ogs_subscription_data_free( + &s6a_message->ula_message.subscription_data); + ogs_free(s6a_message); + break; + } + switch (s6a_message->cmd_code) { + case OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION: + emm_cause = mme_s6a_handle_aia(mme_ue, s6a_message); + if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) { ogs_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]", mme_ue->imsi_bcd, emm_cause); ogs_assert(OGS_OK == @@ -467,43 +414,21 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e) s1ap_send_ue_context_release_command(enb_ue, S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); - - ogs_subscription_data_free( - &s6a_message->ula_message.subscription_data); - ogs_free(s6a_message); - break; } - } - - switch (s6a_message->cmd_code) { - case OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION: - mme_s6a_handle_aia(mme_ue, &s6a_message->aia_message); break; case OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION: - mme_s6a_handle_ula(mme_ue, &s6a_message->ula_message); - - if (mme_ue->nas_eps.type == MME_EPS_TYPE_ATTACH_REQUEST) { - rv = nas_eps_send_emm_to_esm(mme_ue, - &mme_ue->pdn_connectivity_request); - if (rv != OGS_OK) { - ogs_error("nas_eps_send_emm_to_esm() failed"); - ogs_assert(OGS_OK == - nas_eps_send_attach_reject(mme_ue, - OGS_NAS_EMM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED, - OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED)); - } - } else if (mme_ue->nas_eps.type == MME_EPS_TYPE_TAU_REQUEST) { + emm_cause = mme_s6a_handle_ula(mme_ue, s6a_message); + if (emm_cause != OGS_NAS_EMM_CAUSE_REQUEST_ACCEPTED) { + ogs_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]", + mme_ue->imsi_bcd, emm_cause); ogs_assert(OGS_OK == - nas_eps_send_tau_accept(mme_ue, - S1AP_ProcedureCode_id_InitialContextSetup)); - } else if (mme_ue->nas_eps.type == MME_EPS_TYPE_SERVICE_REQUEST) { - ogs_error("[%s] Service request", mme_ue->imsi_bcd); - } else if (mme_ue->nas_eps.type == - MME_EPS_TYPE_DETACH_REQUEST_FROM_UE) { - ogs_error("[%s] Detach request", mme_ue->imsi_bcd); - } else { - ogs_fatal("Invalid Type[%d]", mme_ue->nas_eps.type); - ogs_assert_if_reached(); + nas_eps_send_attach_reject(mme_ue, emm_cause, + OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED)); + + ogs_assert(OGS_OK == + s1ap_send_ue_context_release_command(enb_ue, + S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, + S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0)); } break; case OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION: diff --git a/src/mme/nas-path.c b/src/mme/nas-path.c index d822174ef..b14090334 100644 --- a/src/mme/nas-path.c +++ b/src/mme/nas-path.c @@ -306,7 +306,7 @@ int nas_eps_send_detach_accept(mme_ue_t *mme_ue) } rv = s1ap_send_ue_context_release_command(enb_ue, - S1AP_Cause_PR_nas, S1AP_CauseNas_detach, + S1AP_Cause_PR_nas, S1AP_CauseNas_normal_release, S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK, 0); ogs_expect(rv == OGS_OK);