From c9363b132093581b6fd2ce794aa63cd597bf83a6 Mon Sep 17 00:00:00 2001 From: Sukchan Lee Date: Mon, 18 Jan 2021 11:48:35 -0500 Subject: [PATCH] 5gc: Paging was added --- debian/changelog | 6 + lib/core/ogs-3gpp-types.h | 3 +- lib/sbi/message.c | 26 + lib/sbi/message.h | 3 + lib/sbi/ogs-sbi.h | 1 + meson.build | 4 +- src/amf/amf-sm.c | 2 +- src/amf/context.c | 40 +- src/amf/context.h | 75 +- src/amf/gmm-handler.c | 128 +- src/amf/gmm-sm.c | 64 +- src/amf/namf-handler.c | 379 ++- src/amf/nas-path.c | 23 +- src/amf/nas-path.h | 2 - src/amf/ngap-build.c | 250 +- src/amf/ngap-build.h | 7 +- src/amf/ngap-handler.c | 3 +- src/amf/ngap-path.c | 76 +- src/amf/ngap-path.h | 6 +- src/amf/nsmf-build.c | 48 +- src/amf/nsmf-build.h | 3 + src/amf/nsmf-handler.c | 263 +- src/amf/nudm-handler.c | 27 +- src/amf/sbi-path.c | 41 + src/amf/sbi-path.h | 26 +- src/mme/emm-handler.c | 9 +- src/mme/mme-context.h | 1 + src/mme/s1ap-build.c | 74 +- src/mme/s1ap-handler.c | 6 +- src/mme/s1ap-path.c | 2 +- src/sgwc/context.c | 2 +- src/smf/context.c | 105 + src/smf/context.h | 25 +- src/smf/gsm-sm.c | 44 +- src/smf/gx-handler.c | 8 +- src/smf/n4-handler.c | 220 +- src/smf/n4-handler.h | 4 + src/smf/namf-build.c | 112 +- src/smf/namf-build.h | 11 +- src/smf/namf-handler.c | 177 +- src/smf/namf-handler.h | 3 + src/smf/ngap-build.c | 6 +- src/smf/ngap-build.h | 2 +- src/smf/ngap-handler.c | 4 +- src/smf/nsmf-handler.c | 6 +- src/smf/pfcp-path.c | 26 +- src/smf/pfcp-path.h | 3 + src/smf/pfcp-sm.c | 10 + src/smf/s5c-build.c | 4 +- src/smf/sbi-path.c | 132 +- src/smf/sbi-path.h | 31 +- src/smf/smf-sm.c | 37 +- src/upf/gtp-path.c | 38 +- src/upf/n4-handler.c | 36 + src/upf/n4-handler.h | 4 + src/upf/pfcp-path.c | 43 + src/upf/pfcp-path.h | 3 + src/upf/pfcp-sm.c | 4 + tests/common/ngap-path.c | 1 + tests/registration/abts-main.c | 2 + tests/registration/dereg-test.c | 23 +- tests/registration/guti-test.c | 1 + tests/registration/identity-test.c | 11 + tests/registration/idle-test.c | 33 +- tests/registration/meson.build | 1 + tests/registration/paging-test.c | 3427 ++++++++++++++++++++++++++ tests/registration/ue-context-test.c | 21 +- tests/vonr/qos-flow-test.c | 12 +- tests/vonr/session-test.c | 1098 ++++++++- 69 files changed, 6394 insertions(+), 934 deletions(-) create mode 100644 tests/registration/paging-test.c diff --git a/debian/changelog b/debian/changelog index 14ea6b355..58cfa2bd5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +open5gs (2.1.4) unstable; urgency=medium + + * Paging added + + -- Sukchan Lee Mon, 18 Jan 2021 15:53:28 +0000 + open5gs (2.1.3) unstable; urgency=medium * Bug Fixed diff --git a/lib/core/ogs-3gpp-types.h b/lib/core/ogs-3gpp-types.h index 04b6e3beb..142b086d4 100644 --- a/lib/core/ogs-3gpp-types.h +++ b/lib/core/ogs-3gpp-types.h @@ -365,7 +365,8 @@ typedef struct ogs_pcc_rule_s { ogs_assert((__dST)->id); \ } \ for (__iNDEX = 0; __iNDEX < (__sRC)->num_of_flow; __iNDEX++) { \ - (__dST)->flow[__iNDEX].direction = (__sRC)->flow[__iNDEX].direction; \ + (__dST)->flow[__iNDEX].direction = \ + (__sRC)->flow[__iNDEX].direction; \ (__dST)->flow[__iNDEX].description = \ ogs_strdup((__sRC)->flow[__iNDEX].description); \ ogs_assert((__dST)->flow[__iNDEX].description); \ diff --git a/lib/sbi/message.c b/lib/sbi/message.c index 001357720..9afab6a95 100644 --- a/lib/sbi/message.c +++ b/lib/sbi/message.c @@ -133,6 +133,9 @@ void ogs_sbi_message_free(ogs_sbi_message_t *message) if (message->N1N2MessageTransferRspData) OpenAPI_n1_n2_message_transfer_rsp_data_free( message->N1N2MessageTransferRspData); + if (message->N1N2MsgTxfrFailureNotification) + OpenAPI_n1_n2_msg_txfr_failure_notification_free( + message->N1N2MsgTxfrFailureNotification); if (message->SmContextStatusNotification) OpenAPI_sm_context_status_notification_free( message->SmContextStatusNotification); @@ -712,6 +715,10 @@ static char *build_json(ogs_sbi_message_t *message) item = OpenAPI_n1_n2_message_transfer_rsp_data_convertToJSON( message->N1N2MessageTransferRspData); ogs_assert(item); + } else if (message->N1N2MsgTxfrFailureNotification) { + item = OpenAPI_n1_n2_msg_txfr_failure_notification_convertToJSON( + message->N1N2MsgTxfrFailureNotification); + ogs_assert(item); } else if (message->SmContextStatusNotification) { item = OpenAPI_sm_context_status_notification_convertToJSON( message->SmContextStatusNotification); @@ -1381,6 +1388,25 @@ static int parse_json(ogs_sbi_message_t *message, END break; + CASE(OGS_SBI_SERVICE_NAME_NSMF_CALLBACK) + SWITCH(message->h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_N1_N2_FAILURE_NOTIFY) + message->N1N2MsgTxfrFailureNotification = + OpenAPI_n1_n2_msg_txfr_failure_notification_parseFromJSON( + item); + if (!message->N1N2MsgTxfrFailureNotification) { + rv = OGS_ERROR; + ogs_error("JSON parse error"); + } + break; + + DEFAULT + rv = OGS_ERROR; + ogs_error("Unknown resource name [%s]", + message->h.resource.component[1]); + END + break; + DEFAULT rv = OGS_ERROR; ogs_error("Not implemented API name [%s]", diff --git a/lib/sbi/message.h b/lib/sbi/message.h index 161f26721..8cf3429af 100644 --- a/lib/sbi/message.h +++ b/lib/sbi/message.h @@ -125,6 +125,7 @@ extern "C" { #define OGS_SBI_SERVICE_NAME_NSMF_CALLBACK "nsmf-callback" #define OGS_SBI_RESOURCE_NAME_SM_POLICY_NOTIFY "sm-policy-notify" +#define OGS_SBI_RESOURCE_NAME_N1_N2_FAILURE_NOTIFY "n1-n2-failure-notify" #define OGS_SBI_SERVICE_NAME_NAMF_COMM "namf-comm" #define OGS_SBI_RESOURCE_NAME_UE_CONTEXTS "ue-contexts" @@ -321,6 +322,8 @@ typedef struct ogs_sbi_message_s { SessionManagementSubscriptionData; OpenAPI_n1_n2_message_transfer_req_data_t *N1N2MessageTransferReqData; OpenAPI_n1_n2_message_transfer_rsp_data_t *N1N2MessageTransferRspData; + OpenAPI_n1_n2_msg_txfr_failure_notification_t + *N1N2MsgTxfrFailureNotification; OpenAPI_sm_context_status_notification_t *SmContextStatusNotification; OpenAPI_policy_association_request_t *PolicyAssociationRequest; OpenAPI_policy_association_t *PolicyAssociation; diff --git a/lib/sbi/ogs-sbi.h b/lib/sbi/ogs-sbi.h index ca9ef7554..bb63bbb82 100644 --- a/lib/sbi/ogs-sbi.h +++ b/lib/sbi/ogs-sbi.h @@ -58,6 +58,7 @@ #include "model/session_management_subscription_data.h" #include "model/n1_n2_message_transfer_req_data.h" #include "model/n1_n2_message_transfer_rsp_data.h" +#include "model/n1_n2_msg_txfr_failure_notification.h" #include "model/sm_context_status_notification.h" #include "model/policy_association.h" #include "model/am_policy_data.h" diff --git a/meson.build b/meson.build index bccb8b7be..145c0c157 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,7 @@ # along with this program. If not, see . project('open5gs', 'c', - version : '2.1.3', + version : '2.1.4', license : 'AGPL-3.0-or-later', meson_version : '>= 0.43.0', default_options : [ @@ -24,7 +24,7 @@ project('open5gs', 'c', ], ) -libogslib_version = '2.1.3' +libogslib_version = '2.1.4' prefix = get_option('prefix') bindir = join_paths(prefix, get_option('bindir')) diff --git a/src/amf/amf-sm.c b/src/amf/amf-sm.c index d55786454..c416ae844 100644 --- a/src/amf/amf-sm.c +++ b/src/amf/amf-sm.c @@ -64,7 +64,7 @@ void amf_state_operational(ogs_fsm_t *s, amf_event_t *e) ogs_sbi_object_t *sbi_object = NULL; ogs_sbi_xact_t *sbi_xact = NULL; - int state = AMF_UPDATE_SM_CONTEXT_NO_STATE; + int state = AMF_SESS_SM_CONTEXT_NO_STATE; ogs_sbi_stream_t *stream = NULL; ogs_sbi_request_t *sbi_request = NULL; diff --git a/src/amf/context.c b/src/amf/context.c index adc9c2482..b36d73cb0 100644 --- a/src/amf/context.c +++ b/src/amf/context.c @@ -1179,6 +1179,12 @@ void amf_ue_remove(amf_ue_t *amf_ue) /* Clear Transparent Container */ OGS_ASN_CLEAR_DATA(&amf_ue->container); + /* Clear Paging Info */ + AMF_UE_CLEAR_PAGING_INFO(amf_ue); + + /* Clear N2 Transfer */ + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, pdu_session_resource_setup_request); + /* Delete All Timers */ CLEAR_AMF_UE_ALL_TIMERS(amf_ue); ogs_timer_delete(amf_ue->t3513.timer); @@ -1517,6 +1523,21 @@ 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; + + if (sess->paging.client) + ogs_sbi_client_remove(sess->paging.client); + OGS_NAS_CLEAR_DATA(&sess->ue_pco); OGS_TLV_CLEAR_DATA(&sess->pgw_pco); @@ -1568,7 +1589,24 @@ int amf_sess_xact_count(amf_ue_t *amf_ue) return xact_count; } -bool amf_sess_transfer_needed(amf_ue_t *amf_ue) +int amf_sess_xact_state_count(amf_ue_t *amf_ue, int state) +{ + amf_sess_t *sess = NULL; + ogs_sbi_xact_t *xact = NULL; + int xact_count = 0; + + ogs_assert(amf_ue); + ogs_assert(state); + + ogs_list_for_each(&amf_ue->sess_list, sess) { + ogs_list_for_each(&sess->sbi.xact_list, xact) + if (xact->state == state) xact_count++; + } + + return xact_count; +} + +bool amf_pdu_res_setup_req_transfer_needed(amf_ue_t *amf_ue) { amf_sess_t *sess = NULL; diff --git a/src/amf/context.h b/src/amf/context.h index c906f4724..ff442d4c8 100644 --- a/src/amf/context.h +++ b/src/amf/context.h @@ -262,6 +262,7 @@ struct amf_ue_s { /* UE Info */ ogs_guami_t *guami; + uint16_t gnb_ostream_id; ogs_5gs_tai_t tai; ogs_nr_cgi_t nr_cgi; ogs_time_t ue_location_timestamp; @@ -447,7 +448,71 @@ 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; } transfer; +#define AMF_SESS_STORE_N2_TRANSFER(__sESS, __n2Type, __n2Buf) \ + do { \ + ogs_assert(__sESS); \ + ogs_assert((__sESS)->amf_ue); \ + if (sess->transfer.__n2Type) { \ + ogs_warn("[%s:%d] N2 transfer message duplicated. Overwritten", \ + ((__sESS)->amf_ue)->supi, sess->psi); \ + ogs_pkbuf_free(sess->transfer.__n2Type); \ + } \ + sess->transfer.__n2Type = __n2Buf; \ + ogs_assert(sess->transfer.__n2Type); \ + } 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; \ + } \ + } \ + } while(0); + + struct { + /* Paging Ongoing */ + bool ongoing; + /* Location in N1N2MessageTransferRspData */ + char *location; + /* last Received n1-n2-trasfer-failure-notification-uri from SMF */ + char *n1n2_failure_txf_notif_uri; + /* notification client */ + ogs_sbi_client_t *client; + } paging; +#define AMF_SESS_STORE_PAGING_INFO(__sESS, __lOCATION, __uRI) \ + do { \ + ogs_assert(__sESS); \ + ogs_assert(__lOCATION); \ + ogs_assert(__uRI); \ + AMF_SESS_CLEAR_PAGING_INFO(__sESS) \ + (__sESS)->paging.ongoing = true; \ + ((__sESS)->paging.location) = ogs_strdup(__lOCATION); \ + ((__sESS)->paging.n1n2_failure_txf_notif_uri) = ogs_strdup(__uRI); \ + } while(0); +#define AMF_SESS_CLEAR_PAGING_INFO(__sESS) \ + do { \ + if ((__sESS)->paging.ongoing == true) { \ + ogs_assert((__sESS)->paging.location); \ + ogs_free((__sESS)->paging.location); \ + ((__sESS)->paging.location) = NULL; \ + ogs_assert((__sESS)->paging.n1n2_failure_txf_notif_uri); \ + ogs_free((__sESS)->paging.n1n2_failure_txf_notif_uri); \ + ((__sESS)->paging.n1n2_failure_txf_notif_uri) = NULL; \ + ((__sESS)->paging.ongoing) = false; \ + } \ + } while(0); +#define AMF_UE_CLEAR_PAGING_INFO(__aMF) \ + do { \ + amf_sess_t *sess = NULL; \ + ogs_list_for_each(&((__aMF)->sess_list), sess) { \ + AMF_SESS_CLEAR_PAGING_INFO(sess); \ + } \ + } while(0); /* last payload for sending back to the UE */ uint8_t payload_container_type; @@ -470,6 +535,7 @@ typedef struct amf_sess_s { /* Save Protocol Configuration Options from PGW */ ogs_tlv_octet_t pgw_pco; + } amf_sess_t; void amf_context_init(void); @@ -577,11 +643,14 @@ amf_sess_t *amf_sess_find_by_dnn(amf_ue_t *amf_ue, char *dnn); amf_ue_t *amf_ue_cycle(amf_ue_t *amf_ue); amf_sess_t *amf_sess_cycle(amf_sess_t *sess); -#define SESSION_SYNC_DONE(__aMF) (amf_sess_xact_count(__aMF) == 0) +#define SESSION_SYNC_DONE(__aMF, __sTATE) \ + (amf_sess_xact_state_count(__aMF, __sTATE) == 0) int amf_sess_xact_count(amf_ue_t *amf_ue); +int amf_sess_xact_state_count(amf_ue_t *amf_ue, int state); -#define SESSION_TRANSFER_NEEDED(__aMF) (amf_sess_transfer_needed(__aMF) == true) -bool amf_sess_transfer_needed(amf_ue_t *amf_ue); +#define PDU_RES_SETUP_REQ_TRANSFER_NEEDED(__aMF) \ + (amf_pdu_res_setup_req_transfer_needed(__aMF) == true) +bool amf_pdu_res_setup_req_transfer_needed(amf_ue_t *amf_ue); int amf_find_served_tai(ogs_5gs_tai_t *tai); ogs_s_nssai_t *amf_find_s_nssai( diff --git a/src/amf/gmm-handler.c b/src/amf/gmm-handler.c index a5e328823..5e7ec45be 100644 --- a/src/amf/gmm-handler.c +++ b/src/amf/gmm-handler.c @@ -102,8 +102,11 @@ int gmm_handle_registration_request(amf_ue_t *amf_ue, /* * REGISTRATION_REQUEST * SERVICE_REQUEST + * Clear N2 Transfer * Clear Timer and Message */ + AMF_UE_CLEAR_PAGING_INFO(amf_ue); + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, pdu_session_resource_setup_request); CLEAR_AMF_UE_ALL_TIMERS(amf_ue); if (SECURITY_CONTEXT_IS_VALID(amf_ue)) { @@ -126,7 +129,8 @@ int gmm_handle_registration_request(amf_ue_t *amf_ue, ogs_plmn_id_hexdump(&ran_ue->saved.nr_cgi.plmn_id), (long long)ran_ue->saved.nr_cgi.cell_id); - /* Copy TAI and ECGI from ran_ue */ + /* Copy Stream-No/TAI/ECGI from enb_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)); amf_ue->ue_location_timestamp = ogs_time_now(); @@ -269,36 +273,6 @@ int gmm_handle_registration_update(amf_ue_t *amf_ue, ogs_error("Not implemented for Allowed PDU Session Status IE"); } - if ((registration_request->presencemask & - OGS_NAS_5GS_REGISTRATION_REQUEST_UPLINK_DATA_STATUS_PRESENT) == 0) { - amf_ue->nas.present.uplink_data_status = 0; - } else { - amf_ue->nas.present.uplink_data_status = 1; - - psimask = 0; - psimask |= uplink_data_status->psi << 8; - psimask |= uplink_data_status->psi >> 8; - - ogs_list_for_each(&amf_ue->sess_list, sess) { - if (psimask & (1 << sess->psi)) { -#if REMOVED - /* - * TS23.502 - * 4.2.3.2 UE Triggered Service Request - * - * Step 4. The Nsmf_PDUSession_UpdateSMContext Request is invoked: - * - * - If the UE identifies List Of PDU Sessions To Be Activated - * in the Service Request message; - * if (sess->smfUpCnxState == OpenAPI_up_cnx_state_DEACTIVATED) - */ -#endif - if (SESSION_CONTEXT_IN_SMF(sess)) - amf_sbi_send_activating_session(sess); - } - } - } - if ((registration_request->presencemask & OGS_NAS_5GS_REGISTRATION_REQUEST_PDU_SESSION_STATUS_PRESENT) == 0) { amf_ue->nas.present.pdu_session_status = 0; @@ -318,6 +292,24 @@ int gmm_handle_registration_update(amf_ue_t *amf_ue, } } + if ((registration_request->presencemask & + OGS_NAS_5GS_REGISTRATION_REQUEST_UPLINK_DATA_STATUS_PRESENT) == 0) { + amf_ue->nas.present.uplink_data_status = 0; + } else { + amf_ue->nas.present.uplink_data_status = 1; + + psimask = 0; + psimask |= uplink_data_status->psi << 8; + psimask |= uplink_data_status->psi >> 8; + + 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); + } + } + } + return OGS_OK; } @@ -346,8 +338,10 @@ int gmm_handle_service_request(amf_ue_t *amf_ue, /* * REGISTRATION_REQUEST * SERVICE_REQUEST + * Clear Paging Info * Clear Timer and Message */ + AMF_UE_CLEAR_PAGING_INFO(amf_ue); CLEAR_AMF_UE_ALL_TIMERS(amf_ue); if (SECURITY_CONTEXT_IS_VALID(amf_ue)) { @@ -370,7 +364,8 @@ int gmm_handle_service_request(amf_ue_t *amf_ue, ogs_plmn_id_hexdump(&ran_ue->saved.nr_cgi.plmn_id), (long long)ran_ue->saved.nr_cgi.cell_id); - /* Copy TAI and ECGI from ran_ue */ + /* Copy Stream-No/TAI/ECGI from enb_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)); amf_ue->ue_location_timestamp = ogs_time_now(); @@ -423,44 +418,6 @@ int gmm_handle_service_update(amf_ue_t *amf_ue, xact_count = amf_sess_xact_count(amf_ue); - if ((service_request->presencemask & - OGS_NAS_5GS_SERVICE_REQUEST_ALLOWED_PDU_SESSION_STATUS_PRESENT) == 0) { - amf_ue->nas.present.allowed_pdu_session_status = 0; - } else { - amf_ue->nas.present.allowed_pdu_session_status = 1; - ogs_error("Not implemented for Allowed PDU Session Status IE"); - } - - if ((service_request->presencemask & - OGS_NAS_5GS_SERVICE_REQUEST_UPLINK_DATA_STATUS_PRESENT) == 0) { - amf_ue->nas.present.uplink_data_status = 0; - } else { - amf_ue->nas.present.uplink_data_status = 1; - - psimask = 0; - psimask |= uplink_data_status->psi << 8; - psimask |= uplink_data_status->psi >> 8; - - ogs_list_for_each(&amf_ue->sess_list, sess) { - if (psimask & (1 << sess->psi)) { -#if REMOVED - /* - * TS23.502 - * 4.2.3.2 UE Triggered Service Request - * - * Step 4. The Nsmf_PDUSession_UpdateSMContext Request is invoked: - * - * - If the UE identifies List Of PDU Sessions To Be Activated - * in the Service Request message; - * if (sess->smfUpCnxState == OpenAPI_up_cnx_state_DEACTIVATED) - */ -#endif - if (SESSION_CONTEXT_IN_SMF(sess)) - amf_sbi_send_activating_session(sess); - } - } - } - /* * TS24.501 * 5.6.1.5 Service request procedure not accepted by the network @@ -495,6 +452,32 @@ int gmm_handle_service_update(amf_ue_t *amf_ue, } } + if ((service_request->presencemask & + OGS_NAS_5GS_SERVICE_REQUEST_ALLOWED_PDU_SESSION_STATUS_PRESENT) == 0) { + amf_ue->nas.present.allowed_pdu_session_status = 0; + } else { + amf_ue->nas.present.allowed_pdu_session_status = 1; + ogs_error("Not implemented for Allowed PDU Session Status IE"); + } + + if ((service_request->presencemask & + OGS_NAS_5GS_SERVICE_REQUEST_UPLINK_DATA_STATUS_PRESENT) == 0) { + amf_ue->nas.present.uplink_data_status = 0; + } else { + amf_ue->nas.present.uplink_data_status = 1; + + psimask = 0; + psimask |= uplink_data_status->psi << 8; + psimask |= uplink_data_status->psi >> 8; + + 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); + } + } + } + if (amf_sess_xact_count(amf_ue) == xact_count) nas_5gs_send_service_accept(amf_ue); @@ -527,8 +510,7 @@ int gmm_handle_deregistration_request(amf_ue_t *amf_ue, ogs_info("[%s] SUCI", amf_ue->suci); - amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_sbi_send_release_all_sessions(amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (ogs_list_count(&amf_ue->sess_list) == 0) nas_5gs_send_de_registration_accept(amf_ue); @@ -810,7 +792,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_NO_STATE, NULL, + sess, AMF_SESS_SM_CONTEXT_NO_STATE, NULL, amf_nsmf_pdu_session_build_create_sm_context); } else { diff --git a/src/amf/gmm-sm.c b/src/amf/gmm-sm.c index ca34da5bb..688838bd1 100644 --- a/src/amf/gmm-sm.c +++ b/src/amf/gmm-sm.c @@ -64,6 +64,8 @@ void gmm_state_de_registered(ogs_fsm_t *s, amf_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: + AMF_UE_CLEAR_PAGING_INFO(amf_ue); + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, pdu_session_resource_setup_request); CLEAR_AMF_UE_ALL_TIMERS(amf_ue); break; case OGS_FSM_EXIT_SIG: @@ -159,7 +161,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) } else { amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { amf_ue_sbi_discover_and_send( OpenAPI_nf_type_AUSF, amf_ue, NULL, @@ -226,7 +228,7 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) } amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { amf_ue_sbi_discover_and_send(OpenAPI_nf_type_AUSF, amf_ue, NULL, amf_nausf_auth_build_authenticate); @@ -335,20 +337,32 @@ static void common_register_state(ogs_fsm_t *s, amf_event_t *e) case AMF_TIMER_T3513: if (amf_ue->t3513.retry_count >= amf_timer_cfg(AMF_TIMER_T3513)->max_count) { + amf_sess_t *sess = NULL; + /* Paging failed */ ogs_warn("[%s] Paging failed. Stop", amf_ue->supi); + + ogs_list_for_each(&amf_ue->sess_list, sess) { + if (sess->paging.ongoing == true) { + amf_sbi_send_n1_n2_failure_notify( + sess, OpenAPI_n1_n2_message_transfer_cause_UE_NOT_RESPONDING); + } + } + + /* Clear Paging Info */ + AMF_UE_CLEAR_PAGING_INFO(amf_ue); + + /* Clear N2 Transfer */ + AMF_UE_CLEAR_N2_TRANSFER( + amf_ue, pdu_session_resource_setup_request); + + /* Clear t3513 Timers */ CLEAR_AMF_UE_TIMER(amf_ue->t3513); } else { amf_ue->t3513.retry_count++; - /* - * If t3513 is timeout, the saved pkbuf is used. - * We don't have to set CNDomain. - * So, we just set CNDomain to 0 - */ -#if 0 - ngap_send_paging(amf_ue, 0); -#endif + /* If t3513 is timeout, the saved pkbuf is used. */ + ngap_send_paging(amf_ue); } break; @@ -700,13 +714,6 @@ void gmm_state_security_mode(ogs_fsm_t *s, amf_event_t *e) } else if (amf_ue->nas.message_type == OGS_NAS_5GS_SERVICE_REQUEST) { OGS_FSM_TRAN(s, &gmm_state_registered); -#if 0 - } else if (amf_ue->nas.message_type == - OGS_NAS_5GS_SERVICE_REQUEST || - amf_ue->nas.message_type == - AMF_EPS_TYPE_TAU_REQUEST) { - OGS_FSM_TRAN(s, &gmm_state_registered); -#endif } else { ogs_fatal("Invalid OGS_NAS_5GS[%d]", amf_ue->nas.message_type); ogs_assert_if_reached(); @@ -926,16 +933,10 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e) if (amf_ue->guti_present == 0) OGS_FSM_TRAN(&amf_ue->sm, &gmm_state_registered); - /* - * Do not use nas_5gs_send_registration_accept() - * instead of nas_5gs_send_accept() here. - * - * nas_5gs_send_service_accept() could be used later. - * The reason is why the design could be changed to handle this. - * - * So we'll use nas_5gs_send_accept() at this point. - */ - nas_5gs_send_accept(amf_ue); + /* If nas_5gs_send_service_accept() used, we need change it. */ + ogs_assert(amf_ue->nas.message_type == + OGS_NAS_5GS_REGISTRATION_REQUEST); + nas_5gs_send_registration_accept(amf_ue); break; DEFAULT @@ -1001,7 +1002,7 @@ void gmm_state_initial_context_setup(ogs_fsm_t *s, amf_event_t *e) } amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { amf_ue_sbi_discover_and_send(OpenAPI_nf_type_AUSF, amf_ue, NULL, amf_nausf_auth_build_authenticate); @@ -1066,10 +1067,11 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e) switch (e->id) { case OGS_FSM_ENTRY_SIG: + AMF_UE_CLEAR_PAGING_INFO(amf_ue); + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, pdu_session_resource_setup_request); CLEAR_AMF_UE_ALL_TIMERS(amf_ue); - amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_sbi_send_release_all_sessions(amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (ogs_list_count(&amf_ue->sess_list) == 0) ngap_send_amf_ue_context_release_command(amf_ue, @@ -1126,7 +1128,7 @@ void gmm_state_exception(ogs_fsm_t *s, amf_event_t *e) } else { amf_sbi_send_release_all_sessions( - amf_ue, AMF_RELEASE_SM_CONTEXT_NO_STATE); + amf_ue, AMF_SESS_SM_CONTEXT_NO_STATE); if (amf_sess_xact_count(amf_ue) == xact_count) { amf_ue_sbi_discover_and_send( OpenAPI_nf_type_AUSF, amf_ue, NULL, diff --git a/src/amf/namf-handler.c b/src/amf/namf-handler.c index f07bf304c..680068821 100644 --- a/src/amf/namf-handler.c +++ b/src/amf/namf-handler.c @@ -30,11 +30,10 @@ int amf_namf_comm_handle_n1_n2_message_transfer( int status; amf_ue_t *amf_ue = NULL; - ran_ue_t *ran_ue = NULL; amf_sess_t *sess = NULL; - ogs_pkbuf_t *n1smbuf = NULL; - ogs_pkbuf_t *n2smbuf = NULL; + ogs_pkbuf_t *n1buf = NULL; + ogs_pkbuf_t *n2buf = NULL; ogs_pkbuf_t *gmmbuf = NULL; ogs_pkbuf_t *ngapbuf = NULL; @@ -63,47 +62,6 @@ int amf_namf_comm_handle_n1_n2_message_transfer( return OGS_ERROR; } - n1MessageContainer = N1N2MessageTransferReqData->n1_message_container; - if (!n1MessageContainer) { - ogs_error("No n1MessageContainer"); - return OGS_ERROR; - } - n1MessageContent = n1MessageContainer->n1_message_content; - if (!n1MessageContent || !n1MessageContent->content_id) { - ogs_error("No n1MessageContent"); - return OGS_ERROR; - } - - n2InfoContainer = N1N2MessageTransferReqData->n2_info_container; - if (!n2InfoContainer) { - ogs_error("No n2InfoContainer"); - return OGS_ERROR; - } - smInfo = n2InfoContainer->sm_info; - if (!smInfo) { - ogs_error("No smInfo"); - return OGS_ERROR; - } - n2InfoContent = smInfo->n2_info_content; - if (!n2InfoContent) { - ogs_error("No n2InfoContent"); - return OGS_ERROR; - } - switch (n2InfoContent->ngap_ie_type) { - case OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ: - case OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ: - break; - default: - ogs_error("Not implemented ngap_ie_type[%d]", - n2InfoContent->ngap_ie_type); - return OGS_ERROR; - } - ngapData = n2InfoContent->ngap_data; - if (!ngapData || !ngapData->content_id) { - ogs_error("No ngapData"); - return OGS_ERROR; - } - pdu_session_id = N1N2MessageTransferReqData->pdu_session_id; if (pdu_session_id == OGS_NAS_PDU_SESSION_IDENTITY_UNASSIGNED) { ogs_error("No PDU Session Identity"); @@ -122,9 +80,6 @@ int amf_namf_comm_handle_n1_n2_message_transfer( return OGS_ERROR; } - ran_ue = ran_ue_cycle(amf_ue->ran_ue); - ogs_assert(ran_ue); - sess = amf_sess_find_by_psi(amf_ue, pdu_session_id); if (!sess) { ogs_error("[%s] No PDU Session Context [%d]", @@ -132,82 +87,278 @@ int amf_namf_comm_handle_n1_n2_message_transfer( return OGS_ERROR; } - n1smbuf = ogs_sbi_find_part_by_content_id( - recvmsg, n1MessageContent->content_id); - if (!n1smbuf) { - ogs_error("[%s] No N1 SM Content", amf_ue->supi); - return OGS_ERROR; + n1MessageContainer = N1N2MessageTransferReqData->n1_message_container; + if (n1MessageContainer) { + n1MessageContent = n1MessageContainer->n1_message_content; + if (!n1MessageContent || !n1MessageContent->content_id) { + ogs_error("No n1MessageContent"); + return OGS_ERROR; + } + + n1buf = ogs_sbi_find_part_by_content_id( + recvmsg, n1MessageContent->content_id); + if (!n1buf) { + ogs_error("[%s] No N1 SM Content", amf_ue->supi); + return OGS_ERROR; + } + + /* + * NOTE : The pkbuf created in the SBI message will be removed + * from ogs_sbi_message_free(), so it must be copied. + */ + n1buf = ogs_pkbuf_copy(n1buf); + ogs_assert(n1buf); } - /* - * NOTE : The pkbuf created in the SBI message will be removed - * from ogs_sbi_message_free(), so it must be copied. - */ - n1smbuf = ogs_pkbuf_copy(n1smbuf); - ogs_assert(n1smbuf); - n2smbuf = ogs_sbi_find_part_by_content_id(recvmsg, ngapData->content_id); - if (!n2smbuf) { - ogs_error("[%s] No N2 SM Content", amf_ue->supi); - return OGS_ERROR; + n2InfoContainer = N1N2MessageTransferReqData->n2_info_container; + if (n2InfoContainer) { + smInfo = n2InfoContainer->sm_info; + if (!smInfo) { + ogs_error("No smInfo"); + return OGS_ERROR; + } + n2InfoContent = smInfo->n2_info_content; + if (!n2InfoContent) { + ogs_error("No n2InfoContent"); + return OGS_ERROR; + } + + ngapData = n2InfoContent->ngap_data; + if (!ngapData || !ngapData->content_id) { + ogs_error("No ngapData"); + return OGS_ERROR; + } + n2buf = ogs_sbi_find_part_by_content_id( + recvmsg, ngapData->content_id); + if (!n2buf) { + ogs_error("[%s] No N2 SM Content", amf_ue->supi); + return OGS_ERROR; + } + + /* + * NOTE : The pkbuf created in the SBI message will be removed + * from ogs_sbi_message_free(), so it must be copied. + */ + n2buf = ogs_pkbuf_copy(n2buf); + ogs_assert(n2buf); } - /* - * NOTE : The pkbuf created in the SBI message will be removed - * from ogs_sbi_message_free(), so it must be copied. - */ - n2smbuf = ogs_pkbuf_copy(n2smbuf); - ogs_assert(n2smbuf); - - status = OGS_SBI_HTTP_STATUS_OK; - - gmmbuf = gmm_build_dl_nas_transport(sess, - OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, n1smbuf, 0, 0); - ogs_assert(gmmbuf); switch (n2InfoContent->ngap_ie_type) { case OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ: - if (sess->pdu_session_establishment_accept) { - ogs_pkbuf_free(sess->pdu_session_establishment_accept); - sess->pdu_session_establishment_accept = NULL; + case OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ: + case OpenAPI_ngap_ie_type_PDU_RES_REL_CMD: + /* N1 SM Message */ + if (n1buf) { + gmmbuf = gmm_build_dl_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, n1buf, 0, 0); + ogs_assert(gmmbuf); + } + break; + default: + ogs_error("Not implemented ngap_ie_type[%d]", + n2InfoContent->ngap_ie_type); + return OGS_ERROR; + } + + memset(&sendmsg, 0, sizeof(sendmsg)); + + status = OGS_SBI_HTTP_STATUS_OK; + + memset(&N1N2MessageTransferRspData, 0, sizeof(N1N2MessageTransferRspData)); + N1N2MessageTransferRspData.cause = + OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED; + + sendmsg.N1N2MessageTransferRspData = &N1N2MessageTransferRspData; + + switch (n2InfoContent->ngap_ie_type) { + case OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ: + if (!n2buf) { + ogs_error("[%s] No N2 SM Content", amf_ue->supi); + return OGS_ERROR; } - if (ran_ue->initial_context_setup_request_sent == true) { - ngapbuf = ngap_sess_build_pdu_session_resource_setup_request( - sess, gmmbuf, n2smbuf); - ogs_assert(ngapbuf); - } else { - ngapbuf = ngap_sess_build_initial_context_setup_request( - sess, gmmbuf, n2smbuf); - ogs_assert(ngapbuf); + if (gmmbuf) { + ran_ue_t *ran_ue = NULL; - ran_ue->initial_context_setup_request_sent = true; - } + /*********************************** + * 4.3.2 PDU Session Establishment * + ***********************************/ - if (SESSION_CONTEXT_IN_SMF(sess)) { - /* - * [1-CLIENT] /nsmf-pdusession/v1/sm-contexts - * [2-SERVER] /namf-comm/v1/ue-contexts/{supi}/n1-n2-messages - * - * If [2-SERVER] arrives after [1-CLIENT], - * sm-context-ref is created in [1-CLIENT]. - * So, the PDU session establishment accpet can be transmitted now. - */ - if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK) { - ogs_error("nas_5gs_send_to_gnb() failed"); - status = OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + ran_ue = ran_ue_cycle(amf_ue->ran_ue); + ogs_assert(ran_ue); + + if (sess->pdu_session_establishment_accept) { + ogs_pkbuf_free(sess->pdu_session_establishment_accept); + sess->pdu_session_establishment_accept = NULL; } + + if (ran_ue->initial_context_setup_request_sent == true) { + ngapbuf = ngap_sess_build_pdu_session_resource_setup_request( + sess, gmmbuf, n2buf); + ogs_assert(ngapbuf); + } else { + ngapbuf = ngap_sess_build_initial_context_setup_request( + sess, gmmbuf, n2buf); + ogs_assert(ngapbuf); + + ran_ue->initial_context_setup_request_sent = true; + } + + if (SESSION_CONTEXT_IN_SMF(sess)) { + /* + * [1-CLIENT] /nsmf-pdusession/v1/sm-contexts + * [2-SERVER] /namf-comm/v1/ue-contexts/{supi}/n1-n2-messages + * + * If [2-SERVER] arrives after [1-CLIENT], + * sm-context-ref is created in [1-CLIENT]. + * So, the PDU session establishment accpet can be transmitted. + */ + if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK) + ogs_error("nas_5gs_send_to_gnb() failed"); + } else { + sess->pdu_session_establishment_accept = ngapbuf; + } + } else { - sess->pdu_session_establishment_accept = ngapbuf; + /********************************************* + * 4.2.3.3 Network Triggered Service Request * + *********************************************/ + + if (CM_IDLE(amf_ue)) { + ogs_sbi_server_t *server = NULL; + ogs_sbi_header_t header; + ogs_sbi_client_t *client = NULL; + ogs_sockaddr_t *addr = NULL; + + if (!N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri) { + ogs_error("[%s:%d] No n1-n2-failure-notification-uri", + amf_ue->supi, sess->psi); + return OGS_ERROR; + } + + addr = ogs_sbi_getaddr_from_uri( + N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri); + if (!addr) { + ogs_error("[%s:%d] Invalid URI [%s]", + amf_ue->supi, sess->psi, + N1N2MessageTransferReqData-> + n1n2_failure_txf_notif_uri); + return OGS_ERROR;; + } + + client = ogs_sbi_client_find(addr); + if (!client) { + client = ogs_sbi_client_add(addr); + ogs_assert(client); + } + OGS_SETUP_SBI_CLIENT(&sess->paging, client); + + ogs_freeaddrinfo(addr); + + status = OGS_SBI_HTTP_STATUS_ACCEPTED; + N1N2MessageTransferRspData.cause = + OpenAPI_n1_n2_message_transfer_cause_ATTEMPTING_TO_REACH_UE; + + /* Location */ + server = ogs_sbi_server_from_stream(stream); + ogs_assert(server); + + memset(&header, 0, sizeof(header)); + header.service.name = (char *)OGS_SBI_SERVICE_NAME_NAMF_COMM; + header.api.version = (char *)OGS_SBI_API_V1; + header.resource.component[0] = + (char *)OGS_SBI_RESOURCE_NAME_UE_CONTEXTS; + header.resource.component[1] = amf_ue->supi; + header.resource.component[2] = + (char *)OGS_SBI_RESOURCE_NAME_N1_N2_MESSAGES; + header.resource.component[3] = sess->sm_context_ref; + + sendmsg.http.location = ogs_sbi_server_uri(server, &header); + + /* Store Paging Info */ + AMF_SESS_STORE_PAGING_INFO( + sess, sendmsg.http.location, + N1N2MessageTransferReqData->n1n2_failure_txf_notif_uri); + + /* Store N2 Transfer message */ + AMF_SESS_STORE_N2_TRANSFER( + sess, pdu_session_resource_setup_request, n2buf); + + ngap_send_paging(amf_ue); + + } else if (CM_CONNECTED(amf_ue)) { + ngap_send_pdu_resource_setup_request(sess, n2buf); + + } else { + + ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi); + ogs_assert_if_reached(); + + } + } break; case OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ: - ngapbuf = ngap_build_pdu_session_resource_modify_request( - sess, gmmbuf, n2smbuf); - ogs_assert(ngapbuf); + if (!gmmbuf) { + ogs_error("[%s] No N1 SM Content", amf_ue->supi); + return OGS_ERROR; + } + if (!n2buf) { + ogs_error("[%s] No N2 SM Content", amf_ue->supi); + return OGS_ERROR; + } - if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK) { - ogs_error("nas_5gs_send_to_gnb() failed"); - status = OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR; + if (CM_IDLE(amf_ue)) { + ogs_fatal("[%s] IDLE state is not implemented", amf_ue->supi); + ogs_assert_if_reached(); + + } else if (CM_CONNECTED(amf_ue)) { + ngapbuf = ngap_build_pdu_session_resource_modify_request( + sess, gmmbuf, n2buf); + ogs_assert(ngapbuf); + + if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK) + ogs_error("nas_5gs_send_to_gnb() failed"); + + } else { + ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi); + ogs_assert_if_reached(); + } + + break; + + case OpenAPI_ngap_ie_type_PDU_RES_REL_CMD: + if (!n2buf) { + ogs_error("[%s] No N2 SM Content", amf_ue->supi); + return OGS_ERROR; + } + + if (CM_IDLE(amf_ue)) { + if (gmmbuf) + ogs_pkbuf_free(gmmbuf); + if (n2buf) + ogs_pkbuf_free(n2buf); + + if (N1N2MessageTransferReqData->skip_ind == true) { + N1N2MessageTransferRspData.cause = + OpenAPI_n1_n2_message_transfer_cause_N1_MSG_NOT_TRANSFERRED; + } else { + ogs_fatal("[%s] No skipInd", amf_ue->supi); + ogs_assert_if_reached(); + } + + } else if (CM_CONNECTED(amf_ue)) { + ngapbuf = ngap_build_pdu_session_resource_release_command( + sess, NULL, n2buf); + ogs_assert(ngapbuf); + + if (nas_5gs_send_to_gnb(amf_ue, ngapbuf) != OGS_OK) + ogs_error("nas_5gs_send_to_gnb() failed"); + + } else { + ogs_fatal("[%s] Invalid AMF-UE state", amf_ue->supi); + ogs_assert_if_reached(); } break; @@ -217,21 +368,13 @@ int amf_namf_comm_handle_n1_n2_message_transfer( ogs_assert_if_reached(); } - memset(&sendmsg, 0, sizeof(sendmsg)); - - if (status == OGS_SBI_HTTP_STATUS_OK) { - memset(&N1N2MessageTransferRspData, 0, - sizeof(N1N2MessageTransferRspData)); - N1N2MessageTransferRspData.cause = - OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED; - - sendmsg.N1N2MessageTransferRspData = &N1N2MessageTransferRspData; - } - response = ogs_sbi_build_response(&sendmsg, status); ogs_assert(response); ogs_sbi_server_send_response(stream, response); + if (sendmsg.http.location) + ogs_free(sendmsg.http.location); + return OGS_OK; } @@ -322,7 +465,7 @@ int amf_namf_callback_handle_sm_context_status( ogs_debug("[%s:%d] SM context remove", amf_ue->supi, sess->psi); amf_nsmf_pdu_session_handle_release_sm_context( - sess, AMF_RELEASE_SM_CONTEXT_NO_STATE); + sess, AMF_SESS_SM_CONTEXT_NO_STATE); } cleanup: diff --git a/src/amf/nas-path.c b/src/amf/nas-path.c index 283b3e964..03ecdfbc5 100644 --- a/src/amf/nas-path.c +++ b/src/amf/nas-path.c @@ -89,7 +89,7 @@ void nas_5gs_send_registration_accept(amf_ue_t *amf_ue) ran_ue->initial_context_setup_request_sent = true; } else { - if (SESSION_TRANSFER_NEEDED(amf_ue)) { + if (PDU_RES_SETUP_REQ_TRANSFER_NEEDED(amf_ue)) { ngapbuf = ngap_ue_build_pdu_session_resource_setup_request( amf_ue, gmmbuf); ogs_expect_or_return(ngapbuf); @@ -141,8 +141,7 @@ void nas_5gs_send_service_accept(amf_ue_t *amf_ue) if (ran_ue->ue_context_requested == true && ran_ue->initial_context_setup_request_sent == false) { - ngapbuf = ngap_ue_build_initial_context_setup_request( - amf_ue, gmmbuf); + ngapbuf = ngap_ue_build_initial_context_setup_request(amf_ue, gmmbuf); ogs_expect_or_return(ngapbuf); rv = nas_5gs_send_to_gnb(amf_ue, ngapbuf); @@ -150,7 +149,7 @@ void nas_5gs_send_service_accept(amf_ue_t *amf_ue) ran_ue->initial_context_setup_request_sent = true; } else { - if (SESSION_TRANSFER_NEEDED(amf_ue)) { + if (PDU_RES_SETUP_REQ_TRANSFER_NEEDED(amf_ue)) { ngapbuf = ngap_ue_build_pdu_session_resource_setup_request( amf_ue, gmmbuf); ogs_expect_or_return(ngapbuf); @@ -179,22 +178,6 @@ void nas_5gs_send_service_reject( ogs_expect(rv == OGS_OK); } -void nas_5gs_send_accept(amf_ue_t *amf_ue) -{ - ogs_assert(amf_ue); - - switch(amf_ue->nas.message_type) { - case OGS_NAS_5GS_REGISTRATION_REQUEST: - nas_5gs_send_registration_accept(amf_ue); - break; - case OGS_NAS_5GS_SERVICE_REQUEST: - nas_5gs_send_service_accept(amf_ue); - break; - default: - ogs_error("Unknown message type [%d]", amf_ue->nas.message_type); - } -} - void nas_5gs_send_de_registration_accept(amf_ue_t *amf_ue) { ran_ue_t *ran_ue = NULL; diff --git a/src/amf/nas-path.h b/src/amf/nas-path.h index dd75cf6f2..4063641fe 100644 --- a/src/amf/nas-path.h +++ b/src/amf/nas-path.h @@ -40,8 +40,6 @@ void nas_5gs_send_service_accept(amf_ue_t *amf_ue); void nas_5gs_send_service_reject( amf_ue_t *amf_ue, ogs_nas_5gmm_cause_t gmm_cause); -void nas_5gs_send_accept(amf_ue_t *amf_ue); - void nas_5gs_send_de_registration_accept(amf_ue_t *amf_ue); void nas_5gs_send_identity_request(amf_ue_t *amf_ue); diff --git a/src/amf/ngap-build.c b/src/amf/ngap-build.c index 111afa1b0..4ba569960 100644 --- a/src/amf/ngap-build.c +++ b/src/amf/ngap-build.c @@ -240,8 +240,7 @@ ogs_pkbuf_t *ngap_build_downlink_nas_transport( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -389,8 +388,7 @@ ogs_pkbuf_t *ngap_ue_build_initial_context_setup_request( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -659,7 +657,7 @@ ogs_pkbuf_t *ngap_ue_build_initial_context_setup_request( } ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request( - amf_sess_t *sess, ogs_pkbuf_t *n1smbuf, ogs_pkbuf_t *n2smbuf) + amf_sess_t *sess, ogs_pkbuf_t *gmmbuf, ogs_pkbuf_t *n2smbuf) { int i, j; @@ -752,12 +750,14 @@ ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request( GUAMI = &ie->value.choice.GUAMI; - if (n1smbuf && n2smbuf) { + if (gmmbuf || n2smbuf) { NGAP_NAS_PDU_t *nAS_PDU = NULL; OCTET_STRING_t *transfer = NULL; NGAP_S_NSSAI_t *s_NSSAI = NULL; NGAP_SST_t *sST = NULL; + ogs_assert(n2smbuf); + ie = CALLOC(1, sizeof(NGAP_InitialContextSetupRequestIEs_t)); ASN_SEQUENCE_ADD(&InitialContextSetupRequest->protocolIEs, ie); @@ -771,13 +771,15 @@ ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request( sizeof(struct NGAP_PDUSessionResourceSetupItemCxtReq)); ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); - PDUSessionItem->nAS_PDU = nAS_PDU = CALLOC(1, sizeof(*nAS_PDU)); - ogs_assert(nAS_PDU); + if (gmmbuf) { + PDUSessionItem->nAS_PDU = nAS_PDU = CALLOC(1, sizeof(*nAS_PDU)); + ogs_assert(nAS_PDU); - nAS_PDU->size = n1smbuf->len; - nAS_PDU->buf = CALLOC(nAS_PDU->size, sizeof(uint8_t)); - memcpy(nAS_PDU->buf, n1smbuf->data, nAS_PDU->size); - ogs_pkbuf_free(n1smbuf); + nAS_PDU->size = gmmbuf->len; + nAS_PDU->buf = CALLOC(nAS_PDU->size, sizeof(uint8_t)); + memcpy(nAS_PDU->buf, gmmbuf->data, nAS_PDU->size); + ogs_pkbuf_free(gmmbuf); + } PDUSessionItem->pDUSessionID = sess->psi; @@ -973,8 +975,7 @@ ogs_pkbuf_t *ngap_build_ue_context_modification_request(amf_ue_t *amf_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)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -1106,8 +1107,7 @@ ogs_pkbuf_t *ngap_build_ue_context_release_command( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = NGAP_ProcedureCode_id_UEContextRelease; @@ -1175,7 +1175,6 @@ ogs_pkbuf_t *ngap_ue_build_pdu_session_resource_setup_request( NGAP_PDUSessionResourceSetupListSUReq_t *PDUSessionList = NULL; NGAP_PDUSessionResourceSetupItemSUReq_t *PDUSessionItem = NULL; - ogs_assert(gmmbuf); ogs_assert(amf_ue); ran_ue = ran_ue_cycle(amf_ue->ran_ue); ogs_assert(ran_ue); @@ -1220,20 +1219,22 @@ ogs_pkbuf_t *ngap_ue_build_pdu_session_resource_setup_request( asn_uint642INTEGER(AMF_UE_NGAP_ID, ran_ue->amf_ue_ngap_id); *RAN_UE_NGAP_ID = ran_ue->ran_ue_ngap_id; - ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestIEs_t)); - ASN_SEQUENCE_ADD(&PDUSessionResourceSetupRequest->protocolIEs, ie); + if (gmmbuf) { + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceSetupRequestIEs_t)); + ASN_SEQUENCE_ADD(&PDUSessionResourceSetupRequest->protocolIEs, ie); - ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; - ie->criticality = NGAP_Criticality_reject; - ie->value.present = - NGAP_PDUSessionResourceSetupRequestIEs__value_PR_NAS_PDU; + ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; + ie->criticality = NGAP_Criticality_reject; + ie->value.present = + NGAP_PDUSessionResourceSetupRequestIEs__value_PR_NAS_PDU; - NAS_PDU = &ie->value.choice.NAS_PDU; + NAS_PDU = &ie->value.choice.NAS_PDU; - NAS_PDU->size = gmmbuf->len; - NAS_PDU->buf = CALLOC(NAS_PDU->size, sizeof(uint8_t)); - memcpy(NAS_PDU->buf, gmmbuf->data, NAS_PDU->size); - ogs_pkbuf_free(gmmbuf); + NAS_PDU->size = gmmbuf->len; + NAS_PDU->buf = CALLOC(NAS_PDU->size, sizeof(uint8_t)); + memcpy(NAS_PDU->buf, gmmbuf->data, NAS_PDU->size); + ogs_pkbuf_free(gmmbuf); + } ogs_list_for_each(&amf_ue->sess_list, sess) { NGAP_S_NSSAI_t *s_NSSAI = NULL; @@ -1302,7 +1303,6 @@ ogs_pkbuf_t *ngap_sess_build_pdu_session_resource_setup_request( NGAP_SST_t *sST = NULL; OCTET_STRING_t *transfer = NULL; - ogs_assert(gmmbuf); ogs_assert(n2smbuf); ogs_assert(sess); @@ -1366,12 +1366,15 @@ ogs_pkbuf_t *ngap_sess_build_pdu_session_resource_setup_request( PDUSessionItem->pDUSessionID = sess->psi; - PDUSessionItem->pDUSessionNAS_PDU = - pDUSessionNAS_PDU = CALLOC(1, sizeof(NGAP_NAS_PDU_t)); - pDUSessionNAS_PDU->size = gmmbuf->len; - pDUSessionNAS_PDU->buf = CALLOC(pDUSessionNAS_PDU->size, sizeof(uint8_t)); - memcpy(pDUSessionNAS_PDU->buf, gmmbuf->data, pDUSessionNAS_PDU->size); - ogs_pkbuf_free(gmmbuf); + if (gmmbuf) { + PDUSessionItem->pDUSessionNAS_PDU = + pDUSessionNAS_PDU = CALLOC(1, sizeof(NGAP_NAS_PDU_t)); + pDUSessionNAS_PDU->size = gmmbuf->len; + pDUSessionNAS_PDU->buf = + CALLOC(pDUSessionNAS_PDU->size, sizeof(uint8_t)); + memcpy(pDUSessionNAS_PDU->buf, gmmbuf->data, pDUSessionNAS_PDU->size); + ogs_pkbuf_free(gmmbuf); + } s_NSSAI = &PDUSessionItem->s_NSSAI; sST = &s_NSSAI->sST; @@ -1507,7 +1510,6 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( NGAP_PDUSessionResourceToReleaseItemRelCmd_t *PDUSessionItem = NULL; OCTET_STRING_t *transfer = NULL; - ogs_assert(gmmbuf); ogs_assert(n2smbuf); ogs_assert(sess); @@ -1550,15 +1552,28 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( RAN_UE_NGAP_ID = &ie->value.choice.RAN_UE_NGAP_ID; - ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceReleaseCommandIEs_t)); - ASN_SEQUENCE_ADD(&PDUSessionResourceReleaseCommand->protocolIEs, ie); + 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); - ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = - NGAP_PDUSessionResourceReleaseCommandIEs__value_PR_NAS_PDU; + asn_uint642INTEGER(AMF_UE_NGAP_ID, ran_ue->amf_ue_ngap_id); + *RAN_UE_NGAP_ID = ran_ue->ran_ue_ngap_id; - NAS_PDU = &ie->value.choice.NAS_PDU; + if (gmmbuf) { + ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceReleaseCommandIEs_t)); + ASN_SEQUENCE_ADD(&PDUSessionResourceReleaseCommand->protocolIEs, ie); + + ie->id = NGAP_ProtocolIE_ID_id_NAS_PDU; + ie->criticality = NGAP_Criticality_ignore; + ie->value.present = + NGAP_PDUSessionResourceReleaseCommandIEs__value_PR_NAS_PDU; + + NAS_PDU = &ie->value.choice.NAS_PDU; + + NAS_PDU->size = gmmbuf->len; + NAS_PDU->buf = CALLOC(NAS_PDU->size, sizeof(uint8_t)); + memcpy(NAS_PDU->buf, gmmbuf->data, NAS_PDU->size); + ogs_pkbuf_free(gmmbuf); + } ie = CALLOC(1, sizeof(NGAP_PDUSessionResourceReleaseCommandIEs_t)); ASN_SEQUENCE_ADD(&PDUSessionResourceReleaseCommand->protocolIEs, ie); @@ -1569,17 +1584,6 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( PDUSessionList = &ie->value.choice.PDUSessionResourceToReleaseListRelCmd; - 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); - - asn_uint642INTEGER(AMF_UE_NGAP_ID, ran_ue->amf_ue_ngap_id); - *RAN_UE_NGAP_ID = ran_ue->ran_ue_ngap_id; - - NAS_PDU->size = gmmbuf->len; - NAS_PDU->buf = CALLOC(NAS_PDU->size, sizeof(uint8_t)); - memcpy(NAS_PDU->buf, gmmbuf->data, NAS_PDU->size); - ogs_pkbuf_free(gmmbuf); - PDUSessionItem = CALLOC(1, sizeof(struct NGAP_PDUSessionResourceToReleaseItemRelCmd)); ASN_SEQUENCE_ADD(&PDUSessionList->list, PDUSessionItem); @@ -1595,9 +1599,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( return ogs_ngap_encode(&pdu); } -#if 0 -ogs_pkbuf_t *ngap_build_paging( - amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain) +ogs_pkbuf_t *ngap_build_paging(amf_ue_t *amf_ue) { NGAP_NGAP_PDU_t pdu; NGAP_InitiatingMessage_t *initiatingMessage = NULL; @@ -1605,26 +1607,20 @@ ogs_pkbuf_t *ngap_build_paging( NGAP_PagingIEs_t *ie = NULL; - NGAP_UEIdentityIndexValue_t *UEIdentityIndexValue = NULL; - NGAP_UEPagingID_t *UEPagingID = NULL; - NGAP_CNDomain_t *CNDomain = NULL; - NGAP_TAIList_t *TAIList = NULL; - - NGAP_TAIItemIEs_t *item = NULL; - NGAP_TAIItem_t *tai_item = NULL; - - uint16_t index_value; - uint64_t ue_imsi_value = 0; - int i = 0; - - ogs_assert(amf_ue); + NGAP_UEPagingIdentity_t *UEPagingIdentity = NULL; + NGAP_FiveG_S_TMSI_t *fiveG_S_TMSI = NULL; + NGAP_AMFSetID_t *aMFSetID = NULL; + NGAP_AMFPointer_t *aMFPointer = NULL; + NGAP_FiveG_TMSI_t *fiveG_TMSI = NULL; + NGAP_TAIListForPaging_t *TAIList = NULL; + NGAP_TAIListForPagingItem_t *TAIItem = NULL; + NGAP_TAI_t *tAI = NULL; ogs_debug("Paging"); memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = NGAP_ProcedureCode_id_Paging; @@ -1636,89 +1632,46 @@ ogs_pkbuf_t *ngap_build_paging( ie = CALLOC(1, sizeof(NGAP_PagingIEs_t)); ASN_SEQUENCE_ADD(&Paging->protocolIEs, ie); - ie->id = NGAP_ProtocolIE_ID_id_UEIdentityIndexValue; + ie->id = NGAP_ProtocolIE_ID_id_UEPagingIdentity; ie->criticality = NGAP_Criticality_ignore; - ie->value.present = NGAP_PagingIEs__value_PR_UEIdentityIndexValue; + ie->value.present = NGAP_PagingIEs__value_PR_UEPagingIdentity; - UEIdentityIndexValue = &ie->value.choice.UEIdentityIndexValue; + UEPagingIdentity = &ie->value.choice.UEPagingIdentity; + + UEPagingIdentity->present = NGAP_UEPagingIdentity_PR_fiveG_S_TMSI; + UEPagingIdentity->choice.fiveG_S_TMSI = fiveG_S_TMSI = + CALLOC(1, sizeof(NGAP_FiveG_S_TMSI_t)); + ogs_assert(fiveG_S_TMSI); + + aMFSetID = &fiveG_S_TMSI->aMFSetID; + aMFPointer = &fiveG_S_TMSI->aMFPointer; + fiveG_TMSI = &fiveG_S_TMSI->fiveG_TMSI; + + ogs_ngap_uint16_to_AMFSetID( + ogs_amf_set_id(&amf_ue->guti.amf_id), aMFSetID); + ogs_ngap_uint8_to_AMFPointer( + ogs_amf_pointer(&amf_ue->guti.amf_id), aMFPointer); + ogs_asn_uint32_to_OCTET_STRING(amf_ue->guti.m_tmsi, fiveG_TMSI); ie = CALLOC(1, sizeof(NGAP_PagingIEs_t)); ASN_SEQUENCE_ADD(&Paging->protocolIEs, ie); - ie->id = NGAP_ProtocolIE_ID_id_UEPagingID; + ie->id = NGAP_ProtocolIE_ID_id_TAIListForPaging; ie->criticality = NGAP_Criticality_ignore; - ie->value.present = NGAP_PagingIEs__value_PR_UEPagingID; + ie->value.present = NGAP_PagingIEs__value_PR_TAIListForPaging; - UEPagingID = &ie->value.choice.UEPagingID; + TAIList = &ie->value.choice.TAIListForPaging; - ie = CALLOC(1, sizeof(NGAP_PagingIEs_t)); - ASN_SEQUENCE_ADD(&Paging->protocolIEs, ie); + TAIItem = CALLOC(1, sizeof(NGAP_TAIListForPagingItem_t)); + ASN_SEQUENCE_ADD(&TAIList->list, TAIItem); - ie->id = NGAP_ProtocolIE_ID_id_CNDomain; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = NGAP_PagingIEs__value_PR_CNDomain; - - CNDomain = &ie->value.choice.CNDomain; - - ie = CALLOC(1, sizeof(NGAP_PagingIEs_t)); - ASN_SEQUENCE_ADD(&Paging->protocolIEs, ie); - - ie->id = NGAP_ProtocolIE_ID_id_TAIList; - ie->criticality = NGAP_Criticality_ignore; - ie->value.present = NGAP_PagingIEs__value_PR_TAIList; - - TAIList = &ie->value.choice.TAIList; - - /* Set UE Identity Index value : IMSI mod 4096 */ - UEIdentityIndexValue->size = 2; - UEIdentityIndexValue->buf = - CALLOC(UEIdentityIndexValue->size, sizeof(uint8_t)); - - /* Conver string to value */ - for (i = 0; i < strlen(amf_ue->imsi_bcd); i++) { - ue_imsi_value = ue_imsi_value*10 + (amf_ue->imsi_bcd[i] - '0'); - } - - /* index(10bit) = ue_imsi_value mod 1024 */ - index_value = ue_imsi_value % 1024; - UEIdentityIndexValue->buf[0] = index_value >> 2; - UEIdentityIndexValue->buf[1] = (index_value & 0x3f) << 6; - UEIdentityIndexValue->bits_unused = 6; - - /* Set Paging Identity */ - UEPagingID->present = NGAP_UEPagingID_PR_s_TMSI; - UEPagingID->choice.s_TMSI = - CALLOC(1, sizeof(NGAP_S_TMSI_t)); - ogs_asn_uint8_to_OCTET_STRING(amf_ue->guti.amf_code, - &UEPagingID->choice.s_TMSI->mMEC); - - ogs_asn_uint32_to_OCTET_STRING(amf_ue->guti.m_tmsi, - &UEPagingID->choice.s_TMSI->m_TMSI); - - ogs_debug(" AMF_CODE[%d] M_TMSI[0x%x]", - amf_ue->guti.amf_code, amf_ue->guti.m_tmsi); - ogs_debug(" CN_DOMAIN[%s]", - cn_domain == NGAP_CNDomain_cs ? "CS" : - cn_domain == NGAP_CNDomain_ps ? "PS" : "Unknown"); - - *CNDomain = cn_domain; - - item = CALLOC(1, sizeof(NGAP_TAIItemIEs_t)); - ASN_SEQUENCE_ADD(&TAIList->list, item); - - item->id = NGAP_ProtocolIE_ID_id_TAIItem; - item->criticality = NGAP_Criticality_ignore; - item->value.present = NGAP_TAIItemIEs__value_PR_TAIItem; - - tai_item = &item->value.choice.TAIItem; - - ogs_asn_buffer_to_OCTET_STRING(&amf_ue->tai.plmn_id, sizeof(ogs_plmn_id_t), - &tai_item->tAI.pLMNidentity); - ogs_asn_uint16_to_OCTET_STRING(amf_ue->tai.tac, &tai_item->tAI.tAC); + tAI = &TAIItem->tAI; + ogs_ngap_5gs_tai_to_ASN(&amf_ue->tai, tAI); return ogs_ngap_encode(&pdu); } +#if 0 ogs_pkbuf_t *ngap_build_amf_configuration_transfer( NGAP_SONConfigurationTransfer_t *son_configuration_transfer) { @@ -1737,8 +1690,7 @@ ogs_pkbuf_t *ngap_build_amf_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)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -2217,8 +2169,7 @@ ogs_pkbuf_t *ngap_build_handover_request( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -2500,8 +2451,7 @@ ogs_pkbuf_t *ngap_build_amf_status_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)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = NGAP_ProcedureCode_id_AMFStatusTransfer; @@ -2574,8 +2524,7 @@ ogs_pkbuf_t *ngap_build_error_indication( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = NGAP_ProcedureCode_id_ErrorIndication; @@ -2648,8 +2597,7 @@ ogs_pkbuf_t *ngap_build_s1_reset( memset(&pdu, 0, sizeof (NGAP_NGAP_PDU_t)); pdu.present = NGAP_NGAP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(NGAP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = NGAP_ProcedureCode_id_Reset; diff --git a/src/amf/ngap-build.h b/src/amf/ngap-build.h index de1715a38..8996af8ad 100644 --- a/src/amf/ngap-build.h +++ b/src/amf/ngap-build.h @@ -36,7 +36,7 @@ ogs_pkbuf_t *ngap_build_downlink_nas_transport( ogs_pkbuf_t *ngap_ue_build_initial_context_setup_request( amf_ue_t *amf_ue, ogs_pkbuf_t *gmmbuf); ogs_pkbuf_t *ngap_sess_build_initial_context_setup_request( - amf_sess_t *sess, ogs_pkbuf_t *n1smbuf, ogs_pkbuf_t *n2smbuf); + amf_sess_t *sess, ogs_pkbuf_t *gmmbuf, ogs_pkbuf_t *n2smbuf); ogs_pkbuf_t *ngap_build_ue_context_modification_request(amf_ue_t *amf_ue); ogs_pkbuf_t *ngap_build_ue_context_release_command( ran_ue_t *ran_ue, NGAP_Cause_PR group, long cause); @@ -50,10 +50,7 @@ ogs_pkbuf_t *ngap_build_pdu_session_resource_modify_request( ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command( amf_sess_t *sess, ogs_pkbuf_t *gmmbuf, ogs_pkbuf_t *n2smbuf); -#if 0 -ogs_pkbuf_t *ngap_build_paging( - amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain); -#endif +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); diff --git a/src/amf/ngap-handler.c b/src/amf/ngap-handler.c index 746fd301a..92eb61b70 100644 --- a/src/amf/ngap-handler.c +++ b/src/amf/ngap-handler.c @@ -1876,7 +1876,8 @@ void ngap_handle_path_switch_request( ogs_ngap_ASN_to_5gs_tai( &UserLocationInformationNR->tAI, &ran_ue->saved.tai); - /* Copy TAI and ECGI from ran_ue */ + /* Copy Stream-No/TAI/ECGI from enb_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)); diff --git a/src/amf/ngap-path.c b/src/amf/ngap-path.c index 2140d5679..22c2dbdec 100644 --- a/src/amf/ngap-path.c +++ b/src/amf/ngap-path.c @@ -320,42 +320,78 @@ void ngap_send_amf_ue_context_release_command( } } -#if 0 -void ngap_send_paging(amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain) +void ngap_send_paging(amf_ue_t *amf_ue) { ogs_pkbuf_t *ngapbuf = NULL; amf_gnb_t *gnb = NULL; - int i; + int i, j; int rv; - /* Find enB with matched TAI */ ogs_list_for_each(&amf_self()->gnb_list, gnb) { for (i = 0; i < gnb->num_of_supported_ta_list; i++) { + for (j = 0; j < gnb->supported_ta_list[i].num_of_bplmn_list; j++) { + if (memcmp(&gnb->supported_ta_list[i].bplmn_list[j].plmn_id, + &amf_ue->tai.plmn_id, OGS_PLMN_ID_LEN) == 0 && + gnb->supported_ta_list[i].tac.v == amf_ue->tai.tac.v) { - if (memcmp(&gnb->supported_ta_list[i], &amf_ue->tai, - sizeof(ogs_5gs_tai_t)) == 0) { + if (amf_ue->t3513.pkbuf) { + ngapbuf = amf_ue->t3513.pkbuf; + } else { + ngapbuf = ngap_build_paging(amf_ue); + ogs_expect_or_return(ngapbuf); + } - if (amf_ue->t3413.pkbuf) { - ngapbuf = amf_ue->t3413.pkbuf; - } else { - ngapbuf = ngap_build_paging(amf_ue, cn_domain); - ogs_expect_or_return(ngapbuf); + amf_ue->t3513.pkbuf = ogs_pkbuf_copy(ngapbuf); + ogs_assert(amf_ue->t3513.pkbuf); + + rv = ngap_send_to_gnb(gnb, ngapbuf, amf_ue->gnb_ostream_id); + ogs_expect(rv == OGS_OK); } - - amf_ue->t3413.pkbuf = ogs_pkbuf_copy(ngapbuf); - ogs_assert(amf_ue->t3413.pkbuf); - - rv = ngap_send_to_gnb(gnb, ngapbuf, NGAP_NON_UE_SIGNALLING); - ogs_expect(rv == OGS_OK); } } } - /* Start T3413 */ - ogs_timer_start(amf_ue->t3413.timer, - amf_timer_cfg(AMF_TIMER_T3413)->duration); + /* Start T3513 */ + ogs_timer_start(amf_ue->t3513.timer, + amf_timer_cfg(AMF_TIMER_T3513)->duration); } +void ngap_send_pdu_resource_setup_request( + amf_sess_t *sess, ogs_pkbuf_t *n2smbuf) +{ + int rv; + ran_ue_t *ran_ue = NULL; + amf_ue_t *amf_ue = NULL; + + ogs_pkbuf_t *ngapbuf = NULL; + + ogs_assert(sess); + amf_ue = sess->amf_ue; + ogs_assert(amf_ue); + ran_ue = ran_ue_cycle(amf_ue->ran_ue); + ogs_assert(ran_ue); + + if (ran_ue->ue_context_requested == true && + ran_ue->initial_context_setup_request_sent == false) { + ngapbuf = ngap_sess_build_initial_context_setup_request( + sess, NULL, n2smbuf); + ogs_expect_or_return(ngapbuf); + + rv = nas_5gs_send_to_gnb(amf_ue, ngapbuf); + ogs_expect_or_return(rv == OGS_OK); + + ran_ue->initial_context_setup_request_sent = true; + } else { + ngapbuf = ngap_sess_build_pdu_session_resource_setup_request( + sess, NULL, n2smbuf); + ogs_expect_or_return(ngapbuf); + + rv = nas_5gs_send_to_gnb(amf_ue, ngapbuf); + ogs_expect_or_return(rv == OGS_OK); + } +} + +#if 0 void ngap_send_amf_configuration_transfer( amf_gnb_t *target_gnb, NGAP_SONConfigurationTransfer_t *SONConfigurationTransfer) diff --git a/src/amf/ngap-path.h b/src/amf/ngap-path.h index 5b53ba4a6..e3057484b 100644 --- a/src/amf/ngap-path.h +++ b/src/amf/ngap-path.h @@ -60,9 +60,9 @@ 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); -#if 0 -void ngap_send_paging(amf_ue_t *amf_ue, NGAP_CNDomain_t cn_domain); -#endif +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, diff --git a/src/amf/nsmf-build.c b/src/amf/nsmf-build.c index 051a9ff17..044690060 100644 --- a/src/amf/nsmf-build.c +++ b/src/amf/nsmf-build.c @@ -182,8 +182,7 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST; message.h.service.name = (char *)OGS_SBI_SERVICE_NAME_NSMF_PDUSESSION; message.h.api.version = (char *)OGS_SBI_API_V1; - message.h.resource.component[0] = - (char *)OGS_SBI_RESOURCE_NAME_SM_CONTEXTS; + message.h.resource.component[0] = (char *)OGS_SBI_RESOURCE_NAME_SM_CONTEXTS; message.h.resource.component[1] = sess->sm_context_ref; message.h.resource.component[2] = (char *)OGS_SBI_RESOURCE_NAME_MODIFY; @@ -317,3 +316,48 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_release_sm_context( return request; } + +ogs_sbi_request_t *amf_nsmf_callback_build_n1_n2_failure_notify( + amf_sess_t *sess, OpenAPI_n1_n2_message_transfer_cause_e cause) +{ + ogs_sbi_message_t message; + ogs_sbi_request_t *request = NULL; + + OpenAPI_n1_n2_msg_txfr_failure_notification_t + N1N2MsgTxfrFailureNotification; + + ogs_assert(sess); + ogs_assert(sess->paging.ongoing == true); + ogs_assert(sess->paging.location); + ogs_assert(sess->paging.n1n2_failure_txf_notif_uri); + ogs_assert(cause); + + memset(&message, 0, sizeof(message)); + message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST; + message.h.uri = sess->paging.n1n2_failure_txf_notif_uri; + + memset(&N1N2MsgTxfrFailureNotification, + 0, sizeof(N1N2MsgTxfrFailureNotification)); + N1N2MsgTxfrFailureNotification.cause = cause; + if (sess->paging.location) { + N1N2MsgTxfrFailureNotification.n1n2_msg_data_uri = + sess->paging.location; + } else { + /* TS29.518 6.1.6.2.30 Type: N1N2MsgTxfrFailureNotification + * + * If no Location header was returned when the N1/N2 + * message transfer was initiated, e.g. when a 200 OK + * response was sent for a UE in RRC inactive state, + * this IE shall be set to a dummy URI, i.e. an URI with + * no authority and an empty path (e.g. "http:"). + */ + N1N2MsgTxfrFailureNotification.n1n2_msg_data_uri = (char *)"http:"; + } + + message.N1N2MsgTxfrFailureNotification = &N1N2MsgTxfrFailureNotification; + + request = ogs_sbi_build_request(&message); + ogs_assert(request); + + return request; +} diff --git a/src/amf/nsmf-build.h b/src/amf/nsmf-build.h index bcc1ae69c..e6f052adf 100644 --- a/src/amf/nsmf-build.h +++ b/src/amf/nsmf-build.h @@ -52,6 +52,9 @@ ogs_sbi_request_t *amf_nsmf_pdu_session_build_update_sm_context( ogs_sbi_request_t *amf_nsmf_pdu_session_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); + #ifdef __cplusplus } #endif diff --git a/src/amf/nsmf-handler.c b/src/amf/nsmf-handler.c index d57ffb460..3370431e9 100644 --- a/src/amf/nsmf-handler.c +++ b/src/amf/nsmf-handler.c @@ -193,40 +193,41 @@ int amf_nsmf_pdu_session_handle_update_sm_context( * To Deliver N2 SM Content to gNB Temporarily, * Store N2 SM Context in Session Context */ - if (sess->transfer.pdu_session_resource_setup_request) { - /* - * It should not be reached this way. - * If the problem occurred, free the old n2smbuf - */ - ogs_error("[%s:%d] N2 SM Content is duplicated", - amf_ue->supi, sess->psi); - ogs_pkbuf_free( - sess->transfer.pdu_session_resource_setup_request); - } - /* - * NOTE : The pkbuf created in the SBI message will be removed - * from ogs_sbi_message_free(). - * So it must be copied and push a event queue. - */ - sess->transfer.pdu_session_resource_setup_request = - ogs_pkbuf_copy(n2smbuf); - ogs_assert(sess->transfer.pdu_session_resource_setup_request); + AMF_SESS_STORE_N2_TRANSFER( + sess, pdu_session_resource_setup_request, + ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue)) { - nas_5gs_send_accept(amf_ue); + 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)) { + nas_5gs_send_registration_accept(amf_ue); - /* - * After sending accept message, N2 SM context is freed - * For checking memory, NULL pointer should be set to n2smbuf. - */ - ogs_list_for_each(&amf_ue->sess_list, sess) { - 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; - } + /* 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: + if (SESSION_SYNC_DONE(amf_ue, + AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) && + SESSION_SYNC_DONE(amf_ue, + AMF_UPDATE_SM_CONTEXT_ACTIVATING)) { + 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); + ogs_assert_if_reached(); } break; @@ -274,38 +275,15 @@ int amf_nsmf_pdu_session_handle_update_sm_context( * To Deliver N2 SM Content to gNB Temporarily, * Store N2 SM Context in Session Context */ - if (sess->transfer.path_switch_request_ack) { - /* - * It should not be reached this way. - * If the problem occurred, free the old n2smbuf - */ - ogs_error("[%s:%d] N2 SM Content is duplicated", - amf_ue->supi, sess->psi); - ogs_pkbuf_free(sess->transfer.path_switch_request_ack); - } - /* - * NOTE : The pkbuf created in the SBI message will be removed - * from ogs_sbi_message_free(). - * So it must be copied and push a event queue. - */ - sess->transfer.path_switch_request_ack = - ogs_pkbuf_copy(n2smbuf); - ogs_assert(sess->transfer.path_switch_request_ack); + AMF_SESS_STORE_N2_TRANSFER( + sess, path_switch_request_ack, + ogs_pkbuf_copy(n2smbuf)); - if (SESSION_SYNC_DONE(amf_ue)) { + if (SESSION_SYNC_DONE(amf_ue, state)) { ngap_send_path_switch_ack(sess); - /* - * After sending ack message, N2 SM context is freed - * For checking memory, NULL pointer should be set to n2smbuf. - */ - ogs_list_for_each(&amf_ue->sess_list, sess) { - if (sess->transfer.path_switch_request_ack) { - ogs_pkbuf_free( - sess->transfer.path_switch_request_ack); - sess->transfer.path_switch_request_ack = NULL; - } - } + /* After sending ack message, N2 SM context is freed */ + AMF_UE_CLEAR_N2_TRANSFER(amf_ue, path_switch_request_ack); } break; @@ -351,7 +329,7 @@ int amf_nsmf_pdu_session_handle_update_sm_context( * 6. UEContextReleaseComplete */ - if (SESSION_SYNC_DONE(amf_ue)) { + if (SESSION_SYNC_DONE(amf_ue, state)) { ngap_send_amf_ue_context_release_command(amf_ue, NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, NGAP_UE_CTX_REL_NG_REMOVE_AND_UNLINK, 0); @@ -360,6 +338,7 @@ int amf_nsmf_pdu_session_handle_update_sm_context( } else if (state == AMF_UPDATE_SM_CONTEXT_ACTIVATING) { /* Not reached here */ + ogs_assert_if_reached(); } else if (state == AMF_UPDATE_SM_CONTEXT_N2_RELEASED) { @@ -394,7 +373,7 @@ int amf_nsmf_pdu_session_handle_update_sm_context( */ /* Nothing to do */ - if (SESSION_SYNC_DONE(amf_ue)) { + if (SESSION_SYNC_DONE(amf_ue, state)) { ran_ue_t *ran_ue = ran_ue_cycle(amf_ue->ran_ue); if (ran_ue) { ogs_debug(" SUPI[%s]", amf_ue->supi); @@ -421,7 +400,7 @@ int amf_nsmf_pdu_session_handle_update_sm_context( ogs_debug("[%s:%d] SM context remove", amf_ue->supi, sess->psi); amf_nsmf_pdu_session_handle_release_sm_context( - sess, AMF_RELEASE_SM_CONTEXT_NO_STATE); + sess, AMF_SESS_SM_CONTEXT_NO_STATE); } } } else { @@ -510,92 +489,112 @@ int amf_nsmf_pdu_session_handle_release_sm_context(amf_sess_t *sess, int state) amf_sess_remove(sess); - /* Check last session */ - if (ogs_list_count(&amf_ue->sess_list) == 0) { - - if (state == AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE) { - /* - * 1. Initial context setup failure - * 2. Release All SM contexts - * 3. UE Context release command - * 4. UE Context release complete - */ - ngap_send_amf_ue_context_release_command(amf_ue, - NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, - NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0); - - } else if (state == AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) { - /* - * 1. Registration request - * 2. Release All SM contexts - * 3. Registration accept - */ + if (state == AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) { + /* + * 1. Registration request + * 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)) nas_5gs_send_registration_accept(amf_ue); - } else if (state == AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) { - /* - * 1. Service request - * 2. Release All SM contexts - * 3. Service accept - */ + } else if (state == AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) { + /* + * 1. Service request + * 2. Release All SM contexts + * 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)) nas_5gs_send_service_accept(amf_ue); - } else { - /* NO_STATE */ + } else { - if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_authentication)) { + /* Check last session */ + if (ogs_list_count(&amf_ue->sess_list) == 0) { - amf_ue_sbi_discover_and_send(OpenAPI_nf_type_AUSF, amf_ue, NULL, - amf_nausf_auth_build_authenticate); - - } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_de_registered)) { + if (state == AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE) { /* - * 1. PDU session release request - * 2. PDUSessionResourceReleaseCommand + - * PDU session release command - * 3. PDUSessionResourceReleaseREsponse - * 4. PDU session release complete - * 5. Deregistration request - * 6. UEContextReleaseCommand - * 7. UEContextReleaseComplete - */ - - nas_5gs_send_de_registration_accept(amf_ue); - - } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered)) { - /* - * 1. PDU session release request - * 2. PDUSessionResourceReleaseCommand + - * PDU session release command - * 3. PDUSessionResourceReleaseREsponse - * 4. PDU session release complete - * - * No Deregistration request in the above step - * - * So, Nothing to do! - */ - } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_exception)) { - /* - * 1. GMM Exception + * 1. Initial context setup failure * 2. Release All SM contexts * 3. UE Context release command * 4. UE Context release complete */ ngap_send_amf_ue_context_release_command(amf_ue, NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, - NGAP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0); + NGAP_UE_CTX_REL_NG_CONTEXT_REMOVE, 0); - } else if (OGS_FSM_CHECK(&amf_ue->sm, - gmm_state_initial_context_setup)) { - ogs_fatal("Release SM Context in initial-context-setup"); + } else if (state == AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT) { + + /* Not reached here */ ogs_assert_if_reached(); - } else if (OGS_FSM_CHECK( - &amf_ue->sm, gmm_state_security_mode)) { - ogs_fatal("Release SM Context in security-mode"); + + } else if (state == AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT) { + + /* Not reached here */ ogs_assert_if_reached(); + } else { - ogs_fatal("Release SM Context : INVALID STATE"); - ogs_assert_if_reached(); + /* NO_STATE */ + + if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_authentication)) { + + amf_ue_sbi_discover_and_send( + OpenAPI_nf_type_AUSF, amf_ue, NULL, + amf_nausf_auth_build_authenticate); + + } else if (OGS_FSM_CHECK(&amf_ue->sm, + gmm_state_de_registered)) { + /* + * 1. PDU session release request + * 2. PDUSessionResourceReleaseCommand + + * PDU session release command + * 3. PDUSessionResourceReleaseREsponse + * 4. PDU session release complete + * 5. Deregistration request + * 6. UEContextReleaseCommand + * 7. UEContextReleaseComplete + */ + + nas_5gs_send_de_registration_accept(amf_ue); + + } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_registered)) { + /* + * 1. PDU session release request + * 2. PDUSessionResourceReleaseCommand + + * PDU session release command + * 3. PDUSessionResourceReleaseREsponse + * 4. PDU session release complete + * + * No Deregistration request in the above step + * + * So, Nothing to do! + */ + } else if (OGS_FSM_CHECK(&amf_ue->sm, gmm_state_exception)) { + /* + * 1. GMM Exception + * 2. Release All SM contexts + * 3. UE Context release command + * 4. UE Context release complete + */ + ngap_send_amf_ue_context_release_command(amf_ue, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release, + NGAP_UE_CTX_REL_UE_CONTEXT_REMOVE, 0); + + } else if (OGS_FSM_CHECK(&amf_ue->sm, + gmm_state_initial_context_setup)) { + ogs_fatal("Release SM Context in initial-context-setup"); + ogs_assert_if_reached(); + } else if (OGS_FSM_CHECK( + &amf_ue->sm, gmm_state_security_mode)) { + ogs_fatal("Release SM Context in security-mode"); + ogs_assert_if_reached(); + } else { + ogs_fatal("Release SM Context : INVALID STATE"); + ogs_assert_if_reached(); + } } } } diff --git a/src/amf/nudm-handler.c b/src/amf/nudm-handler.c index df9232c74..c964a797a 100644 --- a/src/amf/nudm-handler.c +++ b/src/amf/nudm-handler.c @@ -25,15 +25,14 @@ int amf_nudm_sdm_handle_provisioned( amf_ue_t *amf_ue, ogs_sbi_message_t *recvmsg) { + int i; + ogs_assert(amf_ue); ogs_assert(recvmsg); SWITCH(recvmsg->h.resource.component[1]) CASE(OGS_SBI_RESOURCE_NAME_AM_DATA) if (recvmsg->AccessAndMobilitySubscriptionData) { - OpenAPI_ambr_rm_t *ue_ambr = - recvmsg->AccessAndMobilitySubscriptionData-> - subscribed_ue_ambr; OpenAPI_list_t *gpsiList = recvmsg->AccessAndMobilitySubscriptionData->gpsis; OpenAPI_ambr_rm_t *SubscribedUeAmbr = @@ -42,15 +41,14 @@ int amf_nudm_sdm_handle_provisioned( recvmsg->AccessAndMobilitySubscriptionData->subscribed_dnn_list; OpenAPI_lnode_t *node = NULL; - if (ue_ambr) { - amf_ue->ue_ambr.uplink = - ogs_sbi_bitrate_from_string(ue_ambr->uplink); - amf_ue->ue_ambr.downlink = - ogs_sbi_bitrate_from_string(ue_ambr->downlink); + /* Clear MSISDN */ + for (i = 0; i < amf_ue->num_of_msisdn; i++) { + ogs_assert(amf_ue->msisdn[i]); + ogs_free(amf_ue->msisdn[i]); } + amf_ue->num_of_msisdn = 0; if (gpsiList) { - amf_ue->num_of_msisdn = 0; OpenAPI_list_for_each(gpsiList, node) { if (node->data) { char *gpsi = NULL; @@ -75,6 +73,10 @@ int amf_nudm_sdm_handle_provisioned( } } + /* Clear Subscribed-UE-AMBR */ + amf_ue->ue_ambr.uplink = 0; + amf_ue->ue_ambr.downlink = 0; + if (SubscribedUeAmbr) { amf_ue->ue_ambr.uplink = ogs_sbi_bitrate_from_string(SubscribedUeAmbr->uplink); @@ -82,6 +84,13 @@ int amf_nudm_sdm_handle_provisioned( ogs_sbi_bitrate_from_string(SubscribedUeAmbr->downlink); } + /* Clear Subscribed-DNN */ + for (i = 0; i < amf_ue->num_of_subscribed_dnn; i++) { + ogs_assert(amf_ue->subscribed_dnn[i]); + ogs_free(amf_ue->subscribed_dnn[i]); + } + amf_ue->num_of_subscribed_dnn = 0; + if (SubscribedDnnList) { OpenAPI_list_for_each(SubscribedDnnList, node) { if (node->data) { diff --git a/src/amf/sbi-path.c b/src/amf/sbi-path.c index 2b62103e7..ecaf5f16c 100644 --- a/src/amf/sbi-path.c +++ b/src/amf/sbi-path.c @@ -273,3 +273,44 @@ void amf_sbi_send_release_all_sessions(amf_ue_t *amf_ue, int state) amf_sbi_send_release_session(sess, state); } } + +static int client_notify_cb(ogs_sbi_response_t *response, void *data) +{ + int rv; + + ogs_sbi_message_t message; + + ogs_assert(response); + + rv = ogs_sbi_parse_response(&message, response); + if (rv != OGS_OK) { + ogs_error("cannot parse HTTP response"); + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + return OGS_ERROR; + } + + if (message.res_status != OGS_SBI_HTTP_STATUS_NO_CONTENT) + ogs_error("N1-N2-Message Transfer Failure Notification failed [%d]", + message.res_status); + + ogs_sbi_message_free(&message); + ogs_sbi_response_free(response); + return OGS_OK; +} + +void amf_sbi_send_n1_n2_failure_notify( + amf_sess_t *sess, OpenAPI_n1_n2_message_transfer_cause_e cause) +{ + ogs_sbi_request_t *request = NULL; + ogs_sbi_client_t *client = NULL; + + ogs_assert(cause); + ogs_assert(sess); + client = sess->paging.client; + ogs_assert(client); + + request = amf_nsmf_callback_build_n1_n2_failure_notify(sess, cause); + ogs_assert(request); + ogs_sbi_client_send_request(client, client_notify_cb, request, NULL); +} diff --git a/src/amf/sbi-path.h b/src/amf/sbi-path.h index 250f57221..77d099bc9 100644 --- a/src/amf/sbi-path.h +++ b/src/amf/sbi-path.h @@ -37,14 +37,17 @@ void amf_ue_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, amf_ue_t *amf_ue, void *data, ogs_sbi_request_t *(*build)(amf_ue_t *amf_ue, void *data)); -#define AMF_UPDATE_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_UPDATE_SM_CONTEXT_NG_RESET 7 +#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_UPDATE_SM_CONTEXT_NG_RESET 7 +#define AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE 8 +#define AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT 9 +#define AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT 10 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)); @@ -57,13 +60,12 @@ void amf_sbi_send_deactivate_all_sessions( amf_ue_t *amf_ue, int state, int group, int cause); void amf_sbi_send_deactivate_all_ue_in_gnb(amf_gnb_t *gnb, int state); -#define AMF_RELEASE_SM_CONTEXT_NO_STATE 0 -#define AMF_RELEASE_SM_CONTEXT_NG_CONTEXT_REMOVE 1 -#define AMF_RELEASE_SM_CONTEXT_REGISTRATION_ACCEPT 2 -#define AMF_RELEASE_SM_CONTEXT_SERVICE_ACCEPT 3 void amf_sbi_send_release_session(amf_sess_t *sess, int state); void amf_sbi_send_release_all_sessions(amf_ue_t *amf_ue, int state); +void amf_sbi_send_n1_n2_failure_notify( + amf_sess_t *sess, OpenAPI_n1_n2_message_transfer_cause_e cause); + #ifdef __cplusplus } #endif diff --git a/src/mme/emm-handler.c b/src/mme/emm-handler.c index a489bb3f2..fe05cb4dd 100644 --- a/src/mme/emm-handler.c +++ b/src/mme/emm-handler.c @@ -99,7 +99,8 @@ int emm_handle_attach_request(mme_ue_t *mme_ue, ogs_plmn_id_hexdump(&enb_ue->saved.e_cgi.plmn_id), enb_ue->saved.e_cgi.cell_id); - /* Copy TAI and ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from enb_ue */ + mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); @@ -489,7 +490,8 @@ int emm_handle_tau_request(mme_ue_t *mme_ue, ogs_plmn_id_hexdump(&enb_ue->saved.e_cgi.plmn_id), enb_ue->saved.e_cgi.cell_id); - /* Copy TAI and ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from enb_ue */ + mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); @@ -605,7 +607,8 @@ int emm_handle_extended_service_request(mme_ue_t *mme_ue, ogs_plmn_id_hexdump(&enb_ue->saved.e_cgi.plmn_id), enb_ue->saved.e_cgi.cell_id); - /* Copy TAI and ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from enb_ue */ + mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); diff --git a/src/mme/mme-context.h b/src/mme/mme-context.h index 1f1f0bd12..4d8e56c5c 100644 --- a/src/mme/mme-context.h +++ b/src/mme/mme-context.h @@ -325,6 +325,7 @@ struct mme_ue_s { uint16_t vlr_ostream_id; /* SCTP output stream id for VLR */ /* UE Info */ + uint16_t enb_ostream_id; ogs_eps_tai_t tai; ogs_e_cgi_t e_cgi; ogs_plmn_id_t last_visited_plmn_id; diff --git a/src/mme/s1ap-build.c b/src/mme/s1ap-build.c index 75027499b..426911eef 100644 --- a/src/mme/s1ap-build.c +++ b/src/mme/s1ap-build.c @@ -200,12 +200,11 @@ ogs_pkbuf_t *s1ap_build_downlink_nas_transport( ogs_assert(emmbuf); ogs_assert(enb_ue); - ogs_debug("[MME] DownlinkNASTransport"); + ogs_debug("DownlinkNASTransport"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -288,12 +287,11 @@ ogs_pkbuf_t *s1ap_build_initial_context_setup_request( subscription_data = &mme_ue->subscription_data; ogs_assert(subscription_data); - ogs_debug("[MME] Initial context setup request"); + ogs_debug("Initial context setup request"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -641,12 +639,11 @@ ogs_pkbuf_t *s1ap_build_ue_context_modification_request(mme_ue_t *mme_ue) enb_ue = enb_ue_cycle(mme_ue->enb_ue); ogs_assert(enb_ue); - ogs_debug("[MME] UE context modification request"); + ogs_debug("UE context modification request"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -782,8 +779,7 @@ ogs_pkbuf_t *s1ap_build_ue_context_release_command( memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_UEContextRelease; @@ -864,8 +860,7 @@ ogs_pkbuf_t *s1ap_build_e_rab_setup_request( memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_E_RABSetup; @@ -994,11 +989,10 @@ ogs_pkbuf_t *s1ap_build_e_rab_modify_request( enb_ue = enb_ue_cycle(mme_ue->enb_ue); ogs_assert(enb_ue); - ogs_debug("[MME] E-RAB modify request"); + ogs_debug("E-RAB modify request"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_E_RABModify; @@ -1125,12 +1119,11 @@ ogs_pkbuf_t *s1ap_build_e_rab_release_command( subscription_data = &mme_ue->subscription_data; ogs_assert(subscription_data); - ogs_debug("[MME] E-RAB release command"); + ogs_debug("E-RAB release command"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_E_RABRelease; @@ -1250,12 +1243,11 @@ ogs_pkbuf_t *s1ap_build_paging( ogs_assert(mme_ue); - ogs_debug("[MME] Paging"); + ogs_debug("Paging"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_Paging; @@ -1318,8 +1310,7 @@ ogs_pkbuf_t *s1ap_build_paging( /* Set Paging Identity */ UEPagingID->present = S1AP_UEPagingID_PR_s_TMSI; - UEPagingID->choice.s_TMSI = - CALLOC(1, sizeof(S1AP_S_TMSI_t)); + UEPagingID->choice.s_TMSI = CALLOC(1, sizeof(S1AP_S_TMSI_t)); ogs_asn_uint8_to_OCTET_STRING(mme_ue->guti.mme_code, &UEPagingID->choice.s_TMSI->mMEC); @@ -1364,12 +1355,11 @@ ogs_pkbuf_t *s1ap_build_mme_configuration_transfer( ogs_assert(son_configuration_transfer); - ogs_debug("[MME] MME Configuration Transfer"); + ogs_debug("MME Configuration Transfer"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -1415,7 +1405,7 @@ ogs_pkbuf_t *s1ap_build_path_switch_ack(mme_ue_t *mme_ue) enb_ue = enb_ue_cycle(mme_ue->enb_ue); ogs_assert(enb_ue); - ogs_debug("[MME] Path switch acknowledge"); + ogs_debug("Path switch acknowledge"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome; @@ -1492,7 +1482,7 @@ ogs_pkbuf_t *s1ap_build_path_switch_failure( S1AP_ENB_UE_S1AP_ID_t *ENB_UE_S1AP_ID = NULL; S1AP_Cause_t *Cause = NULL; - ogs_debug("[MME] Path switch failure"); + ogs_debug("Path switch failure"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_unsuccessfulOutcome; @@ -1574,7 +1564,7 @@ ogs_pkbuf_t *s1ap_build_handover_command(enb_ue_t *source_ue) ogs_assert(source_ue); mme_ue = source_ue->mme_ue; - ogs_debug("[MME] Handover command"); + ogs_debug("Handover command"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome; @@ -1732,7 +1722,7 @@ ogs_pkbuf_t *s1ap_build_handover_preparation_failure( ogs_assert(source_ue); ogs_assert(cause); - ogs_debug("[MME] Handover preparation failure"); + ogs_debug("Handover preparation failure"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_unsuccessfulOutcome; @@ -1830,12 +1820,11 @@ ogs_pkbuf_t *s1ap_build_handover_request( subscription_data = &mme_ue->subscription_data; ogs_assert(subscription_data); - ogs_debug("[MME] Handover request"); + ogs_debug("Handover request"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -2040,7 +2029,7 @@ ogs_pkbuf_t *s1ap_build_handover_cancel_ack(enb_ue_t *source_ue) ogs_assert(source_ue); - ogs_debug("[MME] Handover cancel acknowledge"); + ogs_debug("Handover cancel acknowledge"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_successfulOutcome; @@ -2105,12 +2094,11 @@ ogs_pkbuf_t *s1ap_build_mme_status_transfer( ogs_assert(target_ue); ogs_assert(enb_statustransfer_transparentContainer); - ogs_debug("[MME] MME status transfer"); + ogs_debug("MME status transfer"); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_MMEStatusTransfer; @@ -2178,14 +2166,13 @@ ogs_pkbuf_t *s1ap_build_write_replace_warning_request(sbc_pws_data_t *sbc_pws) S1AP_DataCodingScheme_t *DataCodingScheme = NULL; S1AP_WarningMessageContents_t *WarningMessageContents = NULL; - ogs_debug("[MME] Write-replace warning request"); + ogs_debug("Write-replace warning request"); ogs_assert(sbc_pws); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = @@ -2316,14 +2303,13 @@ ogs_pkbuf_t *s1ap_build_kill_request(sbc_pws_data_t *sbc_pws) S1AP_MessageIdentifier_t *MessageIdentifier = NULL; S1AP_SerialNumber_t *SerialNumber = NULL; - ogs_debug("[MME] Kill request"); + ogs_debug("Kill request"); ogs_assert(sbc_pws); memset(&pdu, 0, sizeof (S1AP_S1AP_PDU_t)); pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage; - pdu.choice.initiatingMessage = - CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); + pdu.choice.initiatingMessage = CALLOC(1, sizeof(S1AP_InitiatingMessage_t)); initiatingMessage = pdu.choice.initiatingMessage; initiatingMessage->procedureCode = S1AP_ProcedureCode_id_Kill; diff --git a/src/mme/s1ap-handler.c b/src/mme/s1ap-handler.c index aee98389d..270184588 100644 --- a/src/mme/s1ap-handler.c +++ b/src/mme/s1ap-handler.c @@ -1331,7 +1331,8 @@ void s1ap_handle_path_switch_request( ogs_plmn_id_hexdump(&enb_ue->saved.e_cgi.plmn_id), enb_ue->saved.e_cgi.cell_id); - /* Copy TAI and ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from enb_ue */ + mme_ue->enb_ostream_id = enb_ue->enb_ostream_id; memcpy(&mme_ue->tai, &enb_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &enb_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); @@ -2046,7 +2047,8 @@ void s1ap_handle_handover_notification( ogs_plmn_id_hexdump(&target_ue->saved.e_cgi.plmn_id), target_ue->saved.e_cgi.cell_id); - /* Copy TAI and ECGI from enb_ue */ + /* Copy Stream-No/TAI/ECGI from enb_ue */ + mme_ue->enb_ostream_id = target_ue->enb_ostream_id; memcpy(&mme_ue->tai, &target_ue->saved.tai, sizeof(ogs_eps_tai_t)); memcpy(&mme_ue->e_cgi, &target_ue->saved.e_cgi, sizeof(ogs_e_cgi_t)); diff --git a/src/mme/s1ap-path.c b/src/mme/s1ap-path.c index 557a6b0c8..c91a5e978 100644 --- a/src/mme/s1ap-path.c +++ b/src/mme/s1ap-path.c @@ -341,7 +341,7 @@ void s1ap_send_paging(mme_ue_t *mme_ue, S1AP_CNDomain_t cn_domain) mme_ue->t3413.pkbuf = ogs_pkbuf_copy(s1apbuf); ogs_assert(mme_ue->t3413.pkbuf); - rv = s1ap_send_to_enb(enb, s1apbuf, S1AP_NON_UE_SIGNALLING); + rv = s1ap_send_to_enb(enb, s1apbuf, mme_ue->enb_ostream_id); ogs_expect(rv == OGS_OK); } } diff --git a/src/sgwc/context.c b/src/sgwc/context.c index 8374c4941..ceebc24ee 100644 --- a/src/sgwc/context.c +++ b/src/sgwc/context.c @@ -687,7 +687,7 @@ sgwc_bearer_t *sgwc_bearer_find_by_error_indication_report( sgwc_sess_t *sess, ogs_pfcp_tlv_error_indication_report_t *error_indication_report) { - ogs_pfcp_f_teid_t *remote_f_teid; + ogs_pfcp_f_teid_t *remote_f_teid = NULL; sgwc_bearer_t *bearer = NULL; sgwc_tunnel_t *tunnel = NULL; diff --git a/src/smf/context.c b/src/smf/context.c index a80f193b7..0e6680163 100644 --- a/src/smf/context.c +++ b/src/smf/context.c @@ -75,6 +75,7 @@ void smf_context_init(void) self.imsi_hash = ogs_hash_make(); self.ipv4_hash = ogs_hash_make(); self.ipv6_hash = ogs_hash_make(); + self.n1n2message_hash = ogs_hash_make(); context_initialized = 1; } @@ -93,6 +94,8 @@ void smf_context_final(void) ogs_hash_destroy(self.ipv4_hash); ogs_assert(self.ipv6_hash); ogs_hash_destroy(self.ipv6_hash); + ogs_assert(self.n1n2message_hash); + ogs_hash_destroy(self.n1n2message_hash); ogs_pool_final(&smf_ue_pool); ogs_pool_final(&smf_bearer_pool); @@ -1011,6 +1014,91 @@ void smf_sess_set_ue_ip(smf_sess_t *sess) } } +void smf_sess_set_paging_n1n2message_location( + smf_sess_t *sess, char *n1n2message_location) +{ + ogs_assert(sess); + ogs_assert(n1n2message_location); + + if (sess->paging.n1n2message_location) { + ogs_hash_set(self.n1n2message_hash, + sess->paging.n1n2message_location, + strlen(sess->paging.n1n2message_location), + NULL); + ogs_free(sess->paging.n1n2message_location); + } + + sess->paging.n1n2message_location = ogs_strdup(n1n2message_location); + ogs_assert(sess->paging.n1n2message_location); + + ogs_hash_set(self.n1n2message_hash, + sess->paging.n1n2message_location, + strlen(sess->paging.n1n2message_location), + sess); +} + +smf_sess_t *smf_sess_find_by_error_indication_report( + smf_ue_t *smf_ue, + ogs_pfcp_tlv_error_indication_report_t *error_indication_report) +{ + smf_sess_t *sess = NULL; + ogs_pfcp_f_teid_t *remote_f_teid = NULL; + + uint32_t teid; + uint16_t len; /* OGS_IPV4_LEN or OGS_IPV6_LEN */ + uint32_t addr[4]; + + ogs_assert(smf_ue); + ogs_assert(error_indication_report); + + if (error_indication_report->presence == 0) { + ogs_error("No Error Indication Report"); + return NULL; + } + + if (error_indication_report->remote_f_teid.presence == 0) { + ogs_error("No Remote F-TEID"); + return NULL; + } + + remote_f_teid = error_indication_report->remote_f_teid.data; + ogs_assert(remote_f_teid); + + teid = be32toh(remote_f_teid->teid); + if (remote_f_teid->ipv4 && remote_f_teid->ipv6) { + ogs_error("User plane should not set both IPv4 and IPv6"); + return NULL; + } else if (remote_f_teid->ipv4) { + len = OGS_IPV4_LEN; + memcpy(addr, &remote_f_teid->addr, len); + } else if (remote_f_teid->ipv6) { + len = OGS_IPV6_LEN; + memcpy(addr, remote_f_teid->addr6, len); + } else { + ogs_error("No IPv4 and IPv6"); + return NULL; + } + + ogs_list_for_each(&smf_ue->sess_list, sess) { + if (teid == sess->gnb_n3_teid) { + if (len == OGS_IPV4_LEN && sess->gnb_n3_ip.ipv4 && + memcmp(addr, &sess->gnb_n3_ip.addr, len) == 0) { + return sess; + } else if (len == OGS_IPV6_LEN && sess->gnb_n3_ip.ipv6 && + memcmp(addr, sess->gnb_n3_ip.addr6, len) == 0) { + return sess; + } + } + } + + ogs_error("Cannot find the session context " + "[TEID:%d,LEN:%d,ADDR:%08x %08x %08x %08x]", + teid, len, be32toh(addr[0]), be32toh(addr[1]), + be32toh(addr[2]), be32toh(addr[3])); + + return NULL; +} + void smf_sess_remove(smf_sess_t *sess) { int i; @@ -1056,6 +1144,14 @@ void smf_sess_remove(smf_sess_t *sess) ogs_pfcp_ue_ip_free(sess->ipv6); } + if (sess->paging.n1n2message_location) { + ogs_hash_set(self.n1n2message_hash, + sess->paging.n1n2message_location, + strlen(sess->paging.n1n2message_location), + NULL); + ogs_free(sess->paging.n1n2message_location); + } + if (sess->sm_context_ref) ogs_free(sess->sm_context_ref); @@ -1171,6 +1267,15 @@ smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6) return (smf_sess_t *)ogs_hash_get(self.ipv6_hash, addr6, OGS_IPV6_LEN); } +smf_sess_t *smf_sess_find_by_paging_n1n2message_location( + char *n1n2message_location) +{ + ogs_assert(self.n1n2message_hash); + ogs_assert(n1n2message_location); + return (smf_sess_t *)ogs_hash_get(self.n1n2message_hash, + n1n2message_location, strlen(n1n2message_location)); +} + smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess) { smf_bearer_t *qos_flow = NULL; diff --git a/src/smf/context.h b/src/smf/context.h index 6a6e90f01..39cc46f01 100644 --- a/src/smf/context.h +++ b/src/smf/context.h @@ -82,6 +82,7 @@ typedef struct smf_context_s { ogs_hash_t *imsi_hash; /* hash table (IMSI) */ ogs_hash_t *ipv4_hash; /* hash table (IPv4 Address) */ ogs_hash_t *ipv6_hash; /* hash table (IPv6 Address) */ + ogs_hash_t *n1n2message_hash; /* hash table (N1N2Message Location) */ uint16_t mtu; /* MTU to advertise in PCO */ @@ -273,6 +274,8 @@ typedef struct smf_sess_s { ogs_tlv_octet_t ue_pco; ogs_tlv_octet_t user_location_information; ogs_tlv_octet_t ue_timezone; + bool create_session_response_apn_ambr; + bool create_session_response_bearer_qos; } gtp; /* Saved from S5-C */ struct { @@ -282,14 +285,23 @@ typedef struct smf_sess_s { ogs_pcc_rule_t pcc_rule[OGS_MAX_NUM_OF_PCC_RULE]; /* Saved from Gx */ int num_of_pcc_rule; + /* Paging */ struct { - bool create_session_response_apn_ambr; - bool create_session_response_bearer_qos; - } gtp_5gc; + bool ue_requested_pdu_session_establishment_done; + char *n1n2message_location; + } paging; /* Release Holding timer of SMF session context */ ogs_timer_t *t_release_holding; + /* State */ +#define SMF_NGAP_STATE_NONE 0 +#define SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED 1 +#define SMF_NGAP_STATE_ERROR_INDICATION_RECEIVED_FROM_5G_AN 2 + struct { + int pdu_session_resource_release; + } ngap_state; + ogs_list_t bearer_list; ogs_gtp_node_t *gnode; @@ -319,6 +331,8 @@ smf_sess_t *smf_sess_add_by_psi(smf_ue_t *smf_ue, uint8_t psi); void smf_sess_select_upf(smf_sess_t *sess); void smf_sess_set_ue_ip(smf_sess_t *sess); +void smf_sess_set_paging_n1n2message_location( + smf_sess_t *sess, char *n1n2message_location); void smf_sess_remove(smf_sess_t *sess); void smf_sess_remove_all(smf_ue_t *smf_ue); @@ -331,6 +345,11 @@ smf_sess_t *smf_sess_find_by_psi(smf_ue_t *smf_ue, uint8_t psi); smf_sess_t *smf_sess_find_by_sm_context_ref(char *sm_context_ref); smf_sess_t *smf_sess_find_by_ipv4(uint32_t addr); smf_sess_t *smf_sess_find_by_ipv6(uint32_t *addr6); +smf_sess_t *smf_sess_find_by_paging_n1n2message_location( + char *n1n2message_location); +smf_sess_t *smf_sess_find_by_error_indication_report( + smf_ue_t *smf_ue, + ogs_pfcp_tlv_error_indication_report_t *error_indication_report); smf_bearer_t *smf_qos_flow_add(smf_sess_t *sess); smf_bearer_t *smf_qos_flow_find_by_qfi(smf_sess_t *sess, uint8_t qfi); diff --git a/src/smf/gsm-sm.c b/src/smf/gsm-sm.c index a10795e2f..f192cead5 100644 --- a/src/smf/gsm-sm.c +++ b/src/smf/gsm-sm.c @@ -26,6 +26,7 @@ #include "gsm-handler.h" #include "ngap-handler.h" #include "pfcp-path.h" +#include "ngap-path.h" void smf_gsm_state_initial(ogs_fsm_t *s, smf_event_t *e) { @@ -40,7 +41,7 @@ void smf_gsm_state_final(ogs_fsm_t *s, smf_event_t *e) void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) { - int rv; + int rv, ngap_state; char *strerror = NULL; smf_ue_t *smf_ue = NULL; smf_sess_t *sess = NULL; @@ -184,13 +185,6 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) CASE(OGS_SBI_SERVICE_NAME_NAMF_COMM) SWITCH(sbi_message->h.resource.component[0]) CASE(OGS_SBI_RESOURCE_NAME_UE_CONTEXTS) - if (sbi_message->res_status != OGS_SBI_HTTP_STATUS_OK && - sbi_message->res_status != OGS_SBI_HTTP_STATUS_ACCEPTED) { - ogs_error("[%s:%d] HTTP response error [%d]", - smf_ue->supi, sess->psi, sbi_message->res_status); - break; - } - smf_namf_comm_handler_n1_n2_message_transfer( sess, e->sbi.state, sbi_message); break; @@ -206,7 +200,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) DEFAULT ogs_error("[%s:%d] Invalid API name [%s]", smf_ue->supi, sess->psi, sbi_message->h.service.name); - + ogs_assert_if_reached(); END break; @@ -269,9 +263,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, NULL, strerror, NULL); ogs_free(strerror); - break; } - break; case SMF_EVT_NGAP_MESSAGE: @@ -307,7 +299,33 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) break; case OpenAPI_n2_sm_info_type_PDU_RES_REL_RSP: - smf_sbi_send_response(stream, OGS_SBI_HTTP_STATUS_NO_CONTENT); + ngap_state = sess->ngap_state.pdu_session_resource_release; + + /* Clear NGAP State */ + sess->ngap_state.pdu_session_resource_release = SMF_NGAP_STATE_NONE; + + if (ngap_state == SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED) { + smf_sbi_send_response(stream, OGS_SBI_HTTP_STATUS_NO_CONTENT); + } else if (ngap_state == + SMF_NGAP_STATE_ERROR_INDICATION_RECEIVED_FROM_5G_AN) { + smf_n1_n2_message_transfer_param_t param; + + smf_sbi_send_response(stream, OGS_SBI_HTTP_STATUS_NO_CONTENT); + + memset(¶m, 0, sizeof(param)); + param.state = SMF_NETWORK_TRIGGERED_SERVICE_REQUEST; + param.n2smbuf = + ngap_build_pdu_session_resource_setup_request_transfer( + sess); + ogs_assert(param.n2smbuf); + + param.n1n2_failure_txf_notif_uri = true; + + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); + } else { + ogs_fatal("Invalid state [%d]", ngap_state); + ogs_assert_if_reached(); + } break; case OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ: @@ -323,12 +341,10 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e) default: ogs_error("Unknown message[%d]", e->ngap.type); } - break; default: ogs_error("Unknown event [%s]", smf_event_get_name(e)); - break; } } diff --git a/src/smf/gx-handler.c b/src/smf/gx-handler.c index b5d338af8..0420ec969 100644 --- a/src/smf/gx-handler.c +++ b/src/smf/gx-handler.c @@ -77,7 +77,7 @@ void smf_gx_handle_cca_initial_request( /* APN-AMBR * if PCRF changes APN-AMBR, this should be included. */ - sess->gtp_5gc.create_session_response_apn_ambr = false; + sess->gtp.create_session_response_apn_ambr = false; if ((gx_message->session_data.pdn.ambr.uplink && (sess->pdn.ambr.uplink / 1000) != (gx_message->session_data.pdn.ambr.uplink / 1000)) || @@ -88,12 +88,12 @@ void smf_gx_handle_cca_initial_request( sess->pdn.ambr.downlink = gx_message->session_data.pdn.ambr.downlink; sess->pdn.ambr.uplink = gx_message->session_data.pdn.ambr.uplink; - sess->gtp_5gc.create_session_response_apn_ambr = true; + sess->gtp.create_session_response_apn_ambr = true; } /* Bearer QoS * if PCRF changes Bearer QoS, this should be included. */ - sess->gtp_5gc.create_session_response_bearer_qos = false; + sess->gtp.create_session_response_bearer_qos = false; if ((gx_message->session_data.pdn.qos.qci && sess->pdn.qos.qci != gx_message->session_data.pdn.qos.qci) || (gx_message->session_data.pdn.qos.arp.priority_level && @@ -112,7 +112,7 @@ void smf_gx_handle_cca_initial_request( sess->pdn.qos.arp.pre_emption_vulnerability = gx_message->session_data.pdn.qos.arp.pre_emption_vulnerability; - sess->gtp_5gc.create_session_response_bearer_qos = true; + sess->gtp.create_session_response_bearer_qos = true; } bearer = smf_default_bearer_in_sess(sess); diff --git a/src/smf/n4-handler.c b/src/smf/n4-handler.c index a5af334fe..a88846a99 100644 --- a/src/smf/n4-handler.c +++ b/src/smf/n4-handler.c @@ -64,6 +64,7 @@ static uint8_t gtp_cause_from_pfcp(uint8_t pfcp_cause) return OGS_GTP_CAUSE_SYSTEM_FAILURE; } + static int sbi_status_from_pfcp(uint8_t pfcp_cause) { switch (pfcp_cause) { @@ -102,8 +103,7 @@ void smf_5gc_n4_handle_session_establishment_response( { int i; - ogs_pkbuf_t *n1smbuf = NULL; - ogs_pkbuf_t *n2smbuf = NULL; + smf_n1_n2_message_transfer_param_t param; ogs_sbi_stream_t *stream = NULL; uint8_t pfcp_cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; @@ -190,14 +190,15 @@ void smf_5gc_n4_handle_session_establishment_response( ogs_assert(up_f_seid); sess->upf_n4_seid = be64toh(up_f_seid->seid); - n1smbuf = gsm_build_pdu_session_establishment_accept(sess); - ogs_assert(n1smbuf); - n2smbuf = ngap_build_pdu_session_resource_setup_request_transfer(sess); - ogs_assert(n2smbuf); + memset(¶m, 0, sizeof(param)); + param.state = SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT; + param.n1smbuf = gsm_build_pdu_session_establishment_accept(sess); + ogs_assert(param.n1smbuf); + param.n2smbuf = ngap_build_pdu_session_resource_setup_request_transfer( + sess); + ogs_assert(param.n2smbuf); - smf_namf_comm_send_n1_n2_message_transfer( - sess, SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT, - n1smbuf, n2smbuf); + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); } void smf_5gc_n4_handle_session_modification_response( @@ -298,36 +299,51 @@ 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_PATH_SWITCH) { ogs_pkbuf_t *n2smbuf = ngap_build_path_switch_request_ack_transfer(sess); ogs_assert(n2smbuf); - smf_sbi_send_sm_context_updated_data_with_n2buf(sess, stream, + smf_sbi_send_sm_context_updated_data_n2smbuf(sess, stream, OpenAPI_n2_sm_info_type_PATH_SWITCH_REQ_ACK, n2smbuf); - } else { - /* ACTIVATED Is NOT Included in RESPONSE */ - smf_sbi_send_sm_context_updated_data(sess, stream, 0); + } else { + sess->paging.ue_requested_pdu_session_establishment_done = true; + smf_sbi_send_http_status_no_content(stream); } } else if (flags & OGS_PFCP_MODIFY_DEACTIVATE) { - /* Only ACTIVING & DEACTIVATED is Included */ - smf_sbi_send_sm_context_updated_data( - sess, stream, OpenAPI_up_cnx_state_DEACTIVATED); + if (flags & OGS_PFCP_MODIFY_ERROR_INDICATION) { + smf_n1_n2_message_transfer_param_t param; + + memset(¶m, 0, sizeof(param)); + param.state = SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN; + param.n2smbuf = + ngap_build_pdu_session_resource_release_command_transfer( + sess, SMF_NGAP_STATE_ERROR_INDICATION_RECEIVED_FROM_5G_AN, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); + ogs_assert(param.n2smbuf); + + param.skip_ind = true; + + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); + } else { + /* Only ACTIVING & DEACTIVATED is Included */ + smf_sbi_send_sm_context_updated_data_up_cnx_state( + sess, stream, OpenAPI_up_cnx_state_DEACTIVATED); + } } else if (flags & OGS_PFCP_MODIFY_CREATE) { - ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; + smf_n1_n2_message_transfer_param_t param; - ogs_assert(qos_flow); - n1smbuf = gsm_build_qos_flow_modification_command( + memset(¶m, 0, sizeof(param)); + param.state = SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION; + param.n1smbuf = gsm_build_qos_flow_modification_command( qos_flow, OGS_NAS_PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED); - ogs_assert(n1smbuf); - n2smbuf = ngap_build_qos_flow_resource_modify_request_transfer( + ogs_assert(param.n1smbuf); + param.n2smbuf = ngap_build_qos_flow_resource_modify_request_transfer( qos_flow); - ogs_assert(n2smbuf); + ogs_assert(param.n2smbuf); - smf_namf_comm_send_n1_n2_message_transfer( - sess, SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION, - n1smbuf, n2smbuf); + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); } } @@ -381,9 +397,19 @@ void smf_5gc_n4_handle_session_deletion_response( ogs_assert(sess); if (trigger == OGS_PFCP_DELETE_TRIGGER_UE_REQUESTED) { + ogs_pkbuf_t *n1smbuf = NULL, *n2smbuf = NULL; - smf_sbi_send_sm_context_updated_data_in_session_deletion(sess, stream); + n1smbuf = gsm_build_pdu_session_release_command( + sess, OGS_5GSM_CAUSE_REGULAR_DEACTIVATION); + ogs_assert(n1smbuf); + n2smbuf = ngap_build_pdu_session_resource_release_command_transfer( + sess, SMF_NGAP_STATE_DELETE_TRIGGER_UE_REQUESTED, + NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); + ogs_assert(n2smbuf); + + smf_sbi_send_sm_context_updated_data_n1_n2_message(sess, stream, + n1smbuf, OpenAPI_n2_sm_info_type_PDU_RES_REL_CMD, n2smbuf); } else { memset(&sendmsg, 0, sizeof(sendmsg)); @@ -643,3 +669,143 @@ void smf_epc_n4_handle_session_deletion_response( SMF_SESS_CLEAR(sess); } + +void smf_n4_handle_session_report_request( + smf_sess_t *sess, ogs_pfcp_xact_t *pfcp_xact, + ogs_pfcp_session_report_request_t *pfcp_req) +{ + smf_bearer_t *qos_flow = NULL; + ogs_pfcp_pdr_t *pdr = NULL; + + ogs_pfcp_report_type_t report_type; + uint8_t cause_value = 0; + uint16_t pdr_id = 0; + + ogs_assert(pfcp_xact); + ogs_assert(pfcp_req); + + cause_value = OGS_GTP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + } + + if (pfcp_req->report_type.presence == 0) { + ogs_error("No Report Type"); + cause_value = OGS_GTP_CAUSE_MANDATORY_IE_MISSING; + } + + if (cause_value != OGS_GTP_CAUSE_REQUEST_ACCEPTED) { + ogs_pfcp_send_error_message(pfcp_xact, 0, + OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE, + cause_value, 0); + return; + } + + ogs_assert(sess); + report_type.value = pfcp_req->report_type.u8; + + if (report_type.downlink_data_report) { + ogs_pfcp_downlink_data_service_information_t *info = NULL; + uint8_t paging_policy_indication_value = 0; + uint8_t qfi = 0; + + if (pfcp_req->downlink_data_report.presence) { + if (pfcp_req->downlink_data_report. + downlink_data_service_information.presence) { + info = pfcp_req->downlink_data_report. + downlink_data_service_information.data; + if (info) { + if (info->qfii && info->ppi) { + paging_policy_indication_value = + info->paging_policy_indication_value; + qfi = info->qfi; + } else if (info->qfii) { + qfi = info->qfi; + } else if (info->ppi) { + paging_policy_indication_value = + info->paging_policy_indication_value; + } else { + ogs_error("Invalid Downlink Data Service Information"); + } + + if (paging_policy_indication_value) { + ogs_warn("Not implement - " + "Paging Policy Indication Value"); + ogs_pfcp_send_error_message(pfcp_xact, 0, + OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE, + OGS_GTP_CAUSE_SERVICE_NOT_SUPPORTED, 0); + return; + } + + if (qfi) { + qos_flow = smf_qos_flow_find_by_qfi(sess, qfi); + if (!qos_flow) + ogs_error("Cannot find the QoS Flow[%d]", qfi); + } + } else { + ogs_error("No Info"); + } + } + + if (pfcp_req->downlink_data_report.pdr_id.presence) { + pdr = ogs_pfcp_pdr_find(&sess->pfcp, + pfcp_req->downlink_data_report.pdr_id.u16); + if (!pdr) + ogs_error("Cannot find the PDR-ID[%d]", pdr_id); + + } else { + ogs_error("No PDR-ID"); + } + } else { + ogs_error("No Downlink Data Report"); + } + + if (!pdr || !qos_flow) { + ogs_error("No Context [%p:%p]", pdr, qos_flow); + ogs_pfcp_send_error_message(pfcp_xact, 0, + OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE, + cause_value, 0); + } + + smf_pfcp_send_session_report_response( + pfcp_xact, sess, OGS_PFCP_CAUSE_REQUEST_ACCEPTED); + + if (sess->paging.ue_requested_pdu_session_establishment_done == true) { + smf_n1_n2_message_transfer_param_t param; + + memset(¶m, 0, sizeof(param)); + param.state = SMF_NETWORK_TRIGGERED_SERVICE_REQUEST; + param.n2smbuf = + ngap_build_pdu_session_resource_setup_request_transfer(sess); + ogs_assert(param.n2smbuf); + + param.n1n2_failure_txf_notif_uri = true; + + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); + } + + } else if (report_type.error_indication_report) { + smf_ue_t *smf_ue = sess->smf_ue; + smf_sess_t *error_indication_session = NULL; + ogs_assert(smf_ue); + + smf_pfcp_send_session_report_response( + pfcp_xact, sess, OGS_PFCP_CAUSE_REQUEST_ACCEPTED); + + error_indication_session = smf_sess_find_by_error_indication_report( + smf_ue, &pfcp_req->error_indication_report); + + if (!error_indication_session) return; + + smf_5gc_pfcp_send_session_modification_request( + error_indication_session, NULL, + OGS_PFCP_MODIFY_DEACTIVATE|OGS_PFCP_MODIFY_ERROR_INDICATION); + + } else { + ogs_error("Not supported Report Type[%d]", report_type.value); + smf_pfcp_send_session_report_response( + pfcp_xact, sess, OGS_PFCP_CAUSE_SYSTEM_FAILURE); + } +} diff --git a/src/smf/n4-handler.h b/src/smf/n4-handler.h index 0696ac3f0..827337719 100644 --- a/src/smf/n4-handler.h +++ b/src/smf/n4-handler.h @@ -46,6 +46,10 @@ void smf_epc_n4_handle_session_deletion_response( smf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_deletion_response_t *rsp); +void smf_n4_handle_session_report_request( + smf_sess_t *sess, ogs_pfcp_xact_t *pfcp_xact, + ogs_pfcp_session_report_request_t *pfcp_req); + #ifdef __cplusplus } #endif diff --git a/src/smf/namf-build.c b/src/smf/namf-build.c index 1ceb69871..1c8d341b7 100644 --- a/src/smf/namf-build.c +++ b/src/smf/namf-build.c @@ -22,7 +22,7 @@ #include "ngap-build.h" ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( - smf_sess_t *sess, smf_n1_n2_message_transfer_data_t *data) + smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param) { int i; smf_ue_t *smf_ue = NULL; @@ -30,6 +30,9 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( ogs_sbi_message_t message; ogs_sbi_request_t *request = NULL; + ogs_sbi_server_t *server = NULL; + ogs_sbi_header_t header; + OpenAPI_n1_n2_message_transfer_req_data_t N1N2MessageTransferReqData; OpenAPI_n1_message_container_t n1MessageContainer; @@ -45,10 +48,9 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( ogs_assert(smf_ue); ogs_assert(smf_ue->supi); - ogs_assert(data); - ogs_assert(data->state); - ogs_assert(data->n1smbuf); - ogs_assert(data->n2smbuf); + ogs_assert(param); + ogs_assert(param->state); + ogs_assert(param->n1smbuf || param->n2smbuf); memset(&message, 0, sizeof(message)); message.h.method = (char *)OGS_SBI_HTTP_METHOD_POST; @@ -62,46 +64,18 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( memset(&N1N2MessageTransferReqData, 0, sizeof(N1N2MessageTransferReqData)); N1N2MessageTransferReqData.pdu_session_id = sess->psi; - N1N2MessageTransferReqData.n1_message_container = &n1MessageContainer; - N1N2MessageTransferReqData.n2_info_container = &n2InfoContainer; - memset(&n1MessageContainer, 0, sizeof(n1MessageContainer)); - n1MessageContainer.n1_message_class = OpenAPI_n1_message_class_SM; - n1MessageContainer.n1_message_content = &n1MessageContent; + if (param->n1smbuf) { + N1N2MessageTransferReqData.n1_message_container = &n1MessageContainer; - memset(&n1MessageContent, 0, sizeof(n1MessageContent)); - n1MessageContent.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; + memset(&n1MessageContainer, 0, sizeof(n1MessageContainer)); + n1MessageContainer.n1_message_class = OpenAPI_n1_message_class_SM; + n1MessageContainer.n1_message_content = &n1MessageContent; - memset(&n2InfoContainer, 0, sizeof(n2InfoContainer)); - n2InfoContainer.n2_information_class = OpenAPI_n2_information_class_SM; - n2InfoContainer.sm_info = &smInfo; + memset(&n1MessageContent, 0, sizeof(n1MessageContent)); + n1MessageContent.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; - memset(&smInfo, 0, sizeof(smInfo)); - smInfo.pdu_session_id = sess->psi; - smInfo.n2_info_content = &n2InfoContent; - - memset(&n2InfoContent, 0, sizeof(n2InfoContent)); - switch (data->state) { - case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT: - n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ; - break; - case SMF_NETWORK_REQUESTED_PDU_SESSION_MODIFICATION: - case SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION: - n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ; - break; - default: - ogs_fatal("Unexpected state [%d]", data->state); - ogs_assert_if_reached(); - } - n2InfoContent.ngap_data = &ngapData; - - memset(&ngapData, 0, sizeof(ngapData)); - ngapData.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; - - message.num_of_part = 0; - - message.part[message.num_of_part].pkbuf = data->n1smbuf; - if (message.part[message.num_of_part].pkbuf) { + message.part[message.num_of_part].pkbuf = param->n1smbuf; message.part[message.num_of_part].content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; message.part[message.num_of_part].content_type = @@ -109,8 +83,40 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( message.num_of_part++; } - message.part[message.num_of_part].pkbuf = data->n2smbuf; - if (message.part[message.num_of_part].pkbuf) { + if (param->n2smbuf) { + N1N2MessageTransferReqData.n2_info_container = &n2InfoContainer; + + memset(&n2InfoContainer, 0, sizeof(n2InfoContainer)); + n2InfoContainer.n2_information_class = OpenAPI_n2_information_class_SM; + n2InfoContainer.sm_info = &smInfo; + + memset(&smInfo, 0, sizeof(smInfo)); + smInfo.pdu_session_id = sess->psi; + smInfo.n2_info_content = &n2InfoContent; + + memset(&n2InfoContent, 0, sizeof(n2InfoContent)); + switch (param->state) { + case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT: + case SMF_NETWORK_TRIGGERED_SERVICE_REQUEST: + n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_SETUP_REQ; + break; + case SMF_NETWORK_REQUESTED_PDU_SESSION_MODIFICATION: + case SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION: + n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_MOD_REQ; + break; + case SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN: + n2InfoContent.ngap_ie_type = OpenAPI_ngap_ie_type_PDU_RES_REL_CMD; + break; + default: + ogs_fatal("Unexpected state [%d]", param->state); + ogs_assert_if_reached(); + } + n2InfoContent.ngap_data = &ngapData; + + memset(&ngapData, 0, sizeof(ngapData)); + ngapData.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; + + message.part[message.num_of_part].pkbuf = param->n2smbuf; message.part[message.num_of_part].content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; message.part[message.num_of_part].content_type = @@ -118,6 +124,23 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( message.num_of_part++; } + if (param->n1n2_failure_txf_notif_uri == true) { + server = ogs_list_first(&ogs_sbi_self()->server_list); + ogs_assert(server); + + memset(&header, 0, sizeof(header)); + header.service.name = (char *)OGS_SBI_SERVICE_NAME_NSMF_CALLBACK; + header.api.version = (char *)OGS_SBI_API_V1; + header.resource.component[0] = + (char *)OGS_SBI_RESOURCE_NAME_N1_N2_FAILURE_NOTIFY; + N1N2MessageTransferReqData.n1n2_failure_txf_notif_uri = + ogs_sbi_server_uri(server, &header); + ogs_assert(N1N2MessageTransferReqData.n1n2_failure_txf_notif_uri); + } + + if (param->skip_ind == true) + N1N2MessageTransferReqData.skip_ind = 1; + request = ogs_sbi_build_request(&message); ogs_assert(request); @@ -125,6 +148,9 @@ ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( if (message.part[i].pkbuf) ogs_pkbuf_free(message.part[i].pkbuf); + if (N1N2MessageTransferReqData.n1n2_failure_txf_notif_uri) + ogs_free(N1N2MessageTransferReqData.n1n2_failure_txf_notif_uri); + return request; } diff --git a/src/smf/namf-build.h b/src/smf/namf-build.h index 6b108fbef..e2ede5e72 100644 --- a/src/smf/namf-build.h +++ b/src/smf/namf-build.h @@ -26,19 +26,24 @@ extern "C" { #endif -typedef struct smf_n1_n2_message_transfer_data_s { +typedef struct smf_n1_n2_message_transfer_param_s { #define SMF_N1_N2_MESSAGE_TRANSFER_NO_STATE 0 #define SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT 1 #define SMF_NETWORK_REQUESTED_PDU_SESSION_MODIFICATION 2 #define SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION 3 +#define SMF_NETWORK_TRIGGERED_SERVICE_REQUEST 4 +#define SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN 5 int state; ogs_pkbuf_t *n1smbuf; ogs_pkbuf_t *n2smbuf; -} smf_n1_n2_message_transfer_data_t; + + bool n1n2_failure_txf_notif_uri; + bool skip_ind; +} smf_n1_n2_message_transfer_param_t; ogs_sbi_request_t *smf_namf_comm_build_n1_n2_message_transfer( - smf_sess_t *sess, smf_n1_n2_message_transfer_data_t *data); + smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param); ogs_sbi_request_t *smf_namf_callback_build_sm_context_status( smf_sess_t *sess, void *data); diff --git a/src/smf/namf-handler.c b/src/smf/namf-handler.c index 734cb8672..7090b78c1 100644 --- a/src/smf/namf-handler.c +++ b/src/smf/namf-handler.c @@ -18,23 +18,136 @@ */ #include "sbi-path.h" +#include "ngap-path.h" #include "binding.h" #include "namf-handler.h" bool smf_namf_comm_handler_n1_n2_message_transfer( smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg) { + smf_ue_t *smf_ue = NULL; + OpenAPI_n1_n2_message_transfer_rsp_data_t *N1N2MessageTransferRspData; + ogs_assert(sess); + smf_ue = sess->smf_ue; + ogs_assert(smf_ue); ogs_assert(state); ogs_assert(recvmsg); switch (state) { case SMF_UE_REQUESTED_PDU_SESSION_ESTABLISHMENT: - smf_qos_flow_binding(sess, NULL); + if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) { + smf_qos_flow_binding(sess, NULL); + } else { + ogs_error("[%s:%d] HTTP response error [%d]", + smf_ue->supi, sess->psi, recvmsg->res_status); + } break; case SMF_NETWORK_REQUESTED_QOS_FLOW_MODIFICATION: - /* Nothing */ + if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) { + /* Nothing */ + } else { + ogs_error("[%s:%d] HTTP response error [%d]", + smf_ue->supi, sess->psi, recvmsg->res_status); + } + break; + + case SMF_NETWORK_TRIGGERED_SERVICE_REQUEST: + N1N2MessageTransferRspData = recvmsg->N1N2MessageTransferRspData; + if (!N1N2MessageTransferRspData) { + ogs_error("No N1N2MessageTransferRspData [status:%d]", + recvmsg->res_status); + break; + } + + if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) { + if (N1N2MessageTransferRspData->cause == + OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) { + /* Nothing */ + } else { + ogs_error("Not implemented [cause:%d]", + N1N2MessageTransferRspData->cause); + ogs_assert_if_reached(); + } + } else if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_ACCEPTED) { + if (N1N2MessageTransferRspData->cause == + OpenAPI_n1_n2_message_transfer_cause_ATTEMPTING_TO_REACH_UE) { + if (recvmsg->http.location) + smf_sess_set_paging_n1n2message_location( + sess, recvmsg->http.location); + else + ogs_error("No HTTP Location"); + } else { + ogs_error("Not implemented [cause:%d]", + N1N2MessageTransferRspData->cause); + ogs_assert_if_reached(); + } + } else { + + /* + * TODO: + * + * TS23.502 4.2.3.3 Network Triggered Service Request + * + * 3c. [Conditional] SMF responds to the UPF + * + * If the SMF receives an indication from the AMF that the UE is + * unreachable or reachable only for regulatory prioritized service + * and the SMF determines that Extended Buffering does not apply, + * the SMF may, based on network policies, either: + * + * - indicate to the UPF to stop sending Data Notifications; + * - indicate to the UPF to stop buffering DL data and + * discard the buffered data; + * - indicate to the UPF to stop sending Data Notifications and + * stop buffering DL data and discard the buffered data; or + * - refrains from sending further Namf_Communication_N1N2MessageTransfer + * message for DL data to the AMF while the UE is unreachable. + */ + + ogs_error("[%s:%d] HTTP response error [status:%d cause:%d]", + smf_ue->supi, sess->psi, recvmsg->res_status, + N1N2MessageTransferRspData->cause); + } + break; + + case SMF_ERROR_INDICATON_RECEIVED_FROM_5G_AN: + N1N2MessageTransferRspData = recvmsg->N1N2MessageTransferRspData; + if (!N1N2MessageTransferRspData) { + ogs_error("No N1N2MessageTransferRspData [status:%d]", + recvmsg->res_status); + break; + } + + if (recvmsg->res_status == OGS_SBI_HTTP_STATUS_OK) { + if (N1N2MessageTransferRspData->cause == + OpenAPI_n1_n2_message_transfer_cause_N1_MSG_NOT_TRANSFERRED) { + smf_n1_n2_message_transfer_param_t param; + + memset(¶m, 0, sizeof(param)); + param.state = SMF_NETWORK_TRIGGERED_SERVICE_REQUEST; + param.n2smbuf = + ngap_build_pdu_session_resource_setup_request_transfer( + sess); + ogs_assert(param.n2smbuf); + + param.n1n2_failure_txf_notif_uri = true; + + smf_namf_comm_send_n1_n2_message_transfer(sess, ¶m); + } else if (N1N2MessageTransferRspData->cause == + OpenAPI_n1_n2_message_transfer_cause_N1_N2_TRANSFER_INITIATED) { + /* Nothing */ + } else { + ogs_error("Not implemented [cause:%d]", + N1N2MessageTransferRspData->cause); + ogs_assert_if_reached(); + } + } else { + ogs_error("[%s:%d] HTTP response error [status:%d cause:%d]", + smf_ue->supi, sess->psi, recvmsg->res_status, + N1N2MessageTransferRspData->cause); + } break; default: @@ -44,3 +157,63 @@ bool smf_namf_comm_handler_n1_n2_message_transfer( return true; } + +bool smf_namf_comm_handler_n1_n2_message_transfer_failure_notify( + ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) +{ + OpenAPI_n1_n2_msg_txfr_failure_notification_t + *N1N2MsgTxfrFailureNotification = NULL; + + smf_sess_t *sess = NULL; + + ogs_assert(stream); + ogs_assert(recvmsg); + + N1N2MsgTxfrFailureNotification = recvmsg->N1N2MsgTxfrFailureNotification; + if (!N1N2MsgTxfrFailureNotification) { + ogs_error("No N1N2MsgTxfrFailureNotification"); + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No N1N2MsgTxfrFailureNotification", NULL); + return false; + } + + if (!N1N2MsgTxfrFailureNotification->cause) { + ogs_error("No Cause"); + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No Cause", NULL); + return false; + } + + if (!N1N2MsgTxfrFailureNotification->n1n2_msg_data_uri) { + ogs_error("No n1n2MsgDataUri"); + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, + recvmsg, "No n1n2MsgDataUri", NULL); + return false; + } + + sess = smf_sess_find_by_paging_n1n2message_location( + N1N2MsgTxfrFailureNotification->n1n2_msg_data_uri); + if (!sess) { + ogs_error("Not found"); + ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, + recvmsg, N1N2MsgTxfrFailureNotification->n1n2_msg_data_uri, NULL); + return false; + } + + /* + * TODO: + * + * TS23.502 4.2.3.3 Network Triggered Service Request + * + * 5. [Conditional] AMF to SMF: + * Namf_Communication_N1N2Transfer Failure Notification. + * + * When a Namf_Communication_N1N2Transfer Failure Notification + * is received, SMF informs the UPF (if applicable). + * + * Procedure for pause of charging at SMF is specified in clause 4.4.4. + */ + + smf_sbi_send_http_status_no_content(stream); + return true; +} diff --git a/src/smf/namf-handler.h b/src/smf/namf-handler.h index aae07b101..844ecfcec 100644 --- a/src/smf/namf-handler.h +++ b/src/smf/namf-handler.h @@ -29,6 +29,9 @@ extern "C" { bool smf_namf_comm_handler_n1_n2_message_transfer( smf_sess_t *sess, int state, ogs_sbi_message_t *recvmsg); +bool smf_namf_comm_handler_n1_n2_message_transfer_failure_notify( + ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg); + #ifdef __cplusplus } #endif diff --git a/src/smf/ngap-build.c b/src/smf/ngap-build.c index ab7f331fb..13c38cb46 100644 --- a/src/smf/ngap-build.c +++ b/src/smf/ngap-build.c @@ -276,11 +276,15 @@ ogs_pkbuf_t *ngap_build_qos_flow_resource_modify_request_transfer( } ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command_transfer( - NGAP_Cause_PR group, long cause) + smf_sess_t *sess, int state, NGAP_Cause_PR group, long cause) { NGAP_PDUSessionResourceReleaseCommandTransfer_t message; NGAP_Cause_t *Cause = NULL; + ogs_assert(sess); + ogs_assert(state); + sess->ngap_state.pdu_session_resource_release = state; + ogs_debug("PDUSessionResourceReleaseCommandTransfer"); memset(&message, 0, sizeof(NGAP_PDUSessionResourceReleaseCommandTransfer_t)); diff --git a/src/smf/ngap-build.h b/src/smf/ngap-build.h index fd1e42c4f..791c02c94 100644 --- a/src/smf/ngap-build.h +++ b/src/smf/ngap-build.h @@ -33,7 +33,7 @@ ogs_pkbuf_t *ngap_build_qos_flow_resource_modify_request_transfer( smf_bearer_t *qos_flow); ogs_pkbuf_t *ngap_build_pdu_session_resource_release_command_transfer( - NGAP_Cause_PR group, long cause); + smf_sess_t *sess, int state, NGAP_Cause_PR group, long cause); ogs_pkbuf_t *ngap_build_path_switch_request_ack_transfer(smf_sess_t *sess); diff --git a/src/smf/ngap-handler.c b/src/smf/ngap-handler.c index e9aa5afc4..71d9c3f71 100644 --- a/src/smf/ngap-handler.c +++ b/src/smf/ngap-handler.c @@ -141,7 +141,7 @@ int ngap_handle_pdu_session_resource_setup_response_transfer( sess, stream, OGS_PFCP_MODIFY_ACTIVATE); } else { /* ACTIVATED Is NOT Included in RESPONSE */ - smf_sbi_send_sm_context_updated_data(sess, stream, 0); + smf_sbi_send_http_status_no_content(stream); } rv = OGS_OK; @@ -343,7 +343,7 @@ int ngap_handle_pdu_session_resource_to_be_switched_dl_transfer( OGS_PFCP_MODIFY_END_MARKER); } else { /* ACTIVATED Is NOT Included in RESPONSE */ - smf_sbi_send_sm_context_updated_data(sess, stream, 0); + smf_sbi_send_http_status_no_content(stream); } rv = OGS_OK; diff --git a/src/smf/nsmf-handler.c b/src/smf/nsmf-handler.c index 9c78aacf1..c69820257 100644 --- a/src/smf/nsmf-handler.c +++ b/src/smf/nsmf-handler.c @@ -440,14 +440,12 @@ bool smf_nsmf_handle_update_sm_context( } else { char *strerror = ogs_msprintf("[%s:%d] Invalid upCnxState [%d]", - smf_ue->supi, sess->psi, - SmContextUpdateData->up_cnx_state); + smf_ue->supi, sess->psi, SmContextUpdateData->up_cnx_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_SBI_HTTP_STATUS_BAD_REQUEST, strerror, NULL, NULL, NULL); ogs_free(strerror); return false; diff --git a/src/smf/pfcp-path.c b/src/smf/pfcp-path.c index 89f0085f9..206346513 100644 --- a/src/smf/pfcp-path.c +++ b/src/smf/pfcp-path.c @@ -285,7 +285,8 @@ void smf_5gc_pfcp_send_session_modification_request( ogs_pfcp_xact_t *xact = NULL; ogs_assert(sess); - ogs_assert(stream); + if ((flags & OGS_PFCP_MODIFY_ERROR_INDICATION) == 0) + ogs_assert(stream); memset(&h, 0, sizeof(ogs_pfcp_header_t)); h.type = OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE; @@ -456,3 +457,26 @@ void smf_epc_pfcp_send_session_deletion_request( rv = ogs_pfcp_xact_commit(xact); ogs_expect(rv == OGS_OK); } + +void smf_pfcp_send_session_report_response( + ogs_pfcp_xact_t *xact, smf_sess_t *sess, uint8_t cause) +{ + int rv; + ogs_pkbuf_t *sxabuf = NULL; + ogs_pfcp_header_t h; + + ogs_assert(xact); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE; + h.seid = sess->upf_n4_seid; + + sxabuf = ogs_pfcp_build_session_report_response(h.type, cause); + ogs_expect_or_return(sxabuf); + + rv = ogs_pfcp_xact_update_tx(xact, &h, sxabuf); + ogs_expect_or_return(rv == OGS_OK); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/src/smf/pfcp-path.h b/src/smf/pfcp-path.h index ebddbf549..728cd7412 100644 --- a/src/smf/pfcp-path.h +++ b/src/smf/pfcp-path.h @@ -45,6 +45,9 @@ void smf_epc_pfcp_send_bearer_modification_request( void smf_epc_pfcp_send_session_deletion_request( smf_sess_t *sess, void *gtp_xact); +void smf_pfcp_send_session_report_response( + ogs_pfcp_xact_t *xact, smf_sess_t *sess, uint8_t cause); + #ifdef __cplusplus } #endif diff --git a/src/smf/pfcp-sm.c b/src/smf/pfcp-sm.c index a208b42d6..48ed88505 100644 --- a/src/smf/pfcp-sm.c +++ b/src/smf/pfcp-sm.c @@ -249,6 +249,16 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e) sess, xact, &message->pfcp_session_deletion_response); break; + case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE: + if (!message->h.seid_presence) { + ogs_error("No SEID"); + break; + } + + smf_n4_handle_session_report_request( + sess, xact, &message->pfcp_session_report_request); + break; + default: ogs_error("Not implemented PFCP message type[%d]", message->h.type); diff --git a/src/smf/s5c-build.c b/src/smf/s5c-build.c index 2a7f76a12..3927697c5 100644 --- a/src/smf/s5c-build.c +++ b/src/smf/s5c-build.c @@ -93,7 +93,7 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( /* APN-AMBR * if PCRF changes APN-AMBR, this should be included. */ - if (sess->gtp_5gc.create_session_response_apn_ambr == true) { + if (sess->gtp.create_session_response_apn_ambr == true) { memset(&ambr, 0, sizeof(ogs_gtp_ambr_t)); ambr.uplink = htobe32(sess->pdn.ambr.uplink / 1000); ambr.downlink = htobe32(sess->pdn.ambr.downlink / 1000); @@ -125,7 +125,7 @@ ogs_pkbuf_t *smf_s5c_build_create_session_response( /* Bearer QoS * if PCRF changes Bearer QoS, this should be included. */ - if (sess->gtp_5gc.create_session_response_bearer_qos == true) { + if (sess->gtp.create_session_response_bearer_qos == true) { memset(&bearer_qos, 0, sizeof(bearer_qos)); bearer_qos.qci = sess->pdn.qos.qci; bearer_qos.priority_level = sess->pdn.qos.arp.priority_level; diff --git a/src/smf/sbi-path.c b/src/smf/sbi-path.c index 598a26f2b..83d2cec85 100644 --- a/src/smf/sbi-path.c +++ b/src/smf/sbi-path.c @@ -152,32 +152,25 @@ void smf_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, } void smf_namf_comm_send_n1_n2_message_transfer( - smf_sess_t *sess, int state, - ogs_pkbuf_t *n1smbuf, ogs_pkbuf_t *n2smbuf) + smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param) { ogs_sbi_xact_t *xact = NULL; smf_ue_t *smf_ue = NULL; - smf_n1_n2_message_transfer_data_t data; - ogs_assert(state); - ogs_assert(n1smbuf); - ogs_assert(n2smbuf); + ogs_assert(param); + ogs_assert(param->state); + ogs_assert(param->n1smbuf || param->n2smbuf); ogs_assert(sess); smf_ue = sess->smf_ue; ogs_assert(smf_ue); - memset(&data, 0, sizeof(data)); - data.state = state; - data.n1smbuf = n1smbuf; - data.n2smbuf = n2smbuf; - xact = ogs_sbi_xact_add(OpenAPI_nf_type_AMF, &sess->sbi, (ogs_sbi_build_f)smf_namf_comm_build_n1_n2_message_transfer, - sess, &data, smf_timer_sbi_client_wait_expire); + sess, param, smf_timer_sbi_client_wait_expire); ogs_assert(xact); - xact->state = state; + xact->state = param->state; ogs_sbi_discover_and_send(xact, (ogs_fsm_handler_t)smf_nf_state_registered, client_cb); @@ -240,38 +233,11 @@ void smf_sbi_send_sm_context_create_error( ogs_pkbuf_free(n1smbuf); } -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) -{ - int status; - - ogs_sbi_message_t sendmsg; - ogs_sbi_response_t *response = NULL; - - OpenAPI_sm_context_updated_data_t SmContextUpdatedData; - - ogs_assert(sess); - ogs_assert(stream); - - memset(&sendmsg, 0, sizeof(sendmsg)); - - if (up_cnx_state) { - memset(&SmContextUpdatedData, 0, sizeof(SmContextUpdatedData)); - SmContextUpdatedData.up_cnx_state = up_cnx_state; - - sendmsg.SmContextUpdatedData = &SmContextUpdatedData; - status = OGS_SBI_HTTP_STATUS_OK; - } else { - status = OGS_SBI_HTTP_STATUS_NO_CONTENT; - } - - response = ogs_sbi_build_response(&sendmsg, status); - ogs_assert(response); - ogs_sbi_server_send_response(stream, response); -} - -void smf_sbi_send_sm_context_updated_data_in_session_deletion( - smf_sess_t *sess, ogs_sbi_stream_t *stream) +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, + ogs_pkbuf_t *n1smbuf, + OpenAPI_n2_sm_info_type_e n2type, ogs_pkbuf_t *n2smbuf) { int i; @@ -285,41 +251,41 @@ void smf_sbi_send_sm_context_updated_data_in_session_deletion( ogs_assert(sess); ogs_assert(stream); + ogs_assert(up_cnx_state != OpenAPI_up_cnx_state_NULL || n1smbuf || n2smbuf); + memset(&sendmsg, 0, sizeof(sendmsg)); memset(&SmContextUpdatedData, 0, sizeof(SmContextUpdatedData)); - sendmsg.num_of_part = 0; + /* up_cnx_state */ + SmContextUpdatedData.up_cnx_state = up_cnx_state; - n1SmMsg.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; - SmContextUpdatedData.n1_sm_msg = &n1SmMsg; + /* n1smbuf */ + if (n1smbuf) { + n1SmMsg.content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; + SmContextUpdatedData.n1_sm_msg = &n1SmMsg; - sendmsg.part[sendmsg.num_of_part].pkbuf = - gsm_build_pdu_session_release_command( - sess, OGS_5GSM_CAUSE_REGULAR_DEACTIVATION); - if (sendmsg.part[sendmsg.num_of_part].pkbuf) { sendmsg.part[sendmsg.num_of_part].content_id = (char *)OGS_SBI_CONTENT_5GNAS_SM_ID; sendmsg.part[sendmsg.num_of_part].content_type = (char *)OGS_SBI_CONTENT_5GNAS_TYPE; + sendmsg.part[sendmsg.num_of_part].pkbuf = n1smbuf; sendmsg.num_of_part++; } - SmContextUpdatedData.n2_sm_info_type = - OpenAPI_n2_sm_info_type_PDU_RES_REL_CMD; - SmContextUpdatedData.n2_sm_info = &n2SmInfo; + /* n2smbuf */ + if (n2smbuf) { + ogs_assert(n2type); + SmContextUpdatedData.n2_sm_info_type = n2type; - memset(&n2SmInfo, 0, sizeof(n2SmInfo)); - n2SmInfo.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; + n2SmInfo.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; + SmContextUpdatedData.n2_sm_info = &n2SmInfo; - sendmsg.part[sendmsg.num_of_part].pkbuf = - ngap_build_pdu_session_resource_release_command_transfer( - NGAP_Cause_PR_nas, NGAP_CauseNas_normal_release); - if (sendmsg.part[sendmsg.num_of_part].pkbuf) { sendmsg.part[sendmsg.num_of_part].content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; sendmsg.part[sendmsg.num_of_part].content_type = (char *)OGS_SBI_CONTENT_NGAP_TYPE; + sendmsg.part[sendmsg.num_of_part].pkbuf = n2smbuf; sendmsg.num_of_part++; } @@ -327,6 +293,7 @@ void smf_sbi_send_sm_context_updated_data_in_session_deletion( response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); + ogs_sbi_server_send_response(stream, response); for (i = 0; i < sendmsg.num_of_part; i++) @@ -426,51 +393,8 @@ void smf_sbi_send_sm_context_status_notify(smf_sess_t *sess) ogs_assert(sess); client = sess->namf.client; ogs_assert(client); - client->cb = client_cb; request = smf_namf_callback_build_sm_context_status(sess, NULL); ogs_assert(request); ogs_sbi_client_send_request(client, client_notify_cb, request, NULL); } - -void smf_sbi_send_sm_context_updated_data_with_n2buf( - smf_sess_t *sess, ogs_sbi_stream_t *stream, - OpenAPI_n2_sm_info_type_e n2_sm_info_type, ogs_pkbuf_t *n2smbuf) -{ - ogs_sbi_message_t sendmsg; - ogs_sbi_response_t *response = NULL; - - OpenAPI_sm_context_updated_data_t SmContextUpdatedData; - OpenAPI_ref_to_binary_data_t n2SmInfo; - - ogs_assert(sess); - ogs_assert(stream); - - memset(&sendmsg, 0, sizeof(sendmsg)); - - memset(&SmContextUpdatedData, 0, sizeof(SmContextUpdatedData)); - - sendmsg.num_of_part = 0; - - sendmsg.SmContextUpdatedData = &SmContextUpdatedData; - - if (n2smbuf) { - SmContextUpdatedData.n2_sm_info_type = n2_sm_info_type; - SmContextUpdatedData.n2_sm_info = &n2SmInfo; - n2SmInfo.content_id = (char *)OGS_SBI_CONTENT_NGAP_SM_ID; - sendmsg.part[sendmsg.num_of_part].content_id = - (char *)OGS_SBI_CONTENT_NGAP_SM_ID; - sendmsg.part[sendmsg.num_of_part].content_type = - (char *)OGS_SBI_CONTENT_NGAP_TYPE; - sendmsg.part[sendmsg.num_of_part].pkbuf = n2smbuf; - sendmsg.num_of_part++; - } - - response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); - ogs_assert(response); - - ogs_sbi_server_send_response(stream, response); - - if (n2smbuf) - ogs_pkbuf_free(n2smbuf); -} \ No newline at end of file diff --git a/src/smf/sbi-path.h b/src/smf/sbi-path.h index 3f24e6538..d29fb5c63 100644 --- a/src/smf/sbi-path.h +++ b/src/smf/sbi-path.h @@ -40,26 +40,39 @@ void smf_sbi_discover_and_send(OpenAPI_nf_type_e target_nf_type, ogs_sbi_request_t *(*build)(smf_sess_t *sess, void *data)); void smf_namf_comm_send_n1_n2_message_transfer( - smf_sess_t *sess, int state, - ogs_pkbuf_t *n1smbuf, ogs_pkbuf_t *n2smbuf); + smf_sess_t *sess, smf_n1_n2_message_transfer_param_t *param); +#define smf_sbi_send_http_status_no_content(__sTREAM) \ + smf_sbi_send_response(__sTREAM, OGS_SBI_HTTP_STATUS_NO_CONTENT); void smf_sbi_send_response(ogs_sbi_stream_t *stream, int status); void smf_sbi_send_sm_context_create_error( ogs_sbi_stream_t *stream, int status, const char *title, const char *detail, ogs_pkbuf_t *n1smbuf); -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); -void smf_sbi_send_sm_context_updated_data_in_session_deletion( - smf_sess_t *sess, ogs_sbi_stream_t *stream); + +#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) +#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) +#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) +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, + ogs_pkbuf_t *n1smbuf, + OpenAPI_n2_sm_info_type_e n2type, ogs_pkbuf_t *n2smbuf); + void smf_sbi_send_sm_context_update_error( ogs_sbi_stream_t *stream, int status, const char *title, const char *detail, ogs_pkbuf_t *n1smbuf, ogs_pkbuf_t *n2smbuf); -void smf_sbi_send_sm_context_updated_data_with_n2buf( - smf_sess_t *sess, ogs_sbi_stream_t *stream, - OpenAPI_n2_sm_info_type_e n2_sm_info_type, ogs_pkbuf_t *n2smbuf); void smf_sbi_send_sm_context_status_notify(smf_sess_t *sess); diff --git a/src/smf/smf-sm.c b/src/smf/smf-sm.c index e64651f08..736728006 100644 --- a/src/smf/smf-sm.c +++ b/src/smf/smf-sm.c @@ -25,6 +25,7 @@ #include "s5c-handler.h" #include "gx-handler.h" #include "nnrf-handler.h" +#include "namf-handler.h" void smf_state_initial(ogs_fsm_t *s, smf_event_t *e) { @@ -199,8 +200,7 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) sess, gx_message, gtp_xact); break; default: - ogs_error("Not implemented(%d)", - gx_message->cc_request_type); + ogs_error("Not implemented(%d)", gx_message->cc_request_type); break; } @@ -299,11 +299,9 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) break; DEFAULT - ogs_error("Invalid HTTP method [%s]", - sbi_message.h.method); + ogs_error("Invalid HTTP method [%s]", sbi_message.h.method); ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_FORBIDDEN, - &sbi_message, + OGS_SBI_HTTP_STATUS_FORBIDDEN, &sbi_message, "Invalid HTTP method", sbi_message.h.method); END break; @@ -388,17 +386,24 @@ void smf_state_operational(ogs_fsm_t *s, smf_event_t *e) break; CASE(OGS_SBI_SERVICE_NAME_NSMF_CALLBACK) - SWITCH(sbi_message.h.resource.component[1]) - CASE(OGS_SBI_RESOURCE_NAME_SM_POLICY_NOTIFY) - /* TODO */ - + SWITCH(sbi_message.h.resource.component[0]) + CASE(OGS_SBI_RESOURCE_NAME_N1_N2_FAILURE_NOTIFY) + smf_namf_comm_handler_n1_n2_message_transfer_failure_notify( + stream, &sbi_message); + break; DEFAULT - ogs_error("Invalid resource name [%s]", - sbi_message.h.resource.component[1]); - ogs_sbi_server_send_error(stream, - OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message, - "Invalid resource name", - sbi_message.h.resource.component[1]); + SWITCH(sbi_message.h.resource.component[1]) + CASE(OGS_SBI_RESOURCE_NAME_SM_POLICY_NOTIFY) + /* TODO */ + + DEFAULT + ogs_error("Invalid resource name [%s]", + sbi_message.h.resource.component[1]); + ogs_sbi_server_send_error(stream, + OGS_SBI_HTTP_STATUS_BAD_REQUEST, &sbi_message, + "Invalid resource name", + sbi_message.h.resource.component[1]); + END END break; diff --git a/src/upf/gtp-path.c b/src/upf/gtp-path.c index 4ba14648f..374e47812 100644 --- a/src/upf/gtp-path.c +++ b/src/upf/gtp-path.c @@ -37,6 +37,7 @@ #include "event.h" #include "gtp-path.h" +#include "pfcp-path.h" #include "rule-match.h" #define UPF_GTP_HANDLED 1 @@ -52,6 +53,8 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) { ogs_pkbuf_t *recvbuf = NULL; int n; + + upf_sess_t *sess = NULL; ogs_pfcp_pdr_t *pdr = NULL; ogs_pfcp_user_plane_report_t report; @@ -74,6 +77,18 @@ static void _gtpv1_tun_recv_cb(short when, ogs_socket_t fd, void *data) if (pdr) { /* Unicast */ ogs_pfcp_up_handle_pdr(pdr, recvbuf, &report); + + if (report.type.downlink_data_report) { + ogs_assert(pdr->sess); + sess = UPF_SESS(pdr->sess); + ogs_assert(sess); + + report.downlink_data.pdr_id = pdr->id; + if (pdr->qer && pdr->qer->qfi) + report.downlink_data.qfi = pdr->qer->qfi; /* for 5GC */ + + upf_pfcp_send_session_report_request(sess, &report); + } } else { if (ogs_app()->parameter.multicast) { upf_gtp_handle_multicast(recvbuf); @@ -89,13 +104,13 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) ssize_t size; char buf[OGS_ADDRSTRLEN]; + upf_sess_t *sess = NULL; + ogs_pkbuf_t *pkbuf = NULL; ogs_sockaddr_t from; ogs_gtp_header_t *gtp_h = NULL; -#if 0 ogs_pfcp_user_plane_report_t report; -#endif uint32_t teid; uint8_t qfi; @@ -188,7 +203,24 @@ static void _gtpv1_u_recv_cb(short when, ogs_socket_t fd, void *data) /* Nothing */ } else if (gtp_h->type == OGS_GTPU_MSGTYPE_ERR_IND) { - /* TODO */ + ogs_pfcp_far_t *far = NULL; + + far = ogs_pfcp_far_find_by_error_indication(pkbuf); + if (far) { + ogs_pfcp_up_handle_error_indication(far, &report); + + if (report.type.error_indication_report) { + ogs_assert(far->sess); + sess = UPF_SESS(far->sess); + ogs_assert(sess); + + upf_pfcp_send_session_report_request(sess, &report); + } + + } else { + ogs_error("[DROP] Cannot find FAR by Error-Indication"); + ogs_log_hexdump(OGS_LOG_ERROR, pkbuf->data, pkbuf->len); + } } else if (gtp_h->type == OGS_GTPU_MSGTYPE_GPDU) { int rv; diff --git a/src/upf/n4-handler.c b/src/upf/n4-handler.c index f24b60540..a6f3ebcf0 100644 --- a/src/upf/n4-handler.c +++ b/src/upf/n4-handler.c @@ -431,3 +431,39 @@ void upf_n4_handle_session_deletion_request( upf_sess_remove(sess); } + +void upf_n4_handle_session_report_response( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_report_response_t *rsp) +{ + uint8_t cause_value = 0; + + ogs_assert(xact); + ogs_assert(rsp); + + ogs_pfcp_xact_commit(xact); + + ogs_debug("Session report resopnse"); + + cause_value = OGS_PFCP_CAUSE_REQUEST_ACCEPTED; + + if (!sess) { + ogs_warn("No Context"); + cause_value = OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND; + } + + if (rsp->cause.presence) { + if (rsp->cause.u8 != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_error("PFCP Cause[%d] : Not Accepted", rsp->cause.u8); + cause_value = rsp->cause.u8; + } + } else { + ogs_error("No Cause"); + cause_value = OGS_PFCP_CAUSE_MANDATORY_IE_MISSING; + } + + if (cause_value != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) { + ogs_error("Cause request not accepted[%d]", cause_value); + return; + } +} diff --git a/src/upf/n4-handler.h b/src/upf/n4-handler.h index 7508cb548..09a46b404 100644 --- a/src/upf/n4-handler.h +++ b/src/upf/n4-handler.h @@ -36,6 +36,10 @@ void upf_n4_handle_session_deletion_request( upf_sess_t *sess, ogs_pfcp_xact_t *xact, ogs_pfcp_session_deletion_request_t *req); +void upf_n4_handle_session_report_response( + upf_sess_t *sess, ogs_pfcp_xact_t *xact, + ogs_pfcp_session_report_response_t *rsp); + #ifdef __cplusplus } #endif diff --git a/src/upf/pfcp-path.c b/src/upf/pfcp-path.c index a7f8cf027..de5bf10ef 100644 --- a/src/upf/pfcp-path.c +++ b/src/upf/pfcp-path.c @@ -250,3 +250,46 @@ void upf_pfcp_send_session_deletion_response(ogs_pfcp_xact_t *xact, rv = ogs_pfcp_xact_commit(xact); ogs_expect(rv == OGS_OK); } + +static void sess_timeout(ogs_pfcp_xact_t *xact, void *data) +{ + uint8_t type; + + ogs_assert(xact); + type = xact->seq[0].type; + + switch (type) { + case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE: + ogs_error("No PFCP session report response"); + break; + default: + ogs_error("Not implemented [type:%d]", type); + break; + } +} + +void upf_pfcp_send_session_report_request( + upf_sess_t *sess, ogs_pfcp_user_plane_report_t *report) +{ + int rv; + ogs_pkbuf_t *n4buf = NULL; + ogs_pfcp_header_t h; + ogs_pfcp_xact_t *xact = NULL; + + ogs_assert(sess); + ogs_assert(report); + + memset(&h, 0, sizeof(ogs_pfcp_header_t)); + h.type = OGS_PFCP_SESSION_REPORT_REQUEST_TYPE; + h.seid = sess->smf_n4_seid; + + n4buf = ogs_pfcp_build_session_report_request(h.type, report); + ogs_expect_or_return(n4buf); + + xact = ogs_pfcp_xact_local_create( + sess->pfcp_node, &h, n4buf, sess_timeout, sess); + ogs_expect_or_return(xact); + + rv = ogs_pfcp_xact_commit(xact); + ogs_expect(rv == OGS_OK); +} diff --git a/src/upf/pfcp-path.h b/src/upf/pfcp-path.h index 06dadce85..4b06467be 100644 --- a/src/upf/pfcp-path.h +++ b/src/upf/pfcp-path.h @@ -38,6 +38,9 @@ void upf_pfcp_send_session_modification_response( void upf_pfcp_send_session_deletion_response(ogs_pfcp_xact_t *xact, upf_sess_t *sess); +void upf_pfcp_send_session_report_request( + upf_sess_t *sess, ogs_pfcp_user_plane_report_t *report); + #ifdef __cplusplus } #endif diff --git a/src/upf/pfcp-sm.c b/src/upf/pfcp-sm.c index 1af1d5c2e..60b3f5cb2 100644 --- a/src/upf/pfcp-sm.c +++ b/src/upf/pfcp-sm.c @@ -224,6 +224,10 @@ void upf_pfcp_state_associated(ogs_fsm_t *s, upf_event_t *e) upf_n4_handle_session_deletion_request( sess, xact, &message->pfcp_session_deletion_request); break; + case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE: + upf_n4_handle_session_report_response( + sess, xact, &message->pfcp_session_report_response); + break; default: ogs_error("Not implemented PFCP message type[%d]", message->h.type); diff --git a/tests/common/ngap-path.c b/tests/common/ngap-path.c index dd222494a..d48d0c30f 100644 --- a/tests/common/ngap-path.c +++ b/tests/common/ngap-path.c @@ -66,6 +66,7 @@ void testngap_recv(test_ue_t *test_ue, ogs_pkbuf_t *pkbuf) testngap_handle_pdu_session_resource_release_command(test_ue, pdu); break; case NGAP_ProcedureCode_id_ErrorIndication: + case NGAP_ProcedureCode_id_Paging: /* Nothing */ break; default: diff --git a/tests/registration/abts-main.c b/tests/registration/abts-main.c index 7be793dfa..0ffb3a673 100644 --- a/tests/registration/abts-main.c +++ b/tests/registration/abts-main.c @@ -23,6 +23,7 @@ abts_suite *test_guti(abts_suite *suite); abts_suite *test_auth(abts_suite *suite); abts_suite *test_idle(abts_suite *suite); abts_suite *test_dereg(abts_suite *suite); +abts_suite *test_paging(abts_suite *suite); abts_suite *test_identity(abts_suite *suite); abts_suite *test_gmm_status(abts_suite *suite); abts_suite *test_ue_context(abts_suite *suite); @@ -34,6 +35,7 @@ const struct testlist { {test_auth}, {test_idle}, {test_dereg}, + {test_paging}, {test_identity}, {test_gmm_status}, {test_ue_context}, diff --git a/tests/registration/dereg-test.c b/tests/registration/dereg-test.c index 657e79473..4d6e0dab4 100644 --- a/tests/registration/dereg-test.c +++ b/tests/registration/dereg-test.c @@ -902,18 +902,22 @@ static void test3_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive PDU session release command */ + /* Receive PDUSessionResourceReleaseCommand + + * DL NAS transport + + * PDU session release command */ recvbuf = testgnb_ngap_read(ngap); ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send PDU session resource release response */ + /* Send PDUSessionResourceReleaseResponse */ sendbuf = testngap_build_pdu_session_resource_release_response(sess); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send PDU session resource release complete */ + /* Send UplinkNASTransport + + * UL NAS trasnport + + * PDU session resource release complete */ sess->ul_nas_transport_param.request_type = 0; sess->ul_nas_transport_param.dnn = 0; sess->ul_nas_transport_param.s_nssai = 0; @@ -1365,19 +1369,22 @@ static void test4_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive PDU session release command */ + /* Receive PDUSessionResourceReleaseCommand + + * DL NAS transport + + * PDU session release command */ recvbuf = testgnb_ngap_read(ngap); ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send PDU session resource release response */ - sendbuf = - testngap_build_pdu_session_resource_release_response(sess); + /* Send PDUSessionResourceReleaseResponse */ + sendbuf = testngap_build_pdu_session_resource_release_response(sess); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send PDU session resource release complete */ + /* Send UplinkNASTransport + + * UL NAS trasnport + + * PDU session resource release complete */ sess->ul_nas_transport_param.request_type = 0; sess->ul_nas_transport_param.dnn = 0; sess->ul_nas_transport_param.s_nssai = 0; diff --git a/tests/registration/guti-test.c b/tests/registration/guti-test.c index a0e537f26..5ab555447 100644 --- a/tests/registration/guti-test.c +++ b/tests/registration/guti-test.c @@ -404,6 +404,7 @@ static void test1_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); + /* TODO : we need to analyze it */ ogs_msleep(100); /* Send Identity response */ diff --git a/tests/registration/identity-test.c b/tests/registration/identity-test.c index 71bf12edc..67ea291d6 100644 --- a/tests/registration/identity-test.c +++ b/tests/registration/identity-test.c @@ -316,6 +316,7 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* TODO : we need to analyze it */ ogs_msleep(100); /* Send De-registration request */ @@ -358,7 +359,15 @@ static void test1_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); + /* TODO : + * + * I can't remeber why do I add the following sleep + * At this point, this commented out. + * I'll need to analyze it later. + */ +#if 0 ogs_msleep(100); +#endif /* INVALID SUCI */ test_ue->mobile_identity_suci.scheme_output[0] = 0x99; @@ -375,6 +384,8 @@ static void test1_func(abts_case *tc, void *data) recvbuf = testgnb_ngap_read(ngap); ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + OGS_NAS_5GS_REGISTRATION_REJECT, test_ue->gmm_message_type); /* Receive UE context release command */ recvbuf = testgnb_ngap_read(ngap); diff --git a/tests/registration/idle-test.c b/tests/registration/idle-test.c index 00dde7b66..04eccd94d 100644 --- a/tests/registration/idle-test.c +++ b/tests/registration/idle-test.c @@ -313,10 +313,6 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* * Send InitialUEMessage + * Service request @@ -357,10 +353,9 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive GTP-U ICMP Packet */ - recvbuf = testgnb_gtpu_read(gtpu); - ABTS_PTR_NOTNULL(tc, recvbuf); - ogs_pkbuf_free(recvbuf); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); @@ -384,10 +379,6 @@ static void test1_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send UE context release complete */ sendbuf = testngap_build_ue_context_release_complete(test_ue); ABTS_PTR_NOTNULL(tc, sendbuf); @@ -436,10 +427,9 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive GTP-U ICMP Packet */ - recvbuf = testgnb_gtpu_read(gtpu); - ABTS_PTR_NOTNULL(tc, recvbuf); - ogs_pkbuf_free(recvbuf); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); @@ -2496,10 +2486,6 @@ static void test6_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* * Send InitialUEMessage + * Service request @@ -2542,10 +2528,9 @@ static void test6_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive GTP-U ICMP Packet */ - recvbuf = testgnb_gtpu_read(gtpu); - ABTS_PTR_NOTNULL(tc, recvbuf); - ogs_pkbuf_free(recvbuf); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); diff --git a/tests/registration/meson.build b/tests/registration/meson.build index 50252ac48..1751c9ab4 100644 --- a/tests/registration/meson.build +++ b/tests/registration/meson.build @@ -21,6 +21,7 @@ test5gc_registration_sources = files(''' auth-test.c idle-test.c dereg-test.c + paging-test.c identity-test.c gmm-status-test.c ue-context-test.c diff --git a/tests/registration/paging-test.c b/tests/registration/paging-test.c new file mode 100644 index 000000000..800fb99a5 --- /dev/null +++ b/tests/registration/paging-test.c @@ -0,0 +1,3427 @@ +/* + * 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 cm_idle_paging_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}" + "]," + "\"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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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 */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection + * + * Otherwise, the following case could occur: + * + * 1. PDUSessionResourceSetupResponse + * 2. UEContextReleaseRequest + * 3. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 4. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 5. PFCP Session Modifcation Request (Deactivated) + * 6. PFCP Session Modifcation Request (OuterHeaderCreation) + * 7. PFCP Session Modifcation Response + * 8. PFCP Session Modifcation Response + * + * As such, N3 status could be activated. + * + * To prevent this situation, we'll use ogs_msleep(100). + */ + ogs_msleep(100); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + + /* + * Send InitialUEMessage + + * Service request + * - Type: Mobile terminated services(2) + * - PDU Session Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 1 << sess->psi; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x2000, test_ue->pdu_session_status); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + +#define ENABLE_PAGING_FAILED 1 + +#if ENABLE_PAGING_FAILED + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + + ogs_msleep(3000); +#endif + + /* + * Send InitialUEMessage + + * Service request + * - Type: Signalling + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + + /* + * Send InitialUEMessage + + * Service request + * - Type: Data + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void cm_idle_error_indication_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}" + "]," + "\"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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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 */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection + * + * Otherwise, the following case could occur: + * + * 1. PDUSessionResourceSetupResponse + * 2. UEContextReleaseRequest + * 3. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 4. /nsmf-pdusession/v1/sm-contexts/{smContextRef}/modify + * 5. PFCP Session Modifcation Request (Deactivated) + * 6. PFCP Session Modifcation Request (OuterHeaderCreation) + * 7. PFCP Session Modifcation Response + * 8. PFCP Session Modifcation Response + * + * As such, N3 status could be activated. + * + * To prevent this situation, we'll use ogs_msleep(100). + */ + ogs_msleep(100); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Error Indication */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_error_indication(gtpu, qos_flow); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Paging */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_Paging, + test_ue->ngap_procedure_code); + + /* + * Send InitialUEMessage + + * Service request + * - Type: Mobile terminated services(2) + * - PDU Session Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_MOBILE_TERMINATED_SERVICES, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void cm_connected_error_indication_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}" + "]," + "\"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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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 */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection + * That's why error-indication should be initiated in CM-CONNECTED */ + ogs_msleep(100); + + /* Send Error Indication */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_error_indication(gtpu, qos_flow); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceRelease, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceReleaseResponse */ + sendbuf = testngap_build_pdu_session_resource_release_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void vonr_qos_flow_test1_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + 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; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"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 icmp from any to assigned\"," + "\"_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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Waiting for creating dedicated QoS flow in PFCP protocol */ + ogs_msleep(100); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue, 1); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void vonr_session_test2_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + 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; + + 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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, 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(ngap, 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(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send Service request Using InitialUEMessage + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param. + psimask.uplink_data_status = (1 << 5 | 1 << 6); + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send PDU Session release request */ + sess->ul_nas_transport_param.request_type = 0; + sess->ul_nas_transport_param.dnn = 0; + sess->ul_nas_transport_param.s_nssai = 0; + + gsmbuf = testgsm_build_pdu_session_release_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceReleaseCommand + + * DL NAS transport + + * PDU session release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDUSessionResourceReleaseResponse */ + sendbuf = testngap_build_pdu_session_resource_release_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send UplinkNASTransport + + * UL NAS trasnport + + * PDU session resource release complete */ + sess->ul_nas_transport_param.request_type = 0; + sess->ul_nas_transport_param.dnn = 0; + sess->ul_nas_transport_param.s_nssai = 0; + + gsmbuf = testgsm_build_pdu_session_release_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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Test Session Remove */ + test_sess_remove(sess); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void registration_ue_context_test4_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}" + "]," + "\"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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive DownlinkNASTransport + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_DownlinkNASTransport, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 0; + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - PDU Session Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 1 << sess->psi; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive DownlinkNASTransport + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_DownlinkNASTransport, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x2000, test_ue->pdu_session_status); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_ue_build_pdu_session_resource_setup_response(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void registration_idle_test1_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + ogs_nas_5gs_mobile_identity_suci_t mobile_identity_suci; + test_ue_t *test_ue = NULL; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + 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\" : \"597223158b8861d7605378c7\" }, " + "\"ambr\" : {" + "\"uplink\" : { \"$numberLong\" : \"1024000\" }, " + "\"downlink\" : { \"$numberLong\" : \"1024000\" } " + "}," + "\"qos\" : { " + "\"qci\" : 9, " + "\"arp\" : { " + "\"priority_level\" : 8," + "\"pre_emption_vulnerability\" : 1, " + "\"pre_emption_capability\" : 1" + "} " + "}, " + "\"type\" : 2" + "}" + "]," + "\"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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 23); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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 */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - PDU Session Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 1 << sess->psi; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x2000, test_ue->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send InitialUEMessage + + * Service request + * - Uplink Data Status + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive InitialContextSetupRequest + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send InitialContextSetupResponse */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +abts_suite *test_paging(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, cm_idle_paging_func, NULL); + abts_run_test(suite, cm_idle_error_indication_func, NULL); + abts_run_test(suite, cm_connected_error_indication_func, NULL); + abts_run_test(suite, vonr_qos_flow_test1_func, NULL); + abts_run_test(suite, vonr_session_test2_func, NULL); + abts_run_test(suite, registration_ue_context_test4_func, NULL); + abts_run_test(suite, registration_idle_test1_func, NULL); + + return suite; +} diff --git a/tests/registration/ue-context-test.c b/tests/registration/ue-context-test.c index c03b9fc70..9f6176c50 100644 --- a/tests/registration/ue-context-test.c +++ b/tests/registration/ue-context-test.c @@ -954,18 +954,22 @@ static void test3_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive PDU session release command */ + /* Receive PDUSessionResourceReleaseCommand + + * DL NAS transport + + * PDU session release command */ recvbuf = testgnb_ngap_read(ngap); ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send PDU session resource release response */ + /* Send PDUSessionResourceReleaseResponse */ sendbuf = testngap_build_pdu_session_resource_release_response(sess); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send PDU session resource release complete */ + /* Send UplinkNASTransport + + * UL NAS trasnport + + * PDU session resource release complete */ sess->ul_nas_transport_param.request_type = 0; sess->ul_nas_transport_param.dnn = 0; sess->ul_nas_transport_param.s_nssai = 0; @@ -1425,10 +1429,6 @@ static void test4_func(abts_case *tc, void *data) ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send UE context release complete */ sendbuf = testngap_build_ue_context_release_complete(test_ue); ABTS_PTR_NOTNULL(tc, sendbuf); @@ -1476,10 +1476,9 @@ static void test4_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive GTP-U ICMP Packet */ - recvbuf = testgnb_gtpu_read(gtpu); - ABTS_PTR_NOTNULL(tc, recvbuf); - ogs_pkbuf_free(recvbuf); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); /* Send GTP-U ICMP Packet */ rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); diff --git a/tests/vonr/qos-flow-test.c b/tests/vonr/qos-flow-test.c index a4c21d789..fcd3a2c24 100644 --- a/tests/vonr/qos-flow-test.c +++ b/tests/vonr/qos-flow-test.c @@ -447,16 +447,20 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status); ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send Initial context setup response */ sendbuf = testngap_build_initial_context_setup_response(test_ue, true); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Receive GTP-U ICMP Packet */ recvbuf = testgnb_gtpu_read(gtpu); ABTS_PTR_NOTNULL(tc, recvbuf); diff --git a/tests/vonr/session-test.c b/tests/vonr/session-test.c index 0502d2517..3d0950aca 100644 --- a/tests/vonr/session-test.c +++ b/tests/vonr/session-test.c @@ -491,16 +491,20 @@ static void test1_func(abts_case *tc, void *data) ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status); ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); - /* Send GTP-U ICMP Packet */ - rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); - ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Send Initial context setup response */ sendbuf = testngap_build_initial_context_setup_response(test_ue, true); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Receive GTP-U ICMP Packet */ recvbuf = testgnb_gtpu_read(gtpu); ABTS_PTR_NOTNULL(tc, recvbuf); @@ -521,21 +525,22 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Receive PDU session release command */ + /* Receive PDUSessionResourceReleaseCommand + + * DL NAS transport + + * PDU session release command */ recvbuf = testgnb_ngap_read(ngap); ABTS_PTR_NOTNULL(tc, recvbuf); testngap_recv(test_ue, recvbuf); - /* Send PDU session resource release response */ + /* Send PDUSessionResourceReleaseResponse */ sendbuf = testngap_build_pdu_session_resource_release_response(sess); ABTS_PTR_NOTNULL(tc, sendbuf); rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); - /* Test Session Remove */ - test_sess_remove(sess); - - /* Send PDU session resource release complete */ + /* Send UplinkNASTransport + + * UL NAS trasnport + + * PDU session resource release complete */ sess->ul_nas_transport_param.request_type = 0; sess->ul_nas_transport_param.dnn = 0; sess->ul_nas_transport_param.s_nssai = 0; @@ -550,6 +555,1077 @@ static void test1_func(abts_case *tc, void *data) rv = testgnb_ngap_send(ngap, sendbuf); ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Test Session Remove */ + test_sess_remove(sess); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void test2_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + 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; + + 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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, 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(ngap, 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(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send Service request Using InitialUEMessage + * - PSI(5) + * PDU SESSION INACTIVE + * no uplink data are pending + * - PSI(6) + * Not PDU SESSION INACTIVE + * uplink data are pending + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 1; + test_ue->service_request_param.psimask.uplink_data_status = 1 << sess->psi; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 1 << sess->psi; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_DATA, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x4000, test_ue->pdu_session_status); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_reactivation_result); + + /* Test Session Remove */ + sess = test_sess_find_by_psi(test_ue, 5); + ogs_assert(sess); + test_sess_remove(sess); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Wait to setup N3 data connection. + * Otherwise, network-triggered service request is initiated */ + ogs_msleep(100); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + ogs_msleep(300); + + /********** Remove Subscriber in Database */ + 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); + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove(test_ue); +} + +static void test3_func(abts_case *tc, void *data) +{ + int rv; + ogs_socknode_t *ngap; + ogs_socknode_t *gtpu; + ogs_pkbuf_t *gmmbuf; + ogs_pkbuf_t *gsmbuf; + ogs_pkbuf_t *nasbuf; + ogs_pkbuf_t *sendbuf; + ogs_pkbuf_t *recvbuf; + ogs_ngap_message_t message; + int i; + + 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; + + 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); + + /* gNB connects to AMF */ + ngap = testngap_client(AF_INET); + ABTS_PTR_NOTNULL(tc, ngap); + + /* gNB connects to UPF */ + gtpu = test_gtpu_server(1, AF_INET); + ABTS_PTR_NOTNULL(tc, gtpu); + + /* Send NG-Setup Reqeust */ + sendbuf = testngap_build_ng_setup_request(0x4000, 22); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive NG-Setup Response */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /********** Insert Subscriber in Database */ + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Identity request */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Authentication request */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Security mode command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Registration accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + + /* Send UE radio capability info indication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, false); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send Registration complete */ + gmmbuf = testgmm_build_registration_complete(test_ue); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Configuration update command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue, "internet", 5); + ogs_assert(sess); + + sess->ul_nas_transport_param.request_type = + OGS_NAS_5GS_REQUEST_TYPE_INITIAL; + sess->ul_nas_transport_param.dnn = 1; + sess->ul_nas_transport_param.s_nssai = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue, gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDUSessionResourceSetupRequest + + * DL NAS transport + + * PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue->ngap_procedure_code); + + /* Send GTP-U ICMP Packet */ + qos_flow = test_qos_flow_find_by_qfi(sess, 1); + ogs_assert(qos_flow); + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Send PDUSessionResourceSetupResponse */ + sendbuf = testngap_sess_build_pdu_session_resource_setup_response(sess); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send GTP-U ICMP Packet */ + rv = test_gtpu_send_ping(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session establishment accept */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive PDU session modification command */ + recvbuf = testgnb_ngap_read(ngap); + 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(ngap, 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(ngap, 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(gtpu, qos_flow, TEST_PING_IPV4); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive GTP-U ICMP Packet */ + recvbuf = testgnb_gtpu_read(gtpu); + ABTS_PTR_NOTNULL(tc, recvbuf); + ogs_pkbuf_free(recvbuf); + + /* Send UE context release request */ + sendbuf = testngap_build_ue_context_release_request(test_ue, + NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, + true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UE context release command */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + + /* Send UE context release complete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* + * Send Service request Using InitialUEMessage + * - PSI(5) + * Not PDU SESSION INACTIVE + * - PSI(6) + * Not PDU SESSION INACTIVE + */ + test_ue->service_request_param.integrity_protected = 0; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 1; + test_ue->service_request_param.psimask.pdu_session_status = 0; + nasbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, NULL); + ABTS_PTR_NOTNULL(tc, nasbuf); + + test_ue->service_request_param.integrity_protected = 1; + test_ue->service_request_param.uplink_data_status = 0; + test_ue->service_request_param.pdu_session_status = 0; + gmmbuf = testgmm_build_service_request( + test_ue, OGS_NAS_SERVICE_TYPE_SIGNALLING, nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue, gmmbuf, true, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive Initial context setup request + + * Service accept */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue, recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue->ngap_procedure_code); + ABTS_INT_EQUAL(tc, 0x0000, test_ue->pdu_session_status); + + /* Test Session Remove */ + sess = test_sess_find_by_psi(test_ue, 5); + ogs_assert(sess); + test_sess_remove(sess); + sess = test_sess_find_by_psi(test_ue, 6); + ogs_assert(sess); + test_sess_remove(sess); + + /* Send Initial context setup response */ + sendbuf = testngap_build_initial_context_setup_response(test_ue, true); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + /* Send UE context release request */ sendbuf = testngap_build_ue_context_release_request(test_ue, NGAP_Cause_PR_radioNetwork, NGAP_CauseRadioNetwork_user_inactivity, @@ -595,6 +1671,8 @@ abts_suite *test_session(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; }