diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index 63b8aee47..2fe32f80e 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -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(¶m, 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(¶m, 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, ¶m); + 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; diff --git a/src/smf/npcf-handler.c b/src/smf/npcf-handler.c index ad7a84b7c..5c5f5ba88 100644 --- a/src/smf/npcf-handler.c +++ b/src/smf/npcf-handler.c @@ -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( diff --git a/src/smf/npcf-handler.h b/src/smf/npcf-handler.h index d9426ebee..260e97dff 100644 --- a/src/smf/npcf-handler.h +++ b/src/smf/npcf-handler.h @@ -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( diff --git a/src/smf/sbi-path.c b/src/smf/sbi-path.c index 9dc92af80..09b82cfe7 100644 --- a/src/smf/sbi-path.c +++ b/src/smf/sbi-path.c @@ -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(¶m, 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, ¶m); +} + void smf_sbi_send_sm_context_create_error( ogs_sbi_stream_t *stream, int status, const char *title, const char *detail, diff --git a/src/smf/sbi-path.h b/src/smf/sbi-path.h index 69515ba9c..8be5920e9 100644 --- a/src/smf/sbi-path.h +++ b/src/smf/sbi-path.h @@ -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, diff --git a/src/smf/smf-sm.h b/src/smf/smf-sm.h index caedd356c..8ccb330b2 100644 --- a/src/smf/smf-sm.h +++ b/src/smf/smf-sm.h @@ -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);