/* * Copyright (C) 2019-2023 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 "ogs-sbi.h" int __ogs_sbi_domain; static ogs_sbi_context_t self; static int context_initialized = 0; static OGS_POOL(nf_instance_pool, ogs_sbi_nf_instance_t); static OGS_POOL(nf_service_pool, ogs_sbi_nf_service_t); static OGS_POOL(xact_pool, ogs_sbi_xact_t); static OGS_POOL(subscription_spec_pool, ogs_sbi_subscription_spec_t); static OGS_POOL(subscription_data_pool, ogs_sbi_subscription_data_t); static OGS_POOL(smf_info_pool, ogs_sbi_smf_info_t); static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t); void ogs_sbi_context_init(OpenAPI_nf_type_e nf_type) { char nf_instance_id[OGS_UUID_FORMATTED_LENGTH + 1]; ogs_assert(nf_type); ogs_assert(context_initialized == 0); /* Initialize SBI context */ memset(&self, 0, sizeof(ogs_sbi_context_t)); ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level); ogs_sbi_message_init(ogs_app()->pool.message, ogs_app()->pool.message); ogs_sbi_server_init(ogs_app()->pool.event, ogs_app()->pool.event); ogs_sbi_client_init(ogs_app()->pool.event, ogs_app()->pool.event); ogs_list_init(&self.nf_instance_list); ogs_pool_init(&nf_instance_pool, ogs_app()->pool.nf); ogs_pool_init(&nf_service_pool, ogs_app()->pool.nf_service); ogs_pool_init(&xact_pool, ogs_app()->pool.xact); ogs_list_init(&self.subscription_spec_list); ogs_pool_init(&subscription_spec_pool, ogs_app()->pool.subscription); ogs_list_init(&self.subscription_data_list); ogs_pool_init(&subscription_data_pool, ogs_app()->pool.subscription); ogs_pool_init(&smf_info_pool, ogs_app()->pool.nf); ogs_pool_init(&nf_info_pool, ogs_app()->pool.nf * OGS_MAX_NUM_OF_NF_INFO); /* Add SELF NF-Instance */ self.nf_instance = ogs_sbi_nf_instance_add(); ogs_assert(self.nf_instance); ogs_uuid_get(&self.uuid); ogs_uuid_format(nf_instance_id, &self.uuid); ogs_sbi_nf_instance_set_id(self.nf_instance, nf_instance_id); ogs_sbi_nf_instance_set_type(self.nf_instance, nf_type); /* Add NRF NF-Instance */ if (nf_type != OpenAPI_nf_type_NRF) { self.nrf_instance = ogs_sbi_nf_instance_add(); ogs_assert(self.nrf_instance); ogs_sbi_nf_instance_set_type(self.nrf_instance, OpenAPI_nf_type_NRF); } /* Add SCP NF-Instance */ if (nf_type != OpenAPI_nf_type_NRF) { self.scp_instance = ogs_sbi_nf_instance_add(); ogs_assert(self.scp_instance); ogs_sbi_nf_instance_set_type(self.scp_instance, OpenAPI_nf_type_SCP); } context_initialized = 1; } void ogs_sbi_context_final(void) { ogs_assert(context_initialized == 1); ogs_sbi_subscription_data_remove_all(); ogs_pool_final(&subscription_data_pool); ogs_sbi_subscription_spec_remove_all(); ogs_pool_final(&subscription_spec_pool); ogs_pool_final(&xact_pool); ogs_sbi_nf_instance_remove_all(); ogs_pool_final(&nf_instance_pool); ogs_pool_final(&nf_service_pool); ogs_pool_final(&smf_info_pool); ogs_pool_final(&nf_info_pool); ogs_sbi_client_final(); ogs_sbi_server_final(); ogs_sbi_message_final(); context_initialized = 0; } ogs_sbi_context_t *ogs_sbi_self(void) { return &self; } static int ogs_sbi_context_prepare(void) { #if ENABLE_ACCEPT_ENCODING self.content_encoding = "gzip"; #endif self.tls.server.scheme = OpenAPI_uri_scheme_http; self.tls.client.scheme = OpenAPI_uri_scheme_http; return OGS_OK; } static int ogs_sbi_context_validation( const char *local, const char *nrf, const char *scp) { /* If SMF is only used in 4G EPC, no SBI interface is required. */ if (local && strcmp(local, "smf") != 0 && ogs_sbi_server_first() == NULL) { ogs_error("No %s.sbi.address: in '%s'", local, ogs_app()->file); return OGS_ERROR; } ogs_assert(context_initialized == 1); switch (self.discovery_config.delegated) { case OGS_SBI_DISCOVERY_DELEGATED_AUTO: if (local && strcmp(local, "nrf") == 0) { /* Skip NRF */ } else if (local && strcmp(local, "scp") == 0) { /* Skip SCP */ } else if (local && strcmp(local, "smf") == 0) { /* Skip SMF since SMF can run 4G */ } else { if (NF_INSTANCE_CLIENT(self.nrf_instance) || NF_INSTANCE_CLIENT(self.scp_instance)) { } else { ogs_error("DELEGATED_AUTO - Both NRF and %s are unavailable", scp && strcmp(scp, "next_scp") == 0 ? "Next-hop SCP" : "SCP"); return OGS_ERROR; } } break; case OGS_SBI_DISCOVERY_DELEGATED_YES: if (NF_INSTANCE_CLIENT(self.scp_instance) == NULL) { ogs_error("DELEGATED_YES - no %s available", scp && strcmp(scp, "next_scp") == 0 ? "Next-hop SCP" : "SCP"); return OGS_ERROR; } break; case OGS_SBI_DISCOVERY_DELEGATED_NO: if (NF_INSTANCE_CLIENT(self.nrf_instance) == NULL) { ogs_error("DELEGATED_NO - no NRF available"); return OGS_ERROR; } break; default: ogs_fatal("Invalid dicovery-config delegated [%d]", self.discovery_config.delegated); ogs_assert_if_reached(); } if (ogs_sbi_self()->tls.server.scheme == OpenAPI_uri_scheme_https) { if (!ogs_sbi_self()->tls.server.private_key) { ogs_error("HTTPS scheme enabled but no server key"); return OGS_ERROR; } if (!ogs_sbi_self()->tls.server.cert) { ogs_error("HTTPS scheme enabled but no server certificate"); return OGS_ERROR; } } if (ogs_sbi_self()->tls.server.verify_client) { if (!ogs_sbi_self()->tls.server.verify_client_cacert) { ogs_error("CLIENT verification enabled but no CA certificate"); return OGS_ERROR; } } return OGS_OK; } int ogs_sbi_context_parse_config( const char *local, const char *nrf, const char *scp) { int rv; yaml_document_t *document = NULL; ogs_yaml_iter_t root_iter; document = ogs_app()->document; ogs_assert(document); rv = ogs_sbi_context_prepare(); if (rv != OGS_OK) return rv; ogs_yaml_iter_init(&root_iter, document); while (ogs_yaml_iter_next(&root_iter)) { const char *root_key = ogs_yaml_iter_key(&root_iter); ogs_assert(root_key); if (local && !strcmp(root_key, local)) { ogs_yaml_iter_t local_iter; ogs_yaml_iter_recurse(&root_iter, &local_iter); while (ogs_yaml_iter_next(&local_iter)) { const char *local_key = ogs_yaml_iter_key(&local_iter); ogs_assert(local_key); if (!strcmp(local_key, "default")) { ogs_yaml_iter_t default_iter; ogs_yaml_iter_recurse(&local_iter, &default_iter); while (ogs_yaml_iter_next(&default_iter)) { const char *default_key = ogs_yaml_iter_key(&default_iter); ogs_assert(default_key); if (!strcmp(default_key, "tls")) { ogs_yaml_iter_t tls_iter; ogs_yaml_iter_recurse(&default_iter, &tls_iter); while (ogs_yaml_iter_next(&tls_iter)) { const char *tls_key = ogs_yaml_iter_key(&tls_iter); ogs_assert(tls_key); if (!strcmp(tls_key, "server")) { ogs_yaml_iter_t server_iter; ogs_yaml_iter_recurse( &tls_iter, &server_iter); while (ogs_yaml_iter_next(&server_iter)) { const char *server_key = ogs_yaml_iter_key(&server_iter); ogs_assert(server_key); if (!strcmp(server_key, "scheme")) { const char *v = ogs_yaml_iter_value( &server_iter); if (v) { if (!ogs_strcasecmp( v, "https")) self.tls.server.scheme = OpenAPI_uri_scheme_https; else if (!ogs_strcasecmp( v, "http")) self.tls.server.scheme = OpenAPI_uri_scheme_http; else ogs_warn( "unknown scheme `%s`", v); } } else if (!strcmp(server_key, "private_key")) { self.tls.server.private_key = ogs_yaml_iter_value( &server_iter); } else if (!strcmp(server_key, "cert")) { self.tls.server.cert = ogs_yaml_iter_value( &server_iter); } else if (!strcmp(server_key, "verify_client")) { self.tls.server.verify_client = ogs_yaml_iter_bool( &server_iter); } else if (!strcmp(server_key, "verify_client_cacert")) { self.tls.server. verify_client_cacert = ogs_yaml_iter_value( &server_iter); } } } else if (!strcmp(tls_key, "client")) { ogs_yaml_iter_t client_iter; ogs_yaml_iter_recurse( &tls_iter, &client_iter); while (ogs_yaml_iter_next(&client_iter)) { const char *client_key = ogs_yaml_iter_key(&client_iter); ogs_assert(client_key); if (!strcmp(client_key, "scheme")) { const char *v = ogs_yaml_iter_value( &client_iter); if (v) { if (!ogs_strcasecmp( v, "https")) self.tls.client.scheme = OpenAPI_uri_scheme_https; else if (!ogs_strcasecmp( v, "http")) self.tls.client.scheme = OpenAPI_uri_scheme_http; else ogs_warn( "unknown scheme `%s`", v); } } else if (!strcmp(client_key, "insecure_skip_verify")) { self.tls.client. insecure_skip_verify = ogs_yaml_iter_bool( &client_iter); } else if (!strcmp(client_key, "cacert")) { self.tls.client.cacert = ogs_yaml_iter_value( &client_iter); } else if (!strcmp(client_key, "client_private_key")) { self.tls.client.private_key = ogs_yaml_iter_value( &client_iter); } else if (!strcmp(client_key, "client_cert")) { self.tls.client.cert = ogs_yaml_iter_value( &client_iter); } } } } } } } } } } ogs_yaml_iter_init(&root_iter, document); while (ogs_yaml_iter_next(&root_iter)) { const char *root_key = ogs_yaml_iter_key(&root_iter); ogs_assert(root_key); if (local && !strcmp(root_key, local)) { ogs_yaml_iter_t local_iter; ogs_yaml_iter_recurse(&root_iter, &local_iter); while (ogs_yaml_iter_next(&local_iter)) { const char *local_key = ogs_yaml_iter_key(&local_iter); ogs_assert(local_key); if (!strcmp(local_key, "sbi")) { ogs_yaml_iter_t sbi_iter; ogs_yaml_iter_recurse(&local_iter, &sbi_iter); while (ogs_yaml_iter_next(&sbi_iter)) { const char *sbi_key = ogs_yaml_iter_key(&sbi_iter); ogs_assert(sbi_key); if (!strcmp(sbi_key, "server")) { rv = ogs_sbi_context_parse_server_config( &sbi_iter, NULL); if (rv != OGS_OK) { ogs_error("ogs_sbi_context_parse_server_" "config() failed"); return rv; } } else if (!strcmp(sbi_key, "client")) { ogs_yaml_iter_t client_iter; ogs_yaml_iter_recurse(&sbi_iter, &client_iter); while (ogs_yaml_iter_next(&client_iter)) { const char *client_key = ogs_yaml_iter_key(&client_iter); ogs_assert(client_key); if (ogs_global_conf()-> parameter.no_nrf == false && nrf && !strcmp(client_key, nrf)) { ogs_yaml_iter_t nrf_array, nrf_iter; ogs_yaml_iter_recurse(&client_iter, &nrf_array); do { ogs_sbi_client_t *client = NULL; if (ogs_yaml_iter_type(&nrf_array) == YAML_MAPPING_NODE) { memcpy(&nrf_iter, &nrf_array, sizeof(ogs_yaml_iter_t)); } else if (ogs_yaml_iter_type( &nrf_array) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&nrf_array)) break; ogs_yaml_iter_recurse( &nrf_array, &nrf_iter); } else if (ogs_yaml_iter_type( &nrf_array) == YAML_SCALAR_NODE) { break; } else ogs_assert_if_reached(); if (NF_INSTANCE_CLIENT( self.nrf_instance)) { ogs_error("Only one NRF client " "can be set"); return OGS_ERROR; } client = ogs_sbi_context_parse_client_config( &nrf_iter); if (!client) { ogs_error("ogs_sbi_context_parse_" "client_config() failed"); return OGS_ERROR; } OGS_SBI_SETUP_CLIENT( self.nrf_instance, client); } while (ogs_yaml_iter_type(&nrf_array) == YAML_SEQUENCE_NODE); } else if (ogs_global_conf()-> parameter.no_scp == false && scp && !strcmp(client_key, scp)) { ogs_yaml_iter_t scp_array, scp_iter; ogs_yaml_iter_recurse( &client_iter, &scp_array); do { ogs_sbi_client_t *client = NULL; if (ogs_yaml_iter_type(&scp_array) == YAML_MAPPING_NODE) { memcpy(&scp_iter, &scp_array, sizeof(ogs_yaml_iter_t)); } else if (ogs_yaml_iter_type( &scp_array) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&scp_array)) break; ogs_yaml_iter_recurse( &scp_array, &scp_iter); } else if (ogs_yaml_iter_type( &scp_array) == YAML_SCALAR_NODE) { break; } else ogs_assert_if_reached(); if (NF_INSTANCE_CLIENT( self.scp_instance)) { ogs_error("Only one SCP client " "can be set"); return OGS_ERROR; } client = ogs_sbi_context_parse_client_config( &scp_iter); if (!client) { ogs_error("ogs_sbi_context_parse_" "client_config() failed"); return OGS_ERROR; } OGS_SBI_SETUP_CLIENT( self.scp_instance, client); } while (ogs_yaml_iter_type(&scp_array) == YAML_SEQUENCE_NODE); } } } else ogs_warn("unknown key `%s`", sbi_key); } } else if (!strcmp(local_key, "service_name")) { ogs_yaml_iter_t service_name_iter; ogs_yaml_iter_recurse(&local_iter, &service_name_iter); ogs_assert(ogs_yaml_iter_type( &service_name_iter) != YAML_MAPPING_NODE); do { const char *v = NULL; if (ogs_yaml_iter_type(&service_name_iter) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&service_name_iter)) break; } v = ogs_yaml_iter_value(&service_name_iter); if (v && strlen(v)) self.service_name[self.num_of_service_name++] = v; } while (ogs_yaml_iter_type( &service_name_iter) == YAML_SEQUENCE_NODE); } else if (!strcmp(local_key, "discovery")) { ogs_yaml_iter_t discovery_iter; ogs_yaml_iter_recurse(&local_iter, &discovery_iter); while (ogs_yaml_iter_next(&discovery_iter)) { const char *discovery_key = ogs_yaml_iter_key(&discovery_iter); ogs_assert(discovery_key); if (!strcmp(discovery_key, "delegated")) { const char *delegated = ogs_yaml_iter_value(&discovery_iter); if (!strcmp(delegated, "auto")) self.discovery_config.delegated = OGS_SBI_DISCOVERY_DELEGATED_AUTO; else if (!strcmp(delegated, "yes")) self.discovery_config.delegated = OGS_SBI_DISCOVERY_DELEGATED_YES; else if (!strcmp(delegated, "no")) self.discovery_config.delegated = OGS_SBI_DISCOVERY_DELEGATED_NO; else ogs_warn("unknown 'delegated' value `%s`", delegated); } else if (!strcmp(discovery_key, "option")) { ogs_yaml_iter_t option_iter; ogs_yaml_iter_recurse( &discovery_iter, &option_iter); while (ogs_yaml_iter_next(&option_iter)) { const char *option_key = ogs_yaml_iter_key(&option_iter); ogs_assert(option_key); if (!strcmp(option_key, "no_service_names")) { self.discovery_config.no_service_names = ogs_yaml_iter_bool(&option_iter); } else if (!strcmp(option_key, "prefer_requester_nf_instance_id")) { self.discovery_config. prefer_requester_nf_instance_id = ogs_yaml_iter_bool(&option_iter); } else ogs_warn("unknown key `%s`", option_key); } } else ogs_warn("unknown key `%s`", discovery_key); } } } } } rv = ogs_sbi_context_validation(local, nrf, scp); if (rv != OGS_OK) return rv; return OGS_OK; } int ogs_sbi_context_parse_hnet_config(ogs_yaml_iter_t *root_iter) { int rv; ogs_yaml_iter_t hnet_array, hnet_iter; ogs_assert(root_iter); ogs_yaml_iter_recurse(root_iter, &hnet_array); do { uint8_t id = 0, scheme = 0; const char *filename = NULL; if (ogs_yaml_iter_type(&hnet_array) == YAML_MAPPING_NODE) { memcpy(&hnet_iter, &hnet_array, sizeof(ogs_yaml_iter_t)); } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&hnet_array)) break; ogs_yaml_iter_recurse(&hnet_array, &hnet_iter); } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SCALAR_NODE) { break; } else ogs_assert_if_reached(); while (ogs_yaml_iter_next(&hnet_iter)) { const char *hnet_key = ogs_yaml_iter_key(&hnet_iter); ogs_assert(hnet_key); if (!strcmp(hnet_key, "id")) { const char *v = ogs_yaml_iter_value(&hnet_iter); if (v) { if (atoi(v) >= 1 && atoi(v) <= 254) id = atoi(v); } } else if (!strcmp(hnet_key, "scheme")) { const char *v = ogs_yaml_iter_value(&hnet_iter); if (v) { if (atoi(v) == 1 || atoi(v) == 2) scheme = atoi(v); } } else if (!strcmp(hnet_key, "key")) { filename = ogs_yaml_iter_value(&hnet_iter); } else ogs_warn("unknown key `%s`", hnet_key); } if (id >= OGS_HOME_NETWORK_PKI_VALUE_MIN && id <= OGS_HOME_NETWORK_PKI_VALUE_MAX && filename) { if (scheme == OGS_PROTECTION_SCHEME_PROFILE_A) { rv = ogs_pem_decode_curve25519_key( filename, self.hnet[id].key); if (rv == OGS_OK) { self.hnet[id].avail = true; self.hnet[id].scheme = scheme; } else { ogs_error("ogs_pem_decode_curve25519_key" "[%s] failed", filename); } } else if (scheme == OGS_PROTECTION_SCHEME_PROFILE_B) { rv = ogs_pem_decode_secp256r1_key( filename, self.hnet[id].key); if (rv == OGS_OK) { self.hnet[id].avail = true; self.hnet[id].scheme = scheme; } else { ogs_error("ogs_pem_decode_secp256r1_key[%s]" " failed", filename); } } else ogs_error("Invalid scheme [%d]", scheme); } else ogs_error("Invalid home network configuration " "[id:%d, filename:%s]", id, filename); } while (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE); return OGS_OK; } int ogs_sbi_context_parse_server_config( ogs_yaml_iter_t *parent, const char *interface) { int rv; ogs_sbi_server_t *server = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; ogs_list_t list, list6; ogs_socknode_t *node = NULL, *node6 = NULL; ogs_assert(parent); ogs_yaml_iter_t server_iter, server_array; ogs_yaml_iter_recurse(parent, &server_array); do { int i, family = AF_UNSPEC; int num = 0; const char *hostname[OGS_MAX_NUM_OF_HOSTNAME]; int num_of_advertise = 0; const char *advertise[OGS_MAX_NUM_OF_HOSTNAME]; uint16_t port = 0; const char *dev = NULL; ogs_sockaddr_t *addr = NULL; const char *private_key = NULL, *cert = NULL; bool verify_client = false; const char *verify_client_cacert = NULL; ogs_sockopt_t option; bool is_option = false; if (ogs_yaml_iter_type(&server_array) == YAML_MAPPING_NODE) { memcpy(&server_iter, &server_array, sizeof(ogs_yaml_iter_t)); } else if (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&server_array)) break; ogs_yaml_iter_recurse(&server_array, &server_iter); } else if (ogs_yaml_iter_type(&server_array) == YAML_SCALAR_NODE) { break; } else ogs_assert_if_reached(); while (ogs_yaml_iter_next(&server_iter)) { const char *server_key = ogs_yaml_iter_key(&server_iter); ogs_assert(server_key); if (!strcmp(server_key, OGS_SBI_INTERFACE_NAME_N32F)) { rv = ogs_sbi_context_parse_server_config( &server_iter, server_key); if (rv != OGS_OK) { ogs_error("ogs_sbi_context_parse_server_config() " "failed[key:%s]", server_key); return rv; } } else if (!strcmp(server_key, "family")) { const char *v = ogs_yaml_iter_value(&server_iter); if (v) family = atoi(v); if (family != AF_UNSPEC && family != AF_INET && family != AF_INET6) { ogs_warn("Ignore family(%d) : AF_UNSPEC(%d), " "AF_INET(%d), AF_INET6(%d) ", family, AF_UNSPEC, AF_INET, AF_INET6); family = AF_UNSPEC; } } else if (!strcmp(server_key, "address")) { ogs_yaml_iter_t hostname_iter; ogs_yaml_iter_recurse(&server_iter, &hostname_iter); ogs_assert(ogs_yaml_iter_type( &hostname_iter) != YAML_MAPPING_NODE); do { if (ogs_yaml_iter_type( &hostname_iter) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&hostname_iter)) break; } ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME); hostname[num++] = ogs_yaml_iter_value(&hostname_iter); } while (ogs_yaml_iter_type( &hostname_iter) == YAML_SEQUENCE_NODE); } else if (!strcmp(server_key, "advertise")) { ogs_yaml_iter_t advertise_iter; ogs_yaml_iter_recurse(&server_iter, &advertise_iter); ogs_assert(ogs_yaml_iter_type( &advertise_iter) != YAML_MAPPING_NODE); do { if (ogs_yaml_iter_type( &advertise_iter) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&advertise_iter)) break; } ogs_assert(num_of_advertise < OGS_MAX_NUM_OF_HOSTNAME); advertise[num_of_advertise++] = ogs_yaml_iter_value(&advertise_iter); } while (ogs_yaml_iter_type( &advertise_iter) == YAML_SEQUENCE_NODE); } else if (!strcmp(server_key, "port")) { const char *v = ogs_yaml_iter_value(&server_iter); if (v) port = atoi(v); } else if (!strcmp(server_key, "dev")) { dev = ogs_yaml_iter_value(&server_iter); } else if (!strcmp(server_key, "scheme")) { const char *v = ogs_yaml_iter_value(&server_iter); if (v) { if (!ogs_strcasecmp(v, "https")) scheme = OpenAPI_uri_scheme_https; else if (!ogs_strcasecmp(v, "http")) scheme = OpenAPI_uri_scheme_http; else ogs_warn("unknown scheme `%s`", v); } } else if (!strcmp(server_key, "private_key")) { private_key = ogs_yaml_iter_value(&server_iter); } else if (!strcmp(server_key, "cert")) { cert = ogs_yaml_iter_value(&server_iter); } else if (!strcmp(server_key, "verify_client")) { verify_client = ogs_yaml_iter_bool(&server_iter); } else if (!strcmp(server_key, "verify_client_cacert")) { verify_client_cacert = ogs_yaml_iter_value(&server_iter); } else if (!strcmp(server_key, "option")) { rv = ogs_app_parse_sockopt_config(&server_iter, &option); if (rv != OGS_OK) { ogs_error("ogs_app_parse_sockopt_config() failed"); return rv; } is_option = true; } } if (scheme == OpenAPI_uri_scheme_NULL) scheme = ogs_sbi_self()->tls.server.scheme; if (!port) { if (scheme == OpenAPI_uri_scheme_https) port = OGS_SBI_HTTPS_PORT; else if (scheme == OpenAPI_uri_scheme_http) port = OGS_SBI_HTTP_PORT; else ogs_assert_if_reached(); } addr = NULL; for (i = 0; i < num; i++) { rv = ogs_addaddrinfo(&addr, family, hostname[i], port, 0); ogs_assert(rv == OGS_OK); } ogs_list_init(&list); ogs_list_init(&list6); if (addr) { if (ogs_global_conf()->parameter.no_ipv4 == 0) ogs_socknode_add(&list, AF_INET, addr, NULL); if (ogs_global_conf()->parameter.no_ipv6 == 0) ogs_socknode_add(&list6, AF_INET6, addr, NULL); ogs_freeaddrinfo(addr); } if (dev) { rv = ogs_socknode_probe( ogs_global_conf()->parameter.no_ipv4 ? NULL : &list, ogs_global_conf()->parameter.no_ipv6 ? NULL : &list6, dev, port, NULL); ogs_assert(rv == OGS_OK); } addr = NULL; for (i = 0; i < num_of_advertise; i++) { rv = ogs_addaddrinfo(&addr, family, advertise[i], port, 0); ogs_assert(rv == OGS_OK); } node = ogs_list_first(&list); if (node) { server = ogs_sbi_server_add( interface, scheme, node->addr, is_option ? &option : NULL); ogs_assert(server); if (addr && ogs_global_conf()->parameter.no_ipv4 == 0) ogs_sbi_server_set_advertise(server, AF_INET, addr); if (verify_client == true) server->verify_client = true; if (verify_client_cacert) { if (server->verify_client_cacert) ogs_free(server->verify_client_cacert); server->verify_client_cacert = ogs_strdup(verify_client_cacert); ogs_assert(server->verify_client_cacert); } if (server->verify_client == true && !server->verify_client_cacert) { ogs_error("CLIENT verification enabled but no CA certificate"); return OGS_ERROR; } if (private_key) { if (server->private_key) ogs_free(server->private_key); server->private_key = ogs_strdup(private_key); ogs_assert(server->private_key); } if (cert) { if (server->cert) ogs_free(server->cert); server->cert = ogs_strdup(cert); ogs_assert(server->cert); } if (scheme == OpenAPI_uri_scheme_https) { if (!server->private_key) { ogs_error("HTTPS scheme enabled but no server key"); return OGS_ERROR; } if (!server->cert) { ogs_error("HTTPS scheme enabled but no server certificate"); return OGS_ERROR; } } } node6 = ogs_list_first(&list6); if (node6) { server = ogs_sbi_server_add( interface, scheme, node6->addr, is_option ? &option : NULL); ogs_assert(server); if (addr && ogs_global_conf()->parameter.no_ipv6 == 0) ogs_sbi_server_set_advertise(server, AF_INET6, addr); if (verify_client == true) server->verify_client = true; if (verify_client_cacert) { if (server->verify_client_cacert) ogs_free(server->verify_client_cacert); server->verify_client_cacert = ogs_strdup(verify_client_cacert); ogs_assert(server->verify_client_cacert); } if (server->verify_client == true && !server->verify_client_cacert) { ogs_error("CLIENT verification enabled but no CA certificate"); return OGS_ERROR; } if (private_key) { if (server->private_key) ogs_free(server->private_key); server->private_key = ogs_strdup(private_key); ogs_assert(server->private_key); } if (cert) { if (server->cert) ogs_free(server->cert); server->cert = ogs_strdup(cert); ogs_assert(server->cert); } if (scheme == OpenAPI_uri_scheme_https) { if (!server->private_key) { ogs_error("HTTPS scheme enabled but no server key"); return OGS_ERROR; } if (!server->cert) { ogs_error("HTTPS scheme enabled but no server certificate"); return OGS_ERROR; } } } if (addr) ogs_freeaddrinfo(addr); ogs_socknode_remove_all(&list); ogs_socknode_remove_all(&list6); } while (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE); return OGS_OK; } ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter) { ogs_sbi_client_t *client = NULL; const char *uri = NULL; int num_of_resolve = 0; const char *resolve[OGS_MAX_NUM_OF_HOSTNAME]; bool insecure_skip_verify = false; const char *cacert = NULL; const char *client_private_key = NULL; const char *client_cert = NULL; bool rc; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; char *fqdn = NULL; uint16_t fqdn_port = 0; ogs_sockaddr_t *addr = NULL; ogs_sockaddr_t *addr6 = NULL; ogs_assert(iter); while (ogs_yaml_iter_next(iter)) { const char *key = ogs_yaml_iter_key(iter); ogs_assert(key); if (!strcmp(key, "uri")) { uri = ogs_yaml_iter_value(iter); } else if (!strcmp(key, "resolve")) { ogs_yaml_iter_t resolve_iter; ogs_yaml_iter_recurse(iter, &resolve_iter); ogs_assert(ogs_yaml_iter_type(&resolve_iter) != YAML_MAPPING_NODE); do { if (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE) { if (!ogs_yaml_iter_next(&resolve_iter)) break; } ogs_assert(num_of_resolve < OGS_MAX_NUM_OF_HOSTNAME); resolve[num_of_resolve++] = ogs_yaml_iter_value(&resolve_iter); } while (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE); } else if (!strcmp(key, "insecure_skip_verify")) { insecure_skip_verify = ogs_yaml_iter_bool(iter); } else if (!strcmp(key, "cacert")) { cacert = ogs_yaml_iter_value(iter); } else if (!strcmp(key, "client_private_key")) { client_private_key = ogs_yaml_iter_value(iter); } else if (!strcmp(key, "client_cert")) { client_cert = ogs_yaml_iter_value(iter); } } if (!uri) { ogs_error("URI[%s] is required", uri ? uri : "NULL"); return NULL; } rc = ogs_sbi_getaddr_from_uri( &scheme, &fqdn, &fqdn_port, &addr, &addr6, (char *)uri); if (rc == false) { if (!scheme) ogs_error("Invalid Scheme in URI[%s]", uri); else ogs_error("Invalid URI[%s]", uri); return NULL; } switch (scheme) { case OpenAPI_uri_scheme_https: if (!fqdn) { ogs_error("HTTPS(TLS) must be set to FQDN [uri:%s]", uri); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); return NULL; } client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, NULL, NULL); ogs_assert(client); break; case OpenAPI_uri_scheme_http: client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6); ogs_assert(client); break; default: ogs_fatal("Invalid Scheme[%d]", scheme); ogs_assert_if_reached(); } if (num_of_resolve) client->resolve = ogs_sbi_client_resolve( scheme, fqdn, fqdn_port, resolve, num_of_resolve); if (insecure_skip_verify == true) client->insecure_skip_verify = true; if (cacert) { if (client->cacert) ogs_free(client->cacert); client->cacert = ogs_strdup(cacert); ogs_assert(client->cacert); } if (client_private_key) { if (client->private_key) ogs_free(client->private_key); client->private_key = ogs_strdup(client_private_key); ogs_assert(client->private_key); } if (client_cert) { if (client->cert) ogs_free(client->cert); client->cert = ogs_strdup(client_cert); ogs_assert(client->cert); } if ((!client_private_key && client_cert) || (client_private_key && !client_cert)) { ogs_error("Either the private key or certificate is missing."); ogs_sbi_client_remove(client); return NULL; } ogs_free(fqdn); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); return client; } bool ogs_sbi_nf_service_is_available(const char *name) { int i; ogs_assert(name); if (self.num_of_service_name == 0) /* If no service name is configured, all services are available */ return true; for (i = 0; i < self.num_of_service_name; i++) /* Only services in the configuration are available */ if (strcmp(self.service_name[i], name) == 0) return true; return false; } ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_add(void) { ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_pool_alloc(&nf_instance_pool, &nf_instance); ogs_assert(nf_instance); memset(nf_instance, 0, sizeof(ogs_sbi_nf_instance_t)); OGS_OBJECT_REF(nf_instance); nf_instance->time.heartbeat_interval = ogs_local_conf()->time.nf_instance.heartbeat_interval; nf_instance->priority = OGS_SBI_DEFAULT_PRIORITY; nf_instance->capacity = OGS_SBI_DEFAULT_CAPACITY; nf_instance->load = OGS_SBI_DEFAULT_LOAD; ogs_list_add(&ogs_sbi_self()->nf_instance_list, nf_instance); ogs_debug("[%s] NFInstance added with Ref [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); return nf_instance; } void ogs_sbi_nf_instance_set_id(ogs_sbi_nf_instance_t *nf_instance, char *id) { ogs_assert(nf_instance); ogs_assert(id); nf_instance->id = ogs_strdup(id); ogs_assert(nf_instance->id); } void ogs_sbi_nf_instance_set_type( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e nf_type) { ogs_assert(nf_instance); ogs_assert(nf_type); nf_instance->nf_type = nf_type; } void ogs_sbi_nf_instance_set_status( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_status_e nf_status) { ogs_assert(nf_instance); ogs_assert(nf_status); nf_instance->nf_status = nf_status; } void ogs_sbi_nf_instance_add_allowed_nf_type( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type) { ogs_assert(nf_instance); ogs_assert(allowed_nf_type); if (nf_instance->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) { nf_instance->allowed_nf_type[nf_instance->num_of_allowed_nf_type] = allowed_nf_type; nf_instance->num_of_allowed_nf_type++; } } bool ogs_sbi_nf_instance_is_allowed_nf_type( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type) { int i; ogs_assert(nf_instance); ogs_assert(allowed_nf_type); if (!nf_instance->num_of_allowed_nf_type) { return true; } for (i = 0; i < nf_instance->num_of_allowed_nf_type; i++) { if (nf_instance->allowed_nf_type[i] == allowed_nf_type) return true; } ogs_error("Not allowed nf-type[%s] in nf-instance[%s]", OpenAPI_nf_type_ToString(allowed_nf_type), OpenAPI_nf_type_ToString(nf_instance->nf_type)); return false; } void ogs_sbi_nf_instance_clear(ogs_sbi_nf_instance_t *nf_instance) { int i; ogs_assert(nf_instance); if (nf_instance->fqdn) ogs_free(nf_instance->fqdn); nf_instance->fqdn = NULL; for (i = 0; i < nf_instance->num_of_ipv4; i++) { if (nf_instance->ipv4[i]) ogs_freeaddrinfo(nf_instance->ipv4[i]); } nf_instance->num_of_ipv4 = 0; for (i = 0; i < nf_instance->num_of_ipv6; i++) { if (nf_instance->ipv6[i]) ogs_freeaddrinfo(nf_instance->ipv6[i]); } nf_instance->num_of_ipv6 = 0; nf_instance->num_of_allowed_nf_type = 0; } void ogs_sbi_nf_instance_remove(ogs_sbi_nf_instance_t *nf_instance) { ogs_assert(nf_instance); ogs_debug("[%s] NFInstance UnRef [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); if (OGS_OBJECT_IS_REF(nf_instance)) { OGS_OBJECT_UNREF(nf_instance); return; } ogs_debug("[%s] NFInstance removed [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_list_remove(&ogs_sbi_self()->nf_instance_list, nf_instance); ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list); ogs_sbi_nf_service_remove_all(nf_instance); ogs_sbi_nf_instance_clear(nf_instance); if (nf_instance->id) { ogs_sbi_subscription_data_remove_all_by_nf_instance_id(nf_instance->id); ogs_free(nf_instance->id); } if (nf_instance->client) ogs_sbi_client_remove(nf_instance->client); ogs_pool_free(&nf_instance_pool, nf_instance); } void ogs_sbi_nf_instance_remove_all(void) { ogs_sbi_nf_instance_t *nf_instance = NULL, *next_nf_instance = NULL; ogs_list_for_each_safe( &ogs_sbi_self()->nf_instance_list, next_nf_instance, nf_instance) ogs_sbi_nf_instance_remove(nf_instance); } ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find(char *id) { ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_assert(id); ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) { if (nf_instance->id && strcmp(nf_instance->id, id) == 0) break; } return nf_instance; } ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_discovery_param( OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type, ogs_sbi_discovery_option_t *discovery_option) { ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_assert(target_nf_type); ogs_assert(requester_nf_type); ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) { if (ogs_sbi_discovery_param_is_matched( nf_instance, target_nf_type, requester_nf_type, discovery_option) == false) continue; return nf_instance; } return NULL; } ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_service_type( ogs_sbi_service_type_e service_type, OpenAPI_nf_type_e requester_nf_type) { ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_sbi_discovery_option_t *discovery_option = NULL; OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL; char *service_name = NULL; ogs_assert(requester_nf_type); ogs_assert(service_type); target_nf_type = ogs_sbi_service_type_to_nf_type(service_type); ogs_assert(target_nf_type); service_name = (char *)ogs_sbi_service_type_to_name(service_type); ogs_assert(service_name); discovery_option = ogs_sbi_discovery_option_new(); ogs_assert(discovery_option); ogs_sbi_discovery_option_add_service_names(discovery_option, service_name); nf_instance = ogs_sbi_nf_instance_find_by_discovery_param( target_nf_type, requester_nf_type, discovery_option); ogs_sbi_discovery_option_free(discovery_option); return nf_instance; } bool ogs_sbi_nf_instance_maximum_number_is_reached(void) { return nf_instance_pool.avail <= 0; } ogs_sbi_nf_service_t *ogs_sbi_nf_service_add( ogs_sbi_nf_instance_t *nf_instance, char *id, const char *name, OpenAPI_uri_scheme_e scheme) { ogs_sbi_nf_service_t *nf_service = NULL; ogs_assert(nf_instance); ogs_assert(id); ogs_assert(name); ogs_pool_alloc(&nf_service_pool, &nf_service); ogs_assert(nf_service); memset(nf_service, 0, sizeof(ogs_sbi_nf_service_t)); nf_service->id = ogs_strdup(id); ogs_assert(nf_service->id); nf_service->name = ogs_strdup(name); ogs_assert(nf_service->name); nf_service->scheme = scheme; ogs_assert(nf_service->scheme); nf_service->status = OpenAPI_nf_service_status_REGISTERED; nf_service->priority = OGS_SBI_DEFAULT_PRIORITY; nf_service->capacity = OGS_SBI_DEFAULT_CAPACITY; nf_service->load = OGS_SBI_DEFAULT_LOAD; nf_service->nf_instance = nf_instance; ogs_list_add(&nf_instance->nf_service_list, nf_service); return nf_service; } void ogs_sbi_nf_service_add_version(ogs_sbi_nf_service_t *nf_service, const char *in_uri, const char *full, const char *expiry) { ogs_assert(nf_service); ogs_assert(in_uri); ogs_assert(full); if (nf_service->num_of_version < OGS_SBI_MAX_NUM_OF_SERVICE_VERSION) { nf_service->version[nf_service->num_of_version].in_uri = ogs_strdup(in_uri); ogs_assert(nf_service->version[nf_service->num_of_version].in_uri); nf_service->version[nf_service->num_of_version].full = ogs_strdup(full); ogs_assert(nf_service->version[nf_service->num_of_version].full); if (expiry) { nf_service->version[nf_service->num_of_version].expiry = ogs_strdup(expiry); ogs_assert( nf_service->version[nf_service->num_of_version].expiry); } nf_service->num_of_version++; } } void ogs_sbi_nf_service_add_allowed_nf_type( ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type) { ogs_assert(nf_service); ogs_assert(allowed_nf_type); if (nf_service->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) { nf_service->allowed_nf_type[nf_service->num_of_allowed_nf_type] = allowed_nf_type; nf_service->num_of_allowed_nf_type++; } } bool ogs_sbi_nf_service_is_allowed_nf_type( ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type) { int i; ogs_assert(nf_service); ogs_assert(allowed_nf_type); if (!nf_service->num_of_allowed_nf_type) { return true; } for (i = 0; i < nf_service->num_of_allowed_nf_type; i++) { if (nf_service->allowed_nf_type[i] == allowed_nf_type) return true; } ogs_assert(nf_service->name); ogs_error("Not allowed nf-type[%s] in nf-service[%s]", OpenAPI_nf_type_ToString(allowed_nf_type), nf_service->name); return false; } void ogs_sbi_nf_service_clear(ogs_sbi_nf_service_t *nf_service) { ogs_sbi_nf_instance_t *nf_instance = NULL; int i; ogs_assert(nf_service); nf_instance = nf_service->nf_instance; ogs_assert(nf_instance); if (nf_service->fqdn) ogs_free(nf_service->fqdn); nf_service->fqdn = NULL; for (i = 0; i < nf_service->num_of_version; i++) { if (nf_service->version[i].in_uri) ogs_free(nf_service->version[i].in_uri); if (nf_service->version[i].full) ogs_free(nf_service->version[i].full); if (nf_service->version[i].expiry) ogs_free(nf_service->version[i].expiry); } nf_service->num_of_version = 0; for (i = 0; i < nf_service->num_of_addr; i++) { if (nf_service->addr[i].ipv4) ogs_freeaddrinfo(nf_service->addr[i].ipv4); if (nf_service->addr[i].ipv6) ogs_freeaddrinfo(nf_service->addr[i].ipv6); } nf_service->num_of_addr = 0; nf_service->num_of_allowed_nf_type = 0; } void ogs_sbi_nf_service_remove(ogs_sbi_nf_service_t *nf_service) { ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_assert(nf_service); nf_instance = nf_service->nf_instance; ogs_assert(nf_instance); ogs_list_remove(&nf_instance->nf_service_list, nf_service); ogs_assert(nf_service->id); ogs_free(nf_service->id); ogs_assert(nf_service->name); ogs_free(nf_service->name); ogs_sbi_nf_service_clear(nf_service); if (nf_service->client) ogs_sbi_client_remove(nf_service->client); ogs_pool_free(&nf_service_pool, nf_service); } void ogs_sbi_nf_service_remove_all(ogs_sbi_nf_instance_t *nf_instance) { ogs_sbi_nf_service_t *nf_service = NULL, *next_nf_service = NULL; ogs_assert(nf_instance); ogs_list_for_each_safe(&nf_instance->nf_service_list, next_nf_service, nf_service) ogs_sbi_nf_service_remove(nf_service); } ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_id( ogs_sbi_nf_instance_t *nf_instance, char *id) { ogs_sbi_nf_service_t *nf_service = NULL; ogs_assert(nf_instance); ogs_assert(id); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { ogs_assert(nf_service->id); if (strcmp(nf_service->id, id) == 0) break; } return nf_service; } ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_name( ogs_sbi_nf_instance_t *nf_instance, char *name) { ogs_sbi_nf_service_t *nf_service = NULL; ogs_assert(nf_instance); ogs_assert(name); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { ogs_assert(nf_service->name); if (strcmp(nf_service->name, name) == 0) return nf_service; } return NULL; } ogs_sbi_nf_info_t *ogs_sbi_nf_info_add( ogs_list_t *list, OpenAPI_nf_type_e nf_type) { ogs_sbi_nf_info_t *nf_info = NULL; ogs_assert(list); ogs_assert(nf_type); ogs_pool_alloc(&nf_info_pool, &nf_info); if (!nf_info) { ogs_fatal("ogs_pool_alloc() failed"); return NULL; } memset(nf_info, 0, sizeof(*nf_info)); nf_info->nf_type = nf_type; ogs_list_add(list, nf_info); return nf_info; } static void amf_info_free(ogs_sbi_amf_info_t *amf_info) { /* Nothing */ } static void smf_info_free(ogs_sbi_smf_info_t *smf_info) { int i, j; ogs_assert(smf_info); for (i = 0; i < smf_info->num_of_slice; i++) { for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) ogs_free(smf_info->slice[i].dnn[j]); smf_info->slice[i].num_of_dnn = 0; } smf_info->num_of_slice = 0; smf_info->num_of_nr_tai = 0; smf_info->num_of_nr_tai_range = 0; ogs_pool_free(&smf_info_pool, smf_info); } static void scp_info_free(ogs_sbi_scp_info_t *scp_info) { int i; for (i = 0; i < scp_info->num_of_domain; i++) { if (scp_info->domain[i].name) ogs_free(scp_info->domain[i].name); if (scp_info->domain[i].fqdn) ogs_free(scp_info->domain[i].fqdn); } scp_info->num_of_domain = 0; } static void sepp_info_free(ogs_sbi_sepp_info_t *sepp_info) { } void ogs_sbi_nf_info_remove(ogs_list_t *list, ogs_sbi_nf_info_t *nf_info) { ogs_assert(list); ogs_assert(nf_info); ogs_list_remove(list, nf_info); switch(nf_info->nf_type) { case OpenAPI_nf_type_AMF: amf_info_free(&nf_info->amf); break; case OpenAPI_nf_type_SMF: smf_info_free(&nf_info->smf); break; case OpenAPI_nf_type_SCP: scp_info_free(&nf_info->scp); break; case OpenAPI_nf_type_SEPP: sepp_info_free(&nf_info->sepp); break; default: ogs_fatal("Not implemented NF-type[%s]", OpenAPI_nf_type_ToString(nf_info->nf_type)); ogs_assert_if_reached(); } ogs_pool_free(&nf_info_pool, nf_info); } void ogs_sbi_nf_info_remove_all(ogs_list_t *list) { ogs_sbi_nf_info_t *nf_info = NULL, *next_nf_info = NULL; ogs_assert(list); ogs_list_for_each_safe(list, next_nf_info, nf_info) ogs_sbi_nf_info_remove(list, nf_info); } ogs_sbi_nf_info_t *ogs_sbi_nf_info_find( ogs_list_t *list, OpenAPI_nf_type_e nf_type) { ogs_sbi_nf_info_t *nf_info = NULL; ogs_assert(list); ogs_assert(nf_type); ogs_list_for_each(list, nf_info) { if (nf_info->nf_type == nf_type) return nf_info; } return NULL; } bool ogs_sbi_check_smf_info_slice( ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn) { int i, j; ogs_assert(smf_info); ogs_assert(s_nssai); ogs_assert(dnn); for (i = 0; i < smf_info->num_of_slice; i++) { if (s_nssai->sst == smf_info->slice[i].s_nssai.sst && s_nssai->sd.v == smf_info->slice[i].s_nssai.sd.v) { for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) { if (ogs_strcasecmp(dnn, smf_info->slice[i].dnn[j]) == 0) return true; } } } return false; } bool ogs_sbi_check_smf_info_tai( ogs_sbi_smf_info_t *smf_info, ogs_5gs_tai_t *tai) { int i, j; ogs_assert(smf_info); ogs_assert(tai); if (smf_info->num_of_nr_tai == 0 && smf_info->num_of_nr_tai_range == 0) return true; for (i = 0; i < smf_info->num_of_nr_tai; i++) { if (memcmp(&tai->plmn_id, &smf_info->nr_tai[i].plmn_id, OGS_PLMN_ID_LEN) == 0) { if (tai->tac.v == smf_info->nr_tai[i].tac.v) return true; } } for (i = 0; i < smf_info->num_of_nr_tai_range; i++) { if (memcmp(&tai->plmn_id, &smf_info->nr_tai_range[i].plmn_id, OGS_PLMN_ID_LEN) == 0) { for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) { if (tai->tac.v >= smf_info->nr_tai_range[i].start[j].v && tai->tac.v <= smf_info->nr_tai_range[i].end[j].v) { return true; } } } } return false; } void ogs_sbi_nf_instance_build_default(ogs_sbi_nf_instance_t *nf_instance) { ogs_sbi_server_t *server = NULL; char *hostname = NULL; ogs_assert(nf_instance); ogs_sbi_nf_instance_set_status(nf_instance, OpenAPI_nf_status_REGISTERED); hostname = NULL; for (server = ogs_sbi_server_first(); server; server = ogs_sbi_server_next(server)) { ogs_sockaddr_t *advertise = NULL; advertise = server->advertise; if (!advertise) advertise = server->node.addr; ogs_assert(advertise); /* First FQDN is selected */ if (!hostname) { hostname = ogs_gethostname(advertise); if (hostname) continue; } if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { ogs_sockaddr_t *addr = NULL; ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise)); ogs_assert(addr); if (addr->ogs_sa_family == AF_INET) { nf_instance->ipv4[nf_instance->num_of_ipv4] = addr; nf_instance->num_of_ipv4++; } else if (addr->ogs_sa_family == AF_INET6) { nf_instance->ipv6[nf_instance->num_of_ipv6] = addr; nf_instance->num_of_ipv6++; } else ogs_assert_if_reached(); } } if (hostname) { nf_instance->fqdn = ogs_strdup(hostname); ogs_assert(nf_instance->fqdn); } nf_instance->time.heartbeat_interval = ogs_local_conf()->time.nf_instance.heartbeat_interval; if (ogs_local_conf()->num_of_serving_plmn_id) { memcpy(nf_instance->plmn_id, ogs_local_conf()->serving_plmn_id, sizeof(nf_instance->plmn_id)); nf_instance->num_of_plmn_id = ogs_local_conf()->num_of_serving_plmn_id; } } ogs_sbi_nf_service_t *ogs_sbi_nf_service_build_default( ogs_sbi_nf_instance_t *nf_instance, const char *name) { ogs_sbi_server_t *server = NULL; ogs_sbi_nf_service_t *nf_service = NULL; ogs_uuid_t uuid; char id[OGS_UUID_FORMATTED_LENGTH + 1]; char *hostname = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; ogs_assert(nf_instance); ogs_assert(name); ogs_uuid_get(&uuid); ogs_uuid_format(id, &uuid); server = ogs_sbi_server_first(); ogs_assert(server); scheme = server->scheme; ogs_assert(scheme); nf_service = ogs_sbi_nf_service_add(nf_instance, id, name, scheme); ogs_assert(nf_service); hostname = NULL; for (server = ogs_sbi_server_first(); server; server = ogs_sbi_server_next(server)) { ogs_sockaddr_t *advertise = NULL; advertise = server->advertise; if (!advertise) advertise = server->node.addr; ogs_assert(advertise); /* First FQDN is selected */ if (!hostname) { hostname = ogs_gethostname(advertise); if (hostname) continue; } if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { bool is_port = true; int port = 0; ogs_sockaddr_t *addr = NULL; ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise)); ogs_assert(addr); port = OGS_PORT(addr); if (nf_service->scheme == OpenAPI_uri_scheme_https) { if (port == OGS_SBI_HTTPS_PORT) is_port = false; } else if (nf_service->scheme == OpenAPI_uri_scheme_http) { if (port == OGS_SBI_HTTP_PORT) is_port = false; } nf_service->addr[nf_service->num_of_addr].is_port = is_port; nf_service->addr[nf_service->num_of_addr].port = port; if (addr->ogs_sa_family == AF_INET) { nf_service->addr[nf_service->num_of_addr].ipv4 = addr; } else if (addr->ogs_sa_family == AF_INET6) { nf_service->addr[nf_service->num_of_addr].ipv6 = addr; } else ogs_assert_if_reached(); nf_service->num_of_addr++; } } if (hostname) { nf_service->fqdn = ogs_strdup(hostname); ogs_assert(nf_service->fqdn); } ogs_info("NF Service [%s]", nf_service->name); return nf_service; } static ogs_sbi_client_t *nf_instance_find_client( ogs_sbi_nf_instance_t *nf_instance) { ogs_sbi_client_t *client = NULL; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; ogs_sbi_nf_info_t *nf_info = NULL; uint16_t port = 0; scheme = ogs_sbi_self()->tls.client.scheme; ogs_assert(scheme); switch (nf_instance->nf_type) { case OpenAPI_nf_type_SEPP: nf_info = ogs_sbi_nf_info_find( &nf_instance->nf_info_list, nf_instance->nf_type); if (nf_info) { if (scheme == OpenAPI_uri_scheme_https) port = nf_info->sepp.https.port; else if (scheme == OpenAPI_uri_scheme_http) port = nf_info->sepp.http.port; else ogs_error("Unknown scheme [%d]", scheme); } break; case OpenAPI_nf_type_SCP: nf_info = ogs_sbi_nf_info_find( &nf_instance->nf_info_list, nf_instance->nf_type); if (nf_info) { if (scheme == OpenAPI_uri_scheme_https) port = nf_info->scp.https.port; else if (scheme == OpenAPI_uri_scheme_http) port = nf_info->scp.http.port; else ogs_error("Unknown scheme [%d]", scheme); } break; default: break; } /* At this point, CLIENT selection method is very simple. */ if (nf_instance->num_of_ipv4) addr = nf_instance->ipv4[0]; if (nf_instance->num_of_ipv6) addr6 = nf_instance->ipv6[0]; if (port) { if (addr) addr->ogs_sin_port = htobe16(port); if (addr6) addr6->ogs_sin_port = htobe16(port); } if (nf_instance->fqdn || addr || addr6) { client = ogs_sbi_client_find( scheme, nf_instance->fqdn, port, addr, addr6); if (!client) { ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); client = ogs_sbi_client_add( scheme, nf_instance->fqdn, port, addr, addr6); if (!client) { ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC); return NULL; } } } return client; } static void nf_service_associate_client(ogs_sbi_nf_service_t *nf_service) { ogs_sbi_client_t *client = NULL; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(nf_service->scheme); /* At this point, CLIENT selection method is very simple. */ if (nf_service->num_of_addr) { addr = nf_service->addr[0].ipv4; addr6 = nf_service->addr[0].ipv6; } if (nf_service->fqdn || addr || addr6) { client = ogs_sbi_client_find( nf_service->scheme, nf_service->fqdn, 0, addr, addr6); if (!client) { ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); client = ogs_sbi_client_add( nf_service->scheme, nf_service->fqdn, 0, addr, addr6); if (!client) { ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC); return; } } } ogs_debug("[%s] NFService associated [%s]", nf_service->name, nf_service->id); if (client) OGS_SBI_SETUP_CLIENT(nf_service, client); } static void nf_service_associate_client_all(ogs_sbi_nf_instance_t *nf_instance) { ogs_sbi_nf_service_t *nf_service = NULL; ogs_assert(nf_instance); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) nf_service_associate_client(nf_service); } bool ogs_sbi_discovery_option_is_matched( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e requester_nf_type, ogs_sbi_discovery_option_t *discovery_option) { ogs_sbi_nf_info_t *nf_info = NULL; ogs_assert(nf_instance); ogs_assert(requester_nf_type); ogs_assert(discovery_option); if (discovery_option->target_nf_instance_id && nf_instance->id && strcmp(nf_instance->id, discovery_option->target_nf_instance_id) != 0) { return false; } if (discovery_option->num_of_service_names) { if (ogs_sbi_discovery_option_service_names_is_matched( nf_instance, requester_nf_type, discovery_option) == false) return false; } if (discovery_option->num_of_target_plmn_list) { if (ogs_sbi_discovery_option_target_plmn_list_is_matched( nf_instance, discovery_option) == false) return false; } ogs_list_for_each(&nf_instance->nf_info_list, nf_info) { if (nf_instance->nf_type != nf_info->nf_type) { ogs_error("Invalid NF-Type [%d:%d]", nf_instance->nf_type, nf_info->nf_type); return false; } switch (nf_info->nf_type) { case OpenAPI_nf_type_SMF: if (discovery_option->num_of_snssais && discovery_option->dnn && ogs_sbi_check_smf_info_slice(&nf_info->smf, &discovery_option->snssais[0], discovery_option->dnn) == false) return false; if (discovery_option->tai_presence && ogs_sbi_check_smf_info_tai(&nf_info->smf, &discovery_option->tai) == false) return false; break; default: break; } } return true; } bool ogs_sbi_discovery_option_service_names_is_matched( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e requester_nf_type, ogs_sbi_discovery_option_t *discovery_option) { ogs_sbi_nf_service_t *nf_service = NULL; int i; ogs_assert(nf_instance); ogs_assert(requester_nf_type); ogs_assert(discovery_option); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { for (i = 0; i < discovery_option->num_of_service_names; i++) { if (nf_service->name && discovery_option->service_names[i] && strcmp(nf_service->name, discovery_option->service_names[i]) == 0) { if (ogs_sbi_nf_service_is_allowed_nf_type( nf_service, requester_nf_type) == true) { return true; } } } } return false; } bool ogs_sbi_discovery_param_serving_plmn_list_is_matched( ogs_sbi_nf_instance_t *nf_instance) { int i, j; ogs_assert(nf_instance); /* * The PLMN-ID is optional and may not be set. * * Does not compare if serving PLMN-ID is not set or NF-Instance is not set. */ if (ogs_local_conf()->num_of_serving_plmn_id == 0 || nf_instance->num_of_plmn_id == 0) return true; for (i = 0; i < nf_instance->num_of_plmn_id; i++) { for (j = 0; j < ogs_local_conf()->num_of_serving_plmn_id; j++) { if (memcmp(&nf_instance->plmn_id[i], &ogs_local_conf()->serving_plmn_id[j], OGS_PLMN_ID_LEN) == 0) { return true; } } } return false; } bool ogs_sbi_discovery_option_requester_plmn_list_is_matched( ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_discovery_option_t *discovery_option) { int i, j; ogs_assert(nf_instance); ogs_assert(discovery_option); for (i = 0; i < nf_instance->num_of_plmn_id; i++) { for (j = 0; j < discovery_option->num_of_requester_plmn_list; j++) { if (memcmp(&nf_instance->plmn_id[i], &discovery_option->requester_plmn_list[j], OGS_PLMN_ID_LEN) == 0) { return true; } } } return false; } bool ogs_sbi_discovery_option_target_plmn_list_is_matched( ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_discovery_option_t *discovery_option) { int i, j; ogs_assert(nf_instance); ogs_assert(discovery_option); for (i = 0; i < nf_instance->num_of_plmn_id; i++) { for (j = 0; j < discovery_option->num_of_target_plmn_list; j++) { if (memcmp(&nf_instance->plmn_id[i], &discovery_option->target_plmn_list[j], OGS_PLMN_ID_LEN) == 0) { return true; } } } return false; } bool ogs_sbi_discovery_param_is_matched( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e target_nf_type, OpenAPI_nf_type_e requester_nf_type, ogs_sbi_discovery_option_t *discovery_option) { ogs_assert(nf_instance); ogs_assert(target_nf_type); ogs_assert(requester_nf_type); if (NF_INSTANCE_EXCLUDED_FROM_DISCOVERY(nf_instance)) return false; if (!OGS_FSM_CHECK(&nf_instance->sm, ogs_sbi_nf_state_registered)) return false; if (nf_instance->nf_type != target_nf_type) return false; /* * For the same PLMN, The target-plmn-list may not be included * in discovery request. * * If the Serving PLMN needs to be discovered, but the target-plmn-list * is not included, the NF of the Home PLMN can be discovered. * * To avoid this situation, if the target-plmn-list is not included * and the serving PLMN is known, it is compared first. * * Refer to the following standard for this issue. * * TS29.510 * 6.2 Nnrf_NFDiscovery Service API * 6.2.3 Resources * Table 6.2.3.2.3.1-1: URI query parameters supported * by the GET method on this resource * * NAME: target-plmn-list * Data type: array(PlmnId) * P: C * Cardinality: 1..N * * This IE shall be included when NF services in a different PLMN, * or NF services of specific PLMN ID(s) in a same PLMN * comprising multiple PLMN IDs, need to be discovered. * When included, this IE shall contain the PLMN ID of the target NF. * If more than one PLMN ID is included, NFs from any PLMN ID present * in the list matches the query parameter. This IE shall also * be included in SNPN scenarios, when the entity owning * the subscription, the Credentials Holder * (see clause 5.30.2.9 in 3GPP TS 23.501 [2]) is a PLMN. * * For inter-PLMN service discovery, at most 1 PLMN ID shall * be included in the list; it shall be included * in the service discovery from the NF in the source PLMN sent * to the NRF in the same PLMN, while it may be absent * in the service discovery request sent from the source NRF * to the target NRF. In such case, if the NRF receives more than * 1 PLMN ID, it shall only consider the first element of the array, * and ignore the rest. */ if (!discovery_option || !discovery_option->num_of_target_plmn_list) { if (ogs_sbi_discovery_param_serving_plmn_list_is_matched( nf_instance) == false) return false; } if (discovery_option) { if (ogs_sbi_discovery_option_is_matched( nf_instance, requester_nf_type, discovery_option) == false) return false; } return true; } void ogs_sbi_client_associate(ogs_sbi_nf_instance_t *nf_instance) { ogs_sbi_client_t *client = NULL; ogs_assert(nf_instance); client = nf_instance_find_client(nf_instance); ogs_assert(client); ogs_debug("[%s] NFInstance associated [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); OGS_SBI_SETUP_CLIENT(nf_instance, client); nf_service_associate_client_all(nf_instance); } int ogs_sbi_default_client_port(OpenAPI_uri_scheme_e scheme) { if (scheme == OpenAPI_uri_scheme_NULL) scheme = ogs_sbi_self()->tls.client.scheme; return scheme == OpenAPI_uri_scheme_https ? OGS_SBI_HTTPS_PORT : OGS_SBI_HTTP_PORT; } ogs_sbi_client_t *ogs_sbi_client_find_by_service_name( ogs_sbi_nf_instance_t *nf_instance, char *name, char *version) { ogs_sbi_nf_service_t *nf_service = NULL; int i; ogs_assert(nf_instance); ogs_assert(name); ogs_assert(version); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { ogs_assert(nf_service->name); if (strcmp(nf_service->name, name) == 0) { for (i = 0; i < nf_service->num_of_version; i++) { if (strcmp(nf_service->version[i].in_uri, version) == 0) { return nf_service->client; } } } } return nf_instance->client; } ogs_sbi_client_t *ogs_sbi_client_find_by_service_type( ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_service_type_e service_type) { ogs_sbi_nf_service_t *nf_service = NULL; ogs_assert(nf_instance); ogs_assert(service_type); ogs_list_for_each(&nf_instance->nf_service_list, nf_service) { ogs_assert(nf_service->name); if (ogs_sbi_service_type_from_name(nf_service->name) == service_type) return nf_service->client; } return nf_instance->client; } void ogs_sbi_object_free(ogs_sbi_object_t *sbi_object) { int i; ogs_assert(sbi_object); if (ogs_list_count(&sbi_object->xact_list)) ogs_error("SBI running [%d]", ogs_list_count(&sbi_object->xact_list)); for (i = 0; i < OGS_SBI_MAX_NUM_OF_SERVICE_TYPE; i++) { ogs_sbi_nf_instance_t *nf_instance = sbi_object->service_type_array[i].nf_instance; if (nf_instance) ogs_sbi_nf_instance_remove(nf_instance); } for (i = 0; i < OGS_SBI_MAX_NUM_OF_NF_TYPE; i++) { ogs_sbi_nf_instance_t *nf_instance = sbi_object->nf_type_array[i].nf_instance; if (nf_instance) ogs_sbi_nf_instance_remove(nf_instance); } } ogs_sbi_xact_t *ogs_sbi_xact_add( ogs_sbi_object_t *sbi_object, ogs_sbi_service_type_e service_type, ogs_sbi_discovery_option_t *discovery_option, ogs_sbi_build_f build, void *context, void *data) { ogs_sbi_xact_t *xact = NULL; ogs_assert(sbi_object); ogs_pool_alloc(&xact_pool, &xact); if (!xact) { ogs_error("ogs_pool_alloc() failed"); return NULL; } memset(xact, 0, sizeof(ogs_sbi_xact_t)); xact->sbi_object = sbi_object; xact->service_type = service_type; xact->requester_nf_type = NF_INSTANCE_TYPE(ogs_sbi_self()->nf_instance); ogs_assert(xact->requester_nf_type); /* * Insert one service-name in the discovery option in the function below. * * - ogs_sbi_xact_add() * - ogs_sbi_send_notification_request() */ if (!discovery_option) { discovery_option = ogs_sbi_discovery_option_new(); ogs_assert(discovery_option); /* ALWAYS add Service-MAP to requester-features in Discovery Option */ OGS_SBI_FEATURES_SET(discovery_option->requester_features, OGS_SBI_NNRF_DISC_SERVICE_MAP); } if (!discovery_option->num_of_service_names) { ogs_sbi_discovery_option_add_service_names( discovery_option, (char *)ogs_sbi_service_type_to_name(service_type)); } xact->discovery_option = discovery_option; xact->t_response = ogs_timer_add( ogs_app()->timer_mgr, ogs_timer_sbi_client_wait_expire, xact); if (!xact->t_response) { ogs_error("ogs_timer_add() failed"); if (xact->discovery_option) ogs_sbi_discovery_option_free(xact->discovery_option); ogs_pool_free(&xact_pool, xact); return NULL; } ogs_timer_start(xact->t_response, ogs_local_conf()->time.message.sbi.client_wait_duration); if (build) { xact->request = (*build)(context, data); if (!xact->request) { ogs_error("SBI build failed"); if (xact->discovery_option) ogs_sbi_discovery_option_free(xact->discovery_option); ogs_timer_delete(xact->t_response); ogs_pool_free(&xact_pool, xact); return NULL; } if (!xact->request->h.uri) { const char *service_name = NULL; ogs_assert(xact->service_type); service_name = ogs_sbi_service_type_to_name(xact->service_type); ogs_assert(service_name); ogs_assert(xact->request->h.service.name); /* * Make sure the service matches * between discover and build functions: * * DISCOVER : amf_ue_sbi_discover_and_send( * OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL, * BUILD : amf_npcf_am_policy_control_build_create() * message.h.service.name = * (char *)OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL; */ if (strcmp(service_name, xact->request->h.service.name) != 0) { ogs_fatal("[%s:%d] is not the same with [%s]", service_name, xact->service_type, xact->request->h.service.name); ogs_assert_if_reached(); } } } ogs_list_add(&sbi_object->xact_list, xact); return xact; } void ogs_sbi_xact_remove(ogs_sbi_xact_t *xact) { ogs_sbi_object_t *sbi_object = NULL; ogs_assert(xact); sbi_object = xact->sbi_object; ogs_assert(sbi_object); if (xact->discovery_option) ogs_sbi_discovery_option_free(xact->discovery_option); ogs_assert(xact->t_response); ogs_timer_delete(xact->t_response); if (xact->request) ogs_sbi_request_free(xact->request); if (xact->target_apiroot) ogs_free(xact->target_apiroot); ogs_list_remove(&sbi_object->xact_list, xact); ogs_pool_free(&xact_pool, xact); } void ogs_sbi_xact_remove_all(ogs_sbi_object_t *sbi_object) { ogs_sbi_xact_t *xact = NULL, *next_xact = NULL; ogs_assert(sbi_object); ogs_list_for_each_safe(&sbi_object->xact_list, next_xact, xact) ogs_sbi_xact_remove(xact); } ogs_sbi_xact_t *ogs_sbi_xact_cycle(ogs_sbi_xact_t *xact) { return ogs_pool_cycle(&xact_pool, xact); } ogs_sbi_subscription_spec_t *ogs_sbi_subscription_spec_add( OpenAPI_nf_type_e nf_type, const char *service_name) { ogs_sbi_subscription_spec_t *subscription_spec = NULL; /* Issue #2630 : The format of subscrCond is invalid. Must be 'oneOf'. */ ogs_assert(!nf_type || !service_name); ogs_pool_alloc(&subscription_spec_pool, &subscription_spec); ogs_assert(subscription_spec); memset(subscription_spec, 0, sizeof(ogs_sbi_subscription_spec_t)); if (nf_type) subscription_spec->subscr_cond.nf_type = nf_type; else if (service_name) subscription_spec->subscr_cond.service_name = ogs_strdup(service_name); else { ogs_fatal("SubscrCond must be 'oneOf'."); ogs_assert_if_reached(); } ogs_list_add(&ogs_sbi_self()->subscription_spec_list, subscription_spec); return subscription_spec; } void ogs_sbi_subscription_spec_remove( ogs_sbi_subscription_spec_t *subscription_spec) { ogs_assert(subscription_spec); ogs_list_remove(&ogs_sbi_self()->subscription_spec_list, subscription_spec); if (subscription_spec->subscr_cond.service_name) ogs_free(subscription_spec->subscr_cond.service_name); ogs_pool_free(&subscription_spec_pool, subscription_spec); } void ogs_sbi_subscription_spec_remove_all(void) { ogs_sbi_subscription_spec_t *subscription_spec = NULL; ogs_sbi_subscription_spec_t *next_subscription_spec = NULL; ogs_list_for_each_safe(&ogs_sbi_self()->subscription_spec_list, next_subscription_spec, subscription_spec) ogs_sbi_subscription_spec_remove(subscription_spec); } ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_add(void) { ogs_sbi_subscription_data_t *subscription_data = NULL; ogs_pool_alloc(&subscription_data_pool, &subscription_data); ogs_assert(subscription_data); memset(subscription_data, 0, sizeof(ogs_sbi_subscription_data_t)); ogs_list_add(&ogs_sbi_self()->subscription_data_list, subscription_data); return subscription_data; } void ogs_sbi_subscription_data_set_id( ogs_sbi_subscription_data_t *subscription_data, char *id) { ogs_assert(subscription_data); ogs_assert(id); subscription_data->id = ogs_strdup(id); ogs_assert(subscription_data->id); } void ogs_sbi_subscription_data_remove( ogs_sbi_subscription_data_t *subscription_data) { ogs_assert(subscription_data); ogs_list_remove(&ogs_sbi_self()->subscription_data_list, subscription_data); if (subscription_data->id) ogs_free(subscription_data->id); if (subscription_data->notification_uri) ogs_free(subscription_data->notification_uri); if (subscription_data->req_nf_instance_id) ogs_free(subscription_data->req_nf_instance_id); if (subscription_data->subscr_cond.service_name) ogs_free(subscription_data->subscr_cond.service_name); if (subscription_data->t_validity) ogs_timer_delete(subscription_data->t_validity); if (subscription_data->t_patch) ogs_timer_delete(subscription_data->t_patch); if (subscription_data->client) ogs_sbi_client_remove(subscription_data->client); ogs_pool_free(&subscription_data_pool, subscription_data); } void ogs_sbi_subscription_data_remove_all_by_nf_instance_id( char *nf_instance_id) { ogs_sbi_subscription_data_t *subscription_data = NULL; ogs_sbi_subscription_data_t *next_subscription_data = NULL; ogs_assert(nf_instance_id); ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list, next_subscription_data, subscription_data) { if (subscription_data->req_nf_instance_id && strcmp(subscription_data->req_nf_instance_id, nf_instance_id) == 0) { ogs_sbi_subscription_data_remove(subscription_data); } } } void ogs_sbi_subscription_data_remove_all(void) { ogs_sbi_subscription_data_t *subscription_data = NULL; ogs_sbi_subscription_data_t *next_subscription_data = NULL; ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list, next_subscription_data, subscription_data) ogs_sbi_subscription_data_remove(subscription_data); } ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_find(char *id) { ogs_sbi_subscription_data_t *subscription_data = NULL; ogs_assert(id); ogs_list_for_each(&ogs_sbi_self()->subscription_data_list, subscription_data) { ogs_assert(subscription_data->id); if (strcmp(subscription_data->id, id) == 0) break; } return subscription_data; } bool ogs_sbi_supi_in_vplmn(char *supi) { char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1]; bool home_network = false; int i; ogs_assert(supi); if (ogs_local_conf()->num_of_serving_plmn_id == 0) { return false; } ogs_extract_digit_from_string(imsi_bcd, supi); for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { char buf[OGS_PLMNIDSTRLEN]; ogs_plmn_id_to_string(&ogs_local_conf()->serving_plmn_id[i], buf); if (strncmp(imsi_bcd, buf, strlen(buf)) == 0) { home_network = true; break; } } if (home_network == false) return true; return false; } bool ogs_sbi_plmn_id_in_vplmn(ogs_plmn_id_t *plmn_id) { bool home_network = false; int i; ogs_assert(plmn_id); if (ogs_local_conf()->num_of_serving_plmn_id == 0) { return false; } if (ogs_plmn_id_mcc(plmn_id) == 0) { ogs_error("No MCC"); return false; } if (ogs_plmn_id_mnc(plmn_id) == 0) { ogs_error("No MNC"); return false; } for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { if (memcmp(&ogs_local_conf()->serving_plmn_id[i], plmn_id, OGS_PLMN_ID_LEN) == 0) { home_network = true; break; } } if (home_network == false) return true; return false; } bool ogs_sbi_fqdn_in_vplmn(char *fqdn) { bool home_network = false; int i; ogs_assert(fqdn); if (ogs_local_conf()->num_of_serving_plmn_id == 0) { return false; } if (ogs_home_network_domain_from_fqdn(fqdn) == NULL) { return false; } for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) { if (ogs_plmn_id_mcc_from_fqdn(fqdn) == ogs_plmn_id_mcc(&ogs_local_conf()->serving_plmn_id[i]) && ogs_plmn_id_mnc_from_fqdn(fqdn) == ogs_plmn_id_mnc(&ogs_local_conf()->serving_plmn_id[i])) { home_network = true; break; } } if (home_network == false) return true; return false; }