diff --git a/lib/pfcp/context.h b/lib/pfcp/context.h index 822a6baac..9d72954bd 100644 --- a/lib/pfcp/context.h +++ b/lib/pfcp/context.h @@ -183,6 +183,10 @@ typedef struct ogs_pfcp_far_s { uint32_t num_of_buffered_packet; ogs_pkbuf_t *buffered_packet[OGS_MAX_NUM_OF_PACKET_BUFFER]; + struct { + bool prepared; + } handover; /* Saved from N2-Handover Request Acknowledge */ + /* Related Context */ ogs_pfcp_sess_t *sess; void *gnode; diff --git a/lib/pfcp/xact.h b/lib/pfcp/xact.h index 03ce79bc7..46cab19fe 100644 --- a/lib/pfcp/xact.h +++ b/lib/pfcp/xact.h @@ -80,7 +80,8 @@ typedef struct ogs_pfcp_xact_s { #define OGS_PFCP_MODIFY_DEACTIVATE ((uint64_t)1<<9) #define OGS_PFCP_MODIFY_END_MARKER ((uint64_t)1<<10) #define OGS_PFCP_MODIFY_ERROR_INDICATION ((uint64_t)1<<11) -#define OGS_PFCP_MODIFY_PATH_SWITCH ((uint64_t)1<<12) +#define OGS_PFCP_MODIFY_XN_HANDOVER ((uint64_t)1<<12) +#define OGS_PFCP_MODIFY_N2_HANDOVER ((uint64_t)1<<13) uint64_t modify_flags; #define OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED 1 diff --git a/lib/sbi/context.h b/lib/sbi/context.h index a185e8a6b..7cd5ce854 100644 --- a/lib/sbi/context.h +++ b/lib/sbi/context.h @@ -136,7 +136,7 @@ typedef struct ogs_sbi_xact_s { ogs_timer_t *t_response; ogs_sbi_stream_t *assoc_stream; - uint8_t state; + int state; ogs_sbi_object_t *sbi_object; } ogs_sbi_xact_t; diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index c994c24af..1ef0fdc0b 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -418,7 +418,7 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) SWITCH(sbi_message.h.resource.component[2]) CASE(OGS_SBI_RESOURCE_NAME_MODIFY) - amf_nsmf_pdu_session_handle_update_sm_context( + amf_nsmf_pdusession_handle_update_sm_context( sess, state, &sbi_message); break; @@ -432,11 +432,11 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) amf_ue->supi, sbi_message.res_status); } - amf_nsmf_pdu_session_handle_release_sm_context(sess, state); + amf_nsmf_pdusession_handle_release_sm_context(sess, state); break; DEFAULT - amf_nsmf_pdu_session_handle_create_sm_context( + amf_nsmf_pdusession_handle_create_sm_context( sess, &sbi_message); END break; diff --git a/src/amf/context.c b/src/amf/context.c index b36d73cb0..f5dbe61ee 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -975,6 +975,10 @@ ran_ue_t *ran_ue_add(amf_gnb_t *gnb, uint32_t ran_ue_ngap_id) ran_ue->gnb_ostream_id = OGS_NEXT_ID(gnb->ostream_id, 1, gnb->max_num_of_ostreams-1); + ran_ue->t_ng_holding = ogs_timer_add( + ogs_app()->timer_mgr, amf_timer_ng_holding_timer_expire, ran_ue); + ogs_assert(ran_ue->t_ng_holding); + ran_ue->gnb = gnb; ogs_list_add(&gnb->ran_ue_list, ran_ue); @@ -991,8 +995,8 @@ void ran_ue_remove(ran_ue_t *ran_ue) ogs_list_remove(&ran_ue->gnb->ran_ue_list, ran_ue); - if (ran_ue->t_ng_holding) - ogs_timer_delete(ran_ue->t_ng_holding); + ogs_assert(ran_ue->t_ng_holding); + ogs_timer_delete(ran_ue->t_ng_holding); ogs_pool_free(&ran_ue_pool, ran_ue); @@ -1177,7 +1181,7 @@ void amf_ue_remove(amf_ue_t *amf_ue) OGS_ASN_CLEAR_DATA(&amf_ue->ueRadioCapability); /* Clear Transparent Container */ - OGS_ASN_CLEAR_DATA(&amf_ue->container); + OGS_ASN_CLEAR_DATA(&amf_ue->handover.container); /* Clear Paging Info */ AMF_UE_CLEAR_PAGING_INFO(amf_ue); @@ -1523,17 +1527,10 @@ void amf_sess_remove(amf_sess_t *sess) if (sess->pdu_session_establishment_accept) ogs_pkbuf_free(sess->pdu_session_establishment_accept); - if (sess->transfer.pdu_session_resource_setup_request) - ogs_pkbuf_free(sess->transfer.pdu_session_resource_setup_request); - sess->transfer.pdu_session_resource_setup_request = NULL; - - if (sess->transfer.path_switch_request_ack) - ogs_pkbuf_free(sess->transfer.path_switch_request_ack); - sess->transfer.path_switch_request_ack = NULL; - - if (sess->transfer.pdu_session_resource_release_command) - ogs_pkbuf_free(sess->transfer.pdu_session_resource_release_command); - sess->transfer.pdu_session_resource_release_command = NULL; + AMF_SESS_CLEAR_N2_TRANSFER(sess, pdu_session_resource_setup_request); + AMF_SESS_CLEAR_N2_TRANSFER(sess, path_switch_request_ack); + AMF_SESS_CLEAR_N2_TRANSFER(sess, handover_request); + AMF_SESS_CLEAR_N2_TRANSFER(sess, handover_command); if (sess->paging.client) ogs_sbi_client_remove(sess->paging.client); diff --git a/src/amf/context.h b/src/amf/context.h index ff442d4c8..f12fa3ce2 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -162,7 +162,6 @@ struct ran_ue_s { bool initial_context_setup_request_sent; /* Handover Info */ - NGAP_HandoverType_t handover_type; ran_ue_t *source_ue; ran_ue_t *target_ue; @@ -184,7 +183,7 @@ struct ran_ue_s { #define NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE 1 #define NGAP_UE_CTX_REL_NG_REMOVE_AND_UNLINK 2 #define NGAP_UE_CTX_REL_UE_CONTEXT_REMOVE 3 -#define NGAP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4 +#define NGAP_UE_CTX_REL_NG_HANDOVER_COMPLETE 4 uint8_t ue_ctx_rel_action; /* Related Context */ @@ -387,8 +386,13 @@ struct amf_ue_s { /* UE Radio Capability */ OCTET_STRING_t ueRadioCapability; - /* NGAP Transparent Container */ - OCTET_STRING_t container; + /* Handover Info */ + struct { + NGAP_HandoverType_t type; + OCTET_STRING_t container; + NGAP_Cause_PR group; + long cause; + } handover; ogs_list_t sess_list; }; @@ -448,7 +452,8 @@ typedef struct amf_sess_s { struct { ogs_pkbuf_t *pdu_session_resource_setup_request; ogs_pkbuf_t *path_switch_request_ack; - ogs_pkbuf_t *pdu_session_resource_release_command; + ogs_pkbuf_t *handover_request; + ogs_pkbuf_t *handover_command; } transfer; #define AMF_SESS_STORE_N2_TRANSFER(__sESS, __n2Type, __n2Buf) \ do { \ @@ -463,14 +468,18 @@ typedef struct amf_sess_s { ogs_assert(sess->transfer.__n2Type); \ } while(0); +#define AMF_SESS_CLEAR_N2_TRANSFER(__sESS, __n2Type) \ + do { \ + if ((__sESS)->transfer.__n2Type) \ + ogs_pkbuf_free((__sESS)->transfer.__n2Type); \ + (__sESS)->transfer.__n2Type = NULL; \ + } while(0); + #define AMF_UE_CLEAR_N2_TRANSFER(__aMF, __n2Type) \ do { \ amf_sess_t *sess = NULL; \ ogs_list_for_each(&((__aMF)->sess_list), sess) { \ - if (sess->transfer.__n2Type) { \ - ogs_pkbuf_free(sess->transfer.__n2Type); \ - sess->transfer.__n2Type = NULL; \ - } \ + AMF_SESS_CLEAR_N2_TRANSFER(sess, __n2Type) \ } \ } while(0); diff --git a/src/amf/gmm-handler.c b/src/amf/gmm-handler.c index db58ebb10..ee9ab6b30 100644 --- a/src/amf/gmm-handler.c +++ b/src/amf/gmm-handler.c @@ -305,7 +305,8 @@ int gmm_handle_registration_update(amf_ue_t *amf_ue, ogs_list_for_each(&amf_ue->sess_list, sess) { if (psimask & (1 << sess->psi)) { if (SESSION_CONTEXT_IN_SMF(sess)) - amf_sbi_send_activating_session(sess); + amf_sbi_send_activating_session( + sess, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST); } } } @@ -473,7 +474,8 @@ int gmm_handle_service_update(amf_ue_t *amf_ue, ogs_list_for_each(&amf_ue->sess_list, sess) { if (psimask & (1 << sess->psi)) { if (SESSION_CONTEXT_IN_SMF(sess)) - amf_sbi_send_activating_session(sess); + amf_sbi_send_activating_session( + sess, AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST); } } } @@ -653,7 +655,7 @@ int gmm_handle_ul_nas_transport(amf_ue_t *amf_ue, ogs_nas_5gs_ul_nas_transport_t *ul_nas_transport) { amf_sess_t *sess = NULL; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; ogs_nas_payload_container_type_t *payload_container_type = NULL; ogs_nas_payload_container_t *payload_container = NULL; @@ -796,7 +798,7 @@ int gmm_handle_ul_nas_transport(amf_ue_t *amf_ue, amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_SESS_SM_CONTEXT_NO_STATE, NULL, - amf_nsmf_pdu_session_build_create_sm_context); + amf_nsmf_pdusession_build_create_sm_context); } else { @@ -819,7 +821,7 @@ int gmm_handle_ul_nas_transport(amf_ue_t *amf_ue, amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_UPDATE_SM_CONTEXT_N1_RELEASED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + amf_nsmf_pdusession_build_update_sm_context); if (gsm_header->message_type == OGS_NAS_5GS_PDU_SESSION_RELEASE_COMPLETE) { diff --git a/src/amf/namf-handler.c b/src/amf/namf-handler.c index 680068821..819177b62 100644 --- a/src/amf/namf-handler.c +++ b/src/amf/namf-handler.c @@ -464,7 +464,7 @@ int amf_namf_callback_handle_sm_context_status( sess->resource_status == OpenAPI_resource_status_RELEASED) { ogs_debug("[%s:%d] SM context remove", amf_ue->supi, sess->psi); - amf_nsmf_pdu_session_handle_release_sm_context( + amf_nsmf_pdusession_handle_release_sm_context( sess, AMF_SESS_SM_CONTEXT_NO_STATE); } diff --git a/src/amf/ngap-build.c b/src/amf/ngap-build.c index 4d5c5f3cf..af326196f 100644 --- a/src/amf/ngap-build.c +++ b/src/amf/ngap-build.c @@ -1616,6 +1616,7 @@ ogs_pkbuf_t *ngap_build_paging(amf_ue_t *amf_ue) NGAP_TAIListForPagingItem_t *TAIItem = NULL; NGAP_TAI_t *tAI = NULL; + ogs_assert(amf_ue); ogs_debug("Paging"); memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); @@ -1671,54 +1672,53 @@ ogs_pkbuf_t *ngap_build_paging(amf_ue_t *amf_ue) return ogs_ngap_encode(&pdu); } -#if 0 -ogs_pkbuf_t *ngap_build_amf_configuration_transfer( - NGAP_SONConfigurationTransfer_t *son_configuration_transfer) +ogs_pkbuf_t *ngap_build_downlink_ran_configuration_transfer( + NGAP_SONConfigurationTransfer_t *transfer) { int rv; NGAP_NGAP_PDU_t pdu; NGAP_InitiatingMessage_t *initiatingMessage = NULL; - NGAP_AMFConfigurationTransfer_t *AMFConfigurationTransfer = NULL; + NGAP_DownlinkRANConfigurationTransfer_t + *DownlinkRANConfigurationTransfer = NULL; - NGAP_AMFConfigurationTransferIEs_t *ie = NULL; + NGAP_DownlinkRANConfigurationTransferIEs_t *ie = NULL; NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer = NULL; - ogs_assert(son_configuration_transfer); - - ogs_debug("AMF Configuration Transfer"); + ogs_assert(transfer); + ogs_debug("DownlinkRANConfigurationTransfer"); memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + ogs_assert(pdu.choice.initiatingMessage); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = - NGAP_ProcedureCode_id_AMFConfigurationTransfer; + NGAP_ProcedureCode_id_DownlinkRANConfigurationTransfer; initiatingMessage->criticality = NGAP_Criticality_ignore; initiatingMessage->value.present = - NGAP_InitiatingMessage__value_PR_AMFConfigurationTransfer; + NGAP_InitiatingMessage__value_PR_DownlinkRANConfigurationTransfer; - AMFConfigurationTransfer = - &initiatingMessage->value.choice.AMFConfigurationTransfer; + DownlinkRANConfigurationTransfer = + &initiatingMessage->value.choice.DownlinkRANConfigurationTransfer; - ie = CALLOC(1, sizeof(NGAP_AMFConfigurationTransferIEs_t)); - ASN_SEQUENCE_ADD(&AMFConfigurationTransfer->protocolIEs, ie); + ie = CALLOC(1, sizeof(NGAP_DownlinkRANConfigurationTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&DownlinkRANConfigurationTransfer->protocolIEs, ie); - ie->id = NGAP_ProtocolIE_ID_id_SONConfigurationTransferMCT; + ie->id = NGAP_ProtocolIE_ID_id_SONConfigurationTransferDL; ie->criticality = NGAP_Criticality_ignore; - ie->value.present = - NGAP_AMFConfigurationTransferIEs__value_PR_SONConfigurationTransfer; + ie->value.present = NGAP_DownlinkRANConfigurationTransferIEs__value_PR_SONConfigurationTransfer; SONConfigurationTransfer = &ie->value.choice.SONConfigurationTransfer; rv = ogs_asn_copy_ie(&asn_DEF_NGAP_SONConfigurationTransfer, - son_configuration_transfer, SONConfigurationTransfer); + transfer, SONConfigurationTransfer); ogs_assert(rv == OGS_OK); return ogs_ngap_encode(&pdu); } -#endif ogs_pkbuf_t *ngap_build_path_switch_ack(amf_ue_t *amf_ue) { @@ -1880,262 +1880,12 @@ ogs_pkbuf_t *ngap_build_path_switch_ack(amf_ue_t *amf_ue) return ogs_ngap_encode(&pdu); } -#if 0 -ogs_pkbuf_t *ngap_build_handover_command(ran_ue_t *source_ue) +ogs_pkbuf_t *ngap_build_handover_request(ran_ue_t *target_ue) { - int rv; - - NGAP_NGAP_PDU_t pdu; - NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; - NGAP_HandoverCommand_t *HandoverCommand = NULL; - - NGAP_HandoverCommandIEs_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_HandoverType_t *HandoverType = NULL; - NGAP_E_RABSubjecttoDataForwardingList_t - *E_RABSubjecttoDataForwardingList = NULL; - NGAP_Target_ToSource_TransparentContainer_t - *Target_ToSource_TransparentContainer = NULL; + int i, j; amf_ue_t *amf_ue = NULL; amf_sess_t *sess = NULL; - amf_bearer_t *bearer = NULL; - - ogs_assert(source_ue); - amf_ue = source_ue->amf_ue; - - ogs_debug("Handover command"); - - 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_HandoverPreparation; - successfulOutcome->criticality = NGAP_Criticality_reject; - successfulOutcome->value.present = - NGAP_SuccessfulOutcome__value_PR_HandoverCommand; - - HandoverCommand = &successfulOutcome->value.choice.HandoverCommand; - ogs_assert(HandoverCommand); - - ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); - ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = NGAP_HandoverCommandIEs__value_PR_AMF_UE_NGAP_ID; - - AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; - - ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); - ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = NGAP_HandoverCommandIEs__value_PR_RAN_UE_NGAP_ID; - - RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; - - ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); - ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_HandoverType; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = NGAP_HandoverCommandIEs__value_PR_HandoverType; - - HandoverType = &ie->value.choice.HandoverType; - - *AMF_UE_NGAP_ID = source_ue->amf_ue_ngap_id; - *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; - *HandoverType = source_ue->handover_type; - - ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]", - source_ue->ran_ue_ngap_id, source_ue->amf_ue_ngap_id); - - sess = amf_sess_first(amf_ue); - while (sess) { - bearer = amf_bearer_first(sess); - while (bearer) { - NGAP_E_RABDataForwardingItem_t *e_rab = NULL; - - if (AMF_HAVE_SGW_DL_INDIRECT_TUNNEL(bearer) || - AMF_HAVE_SGW_UL_INDIRECT_TUNNEL(bearer)) { - NGAP_E_RABDataForwardingItemIEs_t *item = NULL; - - if (E_RABSubjecttoDataForwardingList == NULL) { - ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); - ogs_assert(ie); - ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - - ie->id = - NGAP_ProtocolIE_ID_id_E_RABSubjecttoDataForwardingList; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = - NGAP_HandoverCommandIEs__value_PR_E_RABSubjecttoDataForwardingList; - - E_RABSubjecttoDataForwardingList = - &ie->value.choice.E_RABSubjecttoDataForwardingList; - } - ogs_assert(E_RABSubjecttoDataForwardingList); - - item = CALLOC( - 1, sizeof(NGAP_E_RABDataForwardingItemIEs_t)); - ogs_assert(item); - ASN_SEQUENCE_ADD(&E_RABSubjecttoDataForwardingList->list, item); - - item->id = NGAP_ProtocolIE_ID_id_E_RABDataForwardingItem; - item->criticality = NGAP_Criticality_ignore; - item->value.present = - NGAP_E_RABDataForwardingItemIEs__value_PR_E_RABDataForwardingItem; - - e_rab = &item->value.choice.E_RABDataForwardingItem; - ogs_assert(e_rab); - - e_rab->e_RAB_ID = bearer->ebi; - } - - if (AMF_HAVE_SGW_DL_INDIRECT_TUNNEL(bearer)) { - ogs_assert(e_rab); - e_rab->dL_transportLayerAddress = - (NGAP_TransportLayerAddress_t *) - CALLOC(1, sizeof(NGAP_TransportLayerAddress_t)); - rv = ogs_asn_ip_to_BIT_STRING( - &bearer->sgw_dl_ip, e_rab->dL_transportLayerAddress); - ogs_assert(rv == OGS_OK); - - e_rab->dL_gTP_TEID = (NGAP_GTP_TEID_t *) - CALLOC(1, sizeof(NGAP_GTP_TEID_t)); - ogs_asn_uint32_to_OCTET_STRING( - bearer->sgw_dl_teid, e_rab->dL_gTP_TEID); - ogs_debug(" SGW-DL-TEID[%d]", bearer->sgw_dl_teid); - } - - if (AMF_HAVE_SGW_UL_INDIRECT_TUNNEL(bearer)) { - ogs_assert(e_rab); - e_rab->uL_TransportLayerAddress = - (NGAP_TransportLayerAddress_t *) - CALLOC(1, sizeof(NGAP_TransportLayerAddress_t)); - rv = ogs_asn_ip_to_BIT_STRING( - &bearer->sgw_ul_ip, e_rab->uL_TransportLayerAddress); - ogs_assert(rv == OGS_OK); - - e_rab->uL_GTP_TEID = (NGAP_GTP_TEID_t *) - CALLOC(1, sizeof(NGAP_GTP_TEID_t)); - ogs_asn_uint32_to_OCTET_STRING( - bearer->sgw_ul_teid, e_rab->uL_GTP_TEID); - ogs_debug(" SGW-UL-TEID[%d]", bearer->sgw_dl_teid); - } - - bearer = amf_bearer_next(bearer); - } - sess = amf_sess_next(sess); - } - - ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); - ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_Target_ToSource_TransparentContainer; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_HandoverCommandIEs__value_PR_Target_ToSource_TransparentContainer; - - Target_ToSource_TransparentContainer = - &ie->value.choice.Target_ToSource_TransparentContainer; - - ogs_asn_buffer_to_OCTET_STRING(amf_ue->container.buf, - amf_ue->container.size, Target_ToSource_TransparentContainer); - - return ogs_ngap_encode(&pdu); -} - -ogs_pkbuf_t *ngap_build_handover_preparation_failure( - ran_ue_t *source_ue, NGAP_Cause_t *cause) -{ - NGAP_NGAP_PDU_t pdu; - NGAP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL; - NGAP_HandoverPreparationFailure_t *HandoverPreparationFailure = NULL; - - NGAP_HandoverPreparationFailureIEs_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_Cause_t *Cause = NULL; - - ogs_assert(source_ue); - ogs_assert(cause); - - ogs_debug("Handover preparation failure"); - - memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); - pdu.present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome; - pdu.choice.unsuccessfulOutcome = - CALLOC(1, sizeof(NGAP_UnsuccessfulOutcome_t)); - - unsuccessfulOutcome = pdu.choice.unsuccessfulOutcome; - unsuccessfulOutcome->procedureCode = - NGAP_ProcedureCode_id_HandoverPreparation; - unsuccessfulOutcome->criticality = NGAP_Criticality_reject; - unsuccessfulOutcome->value.present = - NGAP_UnsuccessfulOutcome__value_PR_HandoverPreparationFailure; - - HandoverPreparationFailure = - &unsuccessfulOutcome->value.choice.HandoverPreparationFailure; - - ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); - ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = - NGAP_HandoverPreparationFailureIEs__value_PR_AMF_UE_NGAP_ID; - - AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; - - ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); - ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = - NGAP_HandoverPreparationFailureIEs__value_PR_RAN_UE_NGAP_ID; - - RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; - - ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); - ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_Cause; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = NGAP_HandoverPreparationFailureIEs__value_PR_Cause; - - Cause = &ie->value.choice.Cause; - - ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]", - source_ue->ran_ue_ngap_id, source_ue->amf_ue_ngap_id); - ogs_debug(" Group[%d] Cause[%d]", - cause->present, (int)cause->choice.radioNetwork); - - *AMF_UE_NGAP_ID = source_ue->amf_ue_ngap_id; - *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; - Cause->present = cause->present; - Cause->choice.radioNetwork = cause->choice.radioNetwork; - - return ogs_ngap_encode(&pdu); -} - -ogs_pkbuf_t *ngap_build_handover_request( - amf_ue_t *amf_ue, ran_ue_t *target_ue, - NGAP_RAN_UE_NGAP_ID_t *ran_ue_ngap_id, - NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id, - NGAP_HandoverType_t *handovertype, - NGAP_Cause_t *cause, - NGAP_SourceToTarget_TransparentContainer_t - *source_totarget_transparentContainer) -{ - int rv; NGAP_NGAP_PDU_t pdu; NGAP_InitiatingMessage_t *initiatingMessage = NULL; @@ -2145,25 +1895,19 @@ ogs_pkbuf_t *ngap_build_handover_request( NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; NGAP_HandoverType_t *HandoverType = NULL; NGAP_Cause_t *Cause = NULL; - NGAP_UEAggregateMaximumBitrate_t *UEAggregateMaximumBitrate = NULL; - NGAP_E_RABToBeSetupListHOReq_t *E_RABToBeSetupListHOReq = NULL; - NGAP_Source_ToTarget_TransparentContainer_t - *Source_ToTarget_TransparentContainer = NULL; + NGAP_UEAggregateMaximumBitRate_t *UEAggregateMaximumBitRate = NULL; NGAP_UESecurityCapabilities_t *UESecurityCapabilities = NULL; NGAP_SecurityContext_t *SecurityContext = NULL; - - amf_sess_t *sess = NULL; - amf_bearer_t *bearer = NULL; - ogs_diam_s6a_subscription_data_t *subscription_data = NULL; - - ogs_assert(handovertype); - ogs_assert(cause); - ogs_assert(source_totarget_transparentContainer); + NGAP_PDUSessionResourceSetupListHOReq_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceSetupItemHOReq_t *PDUSessionItem = NULL; + NGAP_AllowedNSSAI_t *AllowedNSSAI = NULL; + NGAP_SourceToTarget_TransparentContainer_t + *SourceToTarget_TransparentContainer = NULL; + NGAP_GUAMI_t *GUAMI = NULL; ogs_assert(target_ue); + amf_ue = target_ue->amf_ue; ogs_assert(amf_ue); - subscription_data = &amf_ue->subscription_data; - ogs_assert(subscription_data); ogs_debug("Handover request"); @@ -2181,6 +1925,7 @@ ogs_pkbuf_t *ngap_build_handover_request( HandoverRequest = &initiatingMessage->value.choice.HandoverRequest; ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; @@ -2189,7 +1934,13 @@ ogs_pkbuf_t *ngap_build_handover_request( AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + asn_uint642INTEGER(AMF_UE_NGAP_ID, target_ue->amf_ue_ngap_id); + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_HandoverType; @@ -2198,7 +1949,12 @@ ogs_pkbuf_t *ngap_build_handover_request( HandoverType = &ie->value.choice.HandoverType; + ogs_debug(" HandoverType[%d]", (int)amf_ue->handover.type); + + *HandoverType = amf_ue->handover.type;; + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_Cause; @@ -2207,38 +1963,32 @@ ogs_pkbuf_t *ngap_build_handover_request( Cause = &ie->value.choice.Cause; - ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); - ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); + Cause->present = amf_ue->handover.group; + Cause->choice.radioNetwork = amf_ue->handover.cause; + ogs_debug(" Group[%d] Cause[%d]", + Cause->present, (int)Cause->choice.radioNetwork); - ie->id = NGAP_ProtocolIE_ID_id_uEaggregateMaximumBitrate; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_HandoverRequestIEs__value_PR_UEAggregateMaximumBitrate; + if (amf_ue->ue_ambr.downlink || amf_ue->ue_ambr.uplink) { + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); - UEAggregateMaximumBitrate = &ie->value.choice.UEAggregateMaximumBitrate; - - ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); - ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_E_RABToBeSetupListHOReq; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_HandoverRequestIEs__value_PR_E_RABToBeSetupListHOReq; - - E_RABToBeSetupListHOReq = &ie->value.choice.E_RABToBeSetupListHOReq; - - ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); - ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_Source_ToTarget_TransparentContainer; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_HandoverRequestIEs__value_PR_Source_ToTarget_TransparentContainer; - - Source_ToTarget_TransparentContainer = - &ie->value.choice.Source_ToTarget_TransparentContainer; + ie->id = NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_UEAggregateMaximumBitRate; + + UEAggregateMaximumBitRate = &ie->value.choice.UEAggregateMaximumBitRate; + + asn_uint642INTEGER( + &UEAggregateMaximumBitRate->uEAggregateMaximumBitRateUL, + amf_ue->ue_ambr.uplink); + asn_uint642INTEGER( + &UEAggregateMaximumBitRate->uEAggregateMaximumBitRateDL, + amf_ue->ue_ambr.downlink); + } ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_UESecurityCapabilities; @@ -2248,124 +1998,373 @@ ogs_pkbuf_t *ngap_build_handover_request( UESecurityCapabilities = &ie->value.choice.UESecurityCapabilities; + UESecurityCapabilities->nRencryptionAlgorithms.size = 2; + UESecurityCapabilities->nRencryptionAlgorithms.buf = + CALLOC(UESecurityCapabilities-> + nRencryptionAlgorithms.size, sizeof(uint8_t)); + UESecurityCapabilities->nRencryptionAlgorithms.bits_unused = 0; + UESecurityCapabilities->nRencryptionAlgorithms.buf[0] = + (amf_ue->ue_security_capability.nr_ea << 1); + + UESecurityCapabilities->nRintegrityProtectionAlgorithms.size = 2; + UESecurityCapabilities->nRintegrityProtectionAlgorithms.buf = + CALLOC(UESecurityCapabilities-> + nRintegrityProtectionAlgorithms.size, sizeof(uint8_t)); + UESecurityCapabilities->nRintegrityProtectionAlgorithms.bits_unused = 0; + UESecurityCapabilities->nRintegrityProtectionAlgorithms.buf[0] = + (amf_ue->ue_security_capability.nr_ia << 1); + + UESecurityCapabilities->eUTRAencryptionAlgorithms.size = 2; + UESecurityCapabilities->eUTRAencryptionAlgorithms.buf = + CALLOC(UESecurityCapabilities-> + eUTRAencryptionAlgorithms.size, sizeof(uint8_t)); + UESecurityCapabilities->eUTRAencryptionAlgorithms.bits_unused = 0; + UESecurityCapabilities->eUTRAencryptionAlgorithms.buf[0] = + (amf_ue->ue_security_capability.eutra_ea << 1); + + UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.size = 2; + UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.buf = + CALLOC(UESecurityCapabilities-> + eUTRAintegrityProtectionAlgorithms.size, sizeof(uint8_t)); + UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.bits_unused = 0; + UESecurityCapabilities->eUTRAintegrityProtectionAlgorithms.buf[0] = + (amf_ue->ue_security_capability.eutra_ia << 1); + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_SecurityContext; ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_HandoverRequestIEs__value_PR_SecurityContext; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_SecurityContext; SecurityContext = &ie->value.choice.SecurityContext; - *AMF_UE_NGAP_ID = target_ue->amf_ue_ngap_id; - *HandoverType = *handovertype; + SecurityContext->nextHopChainingCount = amf_ue->nhcc; + SecurityContext->nextHopNH.size = OGS_SHA256_DIGEST_SIZE; + SecurityContext->nextHopNH.buf = + CALLOC(SecurityContext->nextHopNH.size, sizeof(uint8_t)); + SecurityContext->nextHopNH.bits_unused = 0; + memcpy(SecurityContext->nextHopNH.buf, + amf_ue->nh, SecurityContext->nextHopNH.size); + + ogs_list_for_each(&amf_ue->sess_list, sess) { + OCTET_STRING_t *transfer = NULL; + NGAP_S_NSSAI_t *s_NSSAI = NULL; + NGAP_SST_t *sST = NULL; + + if (!sess->transfer.handover_request) continue; + + if (!PDUSessionList) { + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListHOReq; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_PDUSessionResourceSetupListHOReq; + + PDUSessionList = &ie->value.choice.PDUSessionResourceSetupListHOReq; + } + + PDUSessionItem = CALLOC(1, + sizeof(struct NGAP_PDUSessionResourceSetupItemHOReq)); + ogs_assert(PDUSessionItem); + ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); + + PDUSessionItem->pDUSessionID = sess->psi; + + s_NSSAI = &PDUSessionItem->s_NSSAI; + sST = &s_NSSAI->sST; + + ogs_asn_uint8_to_OCTET_STRING(sess->s_nssai.sst, sST); + if (sess->s_nssai.sd.v != OGS_S_NSSAI_NO_SD_VALUE) { + s_NSSAI->sD = CALLOC(1, sizeof(NGAP_SD_t)); + ogs_asn_uint24_to_OCTET_STRING(sess->s_nssai.sd, s_NSSAI->sD); + } + + transfer = &PDUSessionItem->handoverRequestTransfer; + transfer->size = sess->transfer.handover_request->len; + transfer->buf = CALLOC(transfer->size, sizeof(uint8_t)); + memcpy(transfer->buf, + sess->transfer.handover_request->data, transfer->size); + } + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AllowedNSSAI; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_AllowedNSSAI; + + AllowedNSSAI = &ie->value.choice.AllowedNSSAI; + + for (i = 0; i < amf_self()->num_of_plmn_support; i++) { + if (memcmp(&amf_ue->tai.plmn_id, + &amf_self()->plmn_support[i].plmn_id, OGS_PLMN_ID_LEN) != 0) + continue; + for (j = 0; j < amf_self()->plmn_support[i].num_of_s_nssai; j++) { + NGAP_AllowedNSSAI_Item_t *NGAP_AllowedNSSAI_Item = NULL; + NGAP_S_NSSAI_t *s_NSSAI = NULL; + NGAP_SST_t *sST = NULL; + + NGAP_AllowedNSSAI_Item = (NGAP_AllowedNSSAI_Item_t *) + CALLOC(1, sizeof(NGAP_AllowedNSSAI_Item_t)); + ogs_assert(NGAP_AllowedNSSAI_Item); + s_NSSAI = &NGAP_AllowedNSSAI_Item->s_NSSAI; + sST = &s_NSSAI->sST; + + ogs_asn_uint8_to_OCTET_STRING( + amf_self()->plmn_support[i].s_nssai[j].sst, sST); + if (amf_self()->plmn_support[i].s_nssai[j].sd.v != + OGS_S_NSSAI_NO_SD_VALUE) { + s_NSSAI->sD = CALLOC(1, sizeof(NGAP_SD_t)); + ogs_assert(s_NSSAI->sD); + ogs_asn_uint24_to_OCTET_STRING( + amf_self()->plmn_support[i].s_nssai[j].sd, s_NSSAI->sD); + } + + ASN_SEQUENCE_ADD(&AllowedNSSAI->list, NGAP_AllowedNSSAI_Item); + } + } + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_SourceToTarget_TransparentContainer; + + SourceToTarget_TransparentContainer = + &ie->value.choice.SourceToTarget_TransparentContainer; + + ogs_asn_buffer_to_OCTET_STRING( + amf_ue->handover.container.buf, amf_ue->handover.container.size, + SourceToTarget_TransparentContainer); + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequest->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_GUAMI; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestIEs__value_PR_GUAMI; + + GUAMI = &ie->value.choice.GUAMI; + + ogs_assert(amf_ue->guami); + ogs_asn_buffer_to_OCTET_STRING(&amf_ue->guami->plmn_id, OGS_PLMN_ID_LEN, + &GUAMI->pLMNIdentity); + ogs_ngap_uint8_to_AMFRegionID(ogs_amf_region_id(&amf_ue->guami->amf_id), + &GUAMI->aMFRegionID); + ogs_ngap_uint16_to_AMFSetID(ogs_amf_set_id(&amf_ue->guami->amf_id), + &GUAMI->aMFSetID); + ogs_ngap_uint8_to_AMFPointer(ogs_amf_pointer(&amf_ue->guami->amf_id), + &GUAMI->aMFPointer); + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *ngap_build_handover_preparation_failure( + ran_ue_t *source_ue, NGAP_Cause_t *cause) +{ + NGAP_NGAP_PDU_t pdu; + NGAP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL; + NGAP_HandoverPreparationFailure_t *HandoverPreparationFailure = NULL; + + NGAP_HandoverPreparationFailureIEs_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_Cause_t *Cause = NULL; + + ogs_assert(source_ue); + ogs_assert(cause); + + ogs_debug("HandoverPreparationFailure"); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome; + pdu.choice.unsuccessfulOutcome = + CALLOC(1, sizeof(NGAP_UnsuccessfulOutcome_t)); + + unsuccessfulOutcome = pdu.choice.unsuccessfulOutcome; + unsuccessfulOutcome->procedureCode = + NGAP_ProcedureCode_id_HandoverPreparation; + unsuccessfulOutcome->criticality = NGAP_Criticality_reject; + unsuccessfulOutcome->value.present = + NGAP_UnsuccessfulOutcome__value_PR_HandoverPreparationFailure; + + HandoverPreparationFailure = + &unsuccessfulOutcome->value.choice.HandoverPreparationFailure; + + ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_HandoverPreparationFailureIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_HandoverPreparationFailureIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + asn_uint642INTEGER(AMF_UE_NGAP_ID, source_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_HandoverPreparationFailureIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverPreparationFailure->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverPreparationFailureIEs__value_PR_Cause; + + Cause = &ie->value.choice.Cause; + + ogs_debug(" Group[%d] Cause[%d]", + cause->present, (int)cause->choice.radioNetwork); Cause->present = cause->present; Cause->choice.radioNetwork = cause->choice.radioNetwork; - asn_uint642INTEGER( - &UEAggregateMaximumBitrate->uEaggregateMaximumBitRateUL, - subscription_data->ambr.uplink); - asn_uint642INTEGER( - &UEAggregateMaximumBitrate->uEaggregateMaximumBitRateDL, - subscription_data->ambr.downlink); + return ogs_ngap_encode(&pdu); +} - sess = amf_sess_first(amf_ue); - while (sess) { - bearer = amf_bearer_first(sess); - while (bearer) { - NGAP_E_RABToBeSetupItemHOReqIEs_t *item = NULL; - NGAP_E_RABToBeSetupItemHOReq_t *e_rab = NULL; - NGAP_GBR_QosInformation_t *gbrQosInformation = NULL; +ogs_pkbuf_t *ngap_build_handover_command(ran_ue_t *source_ue) +{ + amf_ue_t *amf_ue = NULL; + amf_sess_t *sess = NULL; - item = CALLOC(1, sizeof(NGAP_E_RABToBeSetupItemHOReqIEs_t)); - ASN_SEQUENCE_ADD(&E_RABToBeSetupListHOReq->list, item); + NGAP_NGAP_PDU_t pdu; + NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; + NGAP_HandoverCommand_t *HandoverCommand = NULL; - item->id = NGAP_ProtocolIE_ID_id_E_RABToBeSetupItemHOReq; - item->criticality = NGAP_Criticality_reject; - item->value.present = - NGAP_E_RABToBeSetupItemHOReqIEs__value_PR_E_RABToBeSetupItemHOReq; + NGAP_HandoverCommandIEs_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_HandoverType_t *HandoverType = NULL; + NGAP_PDUSessionResourceHandoverList_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceHandoverItem_t *PDUSessionItem = NULL; + NGAP_TargetToSource_TransparentContainer_t + *TargetToSource_TransparentContainer = NULL; - e_rab = &item->value.choice.E_RABToBeSetupItemHOReq; + ogs_assert(source_ue); + amf_ue = source_ue->amf_ue; + ogs_assert(amf_ue); - e_rab->e_RAB_ID = bearer->ebi; - e_rab->e_RABlevelQosParameters.qCI = bearer->qos.qci; + ogs_debug("Handover request"); - e_rab->e_RABlevelQosParameters.allocationRetentionPriority. - priorityLevel = bearer->qos.arp.priority_level; - e_rab->e_RABlevelQosParameters.allocationRetentionPriority. - pre_emptionCapability = - !(bearer->qos.arp.pre_emption_capability); - e_rab->e_RABlevelQosParameters.allocationRetentionPriority. - pre_emptionVulnerability = - !(bearer->qos.arp.pre_emption_vulnerability); + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome = CALLOC(1, sizeof(NGAP_SuccessfulOutcome_t)); - if (bearer->qos.mbr.downlink || bearer->qos.mbr.uplink || - bearer->qos.gbr.downlink || bearer->qos.gbr.uplink) { - if (bearer->qos.mbr.downlink == 0) - bearer->qos.mbr.downlink = MAX_BIT_RATE; - if (bearer->qos.mbr.uplink == 0) - bearer->qos.mbr.uplink = MAX_BIT_RATE; - if (bearer->qos.gbr.downlink == 0) - bearer->qos.gbr.downlink = MAX_BIT_RATE; - if (bearer->qos.gbr.uplink == 0) - bearer->qos.gbr.uplink = MAX_BIT_RATE; + successfulOutcome = pdu.choice.successfulOutcome; + successfulOutcome->procedureCode = + NGAP_ProcedureCode_id_HandoverPreparation; + successfulOutcome->criticality = NGAP_Criticality_reject; + successfulOutcome->value.present = + NGAP_SuccessfulOutcome__value_PR_HandoverCommand; - gbrQosInformation = - CALLOC(1, sizeof(struct NGAP_GBR_QosInformation)); - asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateDL, - bearer->qos.mbr.downlink); - asn_uint642INTEGER(&gbrQosInformation->e_RAB_MaximumBitrateUL, - bearer->qos.mbr.uplink); - asn_uint642INTEGER(&gbrQosInformation-> - e_RAB_GuaranteedBitrateDL, bearer->qos.gbr.downlink); - asn_uint642INTEGER(&gbrQosInformation-> - e_RAB_GuaranteedBitrateUL, bearer->qos.gbr.uplink); - e_rab->e_RABlevelQosParameters.gbrQosInformation = - gbrQosInformation; - } + HandoverCommand = &successfulOutcome->value.choice.HandoverCommand; - rv = ogs_asn_ip_to_BIT_STRING( - &bearer->sgw_s1u_ip, &e_rab->transportLayerAddress); - ogs_assert(rv == OGS_OK); - ogs_asn_uint32_to_OCTET_STRING( - bearer->sgw_s1u_teid, &e_rab->gTP_TEID); - ogs_debug(" SGW-NGU-TEID[%d]", bearer->sgw_s1u_teid); + ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); - bearer = amf_bearer_next(bearer); + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCommandIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCommandIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + + asn_uint642INTEGER(AMF_UE_NGAP_ID, source_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_HandoverType; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCommandIEs__value_PR_HandoverType; + + HandoverType = &ie->value.choice.HandoverType; + + ogs_debug(" HandoverType[%d]", (int)amf_ue->handover.type); + + *HandoverType = amf_ue->handover.type;; + + ogs_list_for_each(&amf_ue->sess_list, sess) { + OCTET_STRING_t *transfer = NULL; + + if (!sess->transfer.handover_command) continue; + + if (!PDUSessionList) { + ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceHandoverList; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverCommandIEs__value_PR_PDUSessionResourceHandoverList; + + PDUSessionList = &ie->value.choice.PDUSessionResourceHandoverList; } - sess = amf_sess_next(sess); + + PDUSessionItem = CALLOC(1, sizeof(*PDUSessionItem)); + ogs_assert(PDUSessionItem); + ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); + + PDUSessionItem->pDUSessionID = sess->psi; + + transfer = &PDUSessionItem->handoverCommandTransfer; + transfer->size = sess->transfer.handover_command->len; + transfer->buf = CALLOC(transfer->size, sizeof(uint8_t)); + memcpy(transfer->buf, + sess->transfer.handover_command->data, transfer->size); } + ie = CALLOC(1, sizeof(NGAP_HandoverCommandIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCommand->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCommandIEs__value_PR_TargetToSource_TransparentContainer; + + TargetToSource_TransparentContainer = + &ie->value.choice.TargetToSource_TransparentContainer; + ogs_asn_buffer_to_OCTET_STRING( - source_totarget_transparentContainer->buf, - source_totarget_transparentContainer->size, - Source_ToTarget_TransparentContainer); - - UESecurityCapabilities->encryptionAlgorithms.size = 2; - UESecurityCapabilities->encryptionAlgorithms.buf = - CALLOC(UESecurityCapabilities->encryptionAlgorithms.size, - sizeof(uint8_t)); - UESecurityCapabilities->encryptionAlgorithms.bits_unused = 0; - UESecurityCapabilities->encryptionAlgorithms.buf[0] = - (amf_ue->ue_network_capability.eea << 1); - - UESecurityCapabilities->integrityProtectionAlgorithms.size = 2; - UESecurityCapabilities->integrityProtectionAlgorithms.buf = - CALLOC(UESecurityCapabilities-> - integrityProtectionAlgorithms.size, sizeof(uint8_t)); - UESecurityCapabilities->integrityProtectionAlgorithms.bits_unused = 0; - UESecurityCapabilities->integrityProtectionAlgorithms.buf[0] = - (amf_ue->ue_network_capability.eia << 1); - - SecurityContext->nextHopChainingCount = amf_ue->nhcc; - SecurityContext->nextHopParameter.size = OGS_SHA256_DIGEST_SIZE; - SecurityContext->nextHopParameter.buf = - CALLOC(SecurityContext->nextHopParameter.size, - sizeof(uint8_t)); - SecurityContext->nextHopParameter.bits_unused = 0; - memcpy(SecurityContext->nextHopParameter.buf, - amf_ue->nh, SecurityContext->nextHopParameter.size); + amf_ue->handover.container.buf, amf_ue->handover.container.size, + TargetToSource_TransparentContainer); return ogs_ngap_encode(&pdu); } @@ -2382,12 +2381,11 @@ ogs_pkbuf_t *ngap_build_handover_cancel_ack(ran_ue_t *source_ue) ogs_assert(source_ue); - ogs_debug("Handover cancel acknowledge"); + ogs_debug("Handover cancel"); memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_successfulOutcome; - pdu.choice.successfulOutcome = - CALLOC(1, sizeof(NGAP_SuccessfulOutcome_t)); + pdu.choice.successfulOutcome = CALLOC(1, sizeof(NGAP_SuccessfulOutcome_t)); successfulOutcome = pdu.choice.successfulOutcome; successfulOutcome->procedureCode = NGAP_ProcedureCode_id_HandoverCancel; @@ -2399,6 +2397,7 @@ ogs_pkbuf_t *ngap_build_handover_cancel_ack(ran_ue_t *source_ue) &successfulOutcome->value.choice.HandoverCancelAcknowledge; ie = CALLOC(1, sizeof(NGAP_HandoverCancelAcknowledgeIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverCancelAcknowledge->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; @@ -2409,6 +2408,7 @@ ogs_pkbuf_t *ngap_build_handover_cancel_ack(ran_ue_t *source_ue) AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; ie = CALLOC(1, sizeof(NGAP_HandoverCancelAcknowledgeIEs_t)); + ogs_assert(ie); ASN_SEQUENCE_ADD(&HandoverCancelAcknowledge->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; @@ -2418,90 +2418,90 @@ ogs_pkbuf_t *ngap_build_handover_cancel_ack(ran_ue_t *source_ue) RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; - *AMF_UE_NGAP_ID = source_ue->amf_ue_ngap_id; - *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; + ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); - ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]", - source_ue->ran_ue_ngap_id, source_ue->amf_ue_ngap_id); + asn_uint642INTEGER(AMF_UE_NGAP_ID, source_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = source_ue->ran_ue_ngap_id; return ogs_ngap_encode(&pdu); } -ogs_pkbuf_t *ngap_build_amf_status_transfer( - ran_ue_t *target_ue, - NGAP_RANStatusTransfer_TransparentContainer_t - *gnb_statustransfer_transparentContainer) +ogs_pkbuf_t *ngap_build_uplink_ran_status_transfer( + ran_ue_t *target_ue, + NGAP_RANStatusTransfer_TransparentContainer_t *transfer) { int rv; NGAP_NGAP_PDU_t pdu; NGAP_InitiatingMessage_t *initiatingMessage = NULL; - NGAP_AMFStatusTransfer_t *AMFStatusTransfer = NULL; + NGAP_DownlinkRANStatusTransfer_t *DownlinkRANStatusTransfer = NULL; - NGAP_AMFStatusTransferIEs_t *ie = NULL; + NGAP_DownlinkRANStatusTransferIEs_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_RANStatusTransfer_TransparentContainer_t - *RAN_StatusTransfer_TransparentContainer = NULL; + *RANStatusTransfer_TransparentContainer = NULL; ogs_assert(target_ue); - ogs_assert(gnb_statustransfer_transparentContainer); - - ogs_debug("AMF status transfer"); + ogs_assert(transfer); + + ogs_debug("DownlinkRANStatusTransfer"); memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; - initiatingMessage->procedureCode = NGAP_ProcedureCode_id_AMFStatusTransfer; + initiatingMessage->procedureCode = + NGAP_ProcedureCode_id_DownlinkRANStatusTransfer; initiatingMessage->criticality = NGAP_Criticality_ignore; initiatingMessage->value.present = - NGAP_InitiatingMessage__value_PR_AMFStatusTransfer; + NGAP_InitiatingMessage__value_PR_DownlinkRANStatusTransfer; - AMFStatusTransfer = &initiatingMessage->value.choice.AMFStatusTransfer; + DownlinkRANStatusTransfer = + &initiatingMessage->value.choice.DownlinkRANStatusTransfer; - ie = CALLOC(1, sizeof(NGAP_AMFStatusTransferIEs_t)); - ASN_SEQUENCE_ADD(&AMFStatusTransfer->protocolIEs, ie); + ie = CALLOC(1, sizeof(NGAP_DownlinkRANStatusTransferIEs_t)); + ASN_SEQUENCE_ADD(&DownlinkRANStatusTransfer->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; ie->criticality = NGAP_Criticality_reject; - ie->value.present = NGAP_AMFStatusTransferIEs__value_PR_AMF_UE_NGAP_ID; + ie->value.present = + NGAP_DownlinkRANStatusTransferIEs__value_PR_AMF_UE_NGAP_ID; AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; - ie = CALLOC(1, sizeof(NGAP_AMFStatusTransferIEs_t)); - ASN_SEQUENCE_ADD(&AMFStatusTransfer->protocolIEs, ie); + ie = CALLOC(1, sizeof(NGAP_DownlinkRANStatusTransferIEs_t)); + ASN_SEQUENCE_ADD(&DownlinkRANStatusTransfer->protocolIEs, ie); ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; ie->criticality = NGAP_Criticality_reject; - ie->value.present = NGAP_AMFStatusTransferIEs__value_PR_RAN_UE_NGAP_ID; + ie->value.present = + NGAP_DownlinkRANStatusTransferIEs__value_PR_RAN_UE_NGAP_ID; RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; - ie = CALLOC(1, sizeof(NGAP_AMFStatusTransferIEs_t)); - ASN_SEQUENCE_ADD(&AMFStatusTransfer->protocolIEs, ie); + ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); - ie->id = NGAP_ProtocolIE_ID_id_RAN_StatusTransfer_TransparentContainer; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_AMFStatusTransferIEs__value_PR_RAN_StatusTransfer_TransparentContainer; - - RAN_StatusTransfer_TransparentContainer = - &ie->value.choice.RAN_StatusTransfer_TransparentContainer; - - *AMF_UE_NGAP_ID = target_ue->amf_ue_ngap_id; + asn_uint642INTEGER(AMF_UE_NGAP_ID, target_ue->amf_ue_ngap_id); *RAN_UE_NGAP_ID = target_ue->ran_ue_ngap_id; - ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]", - target_ue->ran_ue_ngap_id, target_ue->amf_ue_ngap_id); + ie = CALLOC(1, sizeof(NGAP_DownlinkRANStatusTransferIEs_t)); + ASN_SEQUENCE_ADD(&DownlinkRANStatusTransfer->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_DownlinkRANStatusTransferIEs__value_PR_RANStatusTransfer_TransparentContainer; + + RANStatusTransfer_TransparentContainer = + &ie->value.choice.RANStatusTransfer_TransparentContainer; rv = ogs_asn_copy_ie( - &asn_DEF_NGAP_RAN_StatusTransfer_TransparentContainer, - gnb_statustransfer_transparentContainer, - RAN_StatusTransfer_TransparentContainer); + &asn_DEF_NGAP_RANStatusTransfer_TransparentContainer, + transfer, RANStatusTransfer_TransparentContainer); ogs_assert(rv == OGS_OK); return ogs_ngap_encode(&pdu); } -#endif diff --git a/src/amf/ngap-build.h b/src/amf/ngap-build.h index a4821da6d..4da080bbb 100644 --- a/src/amf/ngap-build.h +++ b/src/amf/ngap-build.h @@ -52,31 +52,21 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( ogs_pkbuf_t *ngap_build_paging(amf_ue_t *amf_ue); -ogs_pkbuf_t *ngap_build_amf_configuration_transfer( - NGAP_SONConfigurationTransfer_t *son_configuration_transfer); +ogs_pkbuf_t *ngap_build_downlink_ran_configuration_transfer( + NGAP_SONConfigurationTransfer_t *transfer); ogs_pkbuf_t *ngap_build_path_switch_ack(amf_ue_t *amf_ue); -ogs_pkbuf_t *ngap_build_handover_command(ran_ue_t *source_ue); +ogs_pkbuf_t *ngap_build_handover_request(ran_ue_t *target_ue); ogs_pkbuf_t *ngap_build_handover_preparation_failure( ran_ue_t *source_ue, NGAP_Cause_t *cause); -ogs_pkbuf_t *ngap_build_handover_request( - amf_ue_t *amf_ue, ran_ue_t *target_ue, - NGAP_RAN_UE_NGAP_ID_t *ran_ue_ngap_id, - NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id, - NGAP_HandoverType_t *handovertype, - NGAP_Cause_t *cause, - NGAP_SourceToTarget_TransparentContainer_t - *source_totarget_transparentContainer); +ogs_pkbuf_t *ngap_build_handover_command(ran_ue_t *source_ue); +ogs_pkbuf_t *ngap_build_handover_cancel_ack(ran_ue_t *source_ue); -ogs_pkbuf_t *ngap_build_handover_cancel_ack( - ran_ue_t *source_ue); - -ogs_pkbuf_t *ngap_build_amf_status_transfer( +ogs_pkbuf_t *ngap_build_uplink_ran_status_transfer( ran_ue_t *target_ue, - NGAP_RANStatusTransfer_TransparentContainer_t - *gnb_statustransfer_transparentContainer); + NGAP_RANStatusTransfer_TransparentContainer_t *transfer); #ifdef __cplusplus } diff --git a/src/amf/ngap-handler.c b/src/amf/ngap-handler.c index 83ab4f8d7..bd94b30ee 100644 --- a/src/amf/ngap-handler.c +++ b/src/amf/ngap-handler.c @@ -497,6 +497,7 @@ void ngap_handle_uplink_nas_transport( char buf[OGS_ADDRSTRLEN]; int i; + amf_ue_t *amf_ue = NULL; ran_ue_t *ran_ue = NULL; uint64_t amf_ue_ngap_id; @@ -570,6 +571,17 @@ void ngap_handle_uplink_nas_transport( return; } + amf_ue = ran_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &ran_ue->ran_ue_ngap_id, &ran_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + if (!UserLocationInformation) { ogs_error("No UserLocationInformation"); ngap_send_error_indication(gnb, &ran_ue->ran_ue_ngap_id, NULL, @@ -607,17 +619,9 @@ void ngap_handle_uplink_nas_transport( ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id, ran_ue->saved.tai.tac.v, (long long)ran_ue->saved.nr_cgi.cell_id); - if (ran_ue->amf_ue) { - amf_ue_t *amf_ue = ran_ue->amf_ue; - - /* Copy Stream-No/NR-TAI/NR-CGI from ran_ue */ - memcpy(&amf_ue->tai, &ran_ue->saved.tai, sizeof(ogs_5gs_tai_t)); - memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t)); - - } else { - ogs_fatal("No UE Context in UplinkNASTransport"); - ogs_assert_if_reached(); - } + /* Copy NR-TAI/NR-CGI from ran_ue */ + memcpy(&amf_ue->tai, &ran_ue->saved.tai, sizeof(ogs_5gs_tai_t)); + memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t)); ngap_send_to_nas(ran_ue, NGAP_ProcedureCode_id_UplinkNASTransport, NAS_PDU); } @@ -724,7 +728,7 @@ void ngap_handle_initial_context_setup_response( amf_ue_t *amf_ue = NULL; ran_ue_t *ran_ue = NULL; uint64_t amf_ue_ngap_id; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; NGAP_InitialContextSetupResponse_t *InitialContextSetupResponse = NULL; @@ -802,7 +806,15 @@ void ngap_handle_initial_context_setup_response( return; amf_ue = ran_ue->amf_ue; - ogs_expect_or_return(amf_ue); + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &ran_ue->ran_ue_ngap_id, &ran_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } for (i = 0; i < PDUSessionList->list.count; i++) { amf_sess_t *sess = NULL; @@ -859,7 +871,7 @@ void ngap_handle_initial_context_setup_response( amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_UPDATE_SM_CONTEXT_ACTIVATED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + amf_nsmf_pdusession_build_update_sm_context); ogs_pkbuf_free(param.n2smbuf); } @@ -944,7 +956,6 @@ void ngap_handle_initial_context_setup_failure( ogs_debug(" RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld]", ran_ue->ran_ue_ngap_id, (long long)ran_ue->amf_ue_ngap_id); - if (!Cause) { ogs_error("No Cause"); ngap_send_error_indication( @@ -1095,7 +1106,8 @@ void ngap_handle_ue_context_release_request( amf_ue = ran_ue->amf_ue; if (!amf_ue) { - ogs_debug("No UE Context"); + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); ngap_send_ran_ue_context_release_command(ran_ue, NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0); @@ -1255,14 +1267,14 @@ void ngap_handle_ue_context_release_action(ran_ue_t *ran_ue) ogs_expect_or_return(amf_ue); amf_ue_remove(amf_ue); break; - case NGAP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL: -#if 0 - ogs_debug(" Action: Delete indirect tunnel"); + case NGAP_UE_CTX_REL_NG_HANDOVER_COMPLETE: + ogs_debug(" Action: NG handover complete"); source_ue_deassociate_target_ue(ran_ue); ran_ue_remove(ran_ue); ogs_expect_or_return(amf_ue); +#if 0 if (amf_ue_have_indirect_tunnel(amf_ue)) { amf_gtp_send_delete_indirect_data_forwarding_tunnel_request( amf_ue); @@ -1290,7 +1302,7 @@ void ngap_handle_pdu_session_resource_setup_response( amf_ue_t *amf_ue = NULL; ran_ue_t *ran_ue = NULL; uint64_t amf_ue_ngap_id; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; NGAP_PDUSessionResourceSetupResponse_t *PDUSessionResourceSetupResponse; @@ -1438,7 +1450,7 @@ void ngap_handle_pdu_session_resource_setup_response( amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_UPDATE_SM_CONTEXT_ACTIVATED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + amf_nsmf_pdusession_build_update_sm_context); ogs_pkbuf_free(param.n2smbuf); } @@ -1453,7 +1465,7 @@ void ngap_handle_pdu_session_resource_modify_response( amf_ue_t *amf_ue = NULL; ran_ue_t *ran_ue = NULL; uint64_t amf_ue_ngap_id; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; NGAP_PDUSessionResourceModifyResponse_t *PDUSessionResourceModifyResponse; @@ -1601,7 +1613,7 @@ void ngap_handle_pdu_session_resource_modify_response( amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_UPDATE_SM_CONTEXT_MODIFIED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + amf_nsmf_pdusession_build_update_sm_context); ogs_pkbuf_free(param.n2smbuf); } @@ -1616,7 +1628,7 @@ void ngap_handle_pdu_session_resource_release_response( amf_ue_t *amf_ue = NULL; ran_ue_t *ran_ue = NULL; uint64_t amf_ue_ngap_id; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; NGAP_PDUSessionResourceReleaseResponse_t @@ -1765,12 +1777,128 @@ void ngap_handle_pdu_session_resource_release_response( amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, sess, AMF_UPDATE_SM_CONTEXT_N2_RELEASED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + amf_nsmf_pdusession_build_update_sm_context); ogs_pkbuf_free(param.n2smbuf); } } +void ngap_handle_uplink_ran_configuration_transfer( + amf_gnb_t *gnb, ogs_ngap_message_t *message, ogs_pkbuf_t *pkbuf) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_UplinkRANConfigurationTransfer_t + *UplinkRANConfigurationTransfer = NULL; + + NGAP_UplinkRANConfigurationTransferIEs_t *ie = NULL; + NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + UplinkRANConfigurationTransfer = + &initiatingMessage->value.choice.UplinkRANConfigurationTransfer; + ogs_assert(UplinkRANConfigurationTransfer); + + ogs_debug("Uplink ran configuration transfer"); + for (i = 0; + i < UplinkRANConfigurationTransfer->protocolIEs.list.count; i++) { + ie = UplinkRANConfigurationTransfer->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_SONConfigurationTransferUL: + SONConfigurationTransfer = + &ie->value.choice.SONConfigurationTransfer; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] ENB_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (SONConfigurationTransfer) { + NGAP_TargetRANNodeID_t *targetRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *targetGlobalRANNodeID; + NGAP_GlobalGNB_ID_t *targetGlobalGNB_ID; + NGAP_SourceRANNodeID_t *sourceRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *sourceGlobalRANNodeID; + NGAP_GlobalGNB_ID_t *sourceGlobalGNB_ID; + + amf_gnb_t *target_gnb = NULL; + uint32_t target_gnb_id, source_gnb_id; + ogs_5gs_tai_t target_tai, source_tai; + + targetRANNodeID = &SONConfigurationTransfer->targetRANNodeID; + targetGlobalRANNodeID = &targetRANNodeID->globalRANNodeID; + + if (targetGlobalRANNodeID->present != + NGAP_GlobalRANNodeID_PR_globalGNB_ID) { + ogs_error("Not implemented targetGlobalRANNodeID->present[%d]", + targetGlobalRANNodeID->present); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + targetGlobalGNB_ID = targetGlobalRANNodeID->choice.globalGNB_ID; + if (!targetGlobalGNB_ID) { + ogs_error("No targetGlobalGNB_ID"); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + ogs_ngap_GNB_ID_to_uint32(&targetGlobalGNB_ID->gNB_ID, &target_gnb_id); + ogs_ngap_ASN_to_5gs_tai(&targetRANNodeID->selectedTAI, &target_tai); + + sourceRANNodeID = &SONConfigurationTransfer->sourceRANNodeID; + sourceGlobalRANNodeID = &sourceRANNodeID->globalRANNodeID; + + if (sourceGlobalRANNodeID->present != + NGAP_GlobalRANNodeID_PR_globalGNB_ID) { + ogs_error("Not implemented sourceGlobalRANNodeID->present[%d]", + sourceGlobalRANNodeID->present); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + sourceGlobalGNB_ID = sourceGlobalRANNodeID->choice.globalGNB_ID; + if (!sourceGlobalGNB_ID) { + ogs_error("No sourceGlobalGNB_ID"); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + ogs_ngap_GNB_ID_to_uint32(&sourceGlobalGNB_ID->gNB_ID, &source_gnb_id); + ogs_ngap_ASN_to_5gs_tai(&sourceRANNodeID->selectedTAI, &source_tai); + + ogs_debug(" Target : GNB_ID[0x%x], TAC[%d]", + target_gnb_id, target_tai.tac.v); + ogs_debug(" Source : GNB_ID[0x%x], TAC[%d]", + source_gnb_id, source_tai.tac.v); + + target_gnb = amf_gnb_find_by_gnb_id(target_gnb_id); + if (!target_gnb) { + ogs_error("Uplink RAN configuration transfer : " + "cannot find target gNB-id[0x%x]", target_gnb_id); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + ngap_send_downlink_ran_configuration_transfer( + target_gnb, SONConfigurationTransfer); + } +} void ngap_handle_path_switch_request( amf_gnb_t *gnb, ogs_ngap_message_t *message) @@ -1806,7 +1934,7 @@ void ngap_handle_path_switch_request( NGAP_PDUSessionResourceToBeSwitchedDLItem_t *PDUSessionItem = NULL; OCTET_STRING_t *transfer = NULL; - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; ogs_assert(gnb); ogs_assert(gnb->sctp.sock); @@ -1921,7 +2049,7 @@ void ngap_handle_path_switch_request( ogs_ngap_ASN_to_5gs_tai( &UserLocationInformationNR->tAI, &ran_ue->saved.tai); - /* Copy Stream-No/TAI/ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from ran_ue */ amf_ue->gnb_ostream_id = ran_ue->gnb_ostream_id; memcpy(&amf_ue->tai, &ran_ue->saved.tai, sizeof(ogs_5gs_tai_t)); memcpy(&amf_ue->nr_cgi, &ran_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t)); @@ -2041,13 +2169,991 @@ void ngap_handle_path_switch_request( ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, - sess, AMF_UPDATE_SM_CONTEXT_ACTIVATED, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + sess, AMF_UPDATE_SM_CONTEXT_PATH_SWITCH_REQUEST, ¶m, + amf_nsmf_pdusession_build_update_sm_context); ogs_pkbuf_free(param.n2smbuf); } } +void ngap_handle_handover_required( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + amf_ue_t *amf_ue = NULL; + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + + amf_gnb_t *target_gnb = NULL; + uint32_t target_gnb_id; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverRequired_t *HandoverRequired = NULL; + + NGAP_HandoverRequiredIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_HandoverType_t *HandoverType = NULL; + NGAP_Cause_t *Cause = NULL; + NGAP_TargetID_t *TargetID = NULL; + NGAP_TargetRANNodeID_t *targetRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *globalRANNodeID = NULL; + NGAP_GlobalGNB_ID_t *globalGNB_ID = NULL; + NGAP_PDUSessionResourceListHORqd_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceItemHORqd_t *PDUSessionItem = NULL; + OCTET_STRING_t *transfer = NULL; + + NGAP_SourceToTarget_TransparentContainer_t + *SourceToTarget_TransparentContainer = NULL; + + amf_nsmf_pdusession_update_sm_context_param_t param; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + HandoverRequired = &initiatingMessage->value.choice.HandoverRequired; + ogs_assert(HandoverRequired); + + ogs_info("Handover required"); + + for (i = 0; i < HandoverRequired->protocolIEs.list.count; i++) { + ie = HandoverRequired->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_HandoverType: + HandoverType = &ie->value.choice.HandoverType; + break; + case NGAP_ProtocolIE_ID_id_Cause: + Cause = &ie->value.choice.Cause; + break; + case NGAP_ProtocolIE_ID_id_TargetID: + TargetID = &ie->value.choice.TargetID; + break; + case NGAP_ProtocolIE_ID_id_PDUSessionResourceListHORqd: + PDUSessionList = &ie->value.choice.PDUSessionResourceListHORqd; + break; + case NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer: + SourceToTarget_TransparentContainer = + &ie->value.choice.SourceToTarget_TransparentContainer; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!source_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, (uint32_t *)RAN_UE_NGAP_ID, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + + amf_ue = source_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + if (!HandoverType) { + ogs_error("No HandoverType"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!Cause) { + ogs_error("No Cause"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!TargetID) { + ogs_error("No TargetID"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (TargetID->present != NGAP_TargetID_PR_targetRANNodeID) { + ogs_error("Not implemented TargetID[%d]", TargetID->present); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + targetRANNodeID = TargetID->choice.targetRANNodeID; + if (!targetRANNodeID) { + ogs_error("No targetRANNodeID"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + globalRANNodeID = &targetRANNodeID->globalRANNodeID; + if (globalRANNodeID->present != NGAP_GlobalRANNodeID_PR_globalGNB_ID) { + ogs_error("Not implemented globalRANNodeID[%d]", + globalRANNodeID->present); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + globalGNB_ID = globalRANNodeID->choice.globalGNB_ID; + if (!globalGNB_ID) { + ogs_error("No globalGNB_ID"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + ogs_ngap_GNB_ID_to_uint32(&globalGNB_ID->gNB_ID, &target_gnb_id); + target_gnb = amf_gnb_find_by_gnb_id(target_gnb_id); + if (!target_gnb) { + ogs_error("Handover required : cannot find target gNB-id[0x%x]", + target_gnb_id); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!PDUSessionList) { + ogs_error("No PDUSessionList"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!SourceToTarget_TransparentContainer) { + ogs_error("No SourceToTarget_TransparentContainer"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!SECURITY_CONTEXT_IS_VALID(amf_ue)) { + ogs_error("No Security Context"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_nas, NGAP_CauseNas_authentication_failure); + return; + } + + /* Target UE */ + target_ue = ran_ue_add(target_gnb, INVALID_UE_NGAP_ID); + ogs_assert(target_ue); + + /* Source UE - Target UE associated */ + source_ue_associate_target_ue(source_ue, target_ue); + + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + /* Store HandoverType */ + amf_ue->handover.type = *HandoverType; + + /* Store Cause */ + amf_ue->handover.group = Cause->present; + amf_ue->handover.cause = (int)Cause->choice.radioNetwork; + + /* Update Security Context (NextHop) */ + amf_ue->nhcc++; + ogs_kdf_nh_gnb(amf_ue->kamf, amf_ue->nh, amf_ue->nh); + + /* Store Container */ + OGS_ASN_STORE_DATA(&amf_ue->handover.container, + SourceToTarget_TransparentContainer); + + for (i = 0; i < PDUSessionList->list.count; i++) { + amf_sess_t *sess = NULL; + PDUSessionItem = (NGAP_PDUSessionResourceItemHORqd_t *) + PDUSessionList->list.array[i]; + + if (!PDUSessionItem) { + ogs_error("No PDUSessionResourceItemHORqd"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + transfer = &PDUSessionItem->handoverRequiredTransfer; + if (!transfer) { + ogs_error("No handoverRequiredTransfer"); + 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"); + 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); + 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); + 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_HANDOVER_REQUIRED; + ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); + + param.hoState = OpenAPI_ho_state_PREPARING; + param.TargetID = TargetID; + + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED, ¶m, + amf_nsmf_pdusession_build_update_sm_context); + + ogs_pkbuf_free(param.n2smbuf); + } +} + +void ngap_handle_handover_request_ack( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + amf_ue_t *amf_ue = NULL; + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + amf_nsmf_pdusession_update_sm_context_param_t param; + + NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; + NGAP_HandoverRequestAcknowledge_t *HandoverRequestAcknowledge = NULL; + + NGAP_HandoverRequestAcknowledgeIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_PDUSessionResourceAdmittedList_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceAdmittedItem_t *PDUSessionItem = NULL; + OCTET_STRING_t *transfer = NULL; + + NGAP_TargetToSource_TransparentContainer_t + *TargetToSource_TransparentContainer = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + successfulOutcome = message->choice.successfulOutcome; + ogs_assert(successfulOutcome); + HandoverRequestAcknowledge = + &successfulOutcome->value.choice.HandoverRequestAcknowledge; + ogs_assert(HandoverRequestAcknowledge); + + ogs_debug("Handover request acknowledge"); + + for (i = 0; i < HandoverRequestAcknowledge->protocolIEs.list.count; i++) { + ie = HandoverRequestAcknowledge->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_PDUSessionResourceAdmittedList: + PDUSessionList = &ie->value.choice.PDUSessionResourceAdmittedList; + break; + case NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer: + TargetToSource_TransparentContainer = + &ie->value.choice.TargetToSource_TransparentContainer; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!target_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, (uint32_t *)RAN_UE_NGAP_ID, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + if (!RAN_UE_NGAP_ID) { + ogs_error("No RAN_UE_NGAP_ID"); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + target_ue->ran_ue_ngap_id = *RAN_UE_NGAP_ID; + + source_ue = target_ue->source_ue; + if (!source_ue) { + ogs_error("Cannot find Source-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_inconsistent_remote_UE_NGAP_ID); + return; + } + amf_ue = target_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + if (!PDUSessionList) { + ogs_error("No PDUSessionList"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (!TargetToSource_TransparentContainer) { + ogs_error("No TargetToSource_TransparentContainer"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + /* Store Container */ + OGS_ASN_STORE_DATA(&amf_ue->handover.container, + TargetToSource_TransparentContainer); + + for (i = 0; i < PDUSessionList->list.count; i++) { + amf_sess_t *sess = NULL; + PDUSessionItem = (NGAP_PDUSessionResourceAdmittedItem_t *) + PDUSessionList->list.array[i]; + + if (!PDUSessionItem) { + ogs_error("No PDUSessionResourceAdmittedItem"); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + transfer = &PDUSessionItem->handoverRequestAcknowledgeTransfer; + if (!transfer) { + ogs_error("No handoverRequestAcknowledgeTransfer"); + 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"); + 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); + 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); + 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_HANDOVER_REQ_ACK; + ogs_pkbuf_put_data(param.n2smbuf, transfer->buf, transfer->size); + + param.hoState = OpenAPI_ho_state_PREPARED; + + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_HANDOVER_REQ_ACK, ¶m, + amf_nsmf_pdusession_build_update_sm_context); + + ogs_pkbuf_free(param.n2smbuf); + } +} + +void ngap_handle_handover_failure( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + + NGAP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL; + NGAP_HandoverFailure_t *HandoverFailure = NULL; + + NGAP_HandoverFailureIEs_t *ie = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_Cause_t *Cause = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + unsuccessfulOutcome = message->choice.unsuccessfulOutcome; + ogs_assert(unsuccessfulOutcome); + HandoverFailure = + &unsuccessfulOutcome->value.choice.HandoverFailure; + ogs_assert(HandoverFailure); + + ogs_debug("Initial context setup failure"); + + for (i = 0; i < HandoverFailure->protocolIEs.list.count; i++) { + ie = HandoverFailure->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_Cause: + Cause = &ie->value.choice.Cause; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, NULL, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!target_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, NULL, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + source_ue = target_ue->source_ue; + if (!source_ue) { + ogs_error("Cannot find Source-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_inconsistent_remote_UE_NGAP_ID); + return; + } + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + if (!Cause) { + ogs_error("No Cause"); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + ogs_debug(" Cause[Group:%d Cause:%d]", + Cause->present, (int)Cause->choice.radioNetwork); + + ngap_send_handover_preparation_failure(source_ue, Cause); + + ngap_send_ran_ue_context_release_command(target_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_ho_failure_in_target_5GC_ngran_node_or_target_system, + NGAP_UE_CTX_REL_NG_HANDOVER_COMPLETE, 0); +} + +void ngap_handle_handover_cancel( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + amf_ue_t *amf_ue = NULL; + amf_sess_t *sess = NULL; + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + amf_nsmf_pdusession_update_sm_context_param_t param; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverCancel_t *HandoverCancel = NULL; + + NGAP_HandoverCancelIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_Cause_t *Cause = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + HandoverCancel = &initiatingMessage->value.choice.HandoverCancel; + ogs_assert(HandoverCancel); + + ogs_debug("Handover cancel"); + + for (i = 0; i < HandoverCancel->protocolIEs.list.count; i++) { + ie = HandoverCancel->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_Cause: + Cause = &ie->value.choice.Cause; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!source_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, (uint32_t *)RAN_UE_NGAP_ID, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + target_ue = source_ue->target_ue; + if (!target_ue) { + ogs_error("Cannot find Source-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_inconsistent_remote_UE_NGAP_ID); + return; + } + amf_ue = source_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + if (!Cause) { + ogs_error("No Cause"); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + ogs_debug(" Cause[Group:%d Cause:%d]", + Cause->present, (int)Cause->choice.radioNetwork); + + ogs_list_for_each(&amf_ue->sess_list, sess) { + memset(¶m, 0, sizeof(param)); + param.hoState = OpenAPI_ho_state_CANCELLED; + param.ngApCause.group = Cause->present; + param.ngApCause.value = (int)Cause->choice.radioNetwork; + + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL, ¶m, + amf_nsmf_pdusession_build_update_sm_context); + } +} + +void ngap_handle_uplink_ran_status_transfer( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + amf_ue_t *amf_ue = NULL; + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_UplinkRANStatusTransfer_t *UplinkRANStatusTransfer = NULL; + + NGAP_UplinkRANStatusTransferIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_RANStatusTransfer_TransparentContainer_t + *RANStatusTransfer_TransparentContainer = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + UplinkRANStatusTransfer = + &initiatingMessage->value.choice.UplinkRANStatusTransfer; + ogs_assert(UplinkRANStatusTransfer); + + ogs_debug("Handover notify"); + + for (i = 0; i < UplinkRANStatusTransfer->protocolIEs.list.count; i++) { + ie = UplinkRANStatusTransfer->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer: + RANStatusTransfer_TransparentContainer = + &ie->value.choice.RANStatusTransfer_TransparentContainer; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + source_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!source_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, (uint32_t *)RAN_UE_NGAP_ID, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + target_ue = source_ue->target_ue; + if (!target_ue) { + ogs_error("Cannot find Source-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_inconsistent_remote_UE_NGAP_ID); + return; + } + amf_ue = source_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &source_ue->ran_ue_ngap_id, &source_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + + ngap_send_downlink_ran_status_transfer( + target_ue, RANStatusTransfer_TransparentContainer); +} + +void ngap_handle_handover_notification( + amf_gnb_t *gnb, ogs_ngap_message_t *message) +{ + char buf[OGS_ADDRSTRLEN]; + int i; + + amf_ue_t *amf_ue = NULL; + amf_sess_t *sess = NULL; + ran_ue_t *source_ue = NULL, *target_ue = NULL; + uint64_t amf_ue_ngap_id; + amf_nsmf_pdusession_update_sm_context_param_t param; + + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverNotify_t *HandoverNotify = NULL; + + NGAP_HandoverNotifyIEs_t *ie = NULL; + NGAP_RAN_UE_NGAP_ID_t *RAN_UE_NGAP_ID = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_UserLocationInformation_t *UserLocationInformation = NULL; + NGAP_UserLocationInformationNR_t *UserLocationInformationNR = NULL; + + ogs_assert(gnb); + ogs_assert(gnb->sctp.sock); + + ogs_assert(message); + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + HandoverNotify = &initiatingMessage->value.choice.HandoverNotify; + ogs_assert(HandoverNotify); + + ogs_debug("Handover notify"); + + for (i = 0; i < HandoverNotify->protocolIEs.list.count; i++) { + ie = HandoverNotify->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID: + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + case NGAP_ProtocolIE_ID_id_UserLocationInformation: + UserLocationInformation = &ie->value.choice.UserLocationInformation; + break; + default: + break; + } + } + + ogs_debug(" IP[%s] RAN_ID[%d]", + OGS_ADDR(gnb->sctp.addr, buf), gnb->gnb_id); + + if (!AMF_UE_NGAP_ID) { + ogs_error("No AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (asn_INTEGER2ulong(AMF_UE_NGAP_ID, + (unsigned long *)&amf_ue_ngap_id) != 0) { + ogs_error("Invalid AMF_UE_NGAP_ID"); + ngap_send_error_indication(gnb, (uint32_t *)RAN_UE_NGAP_ID, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + target_ue = ran_ue_find_by_amf_ue_ngap_id(amf_ue_ngap_id); + if (!target_ue) { + ogs_error("No RAN UE Context : AMF_UE_NGAP_ID[%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, (uint32_t *)RAN_UE_NGAP_ID, &amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + source_ue = target_ue->source_ue; + if (!source_ue) { + ogs_error("Cannot find Source-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_inconsistent_remote_UE_NGAP_ID); + return; + } + amf_ue = target_ue->amf_ue; + if (!amf_ue) { + ogs_error("Cannot find AMF-UE Context [%lld]", + (long long)amf_ue_ngap_id); + ngap_send_error_indication( + gnb, &target_ue->ran_ue_ngap_id, &target_ue->amf_ue_ngap_id, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_unknown_local_UE_NGAP_ID); + return; + } + + amf_ue_associate_ran_ue(amf_ue, target_ue); + + if (!UserLocationInformation) { + ogs_error("No UserLocationInformation"); + ngap_send_error_indication(gnb, &target_ue->ran_ue_ngap_id, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_semantic_error); + return; + } + + if (UserLocationInformation->present != + NGAP_UserLocationInformation_PR_userLocationInformationNR) { + ogs_error("Not implemented UserLocationInformation[%d]", + UserLocationInformation->present); + ngap_send_error_indication(gnb, &target_ue->ran_ue_ngap_id, NULL, + NGAP_Cause_PR_protocol, NGAP_CauseProtocol_unspecified); + return; + } + + UserLocationInformationNR = + UserLocationInformation->choice.userLocationInformationNR; + ogs_assert(UserLocationInformationNR); + ogs_ngap_ASN_to_nr_cgi( + &UserLocationInformationNR->nR_CGI, &target_ue->saved.nr_cgi); + ogs_ngap_ASN_to_5gs_tai( + &UserLocationInformationNR->tAI, &target_ue->saved.tai); + + ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + source_ue->ran_ue_ngap_id, (long long)source_ue->amf_ue_ngap_id); + ogs_debug(" Source : TAC[%d] CellID[0x%llx]", + source_ue->saved.tai.tac.v, (long long)source_ue->saved.nr_cgi.cell_id); + ogs_debug(" Target : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%lld] ", + target_ue->ran_ue_ngap_id, (long long)target_ue->amf_ue_ngap_id); + ogs_debug(" Target : TAC[%d] CellID[0x%llx]", + target_ue->saved.tai.tac.v, (long long)target_ue->saved.nr_cgi.cell_id); + + /* Copy Stream-No/TAI/ECGI from ran_ue */ + amf_ue->gnb_ostream_id = target_ue->gnb_ostream_id; + memcpy(&amf_ue->tai, &target_ue->saved.tai, sizeof(ogs_5gs_tai_t)); + memcpy(&amf_ue->nr_cgi, &target_ue->saved.nr_cgi, sizeof(ogs_nr_cgi_t)); + + ogs_list_for_each(&amf_ue->sess_list, sess) { + memset(¶m, 0, sizeof(param)); + param.hoState = OpenAPI_ho_state_COMPLETED; + + amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, + sess, AMF_UPDATE_SM_CONTEXT_HANDOVER_NOTIFY, ¶m, + amf_nsmf_pdusession_build_update_sm_context); + } +} + void ngap_handle_ng_reset( amf_gnb_t *gnb, ogs_ngap_message_t *message) { diff --git a/src/amf/ngap-handler.h b/src/amf/ngap-handler.h index 0ccd9161a..55bfb0687 100644 --- a/src/amf/ngap-handler.h +++ b/src/amf/ngap-handler.h @@ -57,6 +57,9 @@ void ngap_handle_ue_context_release_complete( amf_gnb_t *gnb, ogs_ngap_message_t *message); void ngap_handle_ue_context_release_action(ran_ue_t *ran_ue); +void ngap_handle_uplink_ran_configuration_transfer( + amf_gnb_t *gnb, ogs_ngap_message_t *message, ogs_pkbuf_t *pkbuf); + void ngap_handle_path_switch_request( amf_gnb_t *gnb, ogs_ngap_message_t *message); @@ -68,11 +71,8 @@ void ngap_handle_handover_failure( amf_gnb_t *gnb, ogs_ngap_message_t *message); void ngap_handle_handover_cancel( amf_gnb_t *gnb, ogs_ngap_message_t *message); - -void ngap_handle_gnb_status_transfer( +void ngap_handle_uplink_ran_status_transfer( amf_gnb_t *gnb, ogs_ngap_message_t *message); -void ngap_handle_gnb_configuration_transfer( - amf_gnb_t *gnb, ogs_ngap_message_t *message, ogs_pkbuf_t *pkbuf); void ngap_handle_handover_notification( amf_gnb_t *gnb, ogs_ngap_message_t *message); diff --git a/src/amf/ngap-path.c b/src/amf/ngap-path.c index 886731fab..612a2b554 100644 --- a/src/amf/ngap-path.c +++ b/src/amf/ngap-path.c @@ -269,7 +269,7 @@ void ngap_send_ue_context_modification_request(amf_ue_t *amf_ue) void ngap_send_ran_ue_context_release_command( ran_ue_t *ran_ue, NGAP_Cause_PR group, long cause, - uint8_t action, uint32_t delay) + uint8_t action, ogs_time_t duration) { int rv; ogs_pkbuf_t *ngapbuf = NULL; @@ -283,41 +283,34 @@ void ngap_send_ran_ue_context_release_command( ogs_assert(action != NGAP_UE_CTX_REL_INVALID_ACTION); ran_ue->ue_ctx_rel_action = action; - ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]", - group, (int)cause, action, delay); + ogs_debug(" Group[%d] Cause[%d] Action[%d] Duration[%d]", + group, (int)cause, action, (int)duration); ngapbuf = ngap_build_ue_context_release_command(ran_ue, group, cause); ogs_expect_or_return(ngapbuf); - rv = ngap_delayed_send_to_ran_ue(ran_ue, ngapbuf, delay); + rv = ngap_delayed_send_to_ran_ue(ran_ue, ngapbuf, duration); ogs_expect(rv == OGS_OK); - if (ran_ue->t_ng_holding) - ogs_timer_delete(ran_ue->t_ng_holding); - - ran_ue->t_ng_holding = ogs_timer_add( - ogs_app()->timer_mgr, amf_timer_ng_holding_timer_expire, ran_ue); - ogs_assert(ran_ue->t_ng_holding); - ogs_timer_start(ran_ue->t_ng_holding, amf_timer_cfg(AMF_TIMER_NG_HOLDING)->duration); } void ngap_send_amf_ue_context_release_command( amf_ue_t *amf_ue, NGAP_Cause_PR group, long cause, - uint8_t action, uint32_t delay) + uint8_t action, ogs_time_t duration) { ogs_assert(amf_ue); ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); if (ran_ue) { ngap_send_ran_ue_context_release_command(ran_ue, - group, cause, action, delay); + group, cause, action, duration); ogs_debug(" SUPI[%s]", amf_ue->supi); } else { ogs_error("[%s] No NG Context - " - "Group[%d] Cause[%d] Action[%d] Delay[%d]", - amf_ue->supi, group, (int)cause, action, delay); + "Group[%d] Cause[%d] Action[%d] Duration[%d]", + amf_ue->supi, group, (int)cause, action, (int)duration); } } @@ -392,26 +385,22 @@ void ngap_send_pdu_resource_setup_request( } } -#if 0 -void ngap_send_amf_configuration_transfer( - amf_gnb_t *target_gnb, - NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer) +void ngap_send_downlink_ran_configuration_transfer( + amf_gnb_t *target_gnb, NGAP_SONConfigurationTransfer_t *transfer) { int rv; ogs_pkbuf_t *ngapbuf = NULL; ogs_assert(target_gnb); - ogs_assert(SONConfigurationTransfer); + ogs_assert(transfer); - ngapbuf = ngap_build_amf_configuration_transfer(SONConfigurationTransfer); + ngapbuf = ngap_build_downlink_ran_configuration_transfer(transfer); ogs_expect_or_return(ngapbuf); rv = ngap_send_to_gnb(target_gnb, ngapbuf, NGAP_NON_UE_SIGNALLING); ogs_expect(rv == OGS_OK); } -#endif - void ngap_send_path_switch_ack(amf_sess_t *sess) { int rv; @@ -430,18 +419,23 @@ void ngap_send_path_switch_ack(amf_sess_t *sess) ogs_expect(rv == OGS_OK); } -#if 0 -void ngap_send_handover_command(ran_ue_t *source_ue) +void ngap_send_handover_request(amf_ue_t *amf_ue) { int rv; + + ran_ue_t *source_ue = NULL, *target_ue = NULL; ogs_pkbuf_t *ngapbuf = NULL; + ogs_assert(amf_ue); + source_ue = amf_ue->ran_ue; ogs_assert(source_ue); + target_ue = source_ue->target_ue; + ogs_assert(target_ue); - ngapbuf = ngap_build_handover_command(source_ue); + ngapbuf = ngap_build_handover_request(target_ue); ogs_expect_or_return(ngapbuf); - rv = ngap_send_to_ran_ue(source_ue, ngapbuf); + rv = ngap_send_to_ran_ue(target_ue, ngapbuf); ogs_expect(rv == OGS_OK); } @@ -461,6 +455,24 @@ void ngap_send_handover_preparation_failure( ogs_expect(rv == OGS_OK); } +void ngap_send_handover_command(amf_ue_t *amf_ue) +{ + int rv; + + ran_ue_t *source_ue = NULL; + ogs_pkbuf_t *ngapbuf = NULL; + + ogs_assert(amf_ue); + source_ue = amf_ue->ran_ue; + ogs_assert(source_ue); + + ngapbuf = ngap_build_handover_command(source_ue); + ogs_expect_or_return(ngapbuf); + + rv = ngap_send_to_ran_ue(source_ue, ngapbuf); + ogs_expect(rv == OGS_OK); +} + void ngap_send_handover_cancel_ack(ran_ue_t *source_ue) { int rv; @@ -475,69 +487,22 @@ void ngap_send_handover_cancel_ack(ran_ue_t *source_ue) ogs_expect(rv == OGS_OK); } - -void ngap_send_handover_request( - amf_ue_t *amf_ue, - amf_gnb_t *target_gnb, - NGAP_RAN_UE_NGAP_ID_t *ran_ue_ngap_id, - NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id, - NGAP_HandoverType_t *handovertype, - NGAP_Cause_t *cause, - NGAP_Source_ToTarget_TransparentContainer_t - *source_totarget_transparentContainer) -{ - int rv; - ogs_pkbuf_t *ngapbuf = NULL; - - ran_ue_t *source_ue = NULL, *target_ue = NULL; - - ogs_debug("[AMF] Handover request"); - - ogs_assert(target_gnb); - - ogs_assert(amf_ue); - source_ue = ran_ue_cycle(amf_ue->ran_ue); - ogs_assert(source_ue); - ogs_assert(source_ue->target_ue == NULL); - - target_ue = ran_ue_add(target_gnb, INVALID_UE_NGAP_ID); - ogs_assert(target_ue); - - ogs_debug(" Source : RAN_UE_NGAP_ID[%d] AMF_UE_NGAP_ID[%d]", - source_ue->ran_ue_ngap_id, source_ue->amf_ue_ngap_id); - ogs_debug(" Target : RAN_UE_NGAP_ID[Unknown] AMF_UE_NGAP_ID[%d]", - target_ue->amf_ue_ngap_id); - - source_ue_associate_target_ue(source_ue, target_ue); - - ngapbuf = ngap_build_handover_request(amf_ue, target_ue, - ran_ue_ngap_id, amf_ue_ngap_id, - handovertype, cause, - source_totarget_transparentContainer); - ogs_expect_or_return(ngapbuf); - - rv = ngap_send_to_ran_ue(target_ue, ngapbuf); - ogs_expect(rv == OGS_OK); -} - -void ngap_send_amf_status_transfer( +void ngap_send_downlink_ran_status_transfer( ran_ue_t *target_ue, - NGAP_RAN_StatusTransfer_TransparentContainer_t - *gnb_statustransfer_transparentContainer) + NGAP_RANStatusTransfer_TransparentContainer_t *transfer) { int rv; ogs_pkbuf_t *ngapbuf = NULL; ogs_assert(target_ue); + ogs_assert(transfer); - ngapbuf = ngap_build_amf_status_transfer(target_ue, - gnb_statustransfer_transparentContainer); + ngapbuf = ngap_build_uplink_ran_status_transfer(target_ue, transfer); ogs_expect_or_return(ngapbuf); rv = ngap_send_to_ran_ue(target_ue, ngapbuf); ogs_expect(rv == OGS_OK); } -#endif void ngap_send_error_indication( amf_gnb_t *gnb, diff --git a/src/amf/ngap-path.h b/src/amf/ngap-path.h index b25612fec..85208eb4e 100644 --- a/src/amf/ngap-path.h +++ b/src/amf/ngap-path.h @@ -55,41 +55,30 @@ void ngap_send_ue_context_modification_request(amf_ue_t *amf_ue); void ngap_send_ran_ue_context_release_command( ran_ue_t *ran_ue, NGAP_Cause_PR group, long cause, - uint8_t action, uint32_t delay); + uint8_t action, ogs_time_t delay); void ngap_send_amf_ue_context_release_command( amf_ue_t *amf_ue, NGAP_Cause_PR group, long cause, - uint8_t action, uint32_t delay); + uint8_t action, ogs_time_t delay); void ngap_send_paging(amf_ue_t *amf_ue); void ngap_send_pdu_resource_setup_request( amf_sess_t *sess, ogs_pkbuf_t *n2smbuf); -void ngap_send_amf_configuration_transfer( - amf_gnb_t *target_gnb, - NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer); +void ngap_send_downlink_ran_configuration_transfer( + amf_gnb_t *target_gnb, NGAP_SONConfigurationTransfer_t *transfer); void ngap_send_path_switch_ack(amf_sess_t *sess); -void ngap_send_handover_command(ran_ue_t *source_ue); +void ngap_send_handover_request(amf_ue_t *amf_ue); void ngap_send_handover_preparation_failure( ran_ue_t *source_ue, NGAP_Cause_t *cause); - -void ngap_send_handover_request( - amf_ue_t *amf_ue, - amf_gnb_t *target_gnb, - NGAP_RAN_UE_NGAP_ID_t *ran_ue_ngap_id, - NGAP_AMF_UE_NGAP_ID_t *amf_ue_ngap_id, - NGAP_HandoverType_t *handovertype, - NGAP_Cause_t *cause, - NGAP_SourceToTarget_TransparentContainer_t - *source_totarget_transparentContainer); - +void ngap_send_handover_command(amf_ue_t *amf_ue); void ngap_send_handover_cancel_ack(ran_ue_t *source_ue); -void ngap_send_amf_status_transfer( +void ngap_send_downlink_ran_status_transfer( ran_ue_t *target_ue, - NGAP_RANStatusTransfer_TransparentContainer_t - *gnb_statustransfer_transparentContainer); + NGAP_RANStatusTransfer_TransparentContainer_t *transfer); + void ngap_send_error_indication( amf_gnb_t *gnb, uint32_t *ran_ue_ngap_id, diff --git a/src/amf/ngap-sm.c b/src/amf/ngap-sm.c index 5e476ef48..ff927ae40 100644 --- a/src/amf/ngap-sm.c +++ b/src/amf/ngap-sm.c @@ -40,9 +40,7 @@ void ngap_state_final(ogs_fsm_t *s, amf_event_t *e) void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e) { amf_gnb_t *gnb = NULL; -#if 0 ogs_pkbuf_t *pkbuf = NULL; -#endif NGAP_NGAP_PDU_t *pdu = NULL; NGAP_InitiatingMessage_t *initiatingMessage = NULL; @@ -97,26 +95,24 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e) case NGAP_ProcedureCode_id_PathSwitchRequest: ngap_handle_path_switch_request(gnb, pdu); break; -#if 0 - case NGAP_ProcedureCode_id_eNBConfigurationTransfer: + case NGAP_ProcedureCode_id_UplinkRANConfigurationTransfer: pkbuf = e->pkbuf; ogs_assert(pkbuf); - ngap_handle_gnb_configuration_transfer(gnb, pdu, pkbuf); + ngap_handle_uplink_ran_configuration_transfer(gnb, pdu, pkbuf); break; case NGAP_ProcedureCode_id_HandoverPreparation: ngap_handle_handover_required(gnb, pdu); break; - case NGAP_ProcedureCode_id_HandoverCancel: - ngap_handle_handover_cancel(gnb, pdu); - break; - case NGAP_ProcedureCode_id_eNBStatusTransfer: - ngap_handle_gnb_status_transfer(gnb, pdu); + case NGAP_ProcedureCode_id_UplinkRANStatusTransfer: + ngap_handle_uplink_ran_status_transfer(gnb, pdu); break; case NGAP_ProcedureCode_id_HandoverNotification: ngap_handle_handover_notification(gnb, pdu); break; -#endif + case NGAP_ProcedureCode_id_HandoverCancel: + ngap_handle_handover_cancel(gnb, pdu); + break; case NGAP_ProcedureCode_id_NGReset: ngap_handle_ng_reset(gnb, pdu); break; @@ -151,11 +147,9 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e) case NGAP_ProcedureCode_id_UEContextRelease: ngap_handle_ue_context_release_complete(gnb, pdu); break; -#if 0 case NGAP_ProcedureCode_id_HandoverResourceAllocation: ngap_handle_handover_request_ack(gnb, pdu); break; -#endif default: ogs_error("Not implemented(choice:%d, proc:%d)", pdu->present, (int)successfulOutcome->procedureCode); @@ -174,10 +168,10 @@ void ngap_state_operational(ogs_fsm_t *s, amf_event_t *e) case NGAP_ProcedureCode_id_UEContextModification: ngap_handle_ue_context_modification_failure(gnb, pdu); break; +#endif case NGAP_ProcedureCode_id_HandoverResourceAllocation : ngap_handle_handover_failure(gnb, pdu); break; -#endif default: ogs_error("Not implemented(choice:%d, proc:%d)", pdu->present, (int)unsuccessfulOutcome->procedureCode); diff --git a/src/amf/nsmf-build.c b/src/amf/nsmf-build.c index 044690060..ab6e81f5a 100644 --- a/src/amf/nsmf-build.c +++ b/src/amf/nsmf-build.c @@ -19,7 +19,7 @@ #include "nsmf-build.h" -ogs_sbi_request_t *amf_nsmf_pdu_session_build_create_sm_context( +ogs_sbi_request_t *amf_nsmf_pdusession_build_create_sm_context( amf_sess_t *sess, void *data) { ogs_sbi_message_t message; @@ -157,10 +157,10 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_create_sm_context( return request; } -ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( +ogs_sbi_request_t *amf_nsmf_pdusession_build_update_sm_context( amf_sess_t *sess, void *data) { - amf_nsmf_pdu_session_update_sm_context_param_t *param = data; + amf_nsmf_pdusession_update_sm_context_param_t *param = data; ogs_sbi_message_t message; ogs_sbi_request_t *request = NULL; @@ -225,16 +225,28 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( if (param->upCnxState) { SmContextUpdateData.up_cnx_state = param->upCnxState; - if (param->ngApCause.group) { - SmContextUpdateData.ng_ap_cause = &ngApCause; - memset(&ngApCause, 0, sizeof(ngApCause)); - ngApCause.group = param->ngApCause.group; - ngApCause.value = param->ngApCause.value; + message.SmContextUpdateData = &SmContextUpdateData; + } + + if (param->hoState) { + SmContextUpdateData.ho_state = param->hoState; + + if (param->TargetID) { + SmContextUpdateData.target_id = + amf_nsmf_pdusession_build_target_id(param->TargetID); + ogs_assert(SmContextUpdateData.target_id); } message.SmContextUpdateData = &SmContextUpdateData; } + if (param->ngApCause.group) { + SmContextUpdateData.ng_ap_cause = &ngApCause; + memset(&ngApCause, 0, sizeof(ngApCause)); + ngApCause.group = param->ngApCause.group; + ngApCause.value = param->ngApCause.value; + } + memset(&ueLocation, 0, sizeof(ueLocation)); if (param->ue_location) { ueLocation.nr_location = ogs_sbi_build_nr_location( @@ -260,11 +272,14 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( } if (SmContextUpdateData.ue_time_zone) ogs_free(SmContextUpdateData.ue_time_zone); + if (SmContextUpdateData.target_id) + amf_nsmf_pdusession_free_target_id(SmContextUpdateData.target_id); + return request; } -ogs_sbi_request_t *amf_nsmf_pdu_session_build_release_sm_context( +ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context( amf_sess_t *sess, void *data) { ogs_sbi_message_t message; @@ -361,3 +376,109 @@ ogs_sbi_request_t *amf_nsmf_callback_build_n1_n2_failure_notify( return request; } + +OpenAPI_ng_ran_target_id_t *amf_nsmf_pdusession_build_target_id( + NGAP_TargetID_t *TargetID) +{ + ogs_plmn_id_t plmn_id; + ogs_5gs_tai_t nr_tai; + + NGAP_TargetRANNodeID_t *targetRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *globalRANNodeID = NULL; + NGAP_GlobalGNB_ID_t *globalGNB_ID = NULL; + + OpenAPI_ng_ran_target_id_t *targetId = NULL; + OpenAPI_global_ran_node_id_t *ranNodeId = NULL; + OpenAPI_g_nb_id_t *gNbId = NULL; + OpenAPI_tai_t *tai = NULL; + + ogs_assert(TargetID); + + if (TargetID->present != NGAP_TargetID_PR_targetRANNodeID) { + ogs_error("Not implemented TargetID[%d]", TargetID->present); + return NULL; + } + targetRANNodeID = TargetID->choice.targetRANNodeID; + if (!targetRANNodeID) { + ogs_error("No targetRANNodeID"); + return NULL; + } + + globalRANNodeID = &targetRANNodeID->globalRANNodeID; + if (globalRANNodeID->present != NGAP_GlobalRANNodeID_PR_globalGNB_ID) { + ogs_error("Not implemented globalRANNodeID[%d]", + globalRANNodeID->present); + return NULL; + } + + globalGNB_ID = globalRANNodeID->choice.globalGNB_ID; + if (!globalGNB_ID) { + ogs_error("No globalGNB_ID"); + return NULL; + } + + targetId = ogs_calloc(1, sizeof(*targetId)); + ogs_assert(targetId); + + targetId->ran_node_id = ranNodeId = ogs_calloc(1, sizeof(*ranNodeId));; + ogs_assert(ranNodeId); + + memcpy(&plmn_id, globalGNB_ID->pLMNIdentity.buf, OGS_PLMN_ID_LEN); + ranNodeId->plmn_id = ogs_sbi_build_plmn_id(&plmn_id); + ogs_assert(ranNodeId->plmn_id); + + ranNodeId->g_nb_id = gNbId = ogs_calloc(1, sizeof(*gNbId)); + ogs_assert(gNbId); + + gNbId->g_nb_value = ogs_calloc( + 1, OGS_KEYSTRLEN(globalGNB_ID->gNB_ID.choice.gNB_ID.size)); + ogs_assert(gNbId->g_nb_value); + ogs_hex_to_ascii( + globalGNB_ID->gNB_ID.choice.gNB_ID.buf, + globalGNB_ID->gNB_ID.choice.gNB_ID.size, + gNbId->g_nb_value, + OGS_KEYSTRLEN(globalGNB_ID->gNB_ID.choice.gNB_ID.size)); + gNbId->bit_length = 32 - globalGNB_ID->gNB_ID.choice.gNB_ID.bits_unused; + + targetId->tai = tai = ogs_calloc(1, sizeof(*tai));; + ogs_assert(tai); + + ogs_ngap_ASN_to_5gs_tai(&targetRANNodeID->selectedTAI, &nr_tai); + tai->plmn_id = ogs_sbi_build_plmn_id(&nr_tai.plmn_id); + ogs_assert(tai->plmn_id); + tai->tac = ogs_uint24_to_0string(nr_tai.tac); + ogs_assert(tai->tac); + + return targetId; +} + +void amf_nsmf_pdusession_free_target_id(OpenAPI_ng_ran_target_id_t *targetId) +{ + ogs_assert(targetId); + + if (targetId->ran_node_id) { + OpenAPI_global_ran_node_id_t *ranNodeId = targetId->ran_node_id; + OpenAPI_tai_t *tai = targetId->tai; + + if (ranNodeId) { + if (ranNodeId->plmn_id) + OpenAPI_plmn_id_free(ranNodeId->plmn_id); + if (ranNodeId->g_nb_id) { + OpenAPI_g_nb_id_t *gNbId = ranNodeId->g_nb_id; + if (gNbId->g_nb_value) + ogs_free(gNbId->g_nb_value); + ogs_free(gNbId); + } + ogs_free(ranNodeId); + } + + if (tai) { + if (tai->plmn_id) + OpenAPI_plmn_id_free(tai->plmn_id); + if (tai->tac) + ogs_free(tai->tac); + ogs_free(tai); + } + } + ogs_free(targetId); +} diff --git a/src/amf/nsmf-build.h b/src/amf/nsmf-build.h index e6f052adf..8fc261d83 100644 --- a/src/amf/nsmf-build.h +++ b/src/amf/nsmf-build.h @@ -26,7 +26,7 @@ extern "C" { #endif -typedef struct amf_nsmf_pdu_session_update_sm_context_param_s { +typedef struct amf_nsmf_pdusession_update_sm_context_param_s { ogs_pkbuf_t *n1smbuf; ogs_pkbuf_t *n2smbuf; OpenAPI_n2_sm_info_type_e n2SmInfoType; @@ -43,18 +43,27 @@ typedef struct amf_nsmf_pdu_session_update_sm_context_param_s { }; uint8_t indications; }; -} amf_nsmf_pdu_session_update_sm_context_param_t; -ogs_sbi_request_t *amf_nsmf_pdu_session_build_create_sm_context( + OpenAPI_ho_state_e hoState; + OpenAPI_ng_ran_target_id_t *targetId; + NGAP_TargetID_t *TargetID; +} amf_nsmf_pdusession_update_sm_context_param_t; + +ogs_sbi_request_t *amf_nsmf_pdusession_build_create_sm_context( amf_sess_t *sess, void *data); -ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( +ogs_sbi_request_t *amf_nsmf_pdusession_build_update_sm_context( amf_sess_t *sess, void *data); -ogs_sbi_request_t *amf_nsmf_pdu_session_build_release_sm_context( +ogs_sbi_request_t *amf_nsmf_pdusession_build_release_sm_context( amf_sess_t *sess, void *data); ogs_sbi_request_t *amf_nsmf_callback_build_n1_n2_failure_notify( amf_sess_t *sess, OpenAPI_n1_n2_message_transfer_cause_e cause); +OpenAPI_ng_ran_target_id_t *amf_nsmf_pdusession_build_target_id( + NGAP_TargetID_t *TargetID); + +void amf_nsmf_pdusession_free_target_id(OpenAPI_ng_ran_target_id_t *targetId); + #ifdef __cplusplus } #endif diff --git a/src/amf/nsmf-handler.c b/src/amf/nsmf-handler.c index 222bd17a4..341aeb418 100644 --- a/src/amf/nsmf-handler.c +++ b/src/amf/nsmf-handler.c @@ -24,7 +24,7 @@ #include "gmm-build.h" -int amf_nsmf_pdu_session_handle_create_sm_context( +int amf_nsmf_pdusession_handle_create_sm_context( amf_sess_t *sess, ogs_sbi_message_t *recvmsg) { int rv; @@ -142,7 +142,7 @@ int amf_nsmf_pdu_session_handle_create_sm_context( return OGS_OK; } -int amf_nsmf_pdu_session_handle_update_sm_context( +int amf_nsmf_pdusession_handle_update_sm_context( amf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg) { amf_ue_t *amf_ue = NULL; @@ -189,44 +189,46 @@ int amf_nsmf_pdu_session_handle_update_sm_context( return OGS_ERROR; } - /* - * To Deliver N2 SM Content to gNB Temporarily, - * Store N2 SM Context in Session Context - */ - AMF_SESS_STORE_N2_TRANSFER( - sess, pdu_session_resource_setup_request, - ogs_pkbuf_copy(n2smbuf)); + if (state == AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST) { + AMF_SESS_STORE_N2_TRANSFER( + sess, pdu_session_resource_setup_request, + ogs_pkbuf_copy(n2smbuf)); - switch(amf_ue->nas.message_type) { - case OGS_NAS_5GS_REGISTRATION_REQUEST: if (SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) && SESSION_SYNC_DONE(amf_ue, - AMF_UPDATE_SM_CONTEXT_ACTIVATING)) { + AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) { nas_5gs_send_registration_accept(amf_ue); - /* After sending accept message, - * N2 tranfer message is freed */ AMF_UE_CLEAR_N2_TRANSFER( amf_ue, pdu_session_resource_setup_request); } - break; - case OGS_NAS_5GS_SERVICE_REQUEST: + } else if (state == AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST) { + AMF_SESS_STORE_N2_TRANSFER( + sess, pdu_session_resource_setup_request, + ogs_pkbuf_copy(n2smbuf)); + if (SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && SESSION_SYNC_DONE(amf_ue, - AMF_UPDATE_SM_CONTEXT_ACTIVATING)) { + AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST)) { nas_5gs_send_service_accept(amf_ue); - /* After sending accept message, - * N2 tranfer message is freed */ AMF_UE_CLEAR_N2_TRANSFER( amf_ue, pdu_session_resource_setup_request); } - break; - default: - ogs_error("Unknown message type [%d]", - amf_ue->nas.message_type); + } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED) { + AMF_SESS_STORE_N2_TRANSFER( + sess, handover_request, ogs_pkbuf_copy(n2smbuf)); + + if (SESSION_SYNC_DONE(amf_ue, + AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED)) { + ngap_send_handover_request(amf_ue); + + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, handover_request); + } + } else { + ogs_error("Invalid STATE[%d]", state); ogs_assert_if_reached(); } break; @@ -271,10 +273,6 @@ int amf_nsmf_pdu_session_handle_update_sm_context( return OGS_ERROR; } - /* - * To Deliver N2 SM Content to gNB Temporarily, - * Store N2 SM Context in Session Context - */ AMF_SESS_STORE_N2_TRANSFER( sess, path_switch_request_ack, ogs_pkbuf_copy(n2smbuf)); @@ -282,11 +280,30 @@ int amf_nsmf_pdu_session_handle_update_sm_context( if (SESSION_SYNC_DONE(amf_ue, state)) { ngap_send_path_switch_ack(sess); - /* After sending ack message, N2 SM context is freed */ AMF_UE_CLEAR_N2_TRANSFER(amf_ue, path_switch_request_ack); } break; + case OpenAPI_n2_sm_info_type_HANDOVER_CMD: + if (!n2smbuf) { + ogs_error("[%s:%d] No N2 SM Content", + amf_ue->supi, sess->psi); + ngap_send_error_indication2(amf_ue, + NGAP_Cause_PR_protocol, + NGAP_CauseProtocol_semantic_error); + return OGS_ERROR; + } + + AMF_SESS_STORE_N2_TRANSFER( + sess, handover_command, ogs_pkbuf_copy(n2smbuf)); + + if (SESSION_SYNC_DONE(amf_ue, state)) { + ngap_send_handover_command(amf_ue); + + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, handover_command); + } + break; + default: ogs_error("Not implemented [%d]", SmContextUpdatedData->n2_sm_info_type); @@ -335,7 +352,12 @@ int amf_nsmf_pdu_session_handle_update_sm_context( NGAP_UE_CTX_REL_NG_REMOVE_AND_UNLINK, 0); } - } else if (state == AMF_UPDATE_SM_CONTEXT_ACTIVATING) { + } else if (state == AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST) { + + /* Not reached here */ + ogs_assert_if_reached(); + + } else if (state == AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST) { /* Not reached here */ ogs_assert_if_reached(); @@ -363,6 +385,56 @@ int amf_nsmf_pdu_session_handle_update_sm_context( sess->n1_released = true; + } else if (state == AMF_UPDATE_SM_CONTEXT_PATH_SWITCH_REQUEST) { + + /* Not reached here */ + ogs_assert_if_reached(); + + } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED) { + + /* Not reached here */ + ogs_assert_if_reached(); + + } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_REQ_ACK) { + + /* Not reached here */ + ogs_assert_if_reached(); + + } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL) { + + if (SESSION_SYNC_DONE(amf_ue, state)) { + ran_ue_t *source_ue = NULL, *target_ue = NULL; + + source_ue = amf_ue->ran_ue; + ogs_assert(source_ue); + target_ue = source_ue->target_ue; + ogs_assert(target_ue); + + ngap_send_handover_cancel_ack(source_ue); + + ngap_send_ran_ue_context_release_command(target_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_handover_cancelled, + NGAP_UE_CTX_REL_NG_HANDOVER_COMPLETE, + ogs_time_from_msec(300)); + } + + } else if (state == AMF_UPDATE_SM_CONTEXT_HANDOVER_NOTIFY) { + if (SESSION_SYNC_DONE(amf_ue, state)) { + ran_ue_t *target_ue = NULL, *source_ue = NULL; + + target_ue = amf_ue->ran_ue; + ogs_assert(target_ue); + source_ue = target_ue->source_ue; + ogs_assert(source_ue); + + ngap_send_ran_ue_context_release_command(source_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_successful_handover, + NGAP_UE_CTX_REL_NG_HANDOVER_COMPLETE, + ogs_time_from_msec(300)); + } + } else if (state == AMF_REMOVE_S1_CONTEXT_BY_LO_CONNREFUSED) { if (SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); @@ -406,20 +478,21 @@ int amf_nsmf_pdu_session_handle_update_sm_context( } else { ogs_error("Invalid STATE[%d]", state); + ogs_assert_if_reached(); } /* * If resource-status has already been updated by * notify(/namf-callback/v1/{supi}/sm-context-status/{psi}) * Remove 'amf_sess_t' context to call - * amf_nsmf_pdu_session_handle_release_sm_context(). + * amf_nsmf_pdusession_handle_release_sm_context(). */ if (sess->n1_released == true && sess->n2_released == true && sess->resource_status == OpenAPI_resource_status_RELEASED) { ogs_debug("[%s:%d] SM context remove", amf_ue->supi, sess->psi); - amf_nsmf_pdu_session_handle_release_sm_context( + amf_nsmf_pdusession_handle_release_sm_context( sess, AMF_SESS_SM_CONTEXT_NO_STATE); } } @@ -499,7 +572,7 @@ int amf_nsmf_pdu_session_handle_update_sm_context( return OGS_OK; } -int amf_nsmf_pdu_session_handle_release_sm_context(amf_sess_t *sess, int state) +int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state) { amf_ue_t *amf_ue = NULL; @@ -515,9 +588,10 @@ int amf_nsmf_pdu_session_handle_release_sm_context(amf_sess_t *sess, int state) * 2. Release All SM contexts * 3. Registration accept */ - if (SESSION_SYNC_DONE(amf_ue, - AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) && - SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_ACTIVATING)) + if (SESSION_SYNC_DONE( + amf_ue, AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) && + SESSION_SYNC_DONE( + amf_ue, AMF_UPDATE_SM_CONTEXT_REGISTRATION_REQUEST)) nas_5gs_send_registration_accept(amf_ue); } else if (state == AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) { @@ -527,7 +601,7 @@ int amf_nsmf_pdu_session_handle_release_sm_context(amf_sess_t *sess, int state) * 3. Service accept */ if (SESSION_SYNC_DONE(amf_ue, AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && - SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_ACTIVATING)) + SESSION_SYNC_DONE(amf_ue, AMF_UPDATE_SM_CONTEXT_SERVICE_REQUEST)) nas_5gs_send_service_accept(amf_ue); } else { diff --git a/src/amf/nsmf-handler.h b/src/amf/nsmf-handler.h index 1a15c1517..16810f598 100644 --- a/src/amf/nsmf-handler.h +++ b/src/amf/nsmf-handler.h @@ -26,11 +26,11 @@ extern "C" { #include "context.h" -int amf_nsmf_pdu_session_handle_create_sm_context( +int amf_nsmf_pdusession_handle_create_sm_context( amf_sess_t *sess, ogs_sbi_message_t *message); -int amf_nsmf_pdu_session_handle_update_sm_context( +int amf_nsmf_pdusession_handle_update_sm_context( amf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg); -int amf_nsmf_pdu_session_handle_release_sm_context(amf_sess_t *sess, int state); +int amf_nsmf_pdusession_handle_release_sm_context(amf_sess_t *sess, int state); #ifdef __cplusplus } diff --git a/src/amf/sbi-path.c b/src/amf/sbi-path.c index c55ea630f..403752c4d 100644 --- a/src/amf/sbi-path.c +++ b/src/amf/sbi-path.c @@ -167,9 +167,9 @@ void amf_sess_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, } } -void amf_sbi_send_activating_session(amf_sess_t *sess) +void amf_sbi_send_activating_session(amf_sess_t *sess, int state) { - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; ogs_assert(sess); @@ -177,14 +177,14 @@ void amf_sbi_send_activating_session(amf_sess_t *sess) param.upCnxState = OpenAPI_up_cnx_state_ACTIVATING; amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, - sess, AMF_UPDATE_SM_CONTEXT_ACTIVATING, ¶m, - amf_nsmf_pdu_session_build_update_sm_context); + sess, state, ¶m, + amf_nsmf_pdusession_build_update_sm_context); } void amf_sbi_send_deactivate_session( amf_sess_t *sess, int state, int group, int cause) { - amf_nsmf_pdu_session_update_sm_context_param_t param; + amf_nsmf_pdusession_update_sm_context_param_t param; ogs_assert(sess); @@ -196,7 +196,7 @@ void amf_sbi_send_deactivate_session( param.ue_timezone = true; amf_sess_sbi_discover_and_send(OpenAPI_nf_type_SMF, - sess, state, ¶m, amf_nsmf_pdu_session_build_update_sm_context); + sess, state, ¶m, amf_nsmf_pdusession_build_update_sm_context); } void amf_sbi_send_deactivate_all_sessions( @@ -258,7 +258,7 @@ void amf_sbi_send_release_session(amf_sess_t *sess, int state) amf_sess_sbi_discover_and_send( OpenAPI_nf_type_SMF, sess, state, NULL, - amf_nsmf_pdu_session_build_release_sm_context); + amf_nsmf_pdusession_build_release_sm_context); /* Prevent to invoke SMF for this session */ CLEAR_SM_CONTEXT_REF(sess); diff --git a/src/amf/sbi-path.h b/src/amf/sbi-path.h index 4ffed24fb..6881490f8 100644 --- a/src/amf/sbi-path.h +++ b/src/amf/sbi-path.h @@ -38,23 +38,29 @@ void amf_ue_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, ogs_sbi_request_t *(*build)(amf_ue_t *amf_ue, void *data)); #define AMF_SESS_SM_CONTEXT_NO_STATE 0 -#define AMF_UPDATE_SM_CONTEXT_ACTIVATED 1 -#define AMF_UPDATE_SM_CONTEXT_DEACTIVATED 2 -#define AMF_UPDATE_SM_CONTEXT_ACTIVATING 3 -#define AMF_UPDATE_SM_CONTEXT_MODIFIED 4 -#define AMF_UPDATE_SM_CONTEXT_N2_RELEASED 5 -#define AMF_UPDATE_SM_CONTEXT_N1_RELEASED 6 -#define AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE 7 -#define AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT 8 -#define AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT 9 -#define AMF_REMOVE_S1_CONTEXT_BY_LO_CONNREFUSED 10 -#define AMF_REMOVE_S1_CONTEXT_BY_RESET_ALL 11 -#define AMF_REMOVE_S1_CONTEXT_BY_RESET_PARTIAL 12 +#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_PATH_SWITCH_REQUEST 18 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQUIRED 19 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_REQ_ACK 20 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_NOTIFY 21 +#define AMF_UPDATE_SM_CONTEXT_HANDOVER_CANCEL 22 +#define AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE 31 +#define AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT 32 +#define AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT 33 +#define AMF_REMOVE_S1_CONTEXT_BY_LO_CONNREFUSED 51 +#define AMF_REMOVE_S1_CONTEXT_BY_RESET_ALL 52 +#define AMF_REMOVE_S1_CONTEXT_BY_RESET_PARTIAL 53 void amf_sess_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, amf_sess_t *sess, int state, void *data, ogs_sbi_request_t *(*build)(amf_sess_t *sess, void *data)); -void amf_sbi_send_activating_session(amf_sess_t *sess); +void amf_sbi_send_activating_session(amf_sess_t *sess, int state); void amf_sbi_send_deactivate_session( amf_sess_t *sess, int state, int group, int cause); diff --git a/src/mme/mme-context.c b/src/mme/mme-context.c index ea39eccae..451994def 100644 --- a/src/mme/mme-context.c +++ b/src/mme/mme-context.c @@ -2027,6 +2027,10 @@ enb_ue_t *enb_ue_add(mme_enb_t *enb, uint32_t enb_ue_s1ap_id) enb_ue->enb_ostream_id = OGS_NEXT_ID(enb->ostream_id, 1, enb->max_num_of_ostreams-1); + enb_ue->t_s1_holding = ogs_timer_add( + ogs_app()->timer_mgr, mme_timer_s1_holding_timer_expire, enb_ue); + ogs_assert(enb_ue->t_s1_holding); + enb_ue->enb = enb; ogs_list_add(&enb->enb_ue_list, enb_ue); @@ -2046,8 +2050,8 @@ void enb_ue_remove(enb_ue_t *enb_ue) ogs_list_remove(&enb->enb_ue_list, enb_ue); - if (enb_ue->t_s1_holding) - ogs_timer_delete(enb_ue->t_s1_holding); + ogs_assert(enb_ue->t_s1_holding); + ogs_timer_delete(enb_ue->t_s1_holding); ogs_pool_free(&enb_ue_pool, enb_ue); diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index eddd43f2c..115e3b915 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -262,7 +262,7 @@ struct enb_ue_s { #define S1AP_UE_CTX_REL_S1_CONTEXT_REMOVE 1 #define S1AP_UE_CTX_REL_S1_REMOVE_AND_UNLINK 2 #define S1AP_UE_CTX_REL_UE_CONTEXT_REMOVE 3 -#define S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL 4 +#define S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE 4 #define S1AP_UE_CTX_REL_S1_PAGING 5 uint8_t ue_ctx_rel_action; diff --git a/src/mme/mme-s11-handler.c b/src/mme/mme-s11-handler.c index bb99718bf..9226174de 100644 --- a/src/mme/mme-s11-handler.c +++ b/src/mme/mme-s11-handler.c @@ -304,7 +304,7 @@ void mme_s11_handle_modify_bearer_response( s1ap_send_ue_context_release_command(source_ue, S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_successful_handover, - S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, + S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE, ogs_time_from_msec(300)); ); } diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index 426911eef..a138cf5eb 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -1782,13 +1782,9 @@ ogs_pkbuf_t *s1ap_build_handover_preparation_failure( } ogs_pkbuf_t *s1ap_build_handover_request( - mme_ue_t *mme_ue, enb_ue_t *target_ue, - S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id, - S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id, - S1AP_HandoverType_t *handovertype, - S1AP_Cause_t *cause, - S1AP_Source_ToTarget_TransparentContainer_t - *source_totarget_transparentContainer) + enb_ue_t *target_ue, S1AP_HandoverType_t *handovertype, S1AP_Cause_t *cause, + S1AP_Source_ToTarget_TransparentContainer_t + *source_totarget_transparentContainer) { int rv; @@ -1807,6 +1803,7 @@ ogs_pkbuf_t *s1ap_build_handover_request( S1AP_UESecurityCapabilities_t *UESecurityCapabilities = NULL; S1AP_SecurityContext_t *SecurityContext = NULL; + mme_ue_t *mme_ue = NULL; mme_sess_t *sess = NULL; mme_bearer_t *bearer = NULL; ogs_subscription_data_t *subscription_data = NULL; @@ -1816,6 +1813,7 @@ ogs_pkbuf_t *s1ap_build_handover_request( ogs_assert(source_totarget_transparentContainer); ogs_assert(target_ue); + mme_ue = target_ue->mme_ue; ogs_assert(mme_ue); subscription_data = &mme_ue->subscription_data; ogs_assert(subscription_data); @@ -1985,8 +1983,8 @@ ogs_pkbuf_t *s1ap_build_handover_request( } ogs_s1ap_buffer_to_OCTET_STRING( - source_totarget_transparentContainer->buf, - source_totarget_transparentContainer->size, + source_totarget_transparentContainer->buf, + source_totarget_transparentContainer->size, Source_ToTarget_TransparentContainer); UESecurityCapabilities->encryptionAlgorithms.size = 2; diff --git a/src/mme/s1ap-build.h b/src/mme/s1ap-build.h index 28c81273a..fc55463dd 100644 --- a/src/mme/s1ap-build.h +++ b/src/mme/s1ap-build.h @@ -64,11 +64,7 @@ ogs_pkbuf_t *s1ap_build_handover_preparation_failure( enb_ue_t *source_ue, S1AP_Cause_t *cause); ogs_pkbuf_t *s1ap_build_handover_request( - mme_ue_t *mme_ue, enb_ue_t *target_ue, - S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id, - S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id, - S1AP_HandoverType_t *handovertype, - S1AP_Cause_t *cause, + enb_ue_t *target_ue, S1AP_HandoverType_t *handovertype, S1AP_Cause_t *cause, S1AP_Source_ToTarget_TransparentContainer_t *source_totarget_transparentContainer); diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index 8dbbc4d2b..3f620a238 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -1253,8 +1253,8 @@ void s1ap_handle_ue_context_release_action(enb_ue_t *enb_ue) ogs_expect_or_return(mme_ue); mme_ue_remove(mme_ue); break; - case S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL: - ogs_debug(" Action: Delete indirect tunnel"); + case S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE: + ogs_debug(" Action: S1 handover complete"); source_ue_deassociate_target_ue(enb_ue); enb_ue_remove(enb_ue); @@ -1556,15 +1556,15 @@ void s1ap_handle_enb_configuration_transfer( target_tac = be16toh(target_tac); ogs_debug(" Source : ENB_ID[%s:%d], TAC[%d]", - sourceeNB_ID->global_ENB_ID.eNB_ID.present == - S1AP_ENB_ID_PR_homeENB_ID ? "Home" : - sourceeNB_ID->global_ENB_ID.eNB_ID.present == + sourceeNB_ID->global_ENB_ID.eNB_ID.present == + S1AP_ENB_ID_PR_homeENB_ID ? "Home" : + sourceeNB_ID->global_ENB_ID.eNB_ID.present == S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others", source_enb_id, source_tac); ogs_debug(" Target : ENB_ID[%s:%d], TAC[%d]", - targeteNB_ID->global_ENB_ID.eNB_ID.present == - S1AP_ENB_ID_PR_homeENB_ID ? "Home" : - targeteNB_ID->global_ENB_ID.eNB_ID.present == + targeteNB_ID->global_ENB_ID.eNB_ID.present == + S1AP_ENB_ID_PR_homeENB_ID ? "Home" : + targeteNB_ID->global_ENB_ID.eNB_ID.present == S1AP_ENB_ID_PR_macroENB_ID ? "Macro" : "Others", target_enb_id, target_tac); @@ -1687,9 +1687,8 @@ void s1ap_handle_handover_required(mme_enb_t *enb, ogs_s1ap_message_t *message) ogs_assert(HandoverType); source_ue->handover_type = *HandoverType; - s1ap_send_handover_request(mme_ue, target_enb, - ENB_UE_S1AP_ID, MME_UE_S1AP_ID, - HandoverType, Cause, + s1ap_send_handover_request( + source_ue, target_enb, HandoverType, Cause, Source_ToTarget_TransparentContainer); } @@ -1885,7 +1884,7 @@ void s1ap_handle_handover_failure(mme_enb_t *enb, ogs_s1ap_message_t *message) s1ap_send_ue_context_release_command( target_ue, S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system, - S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, 0); + S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE, 0); } void s1ap_handle_handover_cancel(mme_enb_t *enb, ogs_s1ap_message_t *message) @@ -1954,7 +1953,7 @@ void s1ap_handle_handover_cancel(mme_enb_t *enb, ogs_s1ap_message_t *message) s1ap_send_ue_context_release_command( target_ue, S1AP_Cause_PR_radioNetwork, S1AP_CauseRadioNetwork_handover_cancelled, - S1AP_UE_CTX_REL_DELETE_INDIRECT_TUNNEL, + S1AP_UE_CTX_REL_S1_HANDOVER_COMPLETE, ogs_time_from_msec(300)); ogs_debug("Handover Cancel : " diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 4bbc63083..35965b0ed 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -284,7 +284,7 @@ void s1ap_send_ue_context_modification_request(mme_ue_t *mme_ue) void s1ap_send_ue_context_release_command( enb_ue_t *enb_ue, S1AP_Cause_PR group, long cause, - uint8_t action, uint32_t delay) + uint8_t action, ogs_time_t duration) { int rv; ogs_pkbuf_t *s1apbuf = NULL; @@ -298,22 +298,15 @@ void s1ap_send_ue_context_release_command( ogs_assert(action != S1AP_UE_CTX_REL_INVALID_ACTION); enb_ue->ue_ctx_rel_action = action; - ogs_debug(" Group[%d] Cause[%d] Action[%d] Delay[%d]", - group, (int)cause, action, delay); + ogs_debug(" Group[%d] Cause[%d] Action[%d] Duration[%d]", + group, (int)cause, action, (int)duration); s1apbuf = s1ap_build_ue_context_release_command(enb_ue, group, cause); ogs_expect_or_return(s1apbuf); - rv = s1ap_delayed_send_to_enb_ue(enb_ue, s1apbuf, delay); + rv = s1ap_delayed_send_to_enb_ue(enb_ue, s1apbuf, duration); ogs_expect(rv == OGS_OK); - if (enb_ue->t_s1_holding) - ogs_timer_delete(enb_ue->t_s1_holding); - - enb_ue->t_s1_holding = ogs_timer_add( - ogs_app()->timer_mgr, mme_timer_s1_holding_timer_expire, enb_ue); - ogs_assert(enb_ue->t_s1_holding); - ogs_timer_start(enb_ue->t_s1_holding, mme_timer_cfg(MME_TIMER_S1_HOLDING)->duration); } @@ -430,28 +423,21 @@ void s1ap_send_handover_cancel_ack(enb_ue_t *source_ue) void s1ap_send_handover_request( - mme_ue_t *mme_ue, - mme_enb_t *target_enb, - S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id, - S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id, - S1AP_HandoverType_t *handovertype, - S1AP_Cause_t *cause, + enb_ue_t *source_ue, mme_enb_t *target_enb, + S1AP_HandoverType_t *handovertype, S1AP_Cause_t *cause, S1AP_Source_ToTarget_TransparentContainer_t *source_totarget_transparentContainer) { int rv; ogs_pkbuf_t *s1apbuf = NULL; - enb_ue_t *source_ue = NULL, *target_ue = NULL; + enb_ue_t *target_ue = NULL; ogs_info("Handover request"); - ogs_assert(target_enb); - - ogs_assert(mme_ue); - source_ue = enb_ue_cycle(mme_ue->enb_ue); ogs_assert(source_ue); ogs_assert(source_ue->target_ue == NULL); + ogs_assert(target_enb); target_ue = enb_ue_add(target_enb, INVALID_UE_S1AP_ID); ogs_assert(target_ue); @@ -463,9 +449,8 @@ void s1ap_send_handover_request( source_ue_associate_target_ue(source_ue, target_ue); - s1apbuf = s1ap_build_handover_request(mme_ue, target_ue, - enb_ue_s1ap_id, mme_ue_s1ap_id, - handovertype, cause, + s1apbuf = s1ap_build_handover_request( + target_ue, handovertype, cause, source_totarget_transparentContainer); ogs_expect_or_return(s1apbuf); diff --git a/src/mme/s1ap-path.h b/src/mme/s1ap-path.h index 17c80c4a7..74dbce990 100644 --- a/src/mme/s1ap-path.h +++ b/src/mme/s1ap-path.h @@ -54,7 +54,7 @@ void s1ap_send_initial_context_setup_request(mme_ue_t *mme_ue); void s1ap_send_ue_context_modification_request(mme_ue_t *mme_ue); void s1ap_send_ue_context_release_command( enb_ue_t *enb_ue, S1AP_Cause_PR group, long cause, - uint8_t action, uint32_t delay); + uint8_t action, ogs_time_t duration); void s1ap_send_paging(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain); @@ -69,12 +69,8 @@ void s1ap_send_handover_preparation_failure( enb_ue_t *source_ue, S1AP_Cause_t *cause); void s1ap_send_handover_request( - mme_ue_t *mme_ue, - mme_enb_t *target_enb, - S1AP_ENB_UE_S1AP_ID_t *enb_ue_s1ap_id, - S1AP_MME_UE_S1AP_ID_t *mme_ue_s1ap_id, - S1AP_HandoverType_t *handovertype, - S1AP_Cause_t *cause, + enb_ue_t *source_ue, mme_enb_t *target_enb, + S1AP_HandoverType_t *handovertype, S1AP_Cause_t *cause, S1AP_Source_ToTarget_TransparentContainer_t *source_totarget_transparentContainer); diff --git a/src/smf/context.h b/src/smf/context.h index 39cc46f01..ee6c548ad 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -302,6 +302,13 @@ typedef struct smf_sess_s { int pdu_session_resource_release; } ngap_state; + /* Handover */ + struct { + bool prepared; + uint32_t gnb_n3_teid; + ogs_ip_t gnb_n3_ip; + } handover; /* Saved from N2-Handover Request Acknowledge */ + ogs_list_t bearer_list; ogs_gtp_node_t *gnode; diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index f192cead5..2a8119b61 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -329,8 +329,25 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) break; case OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ: - rv = ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( - sess, stream, pkbuf); + rv = ngap_handle_path_switch_request_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_HANDOVER_REQUIRED: + rv = ngap_handle_handover_required_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_HANDOVER_REQ_ACK: + rv = ngap_handle_handover_request_ack(sess, stream, pkbuf); if (rv != OGS_OK) { ogs_error("[%s:%d] Cannot handle NGAP message", smf_ue->supi, sess->psi); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index a88846a99..ab370747d 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -195,7 +195,7 @@ void smf_5gc_n4_handle_session_establishment_response( param.n1smbuf = gsm_build_pdu_session_establishment_accept(sess); ogs_assert(param.n1smbuf); param.n2smbuf = ngap_build_pdu_session_resource_setup_request_transfer( - sess); + sess); ogs_assert(param.n2smbuf); smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); @@ -299,13 +299,18 @@ void smf_5gc_n4_handle_session_modification_response( } if (flags & OGS_PFCP_MODIFY_ACTIVATE) { - if (flags & OGS_PFCP_MODIFY_PATH_SWITCH) { + if (flags & OGS_PFCP_MODIFY_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); + } else if (flags & OGS_PFCP_MODIFY_N2_HANDOVER) { + + smf_sbi_send_sm_context_updated_data_ho_state( + sess, stream, OpenAPI_ho_state_COMPLETED); + } else { sess->paging.ue_requested_pdu_session_establishment_done = true; smf_sbi_send_http_status_no_content(stream); @@ -778,7 +783,8 @@ void smf_n4_handle_session_report_request( memset(¶m, 0, sizeof(param)); param.state = SMF_NETWORK_TRIGGERED_SERVICE_REQUEST; param.n2smbuf = - ngap_build_pdu_session_resource_setup_request_transfer(sess); + ngap_build_pdu_session_resource_setup_request_transfer( + sess); ogs_assert(param.n2smbuf); param.n1n2_failure_txf_notif_uri = true; diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index 13c38cb46..fd45f284e 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -303,14 +303,14 @@ ogs_pkbuf_t *ngap_build_path_switch_request_ack_transfer(smf_sess_t *sess) { NGAP_PathSwitchRequestAcknowledgeTransfer_t message; -#if 0 +#if 0 /* The following is optional. So I've removed */ ogs_ip_t upf_n3_ip; NGAP_UPTransportLayerInformation_t *UPTransportLayerInformation = NULL; NGAP_GTPTunnel_t *gTPTunnel = NULL; +#endif ogs_assert(sess); -#endif ogs_debug("PathSwitchRequestAcknowledgeTransfer"); memset(&message, 0, sizeof(NGAP_PathSwitchRequestAcknowledgeTransfer_t)); @@ -334,3 +334,39 @@ ogs_pkbuf_t *ngap_build_path_switch_request_ack_transfer(smf_sess_t *sess) return ogs_asn_encode( &asn_DEF_NGAP_PathSwitchRequestAcknowledgeTransfer, &message); } + +ogs_pkbuf_t *ngap_build_handover_command_transfer(smf_sess_t *sess) +{ + NGAP_HandoverCommandTransfer_t message; + +#if 0 /* The following is optional. So I've removed */ + ogs_ip_t upf_n3_ip; + + NGAP_UPTransportLayerInformation_t *dLForwardingUP_TNLInformation = NULL; + NGAP_GTPTunnel_t *gTPTunnel = NULL; +#endif + + ogs_assert(sess); + + ogs_debug("HandoverCommandTransfer"); + memset(&message, 0, sizeof(NGAP_HandoverCommandTransfer_t)); + +#if 0 /* The following is optional. So I've removed */ + message.dLForwardingUP_TNLInformation = dLForwardingUP_TNLInformation = + CALLOC(1, sizeof(*dLForwardingUP_TNLInformation)); + ogs_assert(dLForwardingUP_TNLInformation); + + dLForwardingUP_TNLInformation->present = + NGAP_UPTransportLayerInformation_PR_gTPTunnel; + dLForwardingUP_TNLInformation->choice.gTPTunnel = gTPTunnel = + CALLOC(1, sizeof(*gTPTunnel)); + ogs_assert(gTPTunnel); + + ogs_sockaddr_to_ip(sess->upf_n3_addr, sess->upf_n3_addr6, &upf_n3_ip); + ogs_asn_ip_to_BIT_STRING(&upf_n3_ip, &gTPTunnel->transportLayerAddress); + ogs_asn_uint32_to_OCTET_STRING(sess->upf_n3_teid, &gTPTunnel->gTP_TEID); +#endif + + return ogs_asn_encode( + &asn_DEF_NGAP_HandoverCommandTransfer, &message); +} diff --git a/src/smf/ngap-build.h b/src/smf/ngap-build.h index 791c02c94..a9cd7821f 100644 --- a/src/smf/ngap-build.h +++ b/src/smf/ngap-build.h @@ -37,6 +37,8 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command_transfer( ogs_pkbuf_t *ngap_build_path_switch_request_ack_transfer(smf_sess_t *sess); +ogs_pkbuf_t *ngap_build_handover_command_transfer(smf_sess_t *sess); + #ifdef __cplusplus } #endif diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index 71d9c3f71..dd599ffe6 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -20,6 +20,7 @@ #include "ngap-handler.h" #include "sbi-path.h" #include "pfcp-path.h" +#include "ngap-path.h" int ngap_handle_pdu_session_resource_setup_response_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) @@ -230,7 +231,7 @@ cleanup: return rv; } -int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( +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; @@ -246,6 +247,7 @@ int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( NGAP_PathSwitchRequestTransfer_t message; NGAP_UPTransportLayerInformation_t *dL_NGU_UP_TNLInformation = NULL; + NGAP_QosFlowAcceptedItem_t *acceptedQosFlowItem = NULL; NGAP_GTPTunnel_t *gTPTunnel = NULL; NGAP_QosFlowAcceptedList_t *qosFlowAcceptedList = NULL; @@ -274,11 +276,11 @@ int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( if (dL_NGU_UP_TNLInformation->present != NGAP_UPTransportLayerInformation_PR_gTPTunnel) { ogs_error( - "[%s:%d] Unknown NGAP_UPTransportLayerInformation.present [%d]", + "[%s:%d] Unknown dL_NGU_UP_TNLInformation->present [%d]", smf_ue->supi, sess->psi, dL_NGU_UP_TNLInformation->present); smf_sbi_send_sm_context_update_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, - "Unknown NGAP_UPTransportLayerInformation.present", + "Unknown dL_NGU_UP_TNLInformation->present", smf_ue->supi, NULL, NULL); goto cleanup; } @@ -306,7 +308,6 @@ int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( qosFlowAcceptedList = &message.qosFlowAcceptedList; for (i = 0; i < qosFlowAcceptedList->list.count; i++) { - NGAP_QosFlowAcceptedItem_t *acceptedQosFlowItem = NULL; acceptedQosFlowItem = (NGAP_QosFlowAcceptedItem_t *) qosFlowAcceptedList->list.array[i]; if (acceptedQosFlowItem) { @@ -339,7 +340,7 @@ int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( if (far_update) { smf_5gc_pfcp_send_session_modification_request( sess, stream, - OGS_PFCP_MODIFY_ACTIVATE | OGS_PFCP_MODIFY_PATH_SWITCH | + OGS_PFCP_MODIFY_ACTIVATE | OGS_PFCP_MODIFY_XN_HANDOVER | OGS_PFCP_MODIFY_END_MARKER); } else { /* ACTIVATED Is NOT Included in RESPONSE */ @@ -352,3 +353,150 @@ cleanup: ogs_asn_free(&asn_DEF_NGAP_PathSwitchRequestTransfer, &message); return rv; } + +int ngap_handle_handover_required_transfer( + smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf) +{ + smf_ue_t *smf_ue = NULL; + int rv; + + NGAP_HandoverRequiredTransfer_t message; + + ogs_pkbuf_t *n2smbuf = NULL; + + ogs_assert(pkbuf); + ogs_assert(stream); + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + rv = ogs_asn_decode(&asn_DEF_NGAP_HandoverRequiredTransfer, + &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; + } + + n2smbuf = ngap_build_pdu_session_resource_setup_request_transfer(sess); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data( + sess, stream, 0, OpenAPI_ho_state_PREPARING, + NULL, OpenAPI_n2_sm_info_type_PDU_RES_SETUP_REQ, n2smbuf); + + rv = OGS_OK; + +cleanup: + ogs_asn_free(&asn_DEF_NGAP_HandoverRequiredTransfer, &message); + return rv; +} + +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; + + ogs_pfcp_far_t *dl_far = NULL; + + NGAP_HandoverRequestAcknowledgeTransfer_t message; + + NGAP_UPTransportLayerInformation_t *dL_NGU_UP_TNLInformation = NULL; + NGAP_QosFlowListWithDataForwarding_t *qosFlowSetupResponseList = NULL; + NGAP_QosFlowItemWithDataForwarding_t *qosFlowSetupResponseItem = NULL; + NGAP_GTPTunnel_t *gTPTunnel = NULL; + + ogs_pkbuf_t *n2smbuf = NULL; + + ogs_assert(pkbuf); + ogs_assert(stream); + + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); + + rv = ogs_asn_decode(&asn_DEF_NGAP_HandoverRequestAcknowledgeTransfer, + &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; + + dL_NGU_UP_TNLInformation = &message.dL_NGU_UP_TNLInformation; + if (dL_NGU_UP_TNLInformation->present != + NGAP_UPTransportLayerInformation_PR_gTPTunnel) { + ogs_error( + "[%s:%d] Unknown dL_NGU_UP_TNLInformation->present [%d]", + smf_ue->supi, sess->psi, dL_NGU_UP_TNLInformation->present); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "Unknown dL_NGU_UP_TNLInformation->present", + smf_ue->supi, NULL, NULL); + goto cleanup; + } + + gTPTunnel = dL_NGU_UP_TNLInformation->choice.gTPTunnel; + if (!gTPTunnel) { + ogs_error("[%s:%d] No GTPTunnel", smf_ue->supi, sess->psi); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "No GTPTunnel", smf_ue->supi, NULL, NULL); + goto cleanup; + } + + /* Store FAR */ + ogs_asn_BIT_STRING_to_ip(&gTPTunnel->transportLayerAddress, + &sess->handover.gnb_n3_ip); + ogs_asn_OCTET_STRING_to_uint32(&gTPTunnel->gTP_TEID, + &sess->handover.gnb_n3_teid); + sess->handover.prepared = true; + + qosFlowSetupResponseList = &message.qosFlowSetupResponseList; + for (i = 0; i < qosFlowSetupResponseList->list.count; i++) { + qosFlowSetupResponseItem = (NGAP_QosFlowItemWithDataForwarding_t *) + qosFlowSetupResponseList->list.array[i]; + if (qosFlowSetupResponseItem) { + qos_flow = smf_qos_flow_find_by_qfi(sess, + qosFlowSetupResponseItem->qosFlowIdentifier); + + if (qos_flow) { + dl_far = qos_flow->dl_far; + ogs_assert(dl_far); + + dl_far->handover.prepared = true; + + } else { + ogs_error("[%s:%d] No QoS flow", smf_ue->supi, sess->psi); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "No QoS flow", smf_ue->supi, NULL, NULL); + goto cleanup; + } + } + } + + n2smbuf = ngap_build_handover_command_transfer(sess); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data( + sess, stream, 0, OpenAPI_ho_state_PREPARED, + NULL, OpenAPI_n2_sm_info_type_HANDOVER_CMD, n2smbuf); + + rv = OGS_OK; + +cleanup: + ogs_asn_free(&asn_DEF_NGAP_HandoverRequestAcknowledgeTransfer, &message); + return rv; +} diff --git a/src/smf/ngap-handler.h b/src/smf/ngap-handler.h index 8f56ff331..20e1e1127 100644 --- a/src/smf/ngap-handler.h +++ b/src/smf/ngap-handler.h @@ -30,7 +30,11 @@ 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_modify_response_transfer( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); -int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( +int ngap_handle_path_switch_request_transfer( + smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); +int ngap_handle_handover_required_transfer( + smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); +int ngap_handle_handover_request_ack( smf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_pkbuf_t *pkbuf); #ifdef __cplusplus diff --git a/src/smf/nsmf-handler.c b/src/smf/nsmf-handler.c index c69820257..8419a617e 100644 --- a/src/smf/nsmf-handler.c +++ b/src/smf/nsmf-handler.c @@ -341,14 +341,7 @@ bool smf_nsmf_handle_update_sm_context( ngap_send_to_n2sm( sess, stream, SmContextUpdateData->n2_sm_info_type, n2smbuf); - } else { - if (!SmContextUpdateData->up_cnx_state) { - ogs_error("[%s:%d] No upCnxState", smf_ue->supi, sess->psi); - smf_sbi_send_sm_context_update_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, - "No upCnxState", smf_ue->supi, NULL, NULL); - return false; - } + } else if (SmContextUpdateData->up_cnx_state) { if (SmContextUpdateData->up_cnx_state == OpenAPI_up_cnx_state_DEACTIVATED) { @@ -450,6 +443,96 @@ bool smf_nsmf_handle_update_sm_context( return false; } + } else if (SmContextUpdateData->ho_state) { + if (SmContextUpdateData->ho_state == OpenAPI_ho_state_COMPLETED) { + bool far_update = false; + smf_bearer_t *qos_flow = NULL; + + if (sess->handover.prepared == true) { + /* Need to Update? */ + if (memcmp(&sess->gnb_n3_ip, &sess->handover.gnb_n3_ip, + sizeof(sess->gnb_n3_ip)) != 0 || + sess->gnb_n3_teid != sess->handover.gnb_n3_teid) + far_update = true; + + memcpy(&sess->gnb_n3_ip, + &sess->handover.gnb_n3_ip, sizeof(sess->gnb_n3_ip)); + sess->gnb_n3_teid = sess->handover.gnb_n3_teid; + } + sess->handover.prepared = false; + + 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->handover.prepared == true) { + + if (dl_far->apply_action != OGS_PFCP_APPLY_ACTION_FORW) { + far_update = true; + } + + dl_far->apply_action = OGS_PFCP_APPLY_ACTION_FORW; + ogs_pfcp_ip_to_outer_header_creation( + &sess->gnb_n3_ip, + &dl_far->outer_header_creation, + &dl_far->outer_header_creation_len); + dl_far->outer_header_creation.teid = sess->gnb_n3_teid; + } + dl_far->handover.prepared = false; + } + + if (far_update) { + smf_5gc_pfcp_send_session_modification_request( + sess, stream, + OGS_PFCP_MODIFY_ACTIVATE | OGS_PFCP_MODIFY_N2_HANDOVER | + OGS_PFCP_MODIFY_END_MARKER); + } else { + char *strerror = ogs_msprintf( + "[%s:%d] No FAR Update", smf_ue->supi, sess->psi); + ogs_assert(strerror); + + ogs_error("%s", strerror); + smf_sbi_send_sm_context_update_error( + stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + strerror, NULL, NULL, NULL); + ogs_free(strerror); + + return false; + } + } else if (SmContextUpdateData->ho_state == + OpenAPI_ho_state_CANCELLED) { + smf_bearer_t *qos_flow = NULL; + + sess->handover.prepared = false; + + ogs_list_for_each(&sess->bearer_list, qos_flow) { + ogs_pfcp_far_t *dl_far = qos_flow->dl_far; + ogs_assert(dl_far); + + dl_far->handover.prepared = false; + } + + smf_sbi_send_sm_context_updated_data_ho_state( + sess, stream, OpenAPI_ho_state_CANCELLED); + + } else { + char *strerror = ogs_msprintf("[%s:%d] Invalid hoState [%d]", + smf_ue->supi, sess->psi, SmContextUpdateData->ho_state); + ogs_assert(strerror); + + ogs_error("%s", strerror); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, strerror, NULL, NULL, NULL); + ogs_free(strerror); + + return false; + } + } else { + ogs_error("[%s:%d] No UpdateData", smf_ue->supi, sess->psi); + smf_sbi_send_sm_context_update_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, + "No UpdateData", smf_ue->supi, NULL, NULL); + return false; } return true; diff --git a/src/smf/sbi-path.c b/src/smf/sbi-path.c index 83d2cec85..077f8b099 100644 --- a/src/smf/sbi-path.c +++ b/src/smf/sbi-path.c @@ -236,6 +236,7 @@ void smf_sbi_send_sm_context_create_error( void smf_sbi_send_sm_context_updated_data( smf_sess_t *sess, ogs_sbi_stream_t *stream, OpenAPI_up_cnx_state_e up_cnx_state, + OpenAPI_ho_state_e ho_state, ogs_pkbuf_t *n1smbuf, OpenAPI_n2_sm_info_type_e n2type, ogs_pkbuf_t *n2smbuf) { @@ -251,7 +252,9 @@ void smf_sbi_send_sm_context_updated_data( ogs_assert(sess); ogs_assert(stream); - ogs_assert(up_cnx_state != OpenAPI_up_cnx_state_NULL || n1smbuf || n2smbuf); + ogs_assert(up_cnx_state != OpenAPI_up_cnx_state_NULL || + ho_state != OpenAPI_ho_state_NULL || + n1smbuf || n2smbuf); memset(&sendmsg, 0, sizeof(sendmsg)); @@ -260,6 +263,9 @@ void smf_sbi_send_sm_context_updated_data( /* up_cnx_state */ SmContextUpdatedData.up_cnx_state = up_cnx_state; + /* ho_state */ + SmContextUpdatedData.ho_state = ho_state; + /* n1smbuf */ if (n1smbuf) { n1SmMsg.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; diff --git a/src/smf/sbi-path.h b/src/smf/sbi-path.h index d29fb5c63..82cf9c0ec 100644 --- a/src/smf/sbi-path.h +++ b/src/smf/sbi-path.h @@ -54,18 +54,23 @@ void smf_sbi_send_sm_context_create_error( #define smf_sbi_send_sm_context_updated_data_up_cnx_state( \ __sESS, __sTREAM, __uPCnxState) \ smf_sbi_send_sm_context_updated_data(\ - __sESS, __sTREAM, __uPCnxState, NULL, 0, NULL) + __sESS, __sTREAM, __uPCnxState, 0, NULL, 0, NULL) #define smf_sbi_send_sm_context_updated_data_n2smbuf( \ __sESS, __sTREAM, __n2Type, __n2SmBuf) \ smf_sbi_send_sm_context_updated_data(\ - __sESS, __sTREAM, 0, NULL, __n2Type, __n2SmBuf) + __sESS, __sTREAM, 0, 0, NULL, __n2Type, __n2SmBuf) +#define smf_sbi_send_sm_context_updated_data_ho_state( \ + __sESS, __sTREAM, __hoState) \ + smf_sbi_send_sm_context_updated_data(\ + __sESS, __sTREAM, 0, __hoState, NULL, 0, NULL) #define smf_sbi_send_sm_context_updated_data_n1_n2_message( \ __sESS, __sTREAM, __n1SmBuf, __n2Type, __n2SmBuf) \ smf_sbi_send_sm_context_updated_data(\ - __sESS, __sTREAM, 0, __n1SmBuf, __n2Type, __n2SmBuf) + __sESS, __sTREAM, 0, 0, __n1SmBuf, __n2Type, __n2SmBuf) void smf_sbi_send_sm_context_updated_data( smf_sess_t *sess, ogs_sbi_stream_t *stream, OpenAPI_up_cnx_state_e up_cnx_state, + OpenAPI_ho_state_e ho_state, ogs_pkbuf_t *n1smbuf, OpenAPI_n2_sm_info_type_e n2type, ogs_pkbuf_t *n2smbuf); diff --git a/tests/common/ngap-build.c b/tests/common/ngap-build.c index 027f931be..d70c724ec 100644 --- a/tests/common/ngap-build.c +++ b/tests/common/ngap-build.c @@ -25,6 +25,10 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_modify_response_trasfer( test_bearer_t *qos_flow); static ogs_pkbuf_t *testngap_build_path_switch_request_trasfer( test_sess_t *sess); +static ogs_pkbuf_t *testngap_build_handover_required_transfer( + test_sess_t *sess, bool direct); +static ogs_pkbuf_t *testngap_build_handover_request_ack_transfer( + test_sess_t *sess); ogs_pkbuf_t *testngap_build_ng_setup_request(uint32_t gnb_id, uint8_t bitsize) { @@ -1149,6 +1153,101 @@ ogs_pkbuf_t *testngap_build_pdu_session_resource_release_response( return ogs_ngap_encode(&pdu); } +ogs_pkbuf_t *testngap_build_uplink_ran_configuration_transfer( + uint32_t source_gnb_id, uint8_t source_bitsize, + uint32_t target_gnb_id, uint8_t target_bitsize) +{ + int rv; + ogs_plmn_id_t *plmn_id = NULL; + + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_UplinkRANConfigurationTransfer_t + *UplinkRANConfigurationTransfer = NULL; + + NGAP_UplinkRANConfigurationTransferIEs_t *ie = NULL; + NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer = NULL; + NGAP_SourceRANNodeID_t *sourceRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *sourceGlobalRANNodeID; + NGAP_GlobalGNB_ID_t *sourceGlobalGNB_ID; + NGAP_TAI_t *sourceSelectedTAI; + NGAP_TargetRANNodeID_t *targetRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *targetGlobalRANNodeID; + NGAP_GlobalGNB_ID_t *targetGlobalGNB_ID; + NGAP_TAI_t *targetSelectedTAI; + NGAP_SONInformation_t *sONInformation = NULL; + NGAP_SONInformationRequest_t *sONInformationRequest = NULL; + + ogs_debug("Uplink Configuration Transfer"); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + ogs_assert(pdu.choice.initiatingMessage); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = + NGAP_ProcedureCode_id_UplinkRANConfigurationTransfer; + initiatingMessage->criticality = NGAP_Criticality_ignore; + initiatingMessage->value.present = + NGAP_InitiatingMessage__value_PR_UplinkRANConfigurationTransfer; + + UplinkRANConfigurationTransfer = + &initiatingMessage->value.choice.UplinkRANConfigurationTransfer; + + ie = CALLOC(1, sizeof(NGAP_UplinkRANConfigurationTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&UplinkRANConfigurationTransfer->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_SONConfigurationTransferUL; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_UplinkRANConfigurationTransferIEs__value_PR_SONConfigurationTransfer; + + SONConfigurationTransfer = &ie->value.choice.SONConfigurationTransfer; + + plmn_id = &test_self()->plmn_support[0].plmn_id; + + targetRANNodeID = &SONConfigurationTransfer->targetRANNodeID; + targetGlobalRANNodeID = &targetRANNodeID->globalRANNodeID; + targetSelectedTAI = &targetRANNodeID->selectedTAI; + + targetGlobalRANNodeID->present = NGAP_GlobalRANNodeID_PR_globalGNB_ID; + targetGlobalRANNodeID->choice.globalGNB_ID = targetGlobalGNB_ID = + CALLOC(1, sizeof(*targetGlobalGNB_ID)); + ogs_assert(targetGlobalGNB_ID); + + ogs_asn_buffer_to_OCTET_STRING( + plmn_id, OGS_PLMN_ID_LEN, &targetGlobalGNB_ID->pLMNIdentity); + ogs_ngap_uint32_to_GNB_ID(target_gnb_id, target_bitsize, + &targetGlobalGNB_ID->gNB_ID); + ogs_ngap_5gs_tai_to_ASN(&test_self()->nr_tai, targetSelectedTAI); + + sourceRANNodeID = &SONConfigurationTransfer->sourceRANNodeID; + sourceGlobalRANNodeID = &sourceRANNodeID->globalRANNodeID; + sourceSelectedTAI = &sourceRANNodeID->selectedTAI; + + sourceGlobalRANNodeID->present = NGAP_GlobalRANNodeID_PR_globalGNB_ID; + sourceGlobalRANNodeID->choice.globalGNB_ID = sourceGlobalGNB_ID = + CALLOC(1, sizeof(*sourceGlobalGNB_ID)); + ogs_assert(sourceGlobalGNB_ID); + + ogs_asn_buffer_to_OCTET_STRING( + plmn_id, OGS_PLMN_ID_LEN, &sourceGlobalGNB_ID->pLMNIdentity); + ogs_ngap_uint32_to_GNB_ID(source_gnb_id, source_bitsize, + &sourceGlobalGNB_ID->gNB_ID); + ogs_ngap_5gs_tai_to_ASN(&test_self()->nr_tai, sourceSelectedTAI); + + sONInformation = &SONConfigurationTransfer->sONInformation; + + sONInformation->present = NGAP_SONInformation_PR_sONInformationRequest; + sONInformationRequest = &sONInformation->choice.sONInformationRequest; + + *sONInformationRequest = + NGAP_SONInformationRequest_xn_TNL_configuration_info; + + return ogs_ngap_encode(&pdu); +} + ogs_pkbuf_t *testngap_build_path_switch_request(test_ue_t *test_ue) { int rv; @@ -1315,6 +1414,610 @@ ogs_pkbuf_t *testngap_build_path_switch_request(test_ue_t *test_ue) return ogs_ngap_encode(&pdu); } +ogs_pkbuf_t *testngap_build_handover_required( + test_ue_t *test_ue, NGAP_HandoverType_t handover_type, + uint32_t gnb_id, uint8_t bitsize, + NGAP_Cause_PR group, long cause, + bool direct) +{ + test_sess_t *sess = NULL; + + ogs_pkbuf_t *n2smbuf = NULL; + + ogs_plmn_id_t *plmn_id = NULL; + + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverRequired_t *HandoverRequired = NULL; + + NGAP_HandoverRequiredIEs_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_HandoverType_t *HandoverType = NULL; + NGAP_Cause_t *Cause = NULL; + NGAP_TargetID_t *TargetID = NULL; + NGAP_TargetRANNodeID_t *targetRANNodeID = NULL; + NGAP_GlobalRANNodeID_t *globalRANNodeID = NULL; + NGAP_GlobalGNB_ID_t *globalGNB_ID = NULL; + NGAP_TAI_t *selectedTAI = NULL; + + NGAP_PDUSessionResourceListHORqd_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceItemHORqd_t *PDUSessionItem = NULL; + OCTET_STRING_t *transfer = NULL; + + NGAP_SourceToTarget_TransparentContainer_t + *SourceToTarget_TransparentContainer = NULL; + + uint8_t tmp[OGS_MAX_SDU_LEN]; + char *_container = + "40" + "0300001100000a00 010002f839000102 0120000002f83900 0000001000000a"; + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + ogs_assert(pdu.choice.initiatingMessage); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = + NGAP_ProcedureCode_id_HandoverPreparation; + initiatingMessage->criticality = NGAP_Criticality_reject; + initiatingMessage->value.present = + NGAP_InitiatingMessage__value_PR_HandoverRequired; + + HandoverRequired = &initiatingMessage->value.choice.HandoverRequired; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_HandoverType; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_HandoverType; + + HandoverType = &ie->value.choice.HandoverType; + + *HandoverType = handover_type; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_Cause; + + Cause = &ie->value.choice.Cause; + + Cause->present = group; + Cause->choice.radioNetwork = cause; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_TargetID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_TargetID; + + TargetID = &ie->value.choice.TargetID; + + TargetID->present = NGAP_TargetID_PR_targetRANNodeID; + TargetID->choice.targetRANNodeID = targetRANNodeID = + CALLOC(1, sizeof(*targetRANNodeID)); + ogs_assert(targetRANNodeID); + + globalRANNodeID = &targetRANNodeID->globalRANNodeID; + globalRANNodeID->present = NGAP_GlobalRANNodeID_PR_globalGNB_ID; + globalRANNodeID->choice.globalGNB_ID = globalGNB_ID = + CALLOC(1, sizeof(*globalGNB_ID)); + ogs_assert(globalGNB_ID); + + plmn_id = &test_self()->plmn_support[0].plmn_id; + ogs_asn_buffer_to_OCTET_STRING( + plmn_id, OGS_PLMN_ID_LEN, &globalGNB_ID->pLMNIdentity); + + ogs_ngap_uint32_to_GNB_ID(gnb_id, bitsize, &globalGNB_ID->gNB_ID); + + selectedTAI = &targetRANNodeID->selectedTAI; + ogs_ngap_5gs_tai_to_ASN(&test_ue->nr_tai, selectedTAI); + + ogs_list_for_each(&test_ue->sess_list, sess) { + if (!PDUSessionList) { + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceListHORqd; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_PDUSessionResourceListHORqd; + + PDUSessionList = &ie->value.choice.PDUSessionResourceListHORqd; + } + + PDUSessionItem = CALLOC(1, sizeof(*PDUSessionItem)); + ogs_assert(PDUSessionItem); + ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); + + PDUSessionItem->pDUSessionID = sess->psi; + + n2smbuf = testngap_build_handover_required_transfer(sess, direct); + ogs_assert(n2smbuf); + transfer = &PDUSessionItem->handoverRequiredTransfer; + + transfer->size = n2smbuf->len; + transfer->buf = CALLOC(transfer->size, sizeof(uint8_t)); + memcpy(transfer->buf, n2smbuf->data, transfer->size); + ogs_pkbuf_free(n2smbuf); + } + + ie = CALLOC(1, sizeof(NGAP_HandoverRequiredIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequired->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_SourceToTarget_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequiredIEs__value_PR_SourceToTarget_TransparentContainer; + + SourceToTarget_TransparentContainer = + &ie->value.choice.SourceToTarget_TransparentContainer; + + OGS_HEX(_container, strlen(_container), tmp), + + SourceToTarget_TransparentContainer->size = 32; + SourceToTarget_TransparentContainer->buf = + CALLOC(SourceToTarget_TransparentContainer->size, sizeof(uint8_t)); + memcpy(SourceToTarget_TransparentContainer->buf, + tmp, SourceToTarget_TransparentContainer->size); + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *testngap_build_handover_request_ack(test_ue_t *test_ue) +{ + int rv; + test_sess_t *sess = NULL; + + NGAP_NGAP_PDU_t pdu; + NGAP_SuccessfulOutcome_t *successfulOutcome = NULL; + NGAP_HandoverRequestAcknowledge_t *HandoverRequestAcknowledge = NULL; + + NGAP_HandoverRequestAcknowledgeIEs_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_PDUSessionResourceAdmittedList_t *PDUSessionList = NULL; + NGAP_PDUSessionResourceAdmittedItem_t *PDUSessionItem = NULL; + NGAP_TargetToSource_TransparentContainer_t + *TargetToSource_TransparentContainer = NULL; + + uint8_t tmp[OGS_MAX_SDU_LEN]; + char *_container = + "00010000"; + + 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_HandoverResourceAllocation; + successfulOutcome->criticality = NGAP_Criticality_reject; + successfulOutcome->value.present = + NGAP_SuccessfulOutcome__value_PR_HandoverRequestAcknowledge; + + HandoverRequestAcknowledge = + &successfulOutcome->value.choice.HandoverRequestAcknowledge; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestAcknowledgeIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequestAcknowledge->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_HandoverRequestAcknowledgeIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestAcknowledgeIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequestAcknowledge->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_HandoverRequestAcknowledgeIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + + test_ue->ran_ue_ngap_id++; + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + ogs_list_for_each(&test_ue->sess_list, sess) { + OCTET_STRING_t *transfer = NULL; + ogs_pkbuf_t *n2smbuf = NULL; + + if (!PDUSessionList) { + ie = CALLOC(1, sizeof(NGAP_HandoverRequestAcknowledgeIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequestAcknowledge->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_PDUSessionResourceAdmittedList; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_PDUSessionResourceAdmittedList; + + PDUSessionList = &ie->value.choice.PDUSessionResourceAdmittedList; + } + + PDUSessionItem = CALLOC(1, + sizeof(struct NGAP_PDUSessionResourceAdmittedItem)); + ogs_assert(PDUSessionItem); + ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); + + PDUSessionItem->pDUSessionID = sess->psi; + + n2smbuf = testngap_build_handover_request_ack_transfer(sess); + ogs_assert(n2smbuf); + transfer = &PDUSessionItem->handoverRequestAcknowledgeTransfer; + + transfer->size = n2smbuf->len; + transfer->buf = CALLOC(transfer->size, sizeof(uint8_t)); + memcpy(transfer->buf, n2smbuf->data, transfer->size); + ogs_pkbuf_free(n2smbuf); + } + + ie = CALLOC(1, sizeof(NGAP_HandoverRequestAcknowledgeIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverRequestAcknowledge->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverRequestAcknowledgeIEs__value_PR_TargetToSource_TransparentContainer; + + TargetToSource_TransparentContainer = + &ie->value.choice.TargetToSource_TransparentContainer; + + OGS_HEX(_container, strlen(_container), tmp), + + TargetToSource_TransparentContainer->size = 4; + TargetToSource_TransparentContainer->buf = + CALLOC(TargetToSource_TransparentContainer->size, sizeof(uint8_t)); + memcpy(TargetToSource_TransparentContainer->buf, + tmp, TargetToSource_TransparentContainer->size); + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *testngap_build_uplink_ran_status_transfer(test_ue_t *test_ue) +{ + test_sess_t *sess = NULL; + + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_UplinkRANStatusTransfer_t *UplinkRANStatusTransfer = NULL; + + NGAP_UplinkRANStatusTransferIEs_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_RANStatusTransfer_TransparentContainer_t + *RANStatusTransfer_TransparentContainer = NULL; + NGAP_DRBsSubjectToStatusTransferList_t *StatusTransferList = NULL; + + ogs_assert(test_ue); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = + NGAP_ProcedureCode_id_UplinkRANStatusTransfer; + initiatingMessage->criticality = NGAP_Criticality_ignore; + initiatingMessage->value.present = + NGAP_InitiatingMessage__value_PR_UplinkRANStatusTransfer; + + UplinkRANStatusTransfer = &initiatingMessage->value.choice.UplinkRANStatusTransfer; + + ie = CALLOC(1, sizeof(NGAP_UplinkRANStatusTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&UplinkRANStatusTransfer->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = + NGAP_UplinkRANStatusTransferIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_UplinkRANStatusTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&UplinkRANStatusTransfer->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = + NGAP_UplinkRANStatusTransferIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_UplinkRANStatusTransferIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&UplinkRANStatusTransfer->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_RANStatusTransfer_TransparentContainer; + + RANStatusTransfer_TransparentContainer = + &ie->value.choice.RANStatusTransfer_TransparentContainer; + + StatusTransferList = &RANStatusTransfer_TransparentContainer->dRBsSubjectToStatusTransferList; + + ogs_list_for_each(&test_ue->sess_list, sess) { + NGAP_DRBsSubjectToStatusTransferItem_t *StatusTransferItem = NULL; + NGAP_DRB_ID_t *dRB_ID = NULL; + NGAP_DRBStatusUL_t *dRBStatusUL = NULL; + NGAP_DRBStatusUL12_t *dRBStatusUL12 = NULL; + NGAP_COUNTValueForPDCP_SN12_t *uL_COUNTValue = NULL; + NGAP_DRBStatusDL_t *dRBStatusDL = NULL; + NGAP_DRBStatusDL18_t *dRBStatusDL18 = NULL; + NGAP_COUNTValueForPDCP_SN18_t *dL_COUNTValue = NULL; + + StatusTransferItem = CALLOC(1, sizeof(*StatusTransferItem)); + ogs_assert(StatusTransferItem); + ASN_SEQUENCE_ADD(&StatusTransferList->list, StatusTransferItem); + + dRB_ID = &StatusTransferItem->dRB_ID; + + *dRB_ID = sess->psi; + + dRBStatusUL = &StatusTransferItem->dRBStatusUL; + dRBStatusUL->present = NGAP_DRBStatusUL_PR_dRBStatusUL12; + dRBStatusUL->choice.dRBStatusUL12 = dRBStatusUL12 = + CALLOC(1, sizeof(*dRBStatusUL12)); + uL_COUNTValue = &dRBStatusUL12->uL_COUNTValue; + uL_COUNTValue->pDCP_SN12 = 1; + uL_COUNTValue->hFN_PDCP_SN12 = 2; + + dRBStatusDL = &StatusTransferItem->dRBStatusDL; + dRBStatusDL->present = NGAP_DRBStatusDL_PR_dRBStatusDL18; + dRBStatusDL->choice.dRBStatusDL18 = dRBStatusDL18 = + CALLOC(1, sizeof(*dRBStatusDL18)); + dL_COUNTValue = &dRBStatusDL18->dL_COUNTValue; + dL_COUNTValue->pDCP_SN18 = 3; + dL_COUNTValue->hFN_PDCP_SN18 = 4; + } + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *testngap_build_handover_notify(test_ue_t *test_ue) +{ + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverNotify_t *HandoverNotify = NULL; + + NGAP_HandoverNotifyIEs_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_UserLocationInformation_t *UserLocationInformation = NULL; + NGAP_UserLocationInformationNR_t *userLocationInformationNR = NULL; + NGAP_NR_CGI_t *nR_CGI = NULL; + NGAP_TAI_t *tAI = NULL; + + ogs_assert(test_ue); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = + NGAP_ProcedureCode_id_HandoverNotification; + initiatingMessage->criticality = NGAP_Criticality_ignore; + initiatingMessage->value.present = + NGAP_InitiatingMessage__value_PR_HandoverNotify; + + HandoverNotify = &initiatingMessage->value.choice.HandoverNotify; + + ie = CALLOC(1, sizeof(NGAP_HandoverNotifyIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverNotify->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverNotifyIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverNotifyIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverNotify->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverNotifyIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_HandoverNotifyIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverNotify->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_HandoverNotifyIEs__value_PR_UserLocationInformation; + + UserLocationInformation = &ie->value.choice.UserLocationInformation; + + userLocationInformationNR = + CALLOC(1, sizeof(NGAP_UserLocationInformationNR_t)); + ogs_assert(userLocationInformationNR); + + nR_CGI = &userLocationInformationNR->nR_CGI; + ogs_ngap_nr_cgi_to_ASN(&test_ue->nr_cgi, nR_CGI); + + tAI = &userLocationInformationNR->tAI; + ogs_ngap_5gs_tai_to_ASN(&test_ue->nr_tai, tAI); + + UserLocationInformation->present = + NGAP_UserLocationInformation_PR_userLocationInformationNR; + UserLocationInformation->choice.userLocationInformationNR = + userLocationInformationNR; + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *testngap_build_handover_failure(test_ue_t *test_ue, + NGAP_Cause_PR group, long cause) +{ + int rv; + + NGAP_NGAP_PDU_t pdu; + NGAP_UnsuccessfulOutcome_t *unsuccessfulOutcome = NULL; + NGAP_HandoverFailure_t *HandoverFailure = NULL; + + NGAP_HandoverFailureIEs_t *ie = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + NGAP_Cause_t *Cause = NULL; + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome; + pdu.choice.unsuccessfulOutcome = + CALLOC(1, sizeof(NGAP_UnsuccessfulOutcome_t)); + + unsuccessfulOutcome = pdu.choice.unsuccessfulOutcome; + unsuccessfulOutcome->procedureCode = + NGAP_ProcedureCode_id_HandoverResourceAllocation; + unsuccessfulOutcome->criticality = NGAP_Criticality_reject; + unsuccessfulOutcome->value.present = + NGAP_UnsuccessfulOutcome__value_PR_HandoverFailure; + + HandoverFailure = &unsuccessfulOutcome->value.choice.HandoverFailure; + + ie = CALLOC(1, sizeof(NGAP_HandoverFailureIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverFailure->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverFailureIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverFailureIEs_t)); + ASN_SEQUENCE_ADD(&HandoverFailure->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverFailureIEs__value_PR_Cause; + + Cause = &ie->value.choice.Cause; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + + Cause->present = group; + Cause->choice.radioNetwork = cause; + + return ogs_ngap_encode(&pdu); +} + +ogs_pkbuf_t *testngap_build_handover_cancel(test_ue_t *test_ue, + NGAP_Cause_PR group, long cause) +{ + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverCancel_t *HandoverCancel = NULL; + + NGAP_HandoverCancelIEs_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_Cause_t *Cause = NULL; + + ogs_assert(test_ue); + + memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); + pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + + initiatingMessage = pdu.choice.initiatingMessage; + initiatingMessage->procedureCode = NGAP_ProcedureCode_id_HandoverCancel; + initiatingMessage->criticality = NGAP_Criticality_reject; + initiatingMessage->value.present = + NGAP_InitiatingMessage__value_PR_HandoverCancel; + + HandoverCancel = &initiatingMessage->value.choice.HandoverCancel; + + ie = CALLOC(1, sizeof(NGAP_HandoverCancelIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCancel->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCancelIEs__value_PR_AMF_UE_NGAP_ID; + + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + + ie = CALLOC(1, sizeof(NGAP_HandoverCancelIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCancel->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = NGAP_HandoverCancelIEs__value_PR_RAN_UE_NGAP_ID; + + RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; + + asn_uint642INTEGER(AMF_UE_NGAP_ID, test_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = test_ue->ran_ue_ngap_id; + + ie = CALLOC(1, sizeof(NGAP_HandoverCancelIEs_t)); + ogs_assert(ie); + ASN_SEQUENCE_ADD(&HandoverCancel->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_Cause; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = NGAP_HandoverCancelIEs__value_PR_Cause; + + Cause = &ie->value.choice.Cause; + + Cause->present = group; + Cause->choice.radioNetwork = cause; + + return ogs_ngap_encode(&pdu); +} + static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer( test_sess_t *sess) { @@ -1340,6 +2043,7 @@ static ogs_pkbuf_t *testngap_build_pdu_session_resource_setup_response_trasfer( memset(&message, 0, sizeof(message)); dLQosFlowPerTNLInformation = &message.dLQosFlowPerTNLInformation; + uPTransportLayerInformation = &dLQosFlowPerTNLInformation->uPTransportLayerInformation; @@ -1450,6 +2154,93 @@ static ogs_pkbuf_t *testngap_build_path_switch_request_trasfer( qosFlowAcceptedItem->qosFlowIdentifier = qos_flow->qfi; } - return ogs_asn_encode( - &asn_DEF_NGAP_PathSwitchRequestTransfer, &message); + return ogs_asn_encode(&asn_DEF_NGAP_PathSwitchRequestTransfer, &message); +} + +static ogs_pkbuf_t *testngap_build_handover_required_transfer( + test_sess_t *sess, bool direct) +{ + int rv; + + test_bearer_t *qos_flow = NULL; + + ogs_gtp_f_teid_t f_teid; + ogs_ip_t ip; + int len; + + ogs_assert(sess); + + NGAP_HandoverRequiredTransfer_t message; + + NGAP_DirectForwardingPathAvailability_t + *directForwardingPathAvailability = NULL; + + memset(&message, 0, sizeof(message)); + + if (direct == true) { + message.directForwardingPathAvailability = + directForwardingPathAvailability = + CALLOC(1, sizeof(*directForwardingPathAvailability)); + + *directForwardingPathAvailability = + NGAP_DirectForwardingPathAvailability_direct_path_available; + } + + return ogs_asn_encode(&asn_DEF_NGAP_HandoverRequiredTransfer, &message); +} + +static ogs_pkbuf_t *testngap_build_handover_request_ack_transfer( + test_sess_t *sess) +{ + int rv; + test_bearer_t *qos_flow = NULL; + + ogs_gtp_f_teid_t f_teid; + ogs_ip_t ip; + int len; + + ogs_assert(sess); + + NGAP_HandoverRequestAcknowledgeTransfer_t message; + + NGAP_UPTransportLayerInformation_t *dL_NGU_UP_TNLInformation = NULL; + NGAP_QosFlowListWithDataForwarding_t *qosFlowSetupResponseList = NULL; + NGAP_QosFlowItemWithDataForwarding_t *qosFlowSetupResponseItem = NULL; + NGAP_GTPTunnel_t *gTPTunnel = NULL; + + memset(&message, 0, sizeof(message)); + + dL_NGU_UP_TNLInformation = &message.dL_NGU_UP_TNLInformation; + + dL_NGU_UP_TNLInformation->present = + NGAP_UPTransportLayerInformation_PR_gTPTunnel; + dL_NGU_UP_TNLInformation->choice.gTPTunnel = gTPTunnel = + CALLOC(1, sizeof(struct NGAP_GTPTunnel)); + ogs_assert(gTPTunnel); + + ogs_assert(sess->gnb_n3_addr || sess->gnb_n3_addr6); + rv = ogs_gtp_sockaddr_to_f_teid( + sess->gnb_n3_addr, sess->gnb_n3_addr6, &f_teid, &len); + ogs_assert(rv == OGS_OK); + + rv = ogs_gtp_f_teid_to_ip(&f_teid, &ip); + ogs_assert(rv == OGS_OK); + + ogs_asn_ip_to_BIT_STRING(&ip, &gTPTunnel->transportLayerAddress); + ogs_asn_uint32_to_OCTET_STRING(sess->gnb_n3_teid, &gTPTunnel->gTP_TEID); + + qosFlowSetupResponseList = &message.qosFlowSetupResponseList; + + ogs_list_for_each(&sess->bearer_list, qos_flow) { + qosFlowSetupResponseItem = + CALLOC(1, sizeof(struct NGAP_QosFlowItemWithDataForwarding)); + ogs_assert(qosFlowSetupResponseItem); + ASN_SEQUENCE_ADD(&qosFlowSetupResponseList->list, + qosFlowSetupResponseItem); + + qosFlowSetupResponseItem->qosFlowIdentifier = qos_flow->qfi; + } + + return ogs_asn_encode( + &asn_DEF_NGAP_HandoverRequestAcknowledgeTransfer, &message); } diff --git a/tests/common/ngap-build.h b/tests/common/ngap-build.h index bd84369d4..67523ab45 100644 --- a/tests/common/ngap-build.h +++ b/tests/common/ngap-build.h @@ -52,8 +52,25 @@ ogs_pkbuf_t *testngap_build_pdu_session_resource_modify_response( ogs_pkbuf_t *testngap_build_pdu_session_resource_release_response( test_sess_t *sess); +ogs_pkbuf_t *testngap_build_uplink_ran_configuration_transfer( + uint32_t source_gnb_id, uint8_t source_bitsize, + uint32_t target_gnb_id, uint8_t target_bitsize); + ogs_pkbuf_t *testngap_build_path_switch_request(test_ue_t *test_ue); +ogs_pkbuf_t *testngap_build_handover_required( + test_ue_t *test_ue, NGAP_HandoverType_t handover_type, + uint32_t gnb_id, uint8_t bitsize, + NGAP_Cause_PR group, long cause, + bool direct); +ogs_pkbuf_t *testngap_build_uplink_ran_status_transfer(test_ue_t *test_ue); +ogs_pkbuf_t *testngap_build_handover_request_ack(test_ue_t *test_ue); +ogs_pkbuf_t *testngap_build_handover_notify(test_ue_t *test_ue); +ogs_pkbuf_t *testngap_build_handover_failure(test_ue_t *test_ue, + NGAP_Cause_PR group, long cause); +ogs_pkbuf_t *testngap_build_handover_cancel(test_ue_t *test_ue, + NGAP_Cause_PR group, long cause); + #ifdef __cplusplus } #endif diff --git a/tests/common/ngap-handler.c b/tests/common/ngap-handler.c index 33ad5b527..ef9915bb1 100644 --- a/tests/common/ngap-handler.c +++ b/tests/common/ngap-handler.c @@ -600,3 +600,42 @@ void testngap_handle_pdu_session_resource_release_command( if (NAS_PDU) testngap_send_to_nas(test_ue, NAS_PDU); } + +void testngap_handle_handover_request( + test_ue_t *test_ue, ogs_ngap_message_t *message) +{ + int rv, i; + char buf[OGS_ADDRSTRLEN]; + + NGAP_NGAP_PDU_t pdu; + NGAP_InitiatingMessage_t *initiatingMessage = NULL; + NGAP_HandoverRequest_t *HandoverRequest = NULL; + + NGAP_HandoverRequestIEs_t *ie = NULL; + NGAP_AMF_UE_NGAP_ID_t *AMF_UE_NGAP_ID = NULL; + + ogs_assert(test_ue); + ogs_assert(message); + + initiatingMessage = message->choice.initiatingMessage; + ogs_assert(initiatingMessage); + HandoverRequest = &initiatingMessage->value.choice.HandoverRequest; + ogs_assert(HandoverRequest); + + for (i = 0; i < HandoverRequest->protocolIEs.list.count; i++) { + ie = HandoverRequest->protocolIEs.list.array[i]; + switch (ie->id) { + case NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID: + AMF_UE_NGAP_ID = &ie->value.choice.AMF_UE_NGAP_ID; + break; + default: + break; + } + } + + if (AMF_UE_NGAP_ID) { + uint64_t amf_ue_ngap_id; + asn_INTEGER2ulong(AMF_UE_NGAP_ID, (unsigned long *)&amf_ue_ngap_id); + test_ue->amf_ue_ngap_id = (uint64_t)amf_ue_ngap_id; + } +} diff --git a/tests/common/ngap-handler.h b/tests/common/ngap-handler.h index 77f6a7b1f..1b7d596ee 100644 --- a/tests/common/ngap-handler.h +++ b/tests/common/ngap-handler.h @@ -33,6 +33,7 @@ void testngap_handle_initial_context_setup_request( test_ue_t *test_ue, ogs_ngap_message_t *message); void testngap_handle_ue_release_context_command( test_ue_t *test_ue, ogs_ngap_message_t *message); + void testngap_handle_pdu_session_resource_setup_request( test_ue_t *test_ue, ogs_ngap_message_t *message); void testngap_handle_pdu_session_resource_modify_request( @@ -40,6 +41,9 @@ void testngap_handle_pdu_session_resource_modify_request( void testngap_handle_pdu_session_resource_release_command( test_ue_t *test_ue, ogs_ngap_message_t *message); +void testngap_handle_handover_request( + test_ue_t *test_ue, ogs_ngap_message_t *message); + #ifdef __cplusplus } #endif diff --git a/tests/common/ngap-path.c b/tests/common/ngap-path.c index f46000610..1c1641e92 100644 --- a/tests/common/ngap-path.c +++ b/tests/common/ngap-path.c @@ -65,6 +65,13 @@ void testngap_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) case NGAP_ProcedureCode_id_PDUSessionResourceRelease: testngap_handle_pdu_session_resource_release_command(test_ue, pdu); break; + case NGAP_ProcedureCode_id_DownlinkRANConfigurationTransfer: + break; + case NGAP_ProcedureCode_id_HandoverResourceAllocation: + testngap_handle_handover_request(test_ue, pdu); + break; + case NGAP_ProcedureCode_id_DownlinkRANStatusTransfer: + break; case NGAP_ProcedureCode_id_ErrorIndication: case NGAP_ProcedureCode_id_Paging: /* Nothing */ @@ -88,6 +95,10 @@ void testngap_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) break; case NGAP_ProcedureCode_id_PathSwitchRequest: break; + case NGAP_ProcedureCode_id_HandoverPreparation: + break; + case NGAP_ProcedureCode_id_HandoverCancel: + break; case NGAP_ProcedureCode_id_NGReset: break; default: @@ -106,6 +117,8 @@ void testngap_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) switch (unsuccessfulOutcome->procedureCode) { case NGAP_ProcedureCode_id_NGSetup: break; + case NGAP_ProcedureCode_id_HandoverPreparation: + break; default: ogs_error("Not implemented(choice:%d, proc:%d)", pdu->present, (int)unsuccessfulOutcome->procedureCode); diff --git a/tests/handover/5gc-n2-test.c b/tests/handover/5gc-n2-test.c new file mode 100644 index 000000000..a0dcb36ae --- /dev/null +++ b/tests/handover/5gc-n2-test.c @@ -0,0 +1,1850 @@ +/* + * Copyright (C) 2019,2020 by Sukchan Lee + * + * This file is part of Open5GS. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "test-common.h" + +static void test1_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap1, *ngap2; + ogs_socknode_t *gtpu1, *gtpu2; + 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; + + uint8_t tmp[OGS_MAX_SDU_LEN]; + char *_gtp_payload = "34ff0024" + "0000000100000085 010002004500001c 0c0b000040015a7a 0a2d00010a2d0002" + "00000964cd7c291f"; + + 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; + + uint32_t ran_ue_ngap_id; + uint64_t amf_ue_ngap_id; + + const char *_k_string = "70d49a71dd1a2b806a25abe0ef749f1e"; + uint8_t k[OGS_KEY_LEN]; + const char *_opc_string = "6f1bf53d624b3a43af6592854e2444c7"; + uint8_t opc[OGS_KEY_LEN]; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"imsi\" : \"901700000021309\"," + "\"ambr\" : { " + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"pdn\" : [" + "{" + "\"apn\" : \"internet\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}," + "{" + "\"apn\" : \"ims\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 6, " + "\"arp\" : { " + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2," + "\"pcc_rule\" : [" + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 }" + "}," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" + "]" + "}" + "]" + "}" + "]," + "\"security\" : { " + "\"k\" : \"70d49a71dd1a2b806a25abe0ef749f1e\", " + "\"opc\" : \"6f1bf53d624b3a43af6592854e2444c7\", " + "\"amf\" : \"8000\", " + "\"sqn\" : { \"$numberLong\" : \"25235952177090\" } " + "}, " + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2, " + "\"subscriber_status\" : 0, " + "\"access_restriction_data\" : 32, " + "\"__v\" : 0 " + "}"; + + /* 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.type = 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; + + OGS_HEX(_k_string, strlen(_k_string), test_ue->k); + OGS_HEX(_opc_string, strlen(_opc_string), test_ue->opc); + + /* Two gNB connects to AMF */ + ngap1 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap1); + + ngap2 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap2); + + /* Two gNB connects to UPF */ + gtpu1 = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu1); + + gtpu2 = test_gtpu_server(2, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu2); + + /* NG-Setup Reqeust/Response for Source gNB */ + sendbuf = testngap_build_ng_setup_request(0x4000, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* NG-Setup Reqeust/Response for Target gNB */ + sendbuf = testngap_build_ng_setup_request(0x4001, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + if (count) { + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + } + bson_destroy(doc); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /* Send Registration request */ + test_ue->registration_request_param.guti = 1; + 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.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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, 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(ngap1, 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap1); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "ims", 6); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session resource modify response */ + qos_flow = test_qos_flow_find_by_qfi(sess, 2); + ogs_assert(qos_flow); + + sendbuf = testngap_build_pdu_session_resource_modify_response(qos_flow); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDU session resource modify complete */ + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_MODIFICATION_REQUEST; + sess->ul_nas_transport_param.dnn = 0; + sess->ul_nas_transport_param.s_nssai = 0; + + gsmbuf = testgsm_build_pdu_session_modification_complete(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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Waiting for creating dedicated QoS flow in PFCP protocol */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UplinkRANConfigurationTransfer */ + sendbuf = testngap_build_uplink_ran_configuration_transfer( + 0x4000, 28, 0x4001, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive DownlinkRANConfigurationTransfer */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UplinkRANConfigurationTransfer */ + sendbuf = testngap_build_uplink_ran_configuration_transfer( + 0x4001, 28, 0x4000, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive DownlinkRANConfigurationTransfer */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverRequired */ + sendbuf = testngap_build_handover_required( + test_ue, NGAP_HandoverType_intra5gs, + 0x4001, 28, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverRequest */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverRequestAcknoledge */ + ogs_list_for_each(&test_ue->sess_list, sess) + sess->gnb_n3_addr = test_self()->gnb2_addr; + + sendbuf = testngap_build_handover_request_ack(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverCommand */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UplinkRANStatusTransfer */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id--; + ran_ue_ngap_id = test_ue->ran_ue_ngap_id--; + + sendbuf = testngap_build_uplink_ran_status_transfer(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + test_ue->ran_ue_ngap_id = ran_ue_ngap_id; + + /* Receive DownlinkRANStatusTransfer */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverNotify */ + test_ue->nr_cgi.cell_id = 0x40011; + sendbuf = testngap_build_handover_notify(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive UEContextReleaseCommand */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id; + ran_ue_ngap_id = test_ue->ran_ue_ngap_id; + + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + test_ue->ran_ue_ngap_id = ran_ue_ngap_id; + + /* Send GTP-U ICMP Packet */ + sess = test_sess_find_by_psi(test_ue, 5); + ogs_assert(sess); + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu2, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + sess = test_sess_find_by_psi(test_ue, 6); + ogs_assert(sess); + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu2, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 2); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu2, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send HandoverRequired */ + sendbuf = testngap_build_handover_required( + test_ue, NGAP_HandoverType_intra5gs, + 0x4000, 28, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverRequest */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverRequestAcknoledge */ + ogs_list_for_each(&test_ue->sess_list, sess) + sess->gnb_n3_addr = test_self()->gnb1_addr; + + sendbuf = testngap_build_handover_request_ack(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverCommand */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UplinkRANStatusTransfer */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id--; + ran_ue_ngap_id = test_ue->ran_ue_ngap_id--; + + sendbuf = testngap_build_uplink_ran_status_transfer(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + test_ue->ran_ue_ngap_id = ran_ue_ngap_id; + + /* Receive DownlinkRANStatusTransfer */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverNotify */ + test_ue->nr_cgi.cell_id = 0x40001; + sendbuf = testngap_build_handover_notify(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive End Mark */ + recvbuf = test_gtpu_read(gtpu2); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive UEContextReleaseCommand */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id; + ran_ue_ngap_id = test_ue->ran_ue_ngap_id; + + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + test_ue->ran_ue_ngap_id = ran_ue_ngap_id; + + /* Send GTP-U ICMP Packet */ + sess = test_sess_find_by_psi(test_ue, 5); + ogs_assert(sess); + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + sess = test_sess_find_by_psi(test_ue, 6); + ogs_assert(sess); + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 2); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UEContextReleaseRequest */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* Two gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu1); + testgnb_gtpu_close(gtpu2); + + /* Two gNB disonncect from AMF */ + testgnb_ngap_close(ngap1); + testgnb_ngap_close(ngap2); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void test2_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap1, *ngap2; + ogs_socknode_t *gtpu1, *gtpu2; + 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; + + uint8_t tmp[OGS_MAX_SDU_LEN]; + char *_gtp_payload = "34ff0024" + "0000000100000085 010002004500001c 0c0b000040015a7a 0a2d00010a2d0002" + "00000964cd7c291f"; + + 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; + + uint32_t ran_ue_ngap_id; + uint64_t amf_ue_ngap_id; + + const char *_k_string = "70d49a71dd1a2b806a25abe0ef749f1e"; + uint8_t k[OGS_KEY_LEN]; + const char *_opc_string = "6f1bf53d624b3a43af6592854e2444c7"; + uint8_t opc[OGS_KEY_LEN]; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"imsi\" : \"901700000021309\"," + "\"ambr\" : { " + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"pdn\" : [" + "{" + "\"apn\" : \"internet\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}," + "{" + "\"apn\" : \"ims\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 6, " + "\"arp\" : { " + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2," + "\"pcc_rule\" : [" + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 }" + "}," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" + "]" + "}" + "]" + "}" + "]," + "\"security\" : { " + "\"k\" : \"70d49a71dd1a2b806a25abe0ef749f1e\", " + "\"opc\" : \"6f1bf53d624b3a43af6592854e2444c7\", " + "\"amf\" : \"8000\", " + "\"sqn\" : { \"$numberLong\" : \"25235952177090\" } " + "}, " + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2, " + "\"subscriber_status\" : 0, " + "\"access_restriction_data\" : 32, " + "\"__v\" : 0 " + "}"; + + /* 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.type = 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; + + OGS_HEX(_k_string, strlen(_k_string), test_ue->k); + OGS_HEX(_opc_string, strlen(_opc_string), test_ue->opc); + + /* Two gNB connects to AMF */ + ngap1 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap1); + + ngap2 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap2); + + /* Two gNB connects to UPF */ + gtpu1 = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu1); + + gtpu2 = test_gtpu_server(2, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu2); + + /* NG-Setup Reqeust/Response for Source gNB */ + sendbuf = testngap_build_ng_setup_request(0x4000, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* NG-Setup Reqeust/Response for Target gNB */ + sendbuf = testngap_build_ng_setup_request(0x4001, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + if (count) { + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + } + bson_destroy(doc); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /* Send Registration request */ + test_ue->registration_request_param.guti = 1; + 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.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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, 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(ngap1, 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap1); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "ims", 6); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session resource modify response */ + qos_flow = test_qos_flow_find_by_qfi(sess, 2); + ogs_assert(qos_flow); + + sendbuf = testngap_build_pdu_session_resource_modify_response(qos_flow); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDU session resource modify complete */ + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_MODIFICATION_REQUEST; + sess->ul_nas_transport_param.dnn = 0; + sess->ul_nas_transport_param.s_nssai = 0; + + gsmbuf = testgsm_build_pdu_session_modification_complete(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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Waiting for creating dedicated QoS flow in PFCP protocol */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send HandoverRequired */ + sendbuf = testngap_build_handover_required( + test_ue, NGAP_HandoverType_intra5gs, + 0x4001, 28, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverRequest */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverFailure */ + sendbuf = testngap_build_handover_failure(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_unspecified); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverPreparationFailure */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id--; + + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send UEContextReleaseRequest */ + test_ue->amf_ue_ngap_id--; + test_ue->ran_ue_ngap_id--; + + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* Two gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu1); + testgnb_gtpu_close(gtpu2); + + /* Two gNB disonncect from AMF */ + testgnb_ngap_close(ngap1); + testgnb_ngap_close(ngap2); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void test3_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap1, *ngap2; + ogs_socknode_t *gtpu1, *gtpu2; + 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; + + uint8_t tmp[OGS_MAX_SDU_LEN]; + char *_gtp_payload = "34ff0024" + "0000000100000085 010002004500001c 0c0b000040015a7a 0a2d00010a2d0002" + "00000964cd7c291f"; + + 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; + + uint32_t ran_ue_ngap_id; + uint64_t amf_ue_ngap_id; + + const char *_k_string = "70d49a71dd1a2b806a25abe0ef749f1e"; + uint8_t k[OGS_KEY_LEN]; + const char *_opc_string = "6f1bf53d624b3a43af6592854e2444c7"; + uint8_t opc[OGS_KEY_LEN]; + + mongoc_collection_t *collection = NULL; + bson_t *doc = NULL; + int64_t count = 0; + bson_error_t error; + const char *json = + "{" + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"imsi\" : \"901700000021309\"," + "\"ambr\" : { " + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"pdn\" : [" + "{" + "\"apn\" : \"internet\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c6\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}," + "{" + "\"apn\" : \"ims\", " + "\"_id\" : { \"$oid\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 6, " + "\"arp\" : { " + "\"priority_level\" : 6," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2," + "\"pcc_rule\" : [" + "{" + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2d\" }," + "\"qos\" : {" + "\"qci\" : 1," + "\"gbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"mbr\" : {" + "\"downlink\" : { \"$numberLong\" : \"64\" }," + "\"uplink\" : { \"$numberLong\" : \"44\" }" + "}," + "\"arp\" : {" + "\"priority_level\" : 3," + "\"pre_emption_vulnerability\" : 0," + "\"pre_emption_capability\" : 0 }" + "}," + "\"flow\" : [" + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23454 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd31\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50020\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd30\" } }," + "{ \"direction\" : 2," + "\"description\" : \"permit out udp from 10.200.136.98/32 23455 to assigned 1-65535\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2f\" } }," + "{ \"direction\" : 1," + "\"description\" : \"permit out udp from 10.200.136.98/32 1-65535 to assigned 50021\"," + "\"_id\" : { \"$oid\" : \"599eb929c850caabcbfdcd2e\" } }" + "]" + "}" + "]" + "}" + "]," + "\"security\" : { " + "\"k\" : \"70d49a71dd1a2b806a25abe0ef749f1e\", " + "\"opc\" : \"6f1bf53d624b3a43af6592854e2444c7\", " + "\"amf\" : \"8000\", " + "\"sqn\" : { \"$numberLong\" : \"25235952177090\" } " + "}, " + "\"subscribed_rau_tau_timer\" : 12," + "\"network_access_mode\" : 2, " + "\"subscriber_status\" : 0, " + "\"access_restriction_data\" : 32, " + "\"__v\" : 0 " + "}"; + + /* 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.type = 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; + + OGS_HEX(_k_string, strlen(_k_string), test_ue->k); + OGS_HEX(_opc_string, strlen(_opc_string), test_ue->opc); + + /* Two gNB connects to AMF */ + ngap1 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap1); + + ngap2 = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap2); + + /* Two gNB connects to UPF */ + gtpu1 = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu1); + + gtpu2 = test_gtpu_server(2, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu2); + + /* NG-Setup Reqeust/Response for Source gNB */ + sendbuf = testngap_build_ng_setup_request(0x4000, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* NG-Setup Reqeust/Response for Target gNB */ + sendbuf = testngap_build_ng_setup_request(0x4001, 28); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + collection = mongoc_client_get_collection( + ogs_mongoc()->client, ogs_mongoc()->name, "subscribers"); + ABTS_PTR_NOTNULL(tc, collection); + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + if (count) { + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + } + bson_destroy(doc); + + doc = bson_new_from_json((const uint8_t *)json, -1, &error);; + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_insert(collection, + MONGOC_INSERT_NONE, doc, NULL, &error)); + bson_destroy(doc); + + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + do { + count = mongoc_collection_count ( + collection, MONGOC_QUERY_NONE, doc, 0, 0, NULL, &error); + } while (count == 0); + bson_destroy(doc); + + /* Send Registration request */ + test_ue->registration_request_param.guti = 1; + 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.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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, 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(ngap1, 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap1); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "ims", 6); + 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; + + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session resource modify response */ + qos_flow = test_qos_flow_find_by_qfi(sess, 2); + ogs_assert(qos_flow); + + sendbuf = testngap_build_pdu_session_resource_modify_response(qos_flow); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDU session resource modify complete */ + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_MODIFICATION_REQUEST; + sess->ul_nas_transport_param.dnn = 0; + sess->ul_nas_transport_param.s_nssai = 0; + + gsmbuf = testgsm_build_pdu_session_modification_complete(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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Waiting for creating dedicated QoS flow in PFCP protocol */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu1, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu1); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send HandoverRequired */ + sendbuf = testngap_build_handover_required( + test_ue, NGAP_HandoverType_intra5gs, + 0x4001, 28, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_handover_desirable_for_radio_reason, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverRequest */ + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverRequestAcknoledge */ + ogs_list_for_each(&test_ue->sess_list, sess) + sess->gnb_n3_addr = test_self()->gnb2_addr; + + sendbuf = testngap_build_handover_request_ack(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive HandoverCommand */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send HandoverCancel */ + amf_ue_ngap_id = test_ue->amf_ue_ngap_id--; + ran_ue_ngap_id = test_ue->ran_ue_ngap_id--; + + sendbuf = testngap_build_handover_cancel(test_ue, + NGAP_Cause_PR_radioNetwork, + NGAP_CauseRadioNetwork_txnrelocoverall_expiry); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Recv HandoverCancelAcknowledge */ + recvbuf = testgnb_ngap_read(ngap1); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Receive UEContextReleaseCommand */ + test_ue->amf_ue_ngap_id = amf_ue_ngap_id; + test_ue->ran_ue_ngap_id = ran_ue_ngap_id; + + recvbuf = testgnb_ngap_read(ngap2); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap2, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send UEContextReleaseRequest */ + test_ue->amf_ue_ngap_id--; + test_ue->ran_ue_ngap_id--; + + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap1); + 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(ngap1, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + doc = BCON_NEW("imsi", BCON_UTF8(test_ue->imsi)); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_TRUE(tc, mongoc_collection_remove(collection, + MONGOC_REMOVE_SINGLE_REMOVE, doc, NULL, &error)) + bson_destroy(doc); + + mongoc_collection_destroy(collection); + + /* Two gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu1); + testgnb_gtpu_close(gtpu2); + + /* Two gNB disonncect from AMF */ + testgnb_ngap_close(ngap1); + testgnb_ngap_close(ngap2); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +abts_suite *test_5gc_n2(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test1_func, NULL); + abts_run_test(suite, test2_func, NULL); + abts_run_test(suite, test3_func, NULL); + + return suite; +} diff --git a/tests/handover/abts-main.c b/tests/handover/abts-main.c index 23853a494..13127fd98 100644 --- a/tests/handover/abts-main.c +++ b/tests/handover/abts-main.c @@ -22,6 +22,7 @@ abts_suite *test_epc_x2(abts_suite *suite); abts_suite *test_epc_s1(abts_suite *suite); abts_suite *test_5gc_xn(abts_suite *suite); +abts_suite *test_5gc_n2(abts_suite *suite); const struct testlist { abts_suite *(*func)(abts_suite *suite); @@ -29,6 +30,7 @@ const struct testlist { {test_epc_x2}, {test_epc_s1}, {test_5gc_xn}, + {test_5gc_n2}, {NULL}, }; diff --git a/tests/handover/meson.build b/tests/handover/meson.build index 8dabbc40d..b16103d88 100644 --- a/tests/handover/meson.build +++ b/tests/handover/meson.build @@ -20,6 +20,7 @@ testapp_handover_sources = files(''' epc-x2-test.c epc-s1-test.c 5gc-xn-test.c + 5gc-n2-test.c '''.split()) testapp_handover_exe = executable('handover',