[MME] Introduce support for S6a Cancel Location Request

- Added diameter dictionary definitions for Cancel Location
- Cancel Location will completely remove UE from MME, allow for a fresh IMSI attach to occur on next attempt.
- T3422 is used for detach request.
- Added new handling for s6a events in mme-sm, as not all s6a messages are at attach now.  Maybe there's something in a state machine I should've been using here instead of a new flag?

- Testing was completed with UE in idle and connected.  With CLR flags indicating re-attach required and without.  Also sending CLR after UE detach.  And then sending again when mme_ue is empty.
This commit is contained in:
jmasterfunk84 2022-07-26 08:54:47 -06:00 committed by Sukchan Lee
parent ff5023e95b
commit 47cbaca149
16 changed files with 391 additions and 30 deletions

View File

@ -526,6 +526,63 @@ int ogs_dict_s6a_entry(char *conffile)
PARSE_loc_rules( rules, cmd );
}
/* Cancel-Location-Request (CLR) Command - 3GPP TS 29.272 #7.2.7 */
{
struct dict_object * cmd;
struct dict_cmd_data data = {
317, /* Code */
"Cancel-Location-Request", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Destination-Host" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Destination-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "User-Name" }, RULE_REQUIRED, -1, 1 },
{ { .avp_vendor = 10415, .avp_name = "Supported-Features" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "Cancellation-Type" }, RULE_REQUIRED, -1, -1 },
{ { .avp_vendor = 10415, .avp_name = "CLR-Flags" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 },
};
CHECK_dict_new( DICT_COMMAND, &data, s6a, &cmd);
PARSE_loc_rules( rules, cmd );
}
/* Cancel-Location-Answer (CLA) Command - 3GPP TS 29.272 #7.2.8 */
{
struct dict_object * cmd;
struct dict_cmd_data data = {
317, /* Code */
"Cancel-Location-Answer", /* Name */
CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */
CMD_FLAG_PROXIABLE /* Fixed flag values */
};
struct local_rules_definition rules[] =
{
{ { .avp_name = "Session-Id" }, RULE_FIXED_HEAD, -1, 1 },
{ { .avp_name = "Vendor-Specific-Application-Id" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Result-Code" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Experimental-Result" }, RULE_OPTIONAL, -1, 1 },
{ { .avp_name = "Auth-Session-State" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Host" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Origin-Realm" }, RULE_REQUIRED, -1, 1 },
{ { .avp_name = "Failed-AVP" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Proxy-Info" }, RULE_OPTIONAL, -1, -1 },
{ { .avp_name = "Route-Record" }, RULE_OPTIONAL, -1, -1 },
};
CHECK_dict_new( DICT_COMMAND, &data, s6a, &cmd);
PARSE_loc_rules( rules, cmd );
}
}
LOG_D( "Extension 'Dictionary definitions for DCCA 3GPP S6A' initialized");

View File

@ -30,9 +30,13 @@ struct dict_object *ogs_diam_s6a_cmd_ulr = NULL;
struct dict_object *ogs_diam_s6a_cmd_ula = NULL;
struct dict_object *ogs_diam_s6a_cmd_pur = NULL;
struct dict_object *ogs_diam_s6a_cmd_pua = NULL;
struct dict_object *ogs_diam_s6a_cmd_clr = NULL;
struct dict_object *ogs_diam_s6a_cmd_cla = NULL;
struct dict_object *ogs_diam_s6a_ulr_flags = NULL;
struct dict_object *ogs_diam_s6a_ula_flags = NULL;
struct dict_object *ogs_diam_s6a_clr_flags = NULL;
struct dict_object *ogs_diam_s6a_cancellation_type = NULL;
struct dict_object *ogs_diam_s6a_subscription_data = NULL;
struct dict_object *ogs_diam_s6a_req_eutran_auth_info = NULL;
struct dict_object *ogs_diam_s6a_number_of_requested_vectors = NULL;
@ -91,9 +95,13 @@ int ogs_diam_s6a_init(void)
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Update-Location-Answer", &ogs_diam_s6a_cmd_ula);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Request", &ogs_diam_s6a_cmd_pur);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Purge-UE-Answer", &ogs_diam_s6a_cmd_pua);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Cancel-Location-Request", &ogs_diam_s6a_cmd_clr);
CHECK_dict_search(DICT_COMMAND, CMD_BY_NAME, "Cancel-Location-Answer", &ogs_diam_s6a_cmd_cla);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULR-Flags", &ogs_diam_s6a_ulr_flags);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "ULA-Flags", &ogs_diam_s6a_ula_flags);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "CLR-Flags", &ogs_diam_s6a_clr_flags);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Cancellation-Type", &ogs_diam_s6a_cancellation_type);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "UE-SRVCC-Capability", &ogs_diam_s6a_ue_srvcc_capability);
CHECK_dict_search(DICT_AVP, AVP_BY_NAME_ALL_VENDORS, "Requested-EUTRAN-Authentication-Info", &ogs_diam_s6a_req_eutran_auth_info);

View File

@ -59,6 +59,9 @@ extern "C" {
#define OGS_DIAM_S6A_ULR_INITIAL_ATTACH_IND (1 << 5)
#define OGS_DIAM_S6A_ULR_PS_LCS_SUPPORTED_BY_UE (1 << 6)
#define OGS_DIAM_S6A_CLR_S6A_S6D_INDICATOR (1)
#define OGS_DIAM_S6A_CLR_REATTACH_REQUIRED (1 << 1)
#define OGS_DIAM_S6A_UE_SRVCC_NOT_SUPPORTED (0)
#define OGS_DIAM_S6A_UE_SRVCC_SUPPORTED (1)
@ -76,9 +79,13 @@ extern struct dict_object *ogs_diam_s6a_cmd_ulr;
extern struct dict_object *ogs_diam_s6a_cmd_ula;
extern struct dict_object *ogs_diam_s6a_cmd_pur;
extern struct dict_object *ogs_diam_s6a_cmd_pua;
extern struct dict_object *ogs_diam_s6a_cmd_clr;
extern struct dict_object *ogs_diam_s6a_cmd_cla;
extern struct dict_object *ogs_diam_s6a_ulr_flags;
extern struct dict_object *ogs_diam_s6a_ula_flags;
extern struct dict_object *ogs_diam_s6a_clr_flags;
extern struct dict_object *ogs_diam_s6a_cancellation_type;
extern struct dict_object *ogs_diam_s6a_subscription_data;
extern struct dict_object *ogs_diam_s6a_req_eutran_auth_info;
extern struct dict_object *ogs_diam_s6a_number_of_requested_vectors;
@ -140,8 +147,15 @@ typedef struct ogs_diam_s6a_ula_message_s {
ogs_subscription_data_t subscription_data;
} ogs_diam_s6a_ula_message_t;
typedef struct ogs_diam_s6a_clr_message_s {
#define OGS_DIAM_S6A_CLR_FLAGS_S6A_S6D_INDICATOR (0)
#define OGS_DIAM_S6A_CLR_FLAGS_REATTACH_REQUIRED (1)
uint32_t clr_flags;
} ogs_diam_s6a_clr_message_t;
typedef struct ogs_diam_s6a_message_s {
#define OGS_DIAM_S6A_CMD_CODE_UPDATE_LOCATION 316
#define OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION 317
#define OGS_DIAM_S6A_CMD_CODE_AUTHENTICATION_INFORMATION 318
uint16_t cmd_code;
@ -157,6 +171,9 @@ 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;
} ogs_diam_s6a_message_t;

View File

@ -103,6 +103,7 @@ typedef struct ogs_gtp_xact_s {
#define OGS_GTP_DELETE_HANDLE_PDN_CONNECTIVITY_REQUEST 5
#define OGS_GTP_DELETE_UE_CONTEXT_REMOVE 6
#define OGS_GTP_DELETE_IN_PATH_SWITCH_REQUEST 7
#define OGS_GTP_DELETE_NO_ACTION 8
int delete_action;
#define OGS_GTP_RELEASE_SEND_UE_CONTEXT_RELEASE_COMMAND 1

View File

@ -437,6 +437,25 @@ ogs_pkbuf_t *emm_build_security_mode_command(mme_ue_t *mme_ue)
return nas_eps_security_encode(mme_ue, &message);
}
ogs_pkbuf_t *emm_build_detach_request(mme_ue_t *mme_ue)
{
ogs_nas_eps_message_t message;
ogs_assert(mme_ue);
memset(&message, 0, sizeof(message));
message.h.security_header_type =
OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED;
message.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.protocol_discriminator = OGS_NAS_PROTOCOL_DISCRIMINATOR_EMM;
message.emm.h.message_type = OGS_NAS_EPS_DETACH_REQUEST;
message.emm.detach_request_to_ue.detach_type.value = mme_ue->mme_to_ue_detach_type;
return nas_eps_security_encode(mme_ue, &message);
}
ogs_pkbuf_t *emm_build_detach_accept(mme_ue_t *mme_ue)
{
ogs_nas_eps_message_t message;

View File

@ -37,6 +37,7 @@ ogs_pkbuf_t *emm_build_security_mode_command(mme_ue_t *mme_ue);
ogs_pkbuf_t *emm_build_authentication_request(mme_ue_t *mme_ue);
ogs_pkbuf_t *emm_build_authentication_reject(void);
ogs_pkbuf_t *emm_build_detach_request(mme_ue_t *mme_ue);
ogs_pkbuf_t *emm_build_detach_accept(mme_ue_t *mme_ue);
ogs_pkbuf_t *emm_build_tau_accept(mme_ue_t *mme_ue);

View File

@ -129,6 +129,16 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e)
break;
}
if (mme_ue->mme_to_ue_detach_pending) {
ogs_assert(OGS_OK == nas_eps_send_detach_request(mme_ue));
mme_gtp_send_delete_all_sessions(mme_ue, OGS_GTP_DELETE_NO_ACTION);
if (MME_P_TMSI_IS_AVAILABLE(mme_ue)) {
ogs_assert(OGS_OK ==
sgsap_send_detach_indication(mme_ue));
}
break;
}
if (!MME_UE_HAVE_IMSI(mme_ue)) {
ogs_info("Service request : Unknown UE");
ogs_assert(OGS_OK ==
@ -539,6 +549,21 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e)
OGS_FSM_TRAN(s, &emm_state_de_registered);
break;
case OGS_NAS_EPS_DETACH_ACCEPT:
ogs_debug("Detach accept");
CLEAR_MME_UE_TIMER(mme_ue->t3422);
if (enb_ue) {
s1ap_send_ue_context_release_command(enb_ue,
S1AP_Cause_PR_nas, S1AP_CauseNas_detach,
S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0);
} else {
ogs_warn("[%s] No S1 Context", mme_ue->imsi_bcd);
}
OGS_FSM_TRAN(s, &emm_state_de_registered);
break;
case OGS_NAS_EPS_UPLINK_NAS_TRANSPORT:
ogs_debug("Uplink NAS Transport");
ogs_debug(" IMSI[%s]", mme_ue->imsi_bcd);
@ -627,6 +652,23 @@ static void common_register_state(ogs_fsm_t *s, mme_event_t *e)
}
break;
case MME_TIMER_T3422:
if (mme_ue->t3422.retry_count >=
mme_timer_cfg(MME_TIMER_T3422)->max_count) {
ogs_warn("Retransmission of Detach Request failed. "
"Stop retransmission");
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
} else {
rv = nas_eps_send_detach_request(mme_ue);
if (rv == OGS_OK) {
mme_ue->t3422.retry_count++;
} else {
ogs_error("nas_eps_send_detach_request() failed");
OGS_FSM_TRAN(&mme_ue->sm, &emm_state_exception);
}
}
break;
default:
ogs_error("Unknown timer[%s:%d]",
mme_timer_get_name(e->timer_id), e->timer_id);

View File

@ -321,6 +321,9 @@ struct mme_ue_s {
};
} nas_eps;
bool mme_to_ue_detach_pending;
uint8_t mme_to_ue_detach_type;
/* UE identity */
#define MME_UE_HAVE_IMSI(__mME) \
((__mME) && ((__mME)->imsi_len))

View File

@ -20,6 +20,9 @@
#include "mme-event.h"
#include "mme-fd-path.h"
/* handler for Cancel-Location-Request cb */
static struct disp_hdl *hdl_s6a_clr = NULL;
static struct session_handler *mme_s6a_reg = NULL;
struct sess_state {
@ -226,6 +229,7 @@ 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;
@ -634,6 +638,7 @@ 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;
@ -1403,10 +1408,129 @@ static void mme_s6a_ula_cb(void *data, struct msg **msg)
return;
}
/* Callback for incoming Cancel-Location-Request messages */
static int mme_ogs_diam_s6a_clr_cb( struct msg **msg, struct avp *avp,
struct session *session, void *opaque, enum disp_action *act)
{
int ret;
int error = 0;
mme_event_t *e = NULL;
mme_ue_t *mme_ue = NULL;
struct msg *ans, *qry;
ogs_diam_s6a_clr_message_t *clr_message = NULL;
struct avp_hdr *hdr;
union avp_value val;
char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
uint32_t result_code = 0;
ogs_assert(msg);
ogs_diam_s6a_message_t *s6a_message = NULL;
ogs_debug("Cancel-Location-Request");
s6a_message = ogs_calloc(1, sizeof(ogs_diam_s6a_message_t));
ogs_assert(s6a_message);
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;
ret = fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, 0);
ogs_assert(ret == 0);
ans = *msg;
ret = fd_msg_search_avp(qry, ogs_diam_user_name, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
ogs_cpystrn(imsi_bcd, (char*)hdr->avp_value->os.data,
ogs_min(hdr->avp_value->os.len, OGS_MAX_IMSI_BCD_LEN)+1);
mme_ue = mme_ue_find_by_imsi_bcd(imsi_bcd);
if (!mme_ue) {
ogs_error("Cancel Location for Unknown IMSI[%s]", imsi_bcd);
result_code = OGS_DIAM_S6A_ERROR_USER_UNKNOWN;
error++;
}
ret = fd_msg_search_avp(qry, ogs_diam_s6a_cancellation_type, &avp);
ogs_assert(ret == 0);
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
/* Set the Origin-Host, Origin-Realm, andResult-Code AVPs */
ret = fd_msg_rescode_set(ans, (char*)"DIAMETER_SUCCESS", NULL, NULL, 1);
ogs_assert(ret == 0);
/* Set the Auth-Session-State AVP */
ret = fd_msg_avp_new(ogs_diam_auth_session_state, 0, &avp);
ogs_assert(ret == 0);
val.i32 = OGS_DIAM_AUTH_SESSION_NO_STATE_MAINTAINED;
ret = fd_msg_avp_setvalue(avp, &val);
ogs_assert(ret == 0);
ret = fd_msg_avp_add(ans, MSG_BRW_LAST_CHILD, avp);
ogs_assert(ret == 0);
ret = fd_msg_search_avp(qry, ogs_diam_s6a_clr_flags, &avp);
ogs_assert(ret == 0);
if (avp) {
ret = fd_msg_avp_hdr(avp, &hdr);
ogs_assert(ret == 0);
clr_message->clr_flags = hdr->avp_value->i32;
}
/* Set Vendor-Specific-Application-Id AVP */
ret = ogs_diam_message_vendor_specific_appid_set(
ans, OGS_DIAM_S6A_APPLICATION_ID);
ogs_assert(ret == 0);
/* Send the answer */
ret = fd_msg_send(msg, NULL, NULL);
ogs_assert(ret == 0);
ogs_debug("Cancel-Location-Answer");
/* Add this value to the stats */
ogs_assert( pthread_mutex_lock(&ogs_diam_logger_self()->stats_lock) == 0);
ogs_diam_logger_self()->stats.nb_echoed++;
ogs_assert( pthread_mutex_unlock(&ogs_diam_logger_self()->stats_lock) == 0);
if (!error) {
int rv;
e = mme_event_new(MME_EVT_S6A_MESSAGE);
ogs_assert(e);
e->mme_ue = mme_ue;
e->s6a_message = s6a_message;
rv = ogs_queue_push(ogs_app()->queue, e);
if (rv != OGS_OK) {
ogs_error("ogs_queue_push() failed:%d", (int)rv);
ogs_free(s6a_message);
mme_event_free(e);
} else {
ogs_pollset_notify(ogs_app()->pollset);
}
} else {
ret = ogs_diam_message_experimental_rescode_set(ans, result_code);
ogs_assert(ret == 0);
}
return 0;
}
int mme_fd_init(void)
{
int ret;
struct disp_when data;
ret = ogs_diam_init(FD_MODE_CLIENT,
mme_self()->diam_conf_path, mme_self()->diam_config);
@ -1420,6 +1544,12 @@ int mme_fd_init(void)
ret = fd_sess_handler_create(&mme_s6a_reg, &state_cleanup, NULL, NULL);
ogs_assert(ret == 0);
/* Specific handler for Cancel-Location-Request */
data.command = ogs_diam_s6a_cmd_clr;
ret = fd_disp_register(mme_ogs_diam_s6a_clr_cb, DISP_HOW_CC, &data, NULL,
&hdl_s6a_clr);
ogs_assert(ret == 0);
/* Advertise the support for the application in the peer */
ret = fd_disp_app_support(ogs_diam_s6a_application, ogs_diam_vendor, 1, 0);
ogs_assert(ret == 0);
@ -1437,5 +1567,8 @@ void mme_fd_final(void)
ret = fd_sess_handler_destroy(&mme_s6a_reg, NULL);
ogs_assert(ret == OGS_OK);
if (hdl_s6a_clr)
(void) fd_disp_unregister(&hdl_s6a_clr, NULL);
ogs_diam_final();
}

View File

@ -636,6 +636,8 @@ void mme_s11_handle_delete_session_response(
return;
} else if (action == OGS_GTP_DELETE_NO_ACTION) {
} else {
ogs_fatal("Invalid action = %d", action);
ogs_assert_if_reached();

View File

@ -101,3 +101,27 @@ void mme_s6a_handle_ula(mme_ue_t *mme_ue,
mme_ue->num_of_session = i;
mme_ue->context_identifier = slice_data->context_identifier;
}
void mme_s6a_handle_clr(mme_ue_t *mme_ue,
ogs_diam_s6a_clr_message_t *clr_message)
{
ogs_assert(mme_ue);
ogs_assert(clr_message);
if (clr_message->clr_flags & OGS_DIAM_S6A_CLR_REATTACH_REQUIRED) {
mme_ue->mme_to_ue_detach_type = OGS_NAS_DETACH_TYPE_TO_UE_RE_ATTACH_REQUIRED;
} else {
mme_ue->mme_to_ue_detach_type = OGS_NAS_DETACH_TYPE_TO_UE_RE_ATTACH_NOT_REQUIRED;
}
if (OGS_FSM_CHECK(&mme_ue->sm, emm_state_de_registered)) {
// Remove all trace of subscriber even when detached.
mme_ue_hash_remove(mme_ue);
mme_ue_remove(mme_ue);
} else if (ECM_IDLE(mme_ue)) {
ogs_assert(OGS_OK == s1ap_send_paging(mme_ue, S1AP_CNDomain_ps));
mme_ue->mme_to_ue_detach_pending = true;
} else {
ogs_assert(OGS_OK == nas_eps_send_detach_request(mme_ue));
}
}

View File

@ -30,6 +30,8 @@ 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);
#ifdef __cplusplus
}

View File

@ -437,40 +437,42 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
s6a_message = e->s6a_message;
ogs_assert(s6a_message);
enb_ue = enb_ue_cycle(mme_ue->enb_ue);
if (!enb_ue) {
ogs_error("S1 context has already been removed");
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");
ogs_subscription_data_free(
&s6a_message->ula_message.subscription_data);
ogs_free(s6a_message);
break;
}
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);
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_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]",
mme_ue->imsi_bcd, emm_cause);
ogs_assert(OGS_OK ==
nas_eps_send_attach_reject(mme_ue,
emm_cause, OGS_NAS_ESM_CAUSE_PROTOCOL_ERROR_UNSPECIFIED));
ogs_info("[%s] Attach reject [OGS_NAS_EMM_CAUSE:%d]",
mme_ue->imsi_bcd, emm_cause);
ogs_assert(OGS_OK ==
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));
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));
ogs_subscription_data_free(
&s6a_message->ula_message.subscription_data);
ogs_free(s6a_message);
break;
ogs_subscription_data_free(
&s6a_message->ula_message.subscription_data);
ogs_free(s6a_message);
break;
}
}
switch (s6a_message->cmd_code) {
@ -504,6 +506,17 @@ void mme_state_operational(ogs_fsm_t *s, mme_event_t *e)
ogs_assert_if_reached();
}
break;
case OGS_DIAM_S6A_CMD_CODE_CANCEL_LOCATION:
mme_s6a_handle_clr(mme_ue, &s6a_message->clr_message);
if (SESSION_CONTEXT_IS_AVAILABLE(mme_ue) && !mme_ue->mme_to_ue_detach_pending) {
mme_gtp_send_delete_all_sessions(mme_ue, OGS_GTP_DELETE_NO_ACTION);
}
if (MME_P_TMSI_IS_AVAILABLE(mme_ue)) {
ogs_assert(OGS_OK ==
sgsap_send_detach_indication(mme_ue));
}
break;
default:
ogs_error("Invalid Type[%d]", s6a_message->cmd_code);
break;

View File

@ -256,6 +256,42 @@ int nas_eps_send_authentication_reject(mme_ue_t *mme_ue)
return rv;
}
int nas_eps_send_detach_request(mme_ue_t *mme_ue)
{
int rv;
enb_ue_t *enb_ue = NULL;
ogs_pkbuf_t *emmbuf = NULL;
ogs_assert(mme_ue);
enb_ue = enb_ue_cycle(mme_ue->enb_ue);
ogs_expect_or_return_val(enb_ue, OGS_ERROR);
ogs_debug("[%s] Detach request to UE", mme_ue->imsi_bcd);
if (mme_ue->t3422.pkbuf) {
emmbuf = mme_ue->t3422.pkbuf;
ogs_expect_or_return_val(emmbuf, OGS_ERROR);
} else {
emmbuf = emm_build_identity_request(mme_ue);
ogs_expect_or_return_val(emmbuf, OGS_ERROR);
}
mme_ue->t3422.pkbuf = ogs_pkbuf_copy(emmbuf);
ogs_expect_or_return_val(mme_ue->t3422.pkbuf, OGS_ERROR);
ogs_timer_start(mme_ue->t3422.timer,
mme_timer_cfg(MME_TIMER_T3422)->duration);
/* send detach request */
emmbuf = emm_build_detach_request(mme_ue);
ogs_expect_or_return_val(emmbuf, OGS_ERROR);
rv = nas_eps_send_to_downlink_nas_transport(mme_ue, emmbuf);
ogs_expect_or_return_val(rv == OGS_OK, rv);
return rv;
}
int nas_eps_send_detach_accept(mme_ue_t *mme_ue)
{
int rv;

View File

@ -43,6 +43,7 @@ int nas_eps_send_authentication_reject(mme_ue_t *mme_ue);
int nas_eps_send_security_mode_command(mme_ue_t *mme_ue);
int nas_eps_send_detach_request(mme_ue_t *mme_ue);
int nas_eps_send_detach_accept(mme_ue_t *mme_ue);
int nas_eps_send_pdn_connectivity_reject(

View File

@ -272,7 +272,9 @@ void sgsap_handle_detach_ack(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)
ogs_debug(" IMSI[%s]", mme_ue->imsi_bcd);
mme_send_delete_session_or_detach(mme_ue);
if (!mme_ue->mme_to_ue_detach_pending) {
mme_send_delete_session_or_detach(mme_ue);
}
}
void sgsap_handle_paging_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf)