[SMF] On sess. est. fail, don't reply to AMF twice on the same stream

This commit is contained in:
mitmitmitm 2023-07-10 09:29:17 +02:00 committed by Sukchan Lee
parent bae6444262
commit 9cef0f14e3
6 changed files with 186 additions and 86 deletions

View File

@ -545,74 +545,54 @@ void smf_gsm_state_wait_5gc_sm_policy_association(ogs_fsm_t *s, smf_event_t *e)
break;
CASE(OGS_SBI_SERVICE_NAME_NPCF_SMPOLICYCONTROL)
stream = e->h.sbi.data;
/*
* By here, SMF has already sent a response to AMF in
* smf_nudm_sdm_handle_get. Therefore, 'stream = e->h.sbi.data'
* should not be used here. Instead of sending additional error
* replies to AMF over 'stream', SMF should send a
* Namf_Communication_N1N2MessageTransfer request by transitioning
* into smf_gsm_state_5gc_n1_n2_reject. This is according to
*
* TS23.502
* 6.3.1.7 4.3.2.2 UE Requested PDU Session Establishment
* p100
* 11. ...
* If the PDU session establishment failed anywhere between step 5
* and step 11, then the Namf_Communication_N1N2MessageTransfer
* request shall include the N1 SM container with a PDU Session
* Establishment Reject message ...
*/
state = e->h.sbi.state;
SWITCH(sbi_message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_SM_POLICIES)
if (sbi_message->h.resource.component[1]) {
strerror = ogs_msprintf("[%s:%d] "
"Unknown resource name [%s]",
ogs_error("[%s:%d] Unknown resource name [%s]",
smf_ue->supi, sess->psi,
sbi_message->h.resource.component[1]);
ogs_assert(strerror);
ogs_error("%s", strerror);
if (stream)
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
sbi_message, strerror, NULL));
ogs_free(strerror);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
OGS_FSM_TRAN(s, smf_gsm_state_5gc_n1_n2_reject);
} else if (sbi_message->res_status !=
OGS_SBI_HTTP_STATUS_CREATED) {
ogs_error("[%s:%d] HTTP response error [%d]",
smf_ue->supi, sess->psi,
sbi_message->res_status);
OGS_FSM_TRAN(s, smf_gsm_state_5gc_n1_n2_reject);
} else if (smf_npcf_smpolicycontrol_handle_create(
sess, state, sbi_message) == true) {
OGS_FSM_TRAN(s,
&smf_gsm_state_wait_pfcp_establishment);
} else {
ogs_assert(stream);
if (sbi_message->res_status !=
OGS_SBI_HTTP_STATUS_CREATED) {
strerror = ogs_msprintf(
"[%s:%d] HTTP response error [%d]",
smf_ue->supi, sess->psi,
sbi_message->res_status);
ogs_assert(strerror);
ogs_error("%s", strerror);
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
sbi_message->res_status,
sbi_message, strerror, NULL));
ogs_free(strerror);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
break;
}
if (smf_npcf_smpolicycontrol_handle_create(
sess, stream, state, sbi_message) == true) {
OGS_FSM_TRAN(s,
&smf_gsm_state_wait_pfcp_establishment);
} else {
ogs_error(
"smf_npcf_smpolicycontrol_handle_create() failed");
OGS_FSM_TRAN(s, smf_gsm_state_exception);
}
ogs_error(
"smf_npcf_smpolicycontrol_handle_create() failed");
OGS_FSM_TRAN(s, smf_gsm_state_5gc_n1_n2_reject);
}
break;
DEFAULT
strerror = ogs_msprintf("[%s:%d] Invalid resource name [%s]",
ogs_error("[%s:%d] Invalid resource name [%s]",
smf_ue->supi, sess->psi,
sbi_message->h.resource.component[0]);
ogs_assert(strerror);
ogs_error("%s", strerror);
ogs_assert(true ==
ogs_sbi_server_send_error(stream,
OGS_SBI_HTTP_STATUS_BAD_REQUEST,
sbi_message, strerror, NULL));
ogs_free(strerror);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
OGS_FSM_TRAN(s, smf_gsm_state_5gc_n1_n2_reject);
END
break;
@ -714,8 +694,10 @@ void smf_gsm_state_wait_pfcp_establishment(ogs_fsm_t *s, smf_event_t *e)
pfcp_cause = smf_5gc_n4_handle_session_establishment_response(
sess, pfcp_xact,
&pfcp_message->pfcp_session_establishment_response);
if (pfcp_cause != OGS_PFCP_CAUSE_REQUEST_ACCEPTED)
if (pfcp_cause != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
OGS_FSM_TRAN(s, smf_gsm_state_5gc_n1_n2_reject);
return;
}
memset(&param, 0, sizeof(param));
param.state = SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT;
param.n1smbuf =
@ -1648,6 +1630,126 @@ void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e)
}
}
void smf_gsm_state_5gc_n1_n2_reject(ogs_fsm_t *s, smf_event_t *e)
{
smf_ue_t *smf_ue = NULL;
smf_sess_t *sess = NULL;
ogs_sbi_message_t *sbi_message = NULL;
ogs_assert(s);
ogs_assert(e);
smf_sm_debug(e);
sess = e->sess;
ogs_assert(sess);
switch (e->h.id) {
case OGS_FSM_ENTRY_SIG:
if (sess->policy_association_id) {
smf_npcf_smpolicycontrol_param_t param;
int r = 0;
memset(&param, 0, sizeof(param));
param.ue_location = true;
param.ue_timezone = true;
r = smf_sbi_discover_and_send(
OGS_SBI_SERVICE_TYPE_NPCF_SMPOLICYCONTROL, NULL,
smf_npcf_smpolicycontrol_build_delete,
sess, NULL,
OGS_PFCP_DELETE_TRIGGER_AMF_UPDATE_SM_CONTEXT, &param);
ogs_expect(r == OGS_OK);
} else {
smf_namf_comm_send_n1_n2_pdu_establishment_reject(sess);
}
break;
case OGS_FSM_EXIT_SIG:
break;
case OGS_EVENT_SBI_CLIENT:
sbi_message = e->h.sbi.message;
ogs_assert(sbi_message);
sess = e->sess;
ogs_assert(sess);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
SWITCH(sbi_message->h.service.name)
CASE(OGS_SBI_SERVICE_NAME_NPCF_SMPOLICYCONTROL)
SWITCH(sbi_message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_SM_POLICIES)
if (!sbi_message->h.resource.component[1]) {
ogs_error("[%s:%d] HTTP response error [%d]",
smf_ue->supi, sess->psi,
sbi_message->res_status);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
break;
} else {
SWITCH(sbi_message->h.resource.component[2])
CASE(OGS_SBI_RESOURCE_NAME_DELETE)
if (sess->policy_association_id)
ogs_free(sess->policy_association_id);
sess->policy_association_id = NULL;
if (sbi_message->res_status !=
OGS_SBI_HTTP_STATUS_NO_CONTENT) {
ogs_error("[%s:%d] HTTP response error [%d]",
smf_ue->supi, sess->psi,
sbi_message->res_status);
/* In spite of error from PCF, continue with
session teardown, so as to not leave stale
sessions. */
}
smf_namf_comm_send_n1_n2_pdu_establishment_reject(sess);
break;
DEFAULT
ogs_error("[%s:%d] Unknown resource name [%s]",
smf_ue->supi, sess->psi,
sbi_message->h.resource.component[2]);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
END
}
break;
DEFAULT
ogs_error("[%s:%d] Invalid resource name [%s]",
smf_ue->supi, sess->psi,
sbi_message->h.resource.component[0]);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
END
break;
CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM)
SWITCH(sbi_message->h.resource.component[0])
CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS)
OGS_FSM_TRAN(s, smf_gsm_state_session_will_release);
break;
DEFAULT
ogs_error("[%s:%d] Invalid resource name [%s]",
smf_ue->supi, sess->psi,
sbi_message->h.resource.component[0]);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
END
break;
DEFAULT
ogs_error("[%s:%d] Invalid API name [%s]",
smf_ue->supi, sess->psi, sbi_message->h.service.name);
OGS_FSM_TRAN(s, smf_gsm_state_exception);
END
break;
default:
ogs_error("Unknown event [%s]", smf_event_get_name(e));
OGS_FSM_TRAN(s, smf_gsm_state_exception);
}
}
void smf_gsm_state_session_will_release(ogs_fsm_t *s, smf_event_t *e)
{
smf_sess_t *sess = NULL;

View File

@ -269,16 +269,13 @@ static void update_authorized_pcc_rule_and_qos(
}
bool smf_npcf_smpolicycontrol_handle_create(
smf_sess_t *sess, ogs_sbi_stream_t *stream, int state,
ogs_sbi_message_t *recvmsg)
smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg)
{
int rv;
char buf1[OGS_ADDRSTRLEN];
char buf2[OGS_ADDRSTRLEN];
char *strerror = NULL;
smf_ue_t *smf_ue = NULL;
smf_bearer_t *qos_flow = NULL;
ogs_pfcp_pdr_t *dl_pdr = NULL;
ogs_pfcp_pdr_t *ul_pdr = NULL;
@ -297,23 +294,20 @@ bool smf_npcf_smpolicycontrol_handle_create(
ogs_sbi_header_t header;
ogs_assert(sess);
ogs_assert(stream);
smf_ue = sess->smf_ue;
ogs_assert(smf_ue);
ogs_assert(recvmsg);
if (!recvmsg->http.location) {
strerror = ogs_msprintf("[%s:%d] No http.location",
smf_ue->supi, sess->psi);
goto cleanup;
ogs_error("[%s:%d] No http.location", smf_ue->supi, sess->psi);
return false;
}
SmPolicyDecision = recvmsg->SmPolicyDecision;
if (!SmPolicyDecision) {
strerror = ogs_msprintf("[%s:%d] No SmPolicyDecision",
smf_ue->supi, sess->psi);
goto cleanup;
ogs_error("[%s:%d] No SmPolicyDecision", smf_ue->supi, sess->psi);
return false;
}
memset(&header, 0, sizeof(header));
@ -321,17 +315,17 @@ bool smf_npcf_smpolicycontrol_handle_create(
rv = ogs_sbi_parse_header(&message, &header);
if (rv != OGS_OK) {
strerror = ogs_msprintf("[%s:%d] Cannot parse http.location [%s]",
ogs_error("[%s:%d] Cannot parse http.location [%s]",
smf_ue->supi, sess->psi, recvmsg->http.location);
goto cleanup;
return false;
}
if (!message.h.resource.component[1]) {
strerror = ogs_msprintf("[%s:%d] No Assocication ID [%s]",
ogs_error("[%s:%d] No Assocication ID [%s]",
smf_ue->supi, sess->psi, recvmsg->http.location);
ogs_sbi_header_free(&header);
goto cleanup;
return false;
}
if (sess->policy_association_id)
@ -445,9 +439,8 @@ bool smf_npcf_smpolicycontrol_handle_create(
/* Check if selected UPF is associated with SMF */
ogs_assert(sess->pfcp_node);
if (!OGS_FSM_CHECK(&sess->pfcp_node->sm, smf_pfcp_state_associated)) {
strerror = ogs_msprintf("[%s:%d] No associated UPF",
smf_ue->supi, sess->psi);
goto cleanup;
ogs_error("[%s:%d] No associated UPF", smf_ue->supi, sess->psi);
return false;
}
/* Remove all previous QoS flow */
@ -651,17 +644,6 @@ bool smf_npcf_smpolicycontrol_handle_create(
smf_5gc_pfcp_send_session_establishment_request(sess, 0));
return true;
cleanup:
ogs_assert(strerror);
ogs_error("%s", strerror);
ogs_assert(true ==
ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST,
recvmsg, strerror, NULL));
ogs_free(strerror);
return false;
}
bool smf_npcf_smpolicycontrol_handle_update_notify(

View File

@ -27,8 +27,7 @@ extern "C" {
#include "context.h"
bool smf_npcf_smpolicycontrol_handle_create(
smf_sess_t *sess, ogs_sbi_stream_t *stream, int state,
ogs_sbi_message_t *recvmsg);
smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg);
bool smf_npcf_smpolicycontrol_handle_update_notify(
smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg);
bool smf_npcf_smpolicycontrol_handle_terminate_notify(

View File

@ -175,6 +175,20 @@ void smf_namf_comm_send_n1_n2_message_transfer(
}
}
void smf_namf_comm_send_n1_n2_pdu_establishment_reject(
smf_sess_t *sess)
{
smf_n1_n2_message_transfer_param_t param;
memset(&param, 0, sizeof(param));
param.state = SMF_NETWORK_REQUESTED_PDU_SESSION_RELEASE;
param.n1smbuf = gsm_build_pdu_session_establishment_reject(sess,
OGS_5GSM_CAUSE_NETWORK_FAILURE);
ogs_assert(param.n1smbuf);
smf_namf_comm_send_n1_n2_message_transfer(sess, &param);
}
void smf_sbi_send_sm_context_create_error(
ogs_sbi_stream_t *stream,
int status, const char *title, const char *detail,

View File

@ -43,6 +43,8 @@ int smf_sbi_discover_and_send(
void smf_namf_comm_send_n1_n2_message_transfer(
smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param);
void smf_namf_comm_send_n1_n2_pdu_establishment_reject(
smf_sess_t *sess);
void smf_sbi_send_sm_context_create_error(
ogs_sbi_stream_t *stream,

View File

@ -40,6 +40,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_wait_pfcp_deletion(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_wait_epc_auth_release(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_wait_5gc_n1_n2_release(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_5gc_n1_n2_reject(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_session_will_release(ogs_fsm_t *s, smf_event_t *e);
void smf_gsm_state_exception(ogs_fsm_t *s, smf_event_t *e);