From 7b75746fe890b12c67b1c7d6417fe7c1efba41aa Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Mon, 14 Jul 2025 22:03:32 +0900 Subject: [PATCH] [HR] Support Xn/N2 handover for Home-Routed Roaming (Direct Forwarding only) (#2194) This commit adds Xn and N2 handover procedures to the Home-Routed Roaming code. Direct forwarding is now fully operational. Indirect forwarding for N2 handovers is not yet supported. To preserve the GTP-U header and extension header (even without QER) along the source gNB -> V-UPF -> target gNB path, future work will create PDRs without Outer Header Removal IE and FARs without Outer Header Creation IE and implement the necessary UPF logic. --- src/smf/context.c | 8 +- src/smf/gsm-sm.c | 54 ++++++++++ src/smf/n4-handler.c | 31 +++++- src/smf/ngap-build.c | 12 +-- src/smf/ngap-handler.c | 198 +++++++++++++++++++++++++---------- src/smf/nsmf-handler.c | 16 ++- src/smf/sbi-path.h | 8 +- tests/common/test-common.h | 15 +++ tests/handover/5gc-n2-test.c | 10 ++ tests/handover/5gc-xn-test.c | 4 + tests/vonr/af-test.c | 7 -- 11 files changed, 278 insertions(+), 85 deletions(-) diff --git a/src/smf/context.c b/src/smf/context.c index b1c805e01..6670dca1a 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -2328,11 +2328,11 @@ void smf_sess_create_indirect_data_forwarding(smf_sess_t *sess) far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; qer = qos_flow->qer; - ogs_assert(qer); + if (qer) { + ogs_pfcp_pdr_associate_qer(pdr, qer); - ogs_pfcp_pdr_associate_qer(pdr, qer); - - pdr->qfi = qos_flow->qfi; + pdr->qfi = qos_flow->qfi; + } ogs_assert(sess->pfcp_node); if (sess->pfcp_node->up_function_features.ftup) { diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index 017854c91..9922b3d17 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -1665,6 +1665,33 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) ogs_sbi_send_http_status_no_content( stream)); break; + case SMF_UPDATE_STATE_ACTIVATED_FROM_XN_HANDOVER: + ogs_pkbuf_t *n2smbuf = + ngap_build_path_switch_request_ack_transfer( + sess); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data_n2smbuf( + sess, stream, + OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, + n2smbuf); + break; + case SMF_UPDATE_STATE_ACTIVATED_FROM_N2_HANDOVER: + if (smf_sess_have_indirect_data_forwarding(sess) == + true) { + ogs_assert(OGS_OK == + smf_5gc_pfcp_send_all_pdr_modification_request( + sess, stream, + OGS_PFCP_MODIFY_INDIRECT| + OGS_PFCP_MODIFY_REMOVE, + 0, + ogs_local_conf()-> + time.handover.duration)); + } + + smf_sbi_send_sm_context_updated_data_ho_state( + sess, stream, OpenAPI_ho_state_COMPLETED); + break; case SMF_UPDATE_STATE_UE_REQ_MOD: if (sess->amf_to_vsmf_modify_stream_id >= OGS_MIN_POOL_ID && @@ -2727,6 +2754,33 @@ void smf_gsm_state_wait_pfcp_deletion(ogs_fsm_t *s, smf_event_t *e) ogs_sbi_send_http_status_no_content( stream)); break; + case SMF_UPDATE_STATE_ACTIVATED_FROM_XN_HANDOVER: + ogs_pkbuf_t *n2smbuf = + ngap_build_path_switch_request_ack_transfer( + sess); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data_n2smbuf( + sess, stream, + OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, + n2smbuf); + break; + case SMF_UPDATE_STATE_ACTIVATED_FROM_N2_HANDOVER: + if (smf_sess_have_indirect_data_forwarding(sess) == + true) { + ogs_assert(OGS_OK == + smf_5gc_pfcp_send_all_pdr_modification_request( + sess, stream, + OGS_PFCP_MODIFY_INDIRECT| + OGS_PFCP_MODIFY_REMOVE, + 0, + ogs_local_conf()-> + time.handover.duration)); + } + + smf_sbi_send_sm_context_updated_data_ho_state( + sess, stream, OpenAPI_ho_state_COMPLETED); + break; default: ogs_fatal("Unknown state [0x%x]", e->h.sbi.state); ogs_assert_if_reached(); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index d3d1a6f2d..e5818cb7f 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -409,7 +409,36 @@ void smf_5gc_n4_handle_session_modification_response( if (flags & OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING) { if (flags & OGS_PFCP_MODIFY_ACTIVATE) { - if (flags & OGS_PFCP_MODIFY_DL_ONLY) { + if ((flags & OGS_PFCP_MODIFY_XN_HANDOVER) || + (flags & OGS_PFCP_MODIFY_N2_HANDOVER)) { + sess->nsmf_param.request_indication = + OpenAPI_request_indication_UE_REQ_PDU_SES_MOD; + + sess->nsmf_param.up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED; + + sess->nsmf_param.serving_network = true; + + ogs_assert(OGS_OK == + ogs_sockaddr_to_ip( + sess->local_dl_addr, sess->local_dl_addr6, + &sess->nsmf_param.dl_ip)); + sess->nsmf_param.dl_teid = sess->local_dl_teid; + + sess->nsmf_param.an_type = sess->an_type; + sess->nsmf_param.rat_type = sess->sbi_rat_type; + + r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL, + smf_nsmf_pdusession_build_hsmf_update_data, + sess, stream, + flags & OGS_PFCP_MODIFY_XN_HANDOVER ? + SMF_UPDATE_STATE_ACTIVATED_FROM_XN_HANDOVER : + SMF_UPDATE_STATE_ACTIVATED_FROM_N2_HANDOVER, + NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + + } else if (flags & OGS_PFCP_MODIFY_DL_ONLY) { /* * UE-requested PDU Session Modification(ACTIVATED) * diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index 1776b8735..58dd8c726 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -307,12 +307,10 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( qos.arp.priority_level = qosFlowProfile->arp->priority_level; if (qosFlowProfile->arp->preempt_cap == OpenAPI_preemption_capability_NOT_PREEMPT) - qos.arp.pre_emption_capability = - OGS_5GC_PRE_EMPTION_DISABLED; + qos.arp.pre_emption_capability = OGS_5GC_PRE_EMPTION_DISABLED; else if (qosFlowProfile->arp->preempt_cap == OpenAPI_preemption_capability_MAY_PREEMPT) - qos.arp.pre_emption_capability = - OGS_5GC_PRE_EMPTION_ENABLED; + qos.arp.pre_emption_capability = OGS_5GC_PRE_EMPTION_ENABLED; else { ogs_error("Invalid preempt_cap [%d]", qosFlowProfile->arp->preempt_cap); @@ -321,12 +319,10 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_setup_request_transfer( if (qosFlowProfile->arp->preempt_vuln == OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE) - qos.arp.pre_emption_vulnerability = - OGS_5GC_PRE_EMPTION_DISABLED; + qos.arp.pre_emption_vulnerability = OGS_5GC_PRE_EMPTION_DISABLED; else if (qosFlowProfile->arp->preempt_vuln == OpenAPI_preemption_vulnerability_PREEMPTABLE) - qos.arp.pre_emption_vulnerability = - OGS_5GC_PRE_EMPTION_ENABLED; + qos.arp.pre_emption_vulnerability = OGS_5GC_PRE_EMPTION_ENABLED; else { ogs_error("Invalid preempt_vuln [%d]", qosFlowProfile->arp->preempt_vuln); diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index 284810b54..1e9c18ff5 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -163,7 +163,6 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( if (far_update) { uint64_t pfcp_flags = OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE; - if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { /* * UE-requested PDU Session Modification(ACTIVATED) * @@ -188,6 +187,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( * case SMF_UPDATE_STATE_HR_ACTIVATED_FROM_NON_ACTIVATING: * ogs_sbi_send_http_status_no_content */ + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { pfcp_flags |= OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING; pfcp_flags |= OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL; @@ -252,7 +252,7 @@ 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; + int r, rv; NGAP_PDUSessionResourceSetupUnsuccessfulTransfer_t message; NGAP_Cause_t *Cause = NULL; @@ -292,6 +292,40 @@ int ngap_handle_pdu_session_resource_setup_unsuccessful_transfer( Cause->present, (int)Cause->choice.radioNetwork); } + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + /* + * UE-requested PDU Session Modification(DEACTIVATED) + * + * For Home Routed Roaming, delegate PFCP deactivation to H-SMF by + * sending UP_CNX_STATE=DEACTIVATED via HsmfUpdateData. + * + * 1. V*: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD + * 2. V*: smf_nsmf_pdusession_build_hsmf_update_data + * SMF_UPDATE_STATE_HR_DEACTIVATED + * 3. H: smf_nsmf_handle_update_data_in_hsmf + * 4. H: OpenAPI_request_indication_UE_REQ_PDU_SES_MOD + * 5. H: OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING|OGS_PFCP_MODIFY_DL_ONLY| + * OGS_PFCP_MODIFY_DEACTIVATE + * 6. H: ogs_sbi_send_http_status_no_content + * 7. V: case SMF_UPDATE_STATE_HR_DEACTIVATED: + * 8. V: smf_sbi_send_sm_context_updated_data_up_cnx_state( + * OpenAPI_up_cnx_state_DEACTIVATED) + */ + sess->nsmf_param.request_indication = + OpenAPI_request_indication_UE_REQ_PDU_SES_MOD; + + sess->nsmf_param.up_cnx_state = OpenAPI_up_cnx_state_DEACTIVATED; + + sess->nsmf_param.ngap_cause.group = Cause->present; + sess->nsmf_param.ngap_cause.value = (int)Cause->choice.radioNetwork; + + r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL, + smf_nsmf_pdusession_build_hsmf_update_data, + sess, stream, SMF_UPDATE_STATE_DEACTIVATED, NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + } else { /* * TS23.502 * 4.2.3 Service Request procedures @@ -331,11 +365,11 @@ int ngap_handle_pdu_session_resource_setup_unsuccessful_transfer( * has failed and set the upCnxState attribute to DEACTIVATED" * otherwise. */ - - ogs_assert(OGS_OK == - smf_5gc_pfcp_send_all_pdr_modification_request( - sess, stream, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0, 0)); + ogs_assert(OGS_OK == + smf_5gc_pfcp_send_all_pdr_modification_request( + sess, stream, + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_DEACTIVATE, 0, 0)); + } rv = OGS_OK; cleanup: @@ -462,7 +496,8 @@ int ngap_handle_path_switch_request_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) { smf_ue_t *smf_ue = NULL; - int rv, i; + smf_bearer_t *qos_flow = NULL; + int r, rv, i; uint32_t remote_dl_teid; ogs_ip_t remote_dl_ip; @@ -540,52 +575,96 @@ int ngap_handle_path_switch_request_transfer( memcpy(&sess->remote_dl_ip, &remote_dl_ip, sizeof(sess->remote_dl_ip)); sess->remote_dl_teid = remote_dl_teid; - qosFlowAcceptedList = &message.qosFlowAcceptedList; - for (i = 0; i < qosFlowAcceptedList->list.count; i++) { - acceptedQosFlowItem = (NGAP_QosFlowAcceptedItem_t *) - qosFlowAcceptedList->list.array[i]; - if (acceptedQosFlowItem) { - smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi( - sess, acceptedQosFlowItem->qosFlowIdentifier); + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + ogs_list_for_each(&sess->bearer_list, qos_flow) { + ogs_pfcp_far_t *dl_far = qos_flow->dl_far; + ogs_assert(dl_far); + if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { + far_update = true; + } - if (qos_flow) { - ogs_pfcp_far_t *dl_far = qos_flow->dl_far; - ogs_assert(dl_far); - if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { - far_update = true; - } - - dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; - ogs_assert(OGS_OK == - ogs_pfcp_ip_to_outer_header_creation( + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_assert(OGS_OK == + ogs_pfcp_ip_to_outer_header_creation( &sess->remote_dl_ip, &dl_far->outer_header_creation, &dl_far->outer_header_creation_len)); - dl_far->outer_header_creation.teid = sess->remote_dl_teid; - } else { - ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi); - smf_sbi_send_sm_context_update_error_log( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - "No QoS flow", smf_ue->supi); - goto cleanup; + dl_far->outer_header_creation.teid = sess->remote_dl_teid; + } + } else { + qosFlowAcceptedList = &message.qosFlowAcceptedList; + for (i = 0; i < qosFlowAcceptedList->list.count; i++) { + acceptedQosFlowItem = (NGAP_QosFlowAcceptedItem_t *) + qosFlowAcceptedList->list.array[i]; + if (acceptedQosFlowItem) { + smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi( + sess, acceptedQosFlowItem->qosFlowIdentifier); + + if (qos_flow) { + ogs_pfcp_far_t *dl_far = qos_flow->dl_far; + ogs_assert(dl_far); + if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { + far_update = true; + } + + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_assert(OGS_OK == + ogs_pfcp_ip_to_outer_header_creation( + &sess->remote_dl_ip, + &dl_far->outer_header_creation, + &dl_far->outer_header_creation_len)); + dl_far->outer_header_creation.teid = sess->remote_dl_teid; + } } } } if (far_update) { + uint64_t pfcp_flags = + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE| + OGS_PFCP_MODIFY_XN_HANDOVER|OGS_PFCP_MODIFY_END_MARKER; + + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + pfcp_flags |= OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING; + pfcp_flags |= OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL; + } + ogs_assert(OGS_OK == smf_5gc_pfcp_send_all_pdr_modification_request( - sess, stream, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE| - OGS_PFCP_MODIFY_XN_HANDOVER|OGS_PFCP_MODIFY_END_MARKER, - 0, 0)); + sess, stream, pfcp_flags, 0, 0)); } else { - ogs_pkbuf_t *n2smbuf = - ngap_build_path_switch_request_ack_transfer(sess); - ogs_assert(n2smbuf); + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + sess->nsmf_param.request_indication = + OpenAPI_request_indication_UE_REQ_PDU_SES_MOD; - smf_sbi_send_sm_context_updated_data_n2smbuf(sess, stream, - OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, n2smbuf); + sess->nsmf_param.up_cnx_state = OpenAPI_up_cnx_state_ACTIVATED; + + sess->nsmf_param.serving_network = true; + + ogs_assert(OGS_OK == + ogs_sockaddr_to_ip( + sess->local_dl_addr, sess->local_dl_addr6, + &sess->nsmf_param.dl_ip)); + sess->nsmf_param.dl_teid = sess->local_dl_teid; + + sess->nsmf_param.an_type = sess->an_type; + sess->nsmf_param.rat_type = sess->sbi_rat_type; + + r = smf_sbi_discover_and_send( + OGS_SBI_SERVICE_TYPE_NSMF_PDUSESSION, NULL, + smf_nsmf_pdusession_build_hsmf_update_data, sess, stream, + SMF_UPDATE_STATE_ACTIVATED_FROM_XN_HANDOVER, + NULL); + ogs_expect(r == OGS_OK); + ogs_assert(r != OGS_ERROR); + } else { + ogs_pkbuf_t *n2smbuf = + ngap_build_path_switch_request_ack_transfer(sess); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data_n2smbuf(sess, stream, + OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, n2smbuf); + } } rv = OGS_OK; @@ -650,6 +729,7 @@ int ngap_handle_handover_request_ack( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) { smf_ue_t *smf_ue = NULL; + smf_bearer_t *qos_flow = NULL; int rv, i; NGAP_HandoverRequestAcknowledgeTransfer_t message; @@ -715,26 +795,28 @@ int ngap_handle_handover_request_ack( ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, &sess->handover.remote_dl_teid); - qosFlowSetupResponseList = &message.qosFlowSetupResponseList; - for (i = 0; i < qosFlowSetupResponseList->list.count; i++) { - qosFlowSetupResponseItem = (NGAP_QosFlowItemWithDataForwarding_t *) - qosFlowSetupResponseList->list.array[i]; - if (qosFlowSetupResponseItem) { - smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi( - sess, qosFlowSetupResponseItem->qosFlowIdentifier); + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + ogs_list_for_each(&sess->bearer_list, qos_flow) { + ogs_pfcp_far_t *dl_far = qos_flow->dl_far; + ogs_assert(dl_far); - if (qos_flow) { - ogs_pfcp_far_t *dl_far = qos_flow->dl_far; - ogs_assert(dl_far); + dl_far->handover.prepared = true; + } + } else { + qosFlowSetupResponseList = &message.qosFlowSetupResponseList; + for (i = 0; i < qosFlowSetupResponseList->list.count; i++) { + qosFlowSetupResponseItem = (NGAP_QosFlowItemWithDataForwarding_t *) + qosFlowSetupResponseList->list.array[i]; + if (qosFlowSetupResponseItem) { + smf_bearer_t *qos_flow = smf_qos_flow_find_by_qfi( + sess, qosFlowSetupResponseItem->qosFlowIdentifier); - dl_far->handover.prepared = true; + if (qos_flow) { + ogs_pfcp_far_t *dl_far = qos_flow->dl_far; + ogs_assert(dl_far); - } else { - ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi); - smf_sbi_send_sm_context_update_error_log( - stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - "No QoS flow", smf_ue->supi); - goto cleanup; + dl_far->handover.prepared = true; + } } } } diff --git a/src/smf/nsmf-handler.c b/src/smf/nsmf-handler.c index 450e496e3..d17a9260f 100644 --- a/src/smf/nsmf-handler.c +++ b/src/smf/nsmf-handler.c @@ -854,7 +854,7 @@ bool smf_nsmf_handle_update_sm_context( OpenAPI_request_indication_UE_REQ_PDU_SES_MOD; sess->nsmf_param.up_cnx_state = - SmContextUpdateData->up_cnx_state; + OpenAPI_up_cnx_state_DEACTIVATED; if (SmContextUpdateData->ue_location) sess->nsmf_param.ue_location = true; @@ -1030,12 +1030,18 @@ bool smf_nsmf_handle_update_sm_context( } if (far_update) { + uint64_t pfcp_flags = + OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE| + OGS_PFCP_MODIFY_N2_HANDOVER|OGS_PFCP_MODIFY_END_MARKER; + + if (HOME_ROUTED_ROAMING_IN_VSMF(sess)) { + pfcp_flags |= OGS_PFCP_MODIFY_HOME_ROUTED_ROAMING; + pfcp_flags |= OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL; + } + ogs_assert(OGS_OK == smf_5gc_pfcp_send_all_pdr_modification_request( - sess, stream, - OGS_PFCP_MODIFY_DL_ONLY|OGS_PFCP_MODIFY_ACTIVATE| - OGS_PFCP_MODIFY_N2_HANDOVER|OGS_PFCP_MODIFY_END_MARKER, - 0, 0)); + sess, stream, pfcp_flags, 0, 0)); } else { char *strerror = ogs_msprintf( "[%s:%d] No FAR Update", smf_ue->supi, sess->psi); diff --git a/src/smf/sbi-path.h b/src/smf/sbi-path.h index cebcf3c80..ac7596dfb 100644 --- a/src/smf/sbi-path.h +++ b/src/smf/sbi-path.h @@ -66,10 +66,14 @@ bool smf_sbi_send_request( (SMF_UPDATE_STATE_BASE + 0x02U) /* 0x02 */ #define SMF_UPDATE_STATE_ACTIVATED_FROM_NON_ACTIVATING \ (SMF_UPDATE_STATE_BASE + 0x03U) /* 0x03 */ -#define SMF_UPDATE_STATE_DEACTIVATED \ +#define SMF_UPDATE_STATE_ACTIVATED_FROM_XN_HANDOVER \ (SMF_UPDATE_STATE_BASE + 0x04U) /* 0x04 */ -#define SMF_UPDATE_STATE_UE_REQ_MOD \ +#define SMF_UPDATE_STATE_ACTIVATED_FROM_N2_HANDOVER \ (SMF_UPDATE_STATE_BASE + 0x05U) /* 0x05 */ +#define SMF_UPDATE_STATE_DEACTIVATED \ + (SMF_UPDATE_STATE_BASE + 0x06U) /* 0x06 */ +#define SMF_UPDATE_STATE_UE_REQ_MOD \ + (SMF_UPDATE_STATE_BASE + 0x07U) /* 0x07 */ /* Base offset for SMF_REMOVE states */ #define SMF_REMOVE_STATE_BASE 0x30U /* REMOVE at 0x30 */ diff --git a/tests/common/test-common.h b/tests/common/test-common.h index 8b87b5462..488872d37 100644 --- a/tests/common/test-common.h +++ b/tests/common/test-common.h @@ -77,6 +77,21 @@ extern "C" { #define SEND_UE_CONTEXT_RELEASE_COMMAND_IN_INTEGRITY_UNPROTECTED 0 #define SEND_UE_CONTEXT_RELEASE_COMMAND_IN_INTEGRITY_PROTECTED 1 +/* + * [VONR] + * Disable vonr/test8_func when running Home Routed Roaming tests, + * to prevent V-SMF from skipping Update Response (step 14) + * and avoid subsequent SBI timeout and PFCP No Context errors. + * + * [HANDOVER]] + * Normally, with 2 QoS Flows, the system waits for 2 End Markers. + * However, in Home Routed Roaming, the V-SMF uses only a single QoS Flow + * even when multiple QoS Flows are present. + * Therefore, only one End Marker should be awaited. + */ + +#define HOME_ROUTED_ROAMING_TEST 0 + #undef OGS_TEST_INSIDE #ifdef __cplusplus diff --git a/tests/handover/5gc-n2-test.c b/tests/handover/5gc-n2-test.c index 3652666bc..02a1e0c1b 100644 --- a/tests/handover/5gc-n2-test.c +++ b/tests/handover/5gc-n2-test.c @@ -849,10 +849,12 @@ static void direct_complete_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu1); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive UEContextReleaseCommand */ amf_ue_ngap_id = test_ue->amf_ue_ngap_id; @@ -966,10 +968,12 @@ static void direct_complete_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu2); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive UEContextReleaseCommand */ amf_ue_ngap_id = test_ue->amf_ue_ngap_id; @@ -1881,10 +1885,12 @@ static void indirect_complete_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu1); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive UEContextReleaseCommand */ amf_ue_ngap_id = test_ue->amf_ue_ngap_id; @@ -2029,10 +2035,12 @@ static void indirect_complete_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu2); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive UEContextReleaseCommand */ amf_ue_ngap_id = test_ue->amf_ue_ngap_id; @@ -2534,10 +2542,12 @@ static void indirect_cancel_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu1); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive UEContextReleaseCommand */ amf_ue_ngap_id = test_ue->amf_ue_ngap_id; diff --git a/tests/handover/5gc-xn-test.c b/tests/handover/5gc-xn-test.c index d8299056b..8c54e8218 100644 --- a/tests/handover/5gc-xn-test.c +++ b/tests/handover/5gc-xn-test.c @@ -318,10 +318,12 @@ static void test_two_qos_flows(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu1); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive Path Switch Ack */ recvbuf = testgnb_ngap_read(ngap2); @@ -365,10 +367,12 @@ static void test_two_qos_flows(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#if !HOME_ROUTED_ROAMING_TEST /* Receive End Mark */ recvbuf = test_gtpu_read(gtpu2); ABTS_PTR_NOTNULL(tc, recvbuf); ogs_pkbuf_free(recvbuf); +#endif /* Receive Path Switch Ack */ recvbuf = testgnb_ngap_read(ngap1); diff --git a/tests/vonr/af-test.c b/tests/vonr/af-test.c index 306bb2751..1bc04e66b 100644 --- a/tests/vonr/af-test.c +++ b/tests/vonr/af-test.c @@ -3966,13 +3966,6 @@ static void test7_func(abts_case *tc, void *data) test_ue_remove(test_ue); } -/* - * Disable test8_func when running Home Routed Roaming tests, - * to prevent V-SMF from skipping Update Response (step 14) - * and avoid subsequent SBI timeout and PFCP No Context errors. - */ -#define HOME_ROUTED_ROAMING_TEST 0 - #if !HOME_ROUTED_ROAMING_TEST /** * test8_func: