diff --git a/docs/_pages/support.md b/docs/_pages/support.md index 5988bb8ee..cd496fbb4 100644 --- a/docs/_pages/support.md +++ b/docs/_pages/support.md @@ -10,7 +10,7 @@ permalink: /support/ Open5GS is licensed under a dual licensing model designed to meet the development and distribution needs of both commercial and open source projects. -The commercial Open5GS license gives you the full rights to create and distribute software on your own terms without any open source license obligations. With the commercial license you also have access to the official NeoPlane Support and close strategic relationship with [NeoPlane](https://neoplane.io) to make sure your development goals are met. +The commercial Open5GS license gives you the full rights to create and distribute software on your own terms without any open source license obligations. With the commercial license, you also have access to the official NeoPlane Support and close strategic relationship with [NeoPlane](https://neoplane.io) to make sure your development goals are met. Open5GS is also available under AGPL-3.0 open source licenses. The Open5GS open source licensing is ideal for use cases such as open source projects with open source distribution, student/academic purposes, hobby projects, internal research projects without external distribution, or other projects where all AGPL-3.0 obligations can be met. @@ -24,6 +24,6 @@ We work with leading partners in mobile communications to offer our customers co Please contact [sales@nextepc.com](mailto:sales@nextepc.com) for more informations. -**[sysmocom](https://sysmocom.de/)**: Sysmocom was founded in Berlin, Germany by two veterans of the Free / Open Source Software (FOSS) community. They is providing commercial services around Open5GS open source software including support, development, consulting, training and system integration. +**[sysmocom](https://sysmocom.de/)**: Sysmocom was founded in Berlin, Germany by two veterans of the Free / Open Source Software (FOSS) community. They are providing commercial services around Open5GS open source software including support, development, consulting, training and system integration. Please contact [Harald Welte \](mailto:sales@sysmocom.de) for any related inquiries. diff --git a/src/bsf/bsf-sm.c b/src/bsf/bsf-sm.c index 4681c7c7f..553c4f700 100644 --- a/src/bsf/bsf-sm.c +++ b/src/bsf/bsf-sm.c @@ -130,25 +130,26 @@ void bsf_state_operational(ogs_fsm_t *s, bsf_event_t *e) SWITCH(message.h.method) CASE(OGS_SBI_HTTP_METHOD_POST) if (message.PcfBinding && - message.PcfBinding->snssai && - message.PcfBinding->dnn) { - ogs_s_nssai_t s_nssai; + (message.PcfBinding->ipv4_addr || + message.PcfBinding->ipv6_prefix)) { - s_nssai.sst = message.PcfBinding->snssai->sst; - s_nssai.sd = ogs_s_nssai_sd_from_string( - message.PcfBinding->snssai->sd); + if (message.PcfBinding->ipv4_addr) + sess = bsf_sess_find_by_ipv4addr( + message.PcfBinding->ipv4_addr); + if (!sess && message.PcfBinding->ipv6_prefix) + sess = bsf_sess_find_by_ipv6prefix( + message.PcfBinding->ipv6_prefix); - sess = bsf_sess_find_by_snssai_and_dnn( - &s_nssai, message.PcfBinding->dnn); if (!sess) { - sess = bsf_sess_add_by_snssai_and_dnn( - &s_nssai, message.PcfBinding->dnn); + sess = bsf_sess_add_by_ip_address( + message.PcfBinding->ipv4_addr, + message.PcfBinding->ipv6_prefix); ogs_assert(sess); } } break; CASE(OGS_SBI_HTTP_METHOD_GET) - if (!sess && message.param.ipv4addr) + if (message.param.ipv4addr) sess = bsf_sess_find_by_ipv4addr( message.param.ipv4addr); if (!sess && message.param.ipv6prefix) diff --git a/src/bsf/context.c b/src/bsf/context.c index 6cd16a5fc..3fd57a9f4 100644 --- a/src/bsf/context.c +++ b/src/bsf/context.c @@ -27,9 +27,6 @@ static OGS_POOL(bsf_sess_pool, bsf_sess_t); static int context_initialized = 0; -static void clear_ipv4addr(bsf_sess_t *sess); -static void clear_ipv6prefix(bsf_sess_t *sess); - void bsf_context_init(void) { ogs_assert(context_initialized == 0); @@ -120,13 +117,12 @@ int bsf_context_parse_config(void) return OGS_OK; } -bsf_sess_t *bsf_sess_add_by_snssai_and_dnn(ogs_s_nssai_t *s_nssai, char *dnn) +bsf_sess_t *bsf_sess_add_by_ip_address( + char *ipv4addr_string, char *ipv6prefix_string) { bsf_sess_t *sess = NULL; - ogs_assert(s_nssai); - ogs_assert(s_nssai->sst); - ogs_assert(dnn); + ogs_assert(ipv4addr_string || ipv6prefix_string); ogs_pool_alloc(&bsf_sess_pool, &sess); if (!sess) { @@ -136,16 +132,23 @@ bsf_sess_t *bsf_sess_add_by_snssai_and_dnn(ogs_s_nssai_t *s_nssai, char *dnn) } memset(sess, 0, sizeof *sess); + if (ipv4addr_string && + bsf_sess_set_ipv4addr(sess, ipv4addr_string) == false) { + ogs_error("bsf_sess_set_ipv4addr[%s] failed", ipv4addr_string); + ogs_pool_free(&bsf_sess_pool, sess); + return NULL; + } + if (ipv6prefix_string && + bsf_sess_set_ipv6prefix(sess, ipv6prefix_string) == false) { + ogs_error("bsf_sess_set_ipv6prefix[%s] failed", ipv4addr_string); + ogs_pool_free(&bsf_sess_pool, sess); + return NULL; + } + /* SBI Features */ OGS_SBI_FEATURES_SET(sess->management_features, OGS_SBI_NBSF_MANAGEMENT_BINDING_UPDATE); - sess->s_nssai.sst = s_nssai->sst; - sess->s_nssai.sd.v = s_nssai->sd.v; - - sess->dnn = ogs_strdup(dnn); - ogs_assert(sess->dnn); - sess->binding_id = ogs_msprintf("%d", (int)ogs_pool_index(&bsf_sess_pool, sess)); ogs_assert(sess->binding_id); @@ -174,8 +177,16 @@ void bsf_sess_remove(bsf_sess_t *sess) if (sess->gpsi) ogs_free(sess->gpsi); - clear_ipv4addr(sess); - clear_ipv6prefix(sess); + if (sess->ipv4addr_string) { + ogs_hash_set(self.ipv4addr_hash, + &sess->ipv4addr, sizeof(sess->ipv4addr), NULL); + ogs_free(sess->ipv4addr_string); + } + if (sess->ipv6prefix_string) { + ogs_hash_set(self.ipv6prefix_hash, + &sess->ipv6prefix, (sess->ipv6prefix.len >> 3) + 1, NULL); + ogs_free(sess->ipv6prefix_string); + } ogs_assert(sess->dnn); ogs_free(sess->dnn); @@ -202,28 +213,6 @@ void bsf_sess_remove_all(void) bsf_sess_remove(sess); } -static void clear_ipv4addr(bsf_sess_t *sess) -{ - ogs_assert(sess); - - if (sess->ipv4addr_string) { - ogs_hash_set(self.ipv4addr_hash, - &sess->ipv4addr, sizeof(sess->ipv4addr), NULL); - ogs_free(sess->ipv4addr_string); - } -} - -static void clear_ipv6prefix(bsf_sess_t *sess) -{ - ogs_assert(sess); - - if (sess->ipv6prefix_string) { - ogs_hash_set(self.ipv6prefix_hash, - &sess->ipv6prefix, (sess->ipv6prefix.len >> 3) + 1, NULL); - ogs_free(sess->ipv6prefix_string); - } -} - bool bsf_sess_set_ipv4addr(bsf_sess_t *sess, char *ipv4addr_string) { int rv; @@ -231,8 +220,11 @@ bool bsf_sess_set_ipv4addr(bsf_sess_t *sess, char *ipv4addr_string) ogs_assert(sess); ogs_assert(ipv4addr_string); - clear_ipv4addr(sess); - + if (sess->ipv4addr_string) { + ogs_hash_set(self.ipv4addr_hash, + &sess->ipv4addr, sizeof(sess->ipv4addr), NULL); + ogs_free(sess->ipv4addr_string); + } rv = ogs_ipv4_from_string(&sess->ipv4addr, ipv4addr_string); ogs_expect_or_return_val(rv == OGS_OK, false); @@ -252,8 +244,11 @@ bool bsf_sess_set_ipv6prefix(bsf_sess_t *sess, char *ipv6prefix_string) ogs_assert(sess); ogs_assert(ipv6prefix_string); - clear_ipv6prefix(sess); - + if (sess->ipv6prefix_string) { + ogs_hash_set(self.ipv6prefix_hash, + &sess->ipv6prefix, (sess->ipv6prefix.len >> 3) + 1, NULL); + ogs_free(sess->ipv6prefix_string); + } rv = ogs_ipv6prefix_from_string( sess->ipv6prefix.addr6, &sess->ipv6prefix.len, ipv6prefix_string); ogs_expect_or_return_val(rv == OGS_OK, false); diff --git a/src/bsf/context.h b/src/bsf/context.h index f62da657c..963b5ddbb 100644 --- a/src/bsf/context.h +++ b/src/bsf/context.h @@ -41,8 +41,6 @@ typedef struct bsf_context_s { ogs_list_t sess_list; } bsf_context_t; -typedef struct bsf_sess_s bsf_sess_t; - typedef struct bsf_sess_s { ogs_sbi_object_t sbi; @@ -84,7 +82,8 @@ bsf_context_t *bsf_self(void); int bsf_context_parse_config(void); -bsf_sess_t *bsf_sess_add_by_snssai_and_dnn(ogs_s_nssai_t *s_nssai, char *dnn); +bsf_sess_t *bsf_sess_add_by_ip_address( + char *ipv4addr_string, char *ipv6prefix_string); void bsf_sess_remove(bsf_sess_t *sess); void bsf_sess_remove_all(void); diff --git a/src/bsf/nbsf-handler.c b/src/bsf/nbsf-handler.c index ff3aa4516..3cdb38754 100644 --- a/src/bsf/nbsf-handler.c +++ b/src/bsf/nbsf-handler.c @@ -75,11 +75,14 @@ bool bsf_nbsf_management_handle_pcf_binding( RecvPcfBinding = recvmsg->PcfBinding; ogs_assert(RecvPcfBinding); - if (!RecvPcfBinding->ipv4_addr && !RecvPcfBinding->ipv6_prefix) { - strerror = ogs_msprintf( - "No IPv4 address or IPv6 prefix[%p:%p]", - RecvPcfBinding->ipv4_addr, - RecvPcfBinding->ipv6_prefix); + if (!RecvPcfBinding->snssai) { + strerror = ogs_msprintf("No S-NSSAI"); + status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; + goto cleanup; + } + + if (!RecvPcfBinding->dnn) { + strerror = ogs_msprintf("No DNN"); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } @@ -93,11 +96,6 @@ bool bsf_nbsf_management_handle_pcf_binding( goto cleanup; } - if (RecvPcfBinding->ipv4_addr) - bsf_sess_set_ipv4addr(sess, RecvPcfBinding->ipv4_addr); - if (RecvPcfBinding->ipv6_prefix) - bsf_sess_set_ipv6prefix(sess, RecvPcfBinding->ipv6_prefix); - if (RecvPcfBinding->pcf_fqdn) { if (sess->pcf_fqdn) ogs_free(sess->pcf_fqdn); @@ -105,6 +103,13 @@ bool bsf_nbsf_management_handle_pcf_binding( ogs_assert(sess->pcf_fqdn); } + sess->s_nssai.sst = RecvPcfBinding->snssai->sst; + sess->s_nssai.sd = + ogs_s_nssai_sd_from_string(RecvPcfBinding->snssai->sd); + + sess->dnn = ogs_strdup(RecvPcfBinding->dnn); + ogs_assert(sess->dnn); + PcfIpEndPointList = RecvPcfBinding->pcf_ip_end_points; if (PcfIpEndPointList) { diff --git a/src/pcf/sm-sm.c b/src/pcf/sm-sm.c index 10618eaf8..5067a79c3 100644 --- a/src/pcf/sm-sm.c +++ b/src/pcf/sm-sm.c @@ -214,14 +214,23 @@ void pcf_sm_state_operational(ogs_fsm_t *s, pcf_event_t *e) CASE(OGS_SBI_HTTP_METHOD_DELETE) if (message->res_status != OGS_SBI_HTTP_STATUS_NO_CONTENT) { - ogs_error("[%s:%d] HTTP response error [%d]", + ogs_warn("[%s:%d] HTTP response error [%d]", pcf_ue->supi, sess->psi, message->res_status); + +/* + * The PCfBindings resource for that UE may not exist in the BSF + * for reasons such as restarting the BSF. + * + * So, session Release continues even if there is no resource in BSF. + */ +#if 0 ogs_assert(true == ogs_sbi_server_send_error(stream, message->res_status, NULL, "HTTP response error", pcf_ue->supi)); OGS_FSM_TRAN(s, pcf_sm_state_exception); break; +#endif } pcf_nbsf_management_handle_de_register( diff --git a/tests/attach/reset-test.c b/tests/attach/reset-test.c index b014cc4b2..ee6886f26 100644 --- a/tests/attach/reset-test.c +++ b/tests/attach/reset-test.c @@ -336,9 +336,6 @@ static void test2_func(abts_case *tc, void *data) test_ue[i] = test_ue_add_by_suci(&mobile_identity_suci, 13); ogs_assert(test_ue[i]); - /* Multiple eNB-UE-S1AP-UD */ - test_ue[i]->enb_ue_s1ap_id = i; - test_ue[i]->e_cgi.cell_id = 0x54f6401; test_ue[i]->nas.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; test_ue[i]->nas.value = OGS_NAS_ATTACH_TYPE_COMBINED_EPS_IMSI_ATTACH; @@ -357,6 +354,11 @@ static void test2_func(abts_case *tc, void *data) } for (i = 0; i < NUM_OF_TEST_UE; i++) { + if (i > 0) + test_ue[i]->enb_ue_s1ap_id = test_ue[i-1]->enb_ue_s1ap_id; + else + test_ue[i]->enb_ue_s1ap_id = 0; + sess = test_sess_find_by_apn( test_ue[i], "internet", OGS_GTP2_RAT_TYPE_EUTRAN); ogs_assert(sess); @@ -584,6 +586,11 @@ static void test3_func(abts_case *tc, void *data) } for (i = 0; i < NUM_OF_TEST_UE; i++) { + if (i > 0) + test_ue[i]->enb_ue_s1ap_id = test_ue[i-1]->enb_ue_s1ap_id; + else + test_ue[i]->enb_ue_s1ap_id = 0; + sess = test_sess_find_by_apn( test_ue[i], "internet", OGS_GTP2_RAT_TYPE_EUTRAN); ogs_assert(sess); diff --git a/tests/registration/abts-main.c b/tests/registration/abts-main.c index d67e9b979..5f9e77418 100644 --- a/tests/registration/abts-main.c +++ b/tests/registration/abts-main.c @@ -29,6 +29,7 @@ abts_suite *test_identity(abts_suite *suite); abts_suite *test_gmm_status(abts_suite *suite); abts_suite *test_ue_context(abts_suite *suite); abts_suite *test_reset(abts_suite *suite); +abts_suite *test_multi_ue(abts_suite *suite); abts_suite *test_crash(abts_suite *suite); const struct testlist { @@ -44,6 +45,7 @@ const struct testlist { {test_gmm_status}, {test_ue_context}, {test_reset}, + {test_multi_ue}, #if 0 /* Since there is error LOG, we disabled the following test */ {test_crash}, #endif diff --git a/tests/registration/meson.build b/tests/registration/meson.build index 0e0d14411..bee8611f7 100644 --- a/tests/registration/meson.build +++ b/tests/registration/meson.build @@ -27,6 +27,7 @@ test5gc_registration_sources = files(''' gmm-status-test.c ue-context-test.c reset-test.c + multi-ue-test.c crash-test.c '''.split()) diff --git a/tests/registration/multi-ue-test.c b/tests/registration/multi-ue-test.c new file mode 100644 index 000000000..4b3672345 --- /dev/null +++ b/tests/registration/multi-ue-test.c @@ -0,0 +1,349 @@ +/* + * 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" + +#define NUM_OF_TEST_UE 3 + +static void 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[NUM_OF_TEST_UE]; + test_sess_t *sess = NULL; + test_bearer_t *qos_flow = NULL; + + bson_t *doc = NULL; + + /* 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); + + for (i = 0; i < NUM_OF_TEST_UE; i++) { + uint64_t imsi_index; + + /* 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; + + imsi_index = i + 1; + ogs_uint64_to_buffer(imsi_index, 5, mobile_identity_suci.scheme_output); + + test_ue[i] = test_ue_add_by_suci(&mobile_identity_suci, 13); + ogs_assert(test_ue[i]); + + test_ue[i]->nr_cgi.cell_id = 0x40001; + + test_ue[i]->nas.registration.tsc = 0; + test_ue[i]->nas.registration.ksi = OGS_NAS_KSI_NO_KEY_IS_AVAILABLE; + test_ue[i]->nas.registration.follow_on_request = 1; + test_ue[i]->nas.registration.value = OGS_NAS_5GS_REGISTRATION_TYPE_INITIAL; + + test_ue[i]->k_string = "465b5ce8b199b49faa5f0a2ee238a6bc"; + test_ue[i]->opc_string = "e8ed289deba952e4283b54e88e6183ca"; + } + + for (i = 0; i < NUM_OF_TEST_UE; i++) { + if (i > 0) + test_ue[i]->ran_ue_ngap_id = test_ue[i-1]->ran_ue_ngap_id; + else + test_ue[i]->ran_ue_ngap_id = 0; + + /* Send PDU session establishment request */ + sess = test_sess_add_by_dnn_and_psi(test_ue[i], "internet", 5); + ogs_assert(sess); + + /********** Insert Subscriber in Database */ + doc = test_db_new_simple(test_ue[i]); + ABTS_PTR_NOTNULL(tc, doc); + ABTS_INT_EQUAL(tc, OGS_OK, test_db_insert_ue(test_ue[i], doc)); + + /* Send Registration request */ + test_ue[i]->registration_request_param.guti = 1; + gmmbuf = testgmm_build_registration_request(test_ue[i], NULL, false, false); + ABTS_PTR_NOTNULL(tc, gmmbuf); + + test_ue[i]->registration_request_param.gmm_capability = 1; + test_ue[i]->registration_request_param.s1_ue_network_capability = 1; + test_ue[i]->registration_request_param.requested_nssai = 1; + test_ue[i]->registration_request_param.last_visited_registered_tai = 1; + test_ue[i]->registration_request_param.ue_usage_setting = 1; + nasbuf = testgmm_build_registration_request(test_ue[i], NULL, false, false); + ABTS_PTR_NOTNULL(tc, nasbuf); + + sendbuf = testngap_build_initial_ue_message(test_ue[i], gmmbuf, + NGAP_RRCEstablishmentCause_mo_Signalling, 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[i], recvbuf); + + /* Send Identity response */ + gmmbuf = testgmm_build_identity_response(test_ue[i]); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], 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[i], recvbuf); + + /* Send Authentication response */ + gmmbuf = testgmm_build_authentication_response(test_ue[i]); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], 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[i], recvbuf); + + /* Send Security mode complete */ + gmmbuf = testgmm_build_security_mode_complete(test_ue[i], nasbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], 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[i], recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_InitialContextSetup, + test_ue[i]->ngap_procedure_code); + + /* Send UERadioCapabilityInfoIndication */ + sendbuf = testngap_build_ue_radio_capability_info_indication(test_ue[i]); + 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[i], 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[i]); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], 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[i], recvbuf); + + 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 = 0; + + sess->pdu_session_establishment_param.ssc_mode = 1; + sess->pdu_session_establishment_param.epco = 1; + + gsmbuf = testgsm_build_pdu_session_establishment_request(sess); + ABTS_PTR_NOTNULL(tc, gsmbuf); + gmmbuf = testgmm_build_ul_nas_transport(sess, + OGS_NAS_PAYLOAD_CONTAINER_N1_SM_INFORMATION, gsmbuf); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], 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[i], recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceSetup, + test_ue[i]->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); + } + + for (i = 0; i < NUM_OF_TEST_UE; i++) { + /* Send PDU session establishment request */ + sess = test_sess_find_by_psi(test_ue[i], 5); + ogs_assert(sess); + + /* 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; + + sess->pdu_session_establishment_param.ssc_mode = 0; + sess->pdu_session_establishment_param.epco = 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[i], 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[i], recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_PDUSessionResourceRelease, + test_ue[i]->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); + + /* 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; + + sess->pdu_session_establishment_param.ssc_mode = 0; + sess->pdu_session_establishment_param.epco = 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[i], gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + } + + for (i = 0; i < NUM_OF_TEST_UE; i++) { + /* Send De-registration request */ + gmmbuf = testgmm_build_de_registration_request(test_ue[i], 1, true, true); + ABTS_PTR_NOTNULL(tc, gmmbuf); + sendbuf = testngap_build_uplink_nas_transport(test_ue[i], gmmbuf); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + + /* Receive UEContextReleaseCommand */ + recvbuf = testgnb_ngap_read(ngap); + ABTS_PTR_NOTNULL(tc, recvbuf); + testngap_recv(test_ue[i], recvbuf); + ABTS_INT_EQUAL(tc, + NGAP_ProcedureCode_id_UEContextRelease, + test_ue[i]->ngap_procedure_code); + + /* Send UEContextReleaseComplete */ + sendbuf = testngap_build_ue_context_release_complete(test_ue[i]); + ABTS_PTR_NOTNULL(tc, sendbuf); + rv = testgnb_ngap_send(ngap, sendbuf); + ABTS_INT_EQUAL(tc, OGS_OK, rv); + } + + ogs_msleep(300); + + for (i = 0; i < NUM_OF_TEST_UE; i++) { + /********** Remove Subscriber in Database */ + ABTS_INT_EQUAL(tc, OGS_OK, test_db_remove_ue(test_ue[i])); + } + + /* gNB disonncect from UPF */ + testgnb_gtpu_close(gtpu); + + /* gNB disonncect from AMF */ + testgnb_ngap_close(ngap); + + /* Clear Test UE Context */ + test_ue_remove_all(); +} + +abts_suite *test_multi_ue(abts_suite *suite) +{ + suite = ADD_SUITE(suite) + + abts_run_test(suite, test1_func, NULL); + + return suite; +}