/* * 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" static void handle_nf_service( ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_service_t *NFService); static void handle_smf_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_smf_info_t *SmfInfo); static void handle_scp_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_scp_info_t *ScpInfo); static void handle_sepp_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_sepp_info_t *SeppInfo); static void handle_amf_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo); void ogs_nnrf_nfm_handle_nf_register( ogs_sbi_nf_instance_t *nf_instance, ogs_sbi_message_t *recvmsg) { OpenAPI_nf_profile_t *NFProfile = NULL; OpenAPI_lnode_t *node; ogs_assert(recvmsg); ogs_assert(nf_instance); NFProfile = recvmsg->NFProfile; if (!NFProfile) { ogs_error("No NFProfile"); return; } /* TIME : Update heartbeat from NRF */ if (NFProfile->is_heart_beat_timer == true) nf_instance->time.heartbeat_interval = NFProfile->heart_beat_timer; if (NFProfile->plmn_list) { nf_instance->num_of_plmn_id = 0; OpenAPI_list_for_each(NFProfile->plmn_list, node) { OpenAPI_plmn_id_t *PlmnId = node->data; if (PlmnId) { ogs_sbi_parse_plmn_id( &ogs_local_conf()->serving_plmn_id[ ogs_local_conf()->num_of_serving_plmn_id], PlmnId); ogs_local_conf()->num_of_serving_plmn_id++; } } } } void ogs_nnrf_nfm_handle_nf_profile( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_profile_t *NFProfile) { int rv; OpenAPI_lnode_t *node; ogs_assert(nf_instance); ogs_assert(NFProfile); ogs_assert(NFProfile->nf_instance_id); ogs_assert(NFProfile->nf_type); ogs_assert(NFProfile->nf_status); ogs_sbi_nf_instance_clear(nf_instance); nf_instance->nf_type = NFProfile->nf_type; nf_instance->nf_status = NFProfile->nf_status; if (NFProfile->is_heart_beat_timer == true) nf_instance->time.heartbeat_interval = NFProfile->heart_beat_timer; if (NFProfile->fqdn) nf_instance->fqdn = ogs_strdup(NFProfile->fqdn); if (NFProfile->is_priority == true) nf_instance->priority = NFProfile->priority; if (NFProfile->is_capacity == true) nf_instance->capacity = NFProfile->capacity; if (NFProfile->is_load == true) nf_instance->load = NFProfile->load; nf_instance->num_of_plmn_id = 0; OpenAPI_list_for_each(NFProfile->plmn_list, node) { OpenAPI_plmn_id_t *PlmnId = node->data; if (PlmnId) { ogs_sbi_parse_plmn_id( &nf_instance->plmn_id[nf_instance->num_of_plmn_id], PlmnId); nf_instance->num_of_plmn_id++; } } OpenAPI_list_for_each(NFProfile->ipv4_addresses, node) { ogs_sockaddr_t *addr = NULL; if (!node->data) { ogs_error("No IPv4 Address"); continue; } if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { rv = ogs_getaddrinfo( &addr, AF_UNSPEC, node->data, ogs_sbi_default_client_port(OpenAPI_uri_scheme_NULL), 0); if (rv != OGS_OK) { ogs_error("ogs_getaddrinfo[%s] failed", (char *)node->data); continue; } nf_instance->ipv4[nf_instance->num_of_ipv4] = addr; nf_instance->num_of_ipv4++; } } OpenAPI_list_for_each(NFProfile->ipv6_addresses, node) { ogs_sockaddr_t *addr = NULL; if (!node->data) { ogs_error("No IPv6 Address"); continue; } if (nf_instance->num_of_ipv6 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { rv = ogs_getaddrinfo( &addr, AF_UNSPEC, node->data, ogs_sbi_default_client_port(OpenAPI_uri_scheme_NULL), 0); if (rv != OGS_OK) { ogs_error("ogs_getaddrinfo[%s] failed", (char *)node->data); continue; } nf_instance->ipv6[nf_instance->num_of_ipv6] = addr; nf_instance->num_of_ipv6++; } } OpenAPI_list_for_each(NFProfile->allowed_nf_types, node) { OpenAPI_nf_type_e AllowedNfType = (uintptr_t)node->data; if (!AllowedNfType) { ogs_error("AllowedNfType"); continue; } 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] = AllowedNfType; nf_instance->num_of_allowed_nf_type++; } } OpenAPI_list_for_each(NFProfile->nf_services, node) { ogs_sbi_nf_service_t *nf_service = NULL; OpenAPI_nf_service_t *NFService = node->data; if (!NFService) { ogs_error("No NFService"); continue; } if (!NFService->service_instance_id) { ogs_error("No NFService.service_instance_id"); continue; } if (!NFService->service_name) { ogs_error("No NFService.service_name"); continue; } if (!NFService->scheme) { ogs_error("No NFService.scheme"); continue; } nf_service = ogs_sbi_nf_service_find_by_id( nf_instance, NFService->service_instance_id); if (!nf_service) { nf_service = ogs_sbi_nf_service_add( nf_instance, NFService->service_instance_id, NFService->service_name, NFService->scheme); ogs_assert(nf_service); } ogs_sbi_nf_service_clear(nf_service); handle_nf_service(nf_service, NFService); } OpenAPI_list_for_each(NFProfile->nf_service_list, node) { ogs_sbi_nf_service_t *nf_service = NULL; OpenAPI_map_t *NFServiceMap = NULL; OpenAPI_nf_service_t *NFService = node->data; NFServiceMap = node->data; if (NFServiceMap) { NFService = NFServiceMap->value; if (!NFService) { ogs_error("No NFService"); continue; } if (!NFService->service_instance_id) { ogs_error("No NFService.service_instance_id"); continue; } if (!NFService->service_name) { ogs_error("No NFService.service_name"); continue; } if (!NFService->scheme) { ogs_error("No NFService.scheme"); continue; } nf_service = ogs_sbi_nf_service_find_by_id( nf_instance, NFService->service_instance_id); if (!nf_service) { nf_service = ogs_sbi_nf_service_add( nf_instance, NFService->service_instance_id, NFService->service_name, NFService->scheme); ogs_assert(nf_service); } ogs_sbi_nf_service_clear(nf_service); handle_nf_service(nf_service, NFService); } } ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list); if (NFProfile->smf_info) handle_smf_info(nf_instance, NFProfile->smf_info); OpenAPI_list_for_each(NFProfile->smf_info_list, node) { OpenAPI_map_t *SmfInfoMap = node->data; if (SmfInfoMap && SmfInfoMap->value) handle_smf_info(nf_instance, SmfInfoMap->value); } if (NFProfile->amf_info) handle_amf_info(nf_instance, NFProfile->amf_info); OpenAPI_list_for_each(NFProfile->amf_info_list, node) { OpenAPI_map_t *AmfInfoMap = node->data; if (AmfInfoMap && AmfInfoMap->value) handle_amf_info(nf_instance, AmfInfoMap->value); } if (NFProfile->scp_info) handle_scp_info(nf_instance, NFProfile->scp_info); if (NFProfile->sepp_info) handle_sepp_info(nf_instance, NFProfile->sepp_info); } static void handle_nf_service( ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_service_t *NFService) { int rv; OpenAPI_lnode_t *node = NULL; ogs_assert(nf_service); ogs_assert(NFService); OpenAPI_list_for_each(NFService->versions, node) { OpenAPI_nf_service_version_t *NFServiceVersion = node->data; if (!NFServiceVersion) { ogs_error("No NFServiceVersion"); continue; } ogs_sbi_nf_service_add_version(nf_service, NFServiceVersion->api_version_in_uri, NFServiceVersion->api_full_version, NFServiceVersion->expiry); } if (NFService->fqdn) nf_service->fqdn = ogs_strdup(NFService->fqdn); OpenAPI_list_for_each(NFService->ip_end_points, node) { OpenAPI_ip_end_point_t *IpEndPoint = node->data; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; int port = 0; if (!IpEndPoint) { ogs_error("No IpEndPoint"); continue; } if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) { if (!IpEndPoint->is_port) port = ogs_sbi_default_client_port(nf_service->scheme); else port = IpEndPoint->port; if (IpEndPoint->ipv4_address) { rv = ogs_getaddrinfo(&addr, AF_UNSPEC, IpEndPoint->ipv4_address, port, 0); if (rv != OGS_OK) { ogs_error("ogs_getaddrinfo[%s] failed", IpEndPoint->ipv4_address); continue; } } if (IpEndPoint->ipv6_address) { rv = ogs_getaddrinfo(&addr6, AF_UNSPEC, IpEndPoint->ipv6_address, port, 0); if (rv != OGS_OK) { ogs_error("ogs_getaddrinfo[%s] failed", IpEndPoint->ipv6_address); continue; } } if (addr || addr6) { nf_service->addr[nf_service->num_of_addr]. is_port = IpEndPoint->is_port; nf_service->addr[nf_service->num_of_addr]. port = port; nf_service->addr[nf_service->num_of_addr]. ipv4 = addr; nf_service->addr[nf_service->num_of_addr]. ipv6 = addr6; nf_service->num_of_addr++; } } } OpenAPI_list_for_each(NFService->allowed_nf_types, node) { OpenAPI_nf_type_e AllowedNfType = (uintptr_t)node->data; if (!AllowedNfType) { ogs_error("AllowedNfType"); continue; } 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] = AllowedNfType; nf_service->num_of_allowed_nf_type++; } } if (NFService->is_priority == true) nf_service->priority = NFService->priority; if (NFService->is_capacity == true) nf_service->capacity = NFService->capacity; if (NFService->is_load == true) nf_service->load = NFService->load; } static void handle_smf_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_smf_info_t *SmfInfo) { ogs_sbi_nf_info_t *nf_info = NULL; OpenAPI_list_t *sNssaiSmfInfoList = NULL; OpenAPI_snssai_smf_info_item_t *sNssaiSmfInfoItem = NULL; OpenAPI_ext_snssai_t *sNssai = NULL; OpenAPI_list_t *DnnSmfInfoList = NULL; OpenAPI_dnn_smf_info_item_t *DnnSmfInfoItem = NULL; OpenAPI_list_t *TaiList = NULL; OpenAPI_tai_t *TaiItem = NULL; OpenAPI_list_t *TaiRangeList = NULL; OpenAPI_tai_range_t *TaiRangeItem = NULL; OpenAPI_list_t *TacRangeList = NULL; OpenAPI_tac_range_t *TacRangeItem = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL; ogs_assert(nf_instance); ogs_assert(SmfInfo); nf_info = ogs_sbi_nf_info_add( &nf_instance->nf_info_list, OpenAPI_nf_type_SMF); ogs_assert(nf_info); sNssaiSmfInfoList = SmfInfo->s_nssai_smf_info_list; OpenAPI_list_for_each(sNssaiSmfInfoList, node) { sNssaiSmfInfoItem = node->data; if (sNssaiSmfInfoItem) { ogs_assert(nf_info->smf.num_of_slice < OGS_MAX_NUM_OF_SLICE); DnnSmfInfoList = sNssaiSmfInfoItem->dnn_smf_info_list; OpenAPI_list_for_each(DnnSmfInfoList, node2) { DnnSmfInfoItem = node2->data; if (DnnSmfInfoItem && DnnSmfInfoItem->dnn) { int dnn_index = nf_info->smf.slice [nf_info->smf.num_of_slice].num_of_dnn; ogs_assert(dnn_index < OGS_MAX_NUM_OF_DNN); nf_info->smf.slice[nf_info->smf.num_of_slice]. dnn[dnn_index] = ogs_strdup(DnnSmfInfoItem->dnn); ogs_assert( nf_info->smf.slice[nf_info->smf.num_of_slice]. dnn[dnn_index]); nf_info->smf.slice[nf_info->smf.num_of_slice]. num_of_dnn++; } } if (!nf_info->smf.slice[nf_info->smf.num_of_slice].num_of_dnn) { ogs_error("No DNN"); continue; } sNssai = sNssaiSmfInfoItem->s_nssai; if (sNssai) { ogs_s_nssai_t *s_nssai = NULL; s_nssai = &nf_info->smf. slice[nf_info->smf.num_of_slice].s_nssai; s_nssai->sst = sNssai->sst; s_nssai->sd = ogs_s_nssai_sd_from_string(sNssai->sd); nf_info->smf.num_of_slice++; } } } if (nf_info->smf.num_of_slice == 0) { ogs_error("No S-NSSAI(DNN) in smfInfo"); ogs_sbi_nf_info_remove(&nf_instance->nf_info_list, nf_info); return; } TaiList = SmfInfo->tai_list; OpenAPI_list_for_each(TaiList, node) { TaiItem = node->data; if (TaiItem && TaiItem->plmn_id && TaiItem->tac) { ogs_5gs_tai_t *nr_tai = NULL; ogs_assert(nf_info->smf.num_of_nr_tai < OGS_MAX_NUM_OF_TAI); nr_tai = &nf_info->smf.nr_tai[nf_info->smf.num_of_nr_tai]; ogs_assert(nr_tai); ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id); nr_tai->tac = ogs_uint24_from_string(TaiItem->tac); nf_info->smf.num_of_nr_tai++; } } TaiRangeList = SmfInfo->tai_range_list; OpenAPI_list_for_each(TaiRangeList, node) { TaiRangeItem = node->data; if (TaiRangeItem && TaiRangeItem->plmn_id && TaiRangeItem->tac_range_list) { ogs_assert(nf_info->smf.num_of_nr_tai_range < OGS_MAX_NUM_OF_TAI); ogs_sbi_parse_plmn_id( &nf_info->smf.nr_tai_range [nf_info->smf.num_of_nr_tai_range].plmn_id, TaiRangeItem->plmn_id); TacRangeList = TaiRangeItem->tac_range_list; OpenAPI_list_for_each(TacRangeList, node2) { TacRangeItem = node2->data; if (TacRangeItem && TacRangeItem->start && TacRangeItem->end) { int tac_index = nf_info->smf.nr_tai_range [nf_info->smf.num_of_nr_tai_range].num_of_tac_range; ogs_assert(tac_index < OGS_MAX_NUM_OF_TAI); nf_info->smf.nr_tai_range [nf_info->smf.num_of_nr_tai_range]. start[tac_index] = ogs_uint24_from_string(TacRangeItem->start); nf_info->smf.nr_tai_range [nf_info->smf.num_of_nr_tai_range]. end[tac_index] = ogs_uint24_from_string(TacRangeItem->end); nf_info->smf.nr_tai_range [nf_info->smf.num_of_nr_tai_range]. num_of_tac_range++; } } nf_info->smf.num_of_nr_tai_range++; } } } static void handle_scp_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_scp_info_t *ScpInfo) { ogs_sbi_nf_info_t *nf_info = NULL; OpenAPI_list_t *PortList = NULL; OpenAPI_map_t *PortMap = NULL; OpenAPI_map_t *DomainInfoMap = NULL; OpenAPI_scp_domain_info_t *DomainInfo = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL; ogs_sbi_scp_info_t scp_info; ogs_assert(nf_instance); ogs_assert(ScpInfo); memset(&scp_info, 0, sizeof(scp_info)); PortList = ScpInfo->scp_ports; OpenAPI_list_for_each(PortList, node) { PortMap = node->data; if (PortMap) { if (PortMap->key) { double *port = PortMap->value; if (strcmp(PortMap->key, "http") == 0) { if (port) { scp_info.http.presence = true; scp_info.http.port = *port; } else { ogs_error("No Port Value"); } } else if (strcmp(PortMap->key, "https") == 0) { if (port) { scp_info.https.presence = true; scp_info.https.port = *port; } else { ogs_error("No Port Value"); } } else { ogs_error("Unknown Port Key = %s", PortMap->key); } } } } OpenAPI_list_for_each(ScpInfo->scp_domain_info_list, node) { DomainInfoMap = node->data; if (DomainInfoMap && DomainInfoMap->key && DomainInfoMap->value) { scp_info.domain[scp_info.num_of_domain].name = ogs_strdup(DomainInfoMap->key); DomainInfo = DomainInfoMap->value; if (DomainInfo->scp_fqdn) scp_info.domain[scp_info.num_of_domain].fqdn = ogs_strdup(DomainInfo->scp_fqdn); OpenAPI_list_for_each(DomainInfo->scp_ports, node2) { PortMap = node2->data; if (PortMap) { if (PortMap->key) { double *port = PortMap->value; if (strcmp(PortMap->key, "http") == 0) { if (port) { scp_info.domain[scp_info.num_of_domain]. http.presence = true; scp_info.domain[scp_info.num_of_domain]. http.port = *port; } else { ogs_error("No Port Value"); } } else if (strcmp(PortMap->key, "https") == 0) { if (port) { scp_info.domain[scp_info.num_of_domain]. https.presence = true; scp_info.domain[scp_info.num_of_domain]. https.port = *port; } else { ogs_error("No Port Value"); } } else { ogs_error("Unknown Port Key = %s", PortMap->key); } } } } scp_info.num_of_domain++; } } if (scp_info.http.presence || scp_info.https.presence) { nf_info = ogs_sbi_nf_info_add( &nf_instance->nf_info_list, OpenAPI_nf_type_SCP); ogs_assert(nf_info); memcpy(&nf_info->scp, &scp_info, sizeof(scp_info)); } } static void handle_sepp_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_sepp_info_t *SeppInfo) { ogs_sbi_nf_info_t *nf_info = NULL; OpenAPI_list_t *PortList = NULL; OpenAPI_map_t *PortMap = NULL; OpenAPI_lnode_t *node = NULL; ogs_port_t http, https; ogs_assert(nf_instance); ogs_assert(SeppInfo); http.port = 0; https.port = 0; http.presence = false; https.presence = false; PortList = SeppInfo->sepp_ports; OpenAPI_list_for_each(PortList, node) { PortMap = node->data; if (PortMap) { if (PortMap->key) { double *port = PortMap->value; if (strcmp(PortMap->key, "http") == 0) { if (port) { http.presence = true; http.port = *port; } else { ogs_error("No Port Value"); } } else if (strcmp(PortMap->key, "https") == 0) { if (port) { https.presence = true; https.port = *port; } else { ogs_error("No Port Value"); } } else { ogs_error("Unknown Port Key = %s", PortMap->key); } } } } if (http.presence || https.presence) { nf_info = ogs_sbi_nf_info_add( &nf_instance->nf_info_list, OpenAPI_nf_type_SEPP); ogs_assert(nf_info); nf_info->sepp.http.presence = http.presence; nf_info->sepp.http.port = http.port; nf_info->sepp.https.presence = https.presence; nf_info->sepp.https.port = https.port; } } static void handle_amf_info( ogs_sbi_nf_instance_t *nf_instance, OpenAPI_amf_info_t *AmfInfo) { ogs_sbi_nf_info_t *nf_info = NULL; OpenAPI_list_t *GuamiList = NULL; OpenAPI_guami_t *GuamiAmfInfoItem = NULL; OpenAPI_list_t *TaiList = NULL; OpenAPI_tai_t *TaiItem = NULL; OpenAPI_list_t *TaiRangeList = NULL; OpenAPI_tai_range_t *TaiRangeItem = NULL; OpenAPI_list_t *TacRangeList = NULL; OpenAPI_tac_range_t *TacRangeItem = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL; ogs_assert(nf_instance); ogs_assert(AmfInfo); nf_info = ogs_sbi_nf_info_add( &nf_instance->nf_info_list, OpenAPI_nf_type_AMF); ogs_assert(nf_info); nf_info->amf.amf_set_id = ogs_uint64_from_string(AmfInfo->amf_set_id); nf_info->amf.amf_region_id = ogs_uint64_from_string(AmfInfo->amf_region_id); GuamiList = AmfInfo->guami_list; OpenAPI_list_for_each(GuamiList, node) { GuamiAmfInfoItem = node->data; if (GuamiAmfInfoItem) { ogs_assert(nf_info->amf.num_of_guami < OGS_MAX_NUM_OF_SERVED_GUAMI); if (GuamiAmfInfoItem->amf_id && GuamiAmfInfoItem->plmn_id && GuamiAmfInfoItem->plmn_id->mnc && GuamiAmfInfoItem->plmn_id->mcc) { ogs_sbi_parse_guami( &nf_info->amf.guami[nf_info->amf.num_of_guami], GuamiAmfInfoItem); nf_info->amf.num_of_guami++; } } } TaiList = AmfInfo->tai_list; OpenAPI_list_for_each(TaiList, node) { TaiItem = node->data; if (TaiItem && TaiItem->plmn_id && TaiItem->tac) { ogs_5gs_tai_t *nr_tai = NULL; ogs_assert(nf_info->amf.num_of_nr_tai < OGS_MAX_NUM_OF_TAI); nr_tai = &nf_info->amf.nr_tai[nf_info->amf.num_of_nr_tai]; ogs_assert(nr_tai); ogs_sbi_parse_plmn_id(&nr_tai->plmn_id, TaiItem->plmn_id); nr_tai->tac = ogs_uint24_from_string(TaiItem->tac); nf_info->amf.num_of_nr_tai++; } } TaiRangeList = AmfInfo->tai_range_list; OpenAPI_list_for_each(TaiRangeList, node) { TaiRangeItem = node->data; if (TaiRangeItem && TaiRangeItem->plmn_id && TaiRangeItem->tac_range_list) { ogs_assert(nf_info->amf.num_of_nr_tai_range < OGS_MAX_NUM_OF_TAI); ogs_sbi_parse_plmn_id( &nf_info->amf.nr_tai_range [nf_info->amf.num_of_nr_tai_range].plmn_id, TaiRangeItem->plmn_id); TacRangeList = TaiRangeItem->tac_range_list; OpenAPI_list_for_each(TacRangeList, node2) { TacRangeItem = node2->data; if (TacRangeItem && TacRangeItem->start && TacRangeItem->end) { int tac_index = nf_info->amf.nr_tai_range [nf_info->amf.num_of_nr_tai_range].num_of_tac_range; ogs_assert(tac_index < OGS_MAX_NUM_OF_TAI); nf_info->amf.nr_tai_range [nf_info->amf.num_of_nr_tai_range].start[tac_index] = ogs_uint24_from_string(TacRangeItem->start); nf_info->amf.nr_tai_range [nf_info->amf.num_of_nr_tai_range].end[tac_index] = ogs_uint24_from_string(TacRangeItem->end); nf_info->amf.nr_tai_range [nf_info->amf.num_of_nr_tai_range].num_of_tac_range++; } } nf_info->amf.num_of_nr_tai_range++; } } } static void handle_validity_time( ogs_sbi_subscription_data_t *subscription_data, char *validity_time, const char *action) { ogs_time_t time, validity, patch; ogs_assert(validity_time); ogs_assert(subscription_data); ogs_assert(action); if (ogs_sbi_time_from_string(&time, validity_time) == false) { ogs_error("[%s] Subscription %s until %s [parser error]", subscription_data->id, action, validity_time); return; } validity = time - ogs_time_now(); if (validity < 0) { ogs_error("[%s] Subscription %s until %s [validity:%d.%06d]", subscription_data->id, action, validity_time, (int)ogs_time_sec(validity), (int)ogs_time_usec(validity)); return; } /* * Store subscription_data->time.validity_duration to derive NRF validity. * It will be used in ogs_nnrf_nfm_build_status_update(). * * So, you should not remove the following lines. */ subscription_data->time.validity_duration = OGS_SBI_VALIDITY_SEC(validity); if (!subscription_data->t_validity) { subscription_data->t_validity = ogs_timer_add(ogs_app()->timer_mgr, ogs_timer_subscription_validity, subscription_data); ogs_assert(subscription_data->t_validity); } ogs_timer_start(subscription_data->t_validity, validity); /* * PATCH request will be sent before VALIDITY is expired. */ #define PATCH_TIME_FROM_VALIDITY(x) ((x) / 2) patch = PATCH_TIME_FROM_VALIDITY(validity); if (!subscription_data->t_patch) { subscription_data->t_patch = ogs_timer_add(ogs_app()->timer_mgr, ogs_timer_subscription_patch, subscription_data); ogs_assert(subscription_data->t_patch); } ogs_timer_start(subscription_data->t_patch, patch); ogs_info("[%s] Subscription %s until %s " "[duration:%d,validity:%d.%06d,patch:%d.%06d]", subscription_data->id, action, validity_time, subscription_data->time.validity_duration, (int)ogs_time_sec(validity), (int)ogs_time_usec(validity), (int)ogs_time_sec(patch), (int)ogs_time_usec(patch)); } void ogs_nnrf_nfm_handle_nf_status_subscribe( ogs_sbi_subscription_data_t *subscription_data, ogs_sbi_message_t *recvmsg) { OpenAPI_subscription_data_t *SubscriptionData = NULL; ogs_assert(recvmsg); ogs_assert(subscription_data); SubscriptionData = recvmsg->SubscriptionData; if (!SubscriptionData) { ogs_error("No SubscriptionData"); return; } if (recvmsg->http.location) { int rv; ogs_sbi_message_t message; ogs_sbi_header_t header; memset(&header, 0, sizeof(header)); header.uri = recvmsg->http.location; rv = ogs_sbi_parse_header(&message, &header); if (rv != OGS_OK) { ogs_error("Cannot parse http.location [%s]", recvmsg->http.location); return; } if (!message.h.resource.component[1]) { ogs_error("No Subscription ID [%s]", recvmsg->http.location); ogs_sbi_header_free(&header); return; } ogs_sbi_subscription_data_set_id( subscription_data, message.h.resource.component[1]); ogs_sbi_header_free(&header); } else if (SubscriptionData->subscription_id) { /* * For compatibility with v2.5.x and lower versions * * Deprecated : It will be removed soon. */ ogs_sbi_subscription_data_set_id( subscription_data, SubscriptionData->subscription_id); } else { ogs_error("No Subscription ID"); return; } /* SBI Features */ if (SubscriptionData->nrf_supported_features) { subscription_data->nrf_supported_features = ogs_uint64_from_string(SubscriptionData->nrf_supported_features); } else { subscription_data->nrf_supported_features = 0; } /* Subscription Validity Time */ if (SubscriptionData->validity_time) handle_validity_time( subscription_data, SubscriptionData->validity_time, "created"); } void ogs_nnrf_nfm_handle_nf_status_update( ogs_sbi_subscription_data_t *subscription_data, ogs_sbi_message_t *recvmsg) { OpenAPI_subscription_data_t *SubscriptionData = NULL; ogs_assert(recvmsg); ogs_assert(subscription_data); SubscriptionData = recvmsg->SubscriptionData; if (!SubscriptionData) { ogs_error("No SubscriptionData"); return; } /* Subscription Validity Time */ if (SubscriptionData->validity_time) handle_validity_time( subscription_data, SubscriptionData->validity_time, "updated"); } bool ogs_nnrf_nfm_handle_nf_status_notify( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int rv; ogs_sbi_response_t *response = NULL; OpenAPI_notification_data_t *NotificationData = NULL; ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_sbi_message_t message; ogs_sbi_header_t header; ogs_assert(stream); ogs_assert(recvmsg); NotificationData = recvmsg->NotificationData; if (!NotificationData) { ogs_error("No NotificationData"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No NotificationData", NULL)); return false; } if (!NotificationData->nf_instance_uri) { ogs_error("No nfInstanceUri"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No nfInstanceUri", NULL)); return false; } memset(&header, 0, sizeof(header)); header.uri = NotificationData->nf_instance_uri; rv = ogs_sbi_parse_header(&message, &header); if (rv != OGS_OK) { ogs_error("Cannot parse nfInstanceUri [%s]", header.uri); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "Cannot parse nfInstanceUri", header.uri)); return false; } if (!message.h.resource.component[1]) { ogs_error("No nfInstanceId [%s]", header.uri); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "Cannot parse nfInstanceUri", header.uri)); ogs_sbi_header_free(&header); return false; } if (NF_INSTANCE_ID_IS_SELF(message.h.resource.component[1])) { ogs_warn("[%s] The notification is not allowed", message.h.resource.component[1]); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, recvmsg, "The notification is not allowed", message.h.resource.component[1])); ogs_sbi_header_free(&header); return false; } if (NotificationData->event == OpenAPI_notification_event_type_NF_REGISTERED) { OpenAPI_nf_profile_t *NFProfile = NULL; NFProfile = NotificationData->nf_profile; if (!NFProfile) { ogs_error("No NFProfile"); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No NFProfile", NULL)); ogs_sbi_header_free(&header); return false; } if (!NFProfile->nf_instance_id) { ogs_error("No NFProfile.NFInstanceId"); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No NFProfile.NFInstanceId", NULL)); ogs_sbi_header_free(&header); return false; } if (!NFProfile->nf_type) { ogs_error("No NFProfile.NFType"); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No NFProfile.NFType", NULL)); ogs_sbi_header_free(&header); return false; } if (!NFProfile->nf_status) { ogs_error("No NFProfile.NFStatus"); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No NFProfile.NFStatus", NULL)); ogs_sbi_header_free(&header); return false; } nf_instance = ogs_sbi_nf_instance_find(message.h.resource.component[1]); if (!nf_instance) { nf_instance = ogs_sbi_nf_instance_add(); ogs_assert(nf_instance); ogs_sbi_nf_instance_set_id( nf_instance, message.h.resource.component[1]); ogs_sbi_nf_fsm_init(nf_instance); ogs_info("(NRF-notify) NF registered [%s:%d]", nf_instance->id, nf_instance->reference_count); } else { ogs_warn("[%s] (NRF-notify) NF has already been added [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); ogs_sbi_nf_fsm_tran(nf_instance, ogs_sbi_nf_state_registered); } ogs_nnrf_nfm_handle_nf_profile(nf_instance, NFProfile); ogs_info("[%s] (NRF-notify) NF Profile updated [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_sbi_client_associate(nf_instance); switch (nf_instance->nf_type) { case OpenAPI_nf_type_SEPP: ogs_sbi_self()->sepp_instance = nf_instance; break; default: break; } } else if (NotificationData->event == OpenAPI_notification_event_type_NF_DEREGISTERED) { nf_instance = ogs_sbi_nf_instance_find(message.h.resource.component[1]); if (nf_instance) { if (OGS_OBJECT_IS_REF(nf_instance)) { /* There are references to other contexts. */ ogs_warn("[%s] (NRF-notify) NF was referenced " "in other contexts [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); ogs_sbi_nf_fsm_tran( nf_instance, ogs_sbi_nf_state_de_registered); } else { ogs_info("[%s] (NRF-notify) NF_DEREGISTERED event [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_sbi_nf_fsm_fini((nf_instance)); ogs_sbi_nf_instance_remove(nf_instance); } } else { ogs_warn("[%s] (NRF-notify) Not found", message.h.resource.component[1]); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, recvmsg, "Not found", message.h.resource.component[1])); ogs_sbi_header_free(&header); return false; } } else { char *eventstr = OpenAPI_notification_event_type_ToString( NotificationData->event); ogs_error("Not supported event [%d:%s]", NotificationData->event, eventstr ? eventstr : "Unknown"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "Not supported event", eventstr ? eventstr : "Unknown")); ogs_sbi_header_free(&header); return false; } response = ogs_sbi_build_response(recvmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_sbi_header_free(&header); return true; } void ogs_nnrf_disc_handle_nf_discover_search_result( OpenAPI_search_result_t *SearchResult) { OpenAPI_lnode_t *node = NULL; ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_assert(SearchResult); OpenAPI_list_for_each(SearchResult->nf_instances, node) { OpenAPI_nf_profile_t *NFProfile = NULL; if (!node->data) continue; NFProfile = node->data; if (!NFProfile) { ogs_error("No NFProfile"); continue; } if (!NFProfile->nf_instance_id) { ogs_error("No NFProfile.NFInstanceId"); continue; } if (!NFProfile->nf_type) { ogs_error("No NFProfile.NFType"); continue; } if (!NFProfile->nf_status) { ogs_error("No NFProfile.NFStatus"); continue; } nf_instance = ogs_sbi_nf_instance_find(NFProfile->nf_instance_id); if (!nf_instance) { nf_instance = ogs_sbi_nf_instance_add(); ogs_assert(nf_instance); ogs_sbi_nf_instance_set_id(nf_instance, NFProfile->nf_instance_id); ogs_sbi_nf_fsm_init(nf_instance); ogs_info("[%s] (NRF-discover) NF registered [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); } else { ogs_warn("[%s] (NRF-discover) NF has already been added [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_assert(OGS_FSM_STATE(&nf_instance->sm)); ogs_sbi_nf_fsm_tran(nf_instance, ogs_sbi_nf_state_registered); } if (NF_INSTANCE_ID_IS_OTHERS(nf_instance->id)) { ogs_nnrf_nfm_handle_nf_profile(nf_instance, NFProfile); ogs_sbi_client_associate(nf_instance); switch (nf_instance->nf_type) { case OpenAPI_nf_type_SEPP: ogs_sbi_self()->sepp_instance = nf_instance; break; default: break; } /* TIME : Update validity from NRF */ if (SearchResult->is_validity_period && SearchResult->validity_period) { nf_instance->time.validity_duration = SearchResult->validity_period; ogs_assert(nf_instance->t_validity); ogs_timer_start(nf_instance->t_validity, ogs_time_from_sec(nf_instance->time.validity_duration)); } else ogs_warn("[%s] NF Instance validity-time should not 0 [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); ogs_info("[%s] (NF-discover) NF Profile updated [%s:%d]", nf_instance->nf_type ? OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL", nf_instance->id, nf_instance->reference_count); } } }