diff --git a/src/amf/ngap-handler.c b/src/amf/ngap-handler.c index a22964a4c..152beaff7 100644 --- a/src/amf/ngap-handler.c +++ b/src/amf/ngap-handler.c @@ -1473,6 +1473,10 @@ void ngap_handle_pdu_session_resource_setup_response( NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; NGAP_PDUSessionResourceSetupListSURes_t *PDUSessionList = NULL; NGAP_PDUSessionResourceSetupItemSURes_t *PDUSessionItem = NULL; + NGAP_PDUSessionResourceFailedToSetupListSURes_t + *PDUSessionFailedList = NULL; + NGAP_PDUSessionResourceFailedToSetupItemSURes_t + *PDUSessionFailedItem = NULL; OCTET_STRING_t *transfer = NULL; ogs_assert(gnb); @@ -1501,6 +1505,10 @@ void ngap_handle_pdu_session_resource_setup_response( PDUSessionList = &ie->value.choice.PDUSessionResourceSetupListSURes; break; + case NGAP_ProtocolIE_ID_id_PDUSessionResourceFailedToSetupListSURes: + PDUSessionFailedList = + &ie->value.choice.PDUSessionResourceFailedToSetupListSURes; + break; default: break; } @@ -1553,78 +1561,202 @@ void ngap_handle_pdu_session_resource_setup_response( return; } - if (!PDUSessionList) { - ogs_error("No PDUSessionResourceSetupListSURes"); + if (PDUSessionList) { + for (i = 0; i < PDUSessionList->list.count; i++) { + amf_sess_t *sess = NULL; + PDUSessionItem = (NGAP_PDUSessionResourceSetupItemSURes_t *) + PDUSessionList->list.array[i]; + + if (!PDUSessionItem) { + ogs_error("No PDUSessionResourceSetupItemSURes"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + transfer = &PDUSessionItem->pDUSessionResourceSetupResponseTransfer; + if (!transfer) { + ogs_error("No PDUSessionResourceSetupResponseTransfer"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + if (PDUSessionItem->pDUSessionID == + OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED) { + ogs_error("PDU Session Identity is unassigned"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + sess = amf_sess_find_by_psi(amf_ue, PDUSessionItem->pDUSessionID); + if (!sess) { + ogs_error("Cannot find PDU Session ID [%d]", + (int)PDUSessionItem->pDUSessionID); + ogs_assert(OGS_OK == + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); + return; + } + + if (!SESSION_CONTEXT_IN_SMF(sess)) { + ogs_error("Session Context is not in SMF [%d]", + (int)PDUSessionItem->pDUSessionID); + ogs_assert(OGS_OK == + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); + return; + } + + memset(¶m, 0, sizeof(param)); + param.n2smbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_assert(param.n2smbuf); + param.n2SmInfoType = OpenAPI_n2_sm_info_type_PDU_RES_SETUP_RSP; + ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); + + ogs_assert(true == + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_ACTIVATED, ¶m, + amf_nsmf_pdusession_build_update_sm_context)); + + ogs_pkbuf_free(param.n2smbuf); + } + } else if (PDUSessionFailedList) { + for (i = 0; i < PDUSessionFailedList->list.count; i++) { + amf_sess_t *sess = NULL; + PDUSessionFailedItem = + (NGAP_PDUSessionResourceFailedToSetupItemSURes_t *) + PDUSessionFailedList->list.array[i]; + + if (!PDUSessionFailedItem) { + ogs_error("No PDUSessionResourceFailedToSetupItemSURes"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + transfer = + &PDUSessionFailedItem-> + pDUSessionResourceSetupUnsuccessfulTransfer; + if (!transfer) { + ogs_error("No PDUSessionResourceSetupUnsuccessfulTransfer"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + if (PDUSessionFailedItem->pDUSessionID == + OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED) { + ogs_error("PDU Session Identity is unassigned"); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error)); + return; + } + + sess = amf_sess_find_by_psi( + amf_ue, PDUSessionFailedItem->pDUSessionID); + if (!sess) { + ogs_error("Cannot find PDU Session ID [%d]", + (int)PDUSessionFailedItem->pDUSessionID); + ogs_assert(OGS_OK == + ngap_send_error_indication2( + amf_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); + return; + } + + if (!SESSION_CONTEXT_IN_SMF(sess)) { + ogs_error("Session Context is not in SMF [%d]", + (int)PDUSessionFailedItem->pDUSessionID); + ogs_assert(OGS_OK == + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); + return; + } + + /* + * TS23.502 + * 4.2.3 Service Request procedures + * 4.2.3.2 UE Triggered Service Request + * + * 15. ... + * If a PDU Session is rejected by the serving NG-RAN + * with an indication that the PDU Session was rejected + * because User Plane Security Enforcement is not supported + * in the serving NG-RAN and the User Plane Enforcement Policy + * indicates "Required" as described in clause 5.10.3 + * of TS 23.501 [2], the SMF shall trigger the release + * of this PDU Session. + * + * In all other cases of PDU Session rejection, + * the SMF can decide whether to release the PDU Session + * or to deactivate the UP connection of this PDU Session. + * + * + * TS29.502 + * + * 5.2.2.3.2 + * Activation and Deactivation of the User Plane connection + * of a PDU session + * 5.2.2.3.2.2 + * Activation of User Plane connectivity of a PDU session + * + * 3. ... + * N2 SM information received from the 5G-AN + * (see PDU Session Resource Setup Unsuccessful Transfer IE + * in clause 9.3.4.16 of 3GPP TS 38.413 [9]), + * including the Cause of the failure, if resources failed + * to be established for the PDU session. + * + * Upon receipt of this request, the SMF shall: + * - consider that the activation of the User Plane connection + * has failed and set the upCnxState attribute to DEACTIVATED" + * otherwise. + */ + memset(¶m, 0, sizeof(param)); + param.n2smbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + ogs_assert(param.n2smbuf); + param.n2SmInfoType = OpenAPI_n2_sm_info_type_PDU_RES_SETUP_FAIL; + ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); + + amf_ue->deactivation.group = NGAP_Cause_PR_nas; + amf_ue->deactivation.cause = NGAP_CauseNas_normal_release; + + ogs_assert(true == + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_SETUP_FAIL, ¶m, + amf_nsmf_pdusession_build_update_sm_context)); + + ogs_pkbuf_free(param.n2smbuf); + } + } else { + ogs_error("No PDUSessionResourceList"); ogs_assert(OGS_OK == ngap_send_error_indication2(amf_ue, NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error)); - return; - } - - for (i = 0; i < PDUSessionList->list.count; i++) { - amf_sess_t *sess = NULL; - PDUSessionItem = (NGAP_PDUSessionResourceSetupItemSURes_t *) - PDUSessionList->list.array[i]; - - if (!PDUSessionItem) { - ogs_error("No PDUSessionResourceSetupItemSURes"); - ogs_assert(OGS_OK == - ngap_send_error_indication2(amf_ue, - NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error)); - return; - } - - transfer = &PDUSessionItem->pDUSessionResourceSetupResponseTransfer; - if (!transfer) { - ogs_error("No PDUSessionResourceSetupResponseTransfer"); - ogs_assert(OGS_OK == - ngap_send_error_indication2(amf_ue, - NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error)); - return; - } - - if (PDUSessionItem->pDUSessionID == - OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED) { - ogs_error("PDU Session Identity is unassigned"); - ogs_assert(OGS_OK == - ngap_send_error_indication2(amf_ue, - NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error)); - return; - } - - sess = amf_sess_find_by_psi(amf_ue, PDUSessionItem->pDUSessionID); - if (!sess) { - ogs_error("Cannot find PDU Session ID [%d]", - (int)PDUSessionItem->pDUSessionID); - ogs_assert(OGS_OK == - ngap_send_error_indication2(amf_ue, - NGAP_Cause_PR_radioNetwork, - NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); - return; - } - - if (!SESSION_CONTEXT_IN_SMF(sess)) { - ogs_error("Session Context is not in SMF [%d]", - (int)PDUSessionItem->pDUSessionID); - ogs_assert(OGS_OK == - ngap_send_error_indication2(amf_ue, - NGAP_Cause_PR_radioNetwork, - NGAP_CauseRadioNetwork_unknown_PDU_session_ID)); - return; - } - - memset(¶m, 0, sizeof(param)); - param.n2smbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); - ogs_assert(param.n2smbuf); - param.n2SmInfoType = OpenAPI_n2_sm_info_type_PDU_RES_SETUP_RSP; - ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); - - ogs_assert(true == - amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, - sess, AMF_UPDATE_SM_CONTEXT_ACTIVATED, ¶m, - amf_nsmf_pdusession_build_update_sm_context)); - - ogs_pkbuf_free(param.n2smbuf); } } diff --git a/src/amf/nsmf-handler.c b/src/amf/nsmf-handler.c index 670f01a5d..466e79b8d 100644 --- a/src/amf/nsmf-handler.c +++ b/src/amf/nsmf-handler.c @@ -398,6 +398,61 @@ int amf_nsmf_pdusession_handle_update_sm_context( * 3. PFCP Session Modifcation Request (Apply: FORWARD) * 4. PFCP Session Modifcation Response */ + } else if (state == AMF_UPDATE_SM_CONTEXT_SETUP_FAIL) { + /* + * TS23.502 + * 4.2.3 Service Request procedures + * 4.2.3.2 UE Triggered Service Request + * + * 15. ... + * If a PDU Session is rejected by the serving NG-RAN + * with an indication that the PDU Session was rejected + * because User Plane Security Enforcement is not supported + * in the serving NG-RAN and the User Plane Enforcement Policy + * indicates "Required" as described in clause 5.10.3 + * of TS 23.501 [2], the SMF shall trigger the release + * of this PDU Session. + * + * In all other cases of PDU Session rejection, + * the SMF can decide whether to release the PDU Session + * or to deactivate the UP connection of this PDU Session. + * + * + * TS29.502 + * + * 5.2.2.3.2 + * Activation and Deactivation of the User Plane connection + * of a PDU session + * 5.2.2.3.2.2 + * Activation of User Plane connectivity of a PDU session + * + * 3. ... + * N2 SM information received from the 5G-AN + * (see PDU Session Resource Setup Unsuccessful Transfer IE + * in clause 9.3.4.16 of 3GPP TS 38.413 [9]), + * including the Cause of the failure, if resources failed + * to be established for the PDU session. + * + * Upon receipt of this request, the SMF shall: + * - consider that the activation of the User Plane connection + * has failed and set the upCnxState attribute to DEACTIVATED" + * otherwise. + * + * 1. PDUSessionResourceSetupResponse(Unsuccessful) + * 2. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 3. PFCP Session Modifcation Request (Apply:Buff & NOCP) + * 4. PFCP Session Modifcation Response + * 5. UEContextReleaseCommand + * 6. UEContextReleaseComplete + */ + ogs_warn("PDUSessionResourceSetupResponse(Unsuccessful)"); + ogs_assert(amf_ue->deactivation.group); + + ogs_assert(OGS_OK == + ngap_send_amf_ue_context_release_command(amf_ue, + amf_ue->deactivation.group, + amf_ue->deactivation.cause, + NGAP_UE_CTX_REL_NG_REMOVE_AND_UNLINK, 0)); } else if (state == AMF_UPDATE_SM_CONTEXT_MODIFIED) { /* diff --git a/src/amf/sbi-path.h b/src/amf/sbi-path.h index ba2c41396..a631f11f3 100644 --- a/src/amf/sbi-path.h +++ b/src/amf/sbi-path.h @@ -43,18 +43,19 @@ bool amf_ue_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, #define AMF_CREATE_SM_CONTEXT_NO_STATE 0 #define AMF_UPDATE_SM_CONTEXT_ACTIVATED 11 -#define AMF_UPDATE_SM_CONTEXT_DEACTIVATED 12 -#define AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST 13 -#define AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST 14 -#define AMF_UPDATE_SM_CONTEXT_MODIFIED 15 -#define AMF_UPDATE_SM_CONTEXT_N2_RELEASED 16 -#define AMF_UPDATE_SM_CONTEXT_N1_RELEASED 17 -#define AMF_UPDATE_SM_CONTEXT_DUPLICATED_PDU_SESSION_ID 18 -#define AMF_UPDATE_SM_CONTEXT_PATH_SWITCH_REQUEST 19 -#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED 20 -#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQ_ACK 21 -#define AMF_UPDATE_SM_CONTEXT_HANDOVER_NOTIFY 22 -#define AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL 23 +#define AMF_UPDATE_SM_CONTEXT_SETUP_FAIL 12 +#define AMF_UPDATE_SM_CONTEXT_DEACTIVATED 13 +#define AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST 14 +#define AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST 15 +#define AMF_UPDATE_SM_CONTEXT_MODIFIED 16 +#define AMF_UPDATE_SM_CONTEXT_N2_RELEASED 17 +#define AMF_UPDATE_SM_CONTEXT_N1_RELEASED 18 +#define AMF_UPDATE_SM_CONTEXT_DUPLICATED_PDU_SESSION_ID 19 +#define AMF_UPDATE_SM_CONTEXT_PATH_SWITCH_REQUEST 20 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED 21 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQ_ACK 22 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_NOTIFY 23 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL 24 #define AMF_RELEASE_SM_CONTEXT_NO_STATE 31 #define AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE 32 #define AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT 33 diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index d12e0655f..3a6a1a632 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -373,6 +373,16 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) } break; + case OpenAPI_n2_sm_info_type_PDU_RES_SETUP_FAIL: + rv = ngap_handle_pdu_session_resource_setup_unsuccessful_transfer( + sess, stream, pkbuf); + if (rv != OGS_OK) { + ogs_error("[%s:%d] Cannot handle NGAP message", + smf_ue->supi, sess->psi); + OGS_FSM_TRAN(s, smf_gsm_state_exception); + } + break; + case OpenAPI_n2_sm_info_type_PDU_RES_MOD_RSP: rv = ngap_handle_pdu_session_resource_modify_response_transfer( sess, stream, pkbuf); diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index 369ea9975..e9ad851ec 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -155,6 +155,102 @@ cleanup: return rv; } +int ngap_handle_pdu_session_resource_setup_unsuccessful_transfer( + smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) +{ + smf_ue_t *smf_ue = NULL; + int rv; + + NGAP_PDUSessionResourceSetupUnsuccessfulTransfer_t message; + NGAP_Cause_t *Cause = NULL; + + ogs_assert(pkbuf); + ogs_assert(stream); + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + ogs_debug("PDUSessionResourceSetupUnsuccessfulTransfer"); + + rv = ogs_asn_decode( + &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, + &message, sizeof(message), pkbuf); + if (rv != OGS_OK) { + ogs_error("[%s:%d] Cannot decode NGAP message", + smf_ue->supi, sess->psi); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "No N2 SM Info Type", smf_ue->supi, NULL, NULL); + goto cleanup; + } + + rv = OGS_ERROR; + + Cause = &message.cause; + + if (Cause->present == NGAP_Cause_PR_radioNetwork && + Cause->choice.radioNetwork == + NGAP_CauseRadioNetwork_multiple_PDU_session_ID_instances) { + ogs_warn(" Cause[Group:%d Cause:%d]", + Cause->present, (int)Cause->choice.radioNetwork); + } else { + ogs_error(" Cause[Group:%d Cause:%d]", + Cause->present, (int)Cause->choice.radioNetwork); + } + + /* + * TS23.502 + * 4.2.3 Service Request procedures + * 4.2.3.2 UE Triggered Service Request + * + * 15. ... + * If a PDU Session is rejected by the serving NG-RAN + * with an indication that the PDU Session was rejected + * because User Plane Security Enforcement is not supported + * in the serving NG-RAN and the User Plane Enforcement Policy + * indicates "Required" as described in clause 5.10.3 + * of TS 23.501 [2], the SMF shall trigger the release + * of this PDU Session. + * + * In all other cases of PDU Session rejection, + * the SMF can decide whether to release the PDU Session + * or to deactivate the UP connection of this PDU Session. + * + * + * TS29.502 + * + * 5.2.2.3.2 + * Activation and Deactivation of the User Plane connection + * of a PDU session + * 5.2.2.3.2.2 + * Activation of User Plane connectivity of a PDU session + * + * 3. ... + * N2 SM information received from the 5G-AN + * (see PDU Session Resource Setup Unsuccessful Transfer IE + * in clause 9.3.4.16 of 3GPP TS 38.413 [9]), + * including the Cause of the failure, if resources failed + * to be established for the PDU session. + * + * Upon receipt of this request, the SMF shall: + * - consider that the activation of the User Plane connection + * has failed and set the upCnxState attribute to DEACTIVATED" + * otherwise. + */ + + ogs_assert(OGS_OK == + smf_5gc_pfcp_send_session_modification_request( + sess, stream, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0)); + + rv = OGS_OK; +cleanup: + ogs_asn_free( + &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &message); + return rv; +} + int ngap_handle_pdu_session_resource_modify_response_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) { diff --git a/src/smf/ngap-handler.h b/src/smf/ngap-handler.h index 20e1e1127..eaac174bf 100644 --- a/src/smf/ngap-handler.h +++ b/src/smf/ngap-handler.h @@ -28,6 +28,8 @@ extern "C" { int ngap_handle_pdu_session_resource_setup_response_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); +int ngap_handle_pdu_session_resource_setup_unsuccessful_transfer( + smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); int ngap_handle_pdu_session_resource_modify_response_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); int ngap_handle_path_switch_request_transfer( diff --git a/tests/common/ngap-build.c b/tests/common/ngap-build.c index e63ebe116..c592cdbd2 100644 --- a/tests/common/ngap-build.c +++ b/tests/common/ngap-build.c @@ -21,6 +21,8 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer( test_sess_t *sess); +static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_unsuccessful_trasfer( + test_sess_t *sess, NGAP_Cause_PR group, long cause); static ogs_pkbuf_t *testngap_build_qos_flow_resource_modify_response_trasfer( test_bearer_t *qos_flow); static ogs_pkbuf_t *testngap_build_qos_flow_resource_release_response_trasfer( @@ -1069,6 +1071,100 @@ ogs_pkbuf_t *testngap_sess_build_pdu_session_resource_setup_response( return ogs_ngap_encode(&pdu); } +ogs_pkbuf_t *testngap_sess_build_pdu_session_resource_failed_to_setup( + test_sess_t *sess, NGAP_Cause_PR group, long cause) +{ + int rv; + + test_ue_t *test_ue = NULL; + + ogs_pkbuf_t *n2smbuf = NULL; + ogs_pkbuf_t *ngapbuf = NULL; + + NGAP_NGAP_PDU_t pdu; + NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; + NGAP_PDUSessionResourceSetupResponse_t *PDUSessionResourceSetupResponse; + + NGAP_PDUSessionResourceSetupResponseIEs_t *ie = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_PDUSessionResourceFailedToSetupListSURes_t + *PDUSessionFailedList = NULL; + NGAP_PDUSessionResourceFailedToSetupItemSURes_t + *PDUSessionFailedItem = NULL; + OCTET_STRING_t *transfer = NULL; + + ogs_assert(sess); + test_ue = sess->test_ue; + ogs_assert(test_ue); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome = CALLOC(1, sizeof(NGAP_SuccessfulOutcome_t)); + + successfulOutcome = pdu.choice.successfulOutcome; + successfulOutcome->procedureCode = + NGAP_ProcedureCode_id_PDUSessionResourceSetup; + successfulOutcome->criticality = NGAP_Criticality_reject; + successfulOutcome->value.present = + NGAP_SuccessfulOutcome__value_PR_PDUSessionResourceSetupResponse; + + PDUSessionResourceSetupResponse = + &successfulOutcome->value.choice.PDUSessionResourceSetupResponse; + + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupResponseIEs_t)); + ASN_SEQUENCE_ADD(&PDUSessionResourceSetupResponse->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_PDUSessionResourceSetupResponseIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupResponseIEs_t)); + ASN_SEQUENCE_ADD(&PDUSessionResourceSetupResponse->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_PDUSessionResourceSetupResponseIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupResponseIEs_t)); + ASN_SEQUENCE_ADD(&PDUSessionResourceSetupResponse->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceFailedToSetupListSURes; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_PDUSessionResourceSetupResponseIEs__value_PR_PDUSessionResourceFailedToSetupListSURes; + + PDUSessionFailedList = + &ie->value.choice.PDUSessionResourceFailedToSetupListSURes; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + PDUSessionFailedItem = + CALLOC(1, sizeof(struct NGAP_PDUSessionResourceFailedToSetupItemSURes)); + ASN_SEQUENCE_ADD(&PDUSessionFailedList->list, PDUSessionFailedItem); + + PDUSessionFailedItem->pDUSessionID = sess->psi; + + n2smbuf = testngap_build_pdu_session_resource_setup_unsuccessful_trasfer( + sess, group, cause); + ogs_assert(n2smbuf); + transfer = + &PDUSessionFailedItem->pDUSessionResourceSetupUnsuccessfulTransfer; + + transfer->size = n2smbuf->len; + transfer->buf = CALLOC(transfer->size, sizeof(uint8_t)); + memcpy(transfer->buf, n2smbuf->data, transfer->size); + ogs_pkbuf_free(n2smbuf); + + return ogs_ngap_encode(&pdu); +} + ogs_pkbuf_t *testngap_build_qos_flow_resource_modify_response( test_bearer_t *qos_flow) { @@ -2260,6 +2356,27 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer( &asn_DEF_NGAP_PDUSessionResourceSetupResponseTransfer, &message); } +static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_unsuccessful_trasfer( + test_sess_t *sess, NGAP_Cause_PR group, long cause) +{ + int rv; + + ogs_assert(sess); + + NGAP_PDUSessionResourceSetupUnsuccessfulTransfer_t message; + NGAP_Cause_t *Cause = NULL; + + memset(&message, 0, sizeof(message)); + + Cause = &message.cause; + + Cause->present = group; + Cause->choice.radioNetwork = cause; + + return ogs_asn_encode( + &asn_DEF_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, &message); +} + static ogs_pkbuf_t *testngap_build_qos_flow_resource_modify_response_trasfer( test_bearer_t *qos_flow) { diff --git a/tests/common/ngap-build.h b/tests/common/ngap-build.h index 50f3fff4f..0b5efde9a 100644 --- a/tests/common/ngap-build.h +++ b/tests/common/ngap-build.h @@ -49,6 +49,8 @@ ogs_pkbuf_t *testngap_ue_build_pdu_session_resource_setup_response( test_ue_t *test_ue); ogs_pkbuf_t *testngap_sess_build_pdu_session_resource_setup_response( test_sess_t *sess); +ogs_pkbuf_t *testngap_sess_build_pdu_session_resource_failed_to_setup( + test_sess_t *sess, NGAP_Cause_PR group, long cause); ogs_pkbuf_t *testngap_build_qos_flow_resource_modify_response( test_bearer_t *qos_flow); ogs_pkbuf_t *testngap_build_qos_flow_resource_release_response( diff --git a/tests/registration/paging-test.c b/tests/registration/paging-test.c index a410b5420..a30e33371 100644 --- a/tests/registration/paging-test.c +++ b/tests/registration/paging-test.c @@ -585,6 +585,349 @@ static void cm_idle_paging_func(abts_case *tc, void *data) test_ue_remove(test_ue); } +static void cm_connected_paging_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + bson_t *doc = NULL; + + /* Setup Test UE & Session Context */ + memset(&mobile_identity_suci, 0, sizeof(mobile_identity_suci)); + + mobile_identity_suci.h.supi_format = OGS_NAS_5GS_SUPI_FORMAT_IMSI; + mobile_identity_suci.h.type = OGS_NAS_5GS_MOBILE_IDENTITY_SUCI; + mobile_identity_suci.routing_indicator1 = 0; + mobile_identity_suci.routing_indicator2 = 0xf; + mobile_identity_suci.routing_indicator3 = 0xf; + mobile_identity_suci.routing_indicator4 = 0xf; + mobile_identity_suci.protection_scheme_id = OGS_NAS_5GS_NULL_SCHEME; + mobile_identity_suci.home_network_pki_value = 0; + mobile_identity_suci.scheme_output[0] = 0; + mobile_identity_suci.scheme_output[1] = 0; + mobile_identity_suci.scheme_output[2] = 0x20; + mobile_identity_suci.scheme_output[3] = 0x31; + mobile_identity_suci.scheme_output[4] = 0x90; + + test_ue = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue); + + test_ue->nr_cgi.cell_id = 0x40001; + + test_ue->nas.registration.tsc = 0; + test_ue->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue->nas.registration.follow_on_request = 1; + test_ue->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + doc = test_db_new_simple(test_ue); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue, doc)); + + /* Send Registration request */ + gmmbuf = testgmm_build_registration_request(test_ue, NULL); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue->registration_request_param.gmm_capability = 1; + test_ue->registration_request_param.s1_ue_network_capability = 1; + test_ue->registration_request_param.requested_nssai = 1; + test_ue->registration_request_param.last_visited_registered_tai = 1; + test_ue->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, false, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + sess->pdu_session_establishment_param.ssc_mode = 1; + sess->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection + * + * Otherwise, the following case could occur: + * + * 1. PDUSessionResourceSetupResponse + * 2. UEContextReleaseRequest + * 3. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 4. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 5. PFCP Session Modifcation Request (Deactivated) + * 6. PFCP Session Modifcation Request (OuterHeaderCreation) + * 7. PFCP Session Modifcation Response + * 8. PFCP Session Modifcation Response + * + * As such, N3 status could be activated. + * + * To prevent this situation, we'll use ogs_msleep(100). + */ + ogs_msleep(100); + + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - Type: High priority access(5) + * - Uplink Data Status + * - PDU Session Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 1 << sess->psi; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_HIGH_PRIORITY_ACCESS, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_HIGH_PRIORITY_ACCESS, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x2000, test_ue->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send PDUSessionResourceSetupResponse(Unsuccessful) */ + sendbuf = testngap_sess_build_pdu_session_resource_failed_to_setup( + sess, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_multiple_PDU_session_ID_instances); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue)); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + static void cm_idle_error_indication_func(abts_case *tc, void *data) { int rv; @@ -2935,6 +3278,7 @@ abts_suite *test_paging(abts_suite *suite) suite = ADD_SUITE(suite) abts_run_test(suite, cm_idle_paging_func, NULL); + abts_run_test(suite, cm_connected_paging_func, NULL); abts_run_test(suite, cm_idle_error_indication_func, NULL); abts_run_test(suite, cm_connected_error_indication_func, NULL); abts_run_test(suite, vonr_qos_flow_test1_func, NULL);