/* * 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 "sbi-path.h" #include "npcf-handler.h" bool pcf_npcf_am_policy_control_handle_create(pcf_ue_t *pcf_ue, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) { bool rc; int r; OpenAPI_policy_association_request_t *PolicyAssociationRequest = NULL; OpenAPI_guami_t *Guami = NULL; OpenAPI_lnode_t *node = NULL; uint64_t supported_features = 0; ogs_sbi_server_t *server = NULL; ogs_sbi_client_t *client = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; char *fqdn = NULL; uint16_t fqdn_port = 0; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; ogs_assert(pcf_ue); ogs_assert(stream); server = ogs_sbi_server_from_stream(stream); ogs_assert(server); ogs_assert(message); PolicyAssociationRequest = message->PolicyAssociationRequest; if (!PolicyAssociationRequest) { ogs_error("[%s] No PolicyAssociationRequest", pcf_ue->supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, "[%s] No PolicyAssociationRequest", pcf_ue->supi, NULL)); return false; } if (!PolicyAssociationRequest->notification_uri) { ogs_error("[%s] No notificationUri", pcf_ue->supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, "No notificationUri", pcf_ue->supi, NULL)); return false; } if (!PolicyAssociationRequest->supi) { ogs_error("[%s] No supi", pcf_ue->supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, "No supi", pcf_ue->supi, NULL)); return false; } if (!PolicyAssociationRequest->supp_feat) { ogs_error("[%s] No suppFeat", pcf_ue->supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, "No suppFeat", pcf_ue->supi, NULL)); return false; } rc = ogs_sbi_getaddr_from_uri(&scheme, &fqdn, &fqdn_port, &addr, &addr6, PolicyAssociationRequest->notification_uri); if (rc == false || scheme == OpenAPI_uri_scheme_NULL) { ogs_error("[%s] Invalid URI [%s]", pcf_ue->supi, PolicyAssociationRequest->notification_uri); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, message, "[%s] Invalid URI", pcf_ue->supi, NULL)); return false; } if (pcf_ue->notification_uri) ogs_free(pcf_ue->notification_uri); pcf_ue->notification_uri = ogs_strdup( PolicyAssociationRequest->notification_uri); ogs_assert(pcf_ue->notification_uri); client = ogs_sbi_client_find(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC); ogs_free(fqdn); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); return false; } } OGS_SBI_SETUP_CLIENT(&pcf_ue->namf, client); ogs_free(fqdn); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); supported_features = ogs_uint64_from_string(PolicyAssociationRequest->supp_feat); pcf_ue->am_policy_control_features &= supported_features; if (PolicyAssociationRequest->gpsi) { if (pcf_ue->gpsi) ogs_free(pcf_ue->gpsi); pcf_ue->gpsi = ogs_strdup(PolicyAssociationRequest->gpsi); } pcf_ue->access_type = PolicyAssociationRequest->access_type; if (PolicyAssociationRequest->pei) { if (pcf_ue->pei) ogs_free(pcf_ue->pei); pcf_ue->pei = ogs_strdup(PolicyAssociationRequest->pei); } Guami = PolicyAssociationRequest->guami; if (Guami && Guami->amf_id && Guami->plmn_id && Guami->plmn_id->mnc && Guami->plmn_id->mcc) { ogs_sbi_parse_guami(&pcf_ue->guami, PolicyAssociationRequest->guami); } OpenAPI_list_for_each(PolicyAssociationRequest->allowed_snssais, node) { struct OpenAPI_snssai_s *Snssai = node->data; if (Snssai) { ogs_s_nssai_t s_nssai; s_nssai.sst = Snssai->sst; s_nssai.sd = ogs_s_nssai_sd_from_string(Snssai->sd); pcf_metrics_inst_by_slice_add(&pcf_ue->guami.plmn_id, &s_nssai, PCF_METR_CTR_PA_POLICYAMASSOREQ, 1); } else { ogs_error("[%s] No Snssai", pcf_ue->supi); } } if (PolicyAssociationRequest->rat_type) pcf_ue->rat_type = PolicyAssociationRequest->rat_type; pcf_ue->policy_association_request = OpenAPI_policy_association_request_copy( pcf_ue->policy_association_request, message->PolicyAssociationRequest); if (PolicyAssociationRequest->ue_ambr) pcf_ue->subscribed_ue_ambr = OpenAPI_ambr_copy( pcf_ue->subscribed_ue_ambr, PolicyAssociationRequest->ue_ambr); if (ogs_sbi_supi_in_vplmn(pcf_ue->supi) == true) { /* Visited PLMN */ OpenAPI_policy_association_t PolicyAssociation; ogs_sbi_message_t sendmsg; ogs_sbi_header_t header; ogs_sbi_response_t *response = NULL; memset(&PolicyAssociation, 0, sizeof(PolicyAssociation)); PolicyAssociation.request = pcf_ue->policy_association_request; PolicyAssociation.supp_feat = ogs_uint64_to_string(pcf_ue->am_policy_control_features); ogs_assert(PolicyAssociation.supp_feat); memset(&header, 0, sizeof(header)); header.service.name = (char *)OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL; header.api.version = (char *)OGS_SBI_API_V1; header.resource.component[0] = (char *)OGS_SBI_RESOURCE_NAME_POLICIES; header.resource.component[1] = pcf_ue->association_id; memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.PolicyAssociation = &PolicyAssociation; sendmsg.http.location = ogs_sbi_server_uri(server, &header); response = ogs_sbi_build_response( &sendmsg, OGS_SBI_HTTP_STATUS_CREATED); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(sendmsg.http.location); ogs_free(PolicyAssociation.supp_feat); return true; } else { /* Home PLMN */ r = pcf_ue_sbi_discover_and_send(OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, pcf_nudr_dr_build_query_am_data, pcf_ue, stream, NULL); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); return (r == OGS_OK); } } bool pcf_npcf_smpolicycontrol_handle_create(pcf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) { bool rc; int status = 0; int r; char *strerror = NULL; pcf_ue_t *pcf_ue = NULL; OpenAPI_sm_policy_context_data_t *SmPolicyContextData = NULL; OpenAPI_plmn_id_nid_t *servingNetwork = NULL; OpenAPI_snssai_t *sliceInfo = NULL; ogs_sbi_client_t *client = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; char *fqdn = NULL; uint16_t fqdn_port = 0; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; char *home_network_domain = NULL; ogs_assert(sess); pcf_ue = sess->pcf_ue; ogs_assert(stream); ogs_assert(message); SmPolicyContextData = message->SmPolicyContextData; if (!SmPolicyContextData) { strerror = ogs_msprintf("[%s:%d] No SmPolicyContextData", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->supi) { strerror = ogs_msprintf("[%s:%d] No supi", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->pdu_session_id) { strerror = ogs_msprintf("[%s:%d] No pduSessionId", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->pdu_session_type) { strerror = ogs_msprintf("[%s:%d] No pduSessionType", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->dnn) { strerror = ogs_msprintf("[%s:%d] No dnn", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->notification_uri) { strerror = ogs_msprintf("[%s:%d] No notificationUri", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!SmPolicyContextData->ipv4_address && !SmPolicyContextData->ipv6_address_prefix) { strerror = ogs_msprintf( "[%s:%d] No IPv4 address[%p] or IPv6 prefix[%p]", pcf_ue->supi, sess->psi, SmPolicyContextData->ipv4_address, SmPolicyContextData->ipv6_address_prefix); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } sliceInfo = SmPolicyContextData->slice_info; if (!sliceInfo) { strerror = ogs_msprintf("[%s:%d] No sliceInfo", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!sliceInfo->sst) { strerror = ogs_msprintf("[%s:%d] No sliceInfo->sst", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } servingNetwork = SmPolicyContextData->serving_network; if (servingNetwork) { if (!servingNetwork->mcc) { strerror = ogs_msprintf("[%s:%d] No servingNetwork->mcc", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!servingNetwork->mnc) { strerror = ogs_msprintf("[%s:%d] No servingNetwork->mnc", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } } else { ogs_warn("No servingNetwork"); } rc = ogs_sbi_getaddr_from_uri(&scheme, &fqdn, &fqdn_port, &addr, &addr6, SmPolicyContextData->notification_uri); if (rc == false || scheme == OpenAPI_uri_scheme_NULL) { strerror = ogs_msprintf("[%s:%d] Invalid URI [%s]", pcf_ue->supi, sess->psi, SmPolicyContextData->notification_uri); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (SmPolicyContextData->supp_feat) { uint64_t supported_features = ogs_uint64_from_string(SmPolicyContextData->supp_feat); sess->smpolicycontrol_features &= supported_features; } else { sess->smpolicycontrol_features = 0; } sess->pdu_session_type = SmPolicyContextData->pdu_session_type; /* Serving PLMN & Home PLMN */ if (servingNetwork) { sess->serving.presence = true; ogs_sbi_parse_plmn_id_nid(&sess->serving.plmn_id, servingNetwork); sess->home.presence = true; memcpy(&sess->home.plmn_id, &sess->serving.plmn_id, OGS_PLMN_ID_LEN); } /* * TS29.512 * 5 Npcf_SMPolicyControl Service API * 5.6 Data Model * 5.6.2 Structured data types * Table 5.6.2.3-1: Definition of type SmPolicyContextData * * NAME: dnn * Data type: Dnn * P: M * Cardinality: 1 * The DNN of the PDU session, a full DNN with both the Network Identifier * and Operator Identifier, or a DNN with the Network Identifier only */ home_network_domain = ogs_home_network_domain_from_fqdn( SmPolicyContextData->dnn); if (home_network_domain) { char dnn_network_identifer[OGS_MAX_DNN_LEN+1]; uint16_t mcc = 0, mnc = 0; ogs_assert(home_network_domain > SmPolicyContextData->dnn); ogs_cpystrn(dnn_network_identifer, SmPolicyContextData->dnn, ogs_min(OGS_MAX_DNN_LEN, home_network_domain - SmPolicyContextData->dnn)); if (sess->dnn) ogs_free(sess->dnn); sess->dnn = ogs_strdup(dnn_network_identifer); ogs_assert(sess->dnn); if (sess->full_dnn) ogs_free(sess->full_dnn); sess->full_dnn = ogs_strdup(SmPolicyContextData->dnn); ogs_assert(sess->full_dnn); mcc = ogs_plmn_id_mcc_from_fqdn(sess->full_dnn); mnc = ogs_plmn_id_mnc_from_fqdn(sess->full_dnn); /* * To generate the Home PLMN ID of the SMF-UE, * the length of the MNC is obtained * by comparing the MNC part of the SUPI and full-DNN. */ if (mcc && mnc && strncmp(pcf_ue->supi, "imsi-", strlen("imsi-")) == 0) { int mnc_len = 0; char buf[OGS_PLMNIDSTRLEN]; ogs_snprintf(buf, OGS_PLMNIDSTRLEN, "%03d%02d", mcc, mnc); if (strncmp(pcf_ue->supi + 5, buf, strlen(buf)) == 0) mnc_len = 2; ogs_snprintf(buf, OGS_PLMNIDSTRLEN, "%03d%03d", mcc, mnc); if (strncmp(pcf_ue->supi + 5, buf, strlen(buf)) == 0) mnc_len = 3; /* Change Home PLMN for VPLMN */ if (mnc_len == 2 || mnc_len == 3) { if (sess->home.presence == true) ogs_plmn_id_build(&sess->home.plmn_id, mcc, mnc, mnc_len); } } } else { if (sess->dnn) ogs_free(sess->dnn); sess->dnn = ogs_strdup(SmPolicyContextData->dnn); ogs_assert(sess->dnn); if (sess->full_dnn) ogs_free(sess->full_dnn); sess->full_dnn = NULL; } if (sess->notification_uri) ogs_free(sess->notification_uri); sess->notification_uri = ogs_strdup(SmPolicyContextData->notification_uri); ogs_assert(sess->notification_uri); client = ogs_sbi_client_find(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { strerror = ogs_msprintf("%s: ogs_sbi_client_add() failed", OGS_FUNC); status = OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR; ogs_freeaddrinfo(addr); goto cleanup; } } OGS_SBI_SETUP_CLIENT(&sess->nsmf, client); ogs_free(fqdn); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); if (SmPolicyContextData->ipv4_address) ogs_assert(true == pcf_sess_set_ipv4addr(sess, SmPolicyContextData->ipv4_address)); if (SmPolicyContextData->ipv6_address_prefix) ogs_assert(true == pcf_sess_set_ipv6prefix( sess, SmPolicyContextData->ipv6_address_prefix)); if (SmPolicyContextData->ipv4_frame_route_list) { OpenAPI_lnode_t *node = NULL; OpenAPI_clear_and_free_string_list(sess->ipv4_frame_route_list); sess->ipv4_frame_route_list = OpenAPI_list_create(); OpenAPI_list_for_each(SmPolicyContextData->ipv4_frame_route_list, node) { if (!node->data) continue; OpenAPI_list_add(sess->ipv4_frame_route_list, ogs_strdup(node->data)); } } if (SmPolicyContextData->ipv6_frame_route_list) { OpenAPI_lnode_t *node = NULL; OpenAPI_clear_and_free_string_list(sess->ipv6_frame_route_list); sess->ipv6_frame_route_list = OpenAPI_list_create(); OpenAPI_list_for_each(SmPolicyContextData->ipv6_frame_route_list, node) { if (!node->data) continue; OpenAPI_list_add(sess->ipv6_frame_route_list, ogs_strdup(node->data)); } } sess->s_nssai.sst = sliceInfo->sst; sess->s_nssai.sd = ogs_s_nssai_sd_from_string(sliceInfo->sd); pcf_metrics_inst_by_slice_add(&pcf_ue->guami.plmn_id, &sess->s_nssai, PCF_METR_GAUGE_PA_SESSIONNBR, 1); pcf_metrics_inst_by_slice_add(&pcf_ue->guami.plmn_id, &sess->s_nssai, PCF_METR_CTR_PA_POLICYSMASSOREQ, 1); if (SmPolicyContextData->subs_sess_ambr) sess->subscribed_sess_ambr = OpenAPI_ambr_copy( sess->subscribed_sess_ambr, SmPolicyContextData->subs_sess_ambr); if (SmPolicyContextData->subs_def_qos) sess->subscribed_default_qos = OpenAPI_subscribed_default_qos_copy( sess->subscribed_default_qos, SmPolicyContextData->subs_def_qos); if (ogs_sbi_supi_in_vplmn(pcf_ue->supi) == true) { /* Visited PLMN */ ogs_sbi_nf_instance_t *nf_instance = NULL; ogs_sbi_service_type_e service_type = OGS_SBI_SERVICE_TYPE_NULL; service_type = OGS_SBI_SERVICE_TYPE_NPCF_POLICYAUTHORIZATION; nf_instance = OGS_SBI_GET_NF_INSTANCE( sess->sbi.service_type_array[service_type]); if (!nf_instance) { OpenAPI_nf_type_e requester_nf_type = NF_INSTANCE_TYPE(ogs_sbi_self()->nf_instance); ogs_assert(requester_nf_type); nf_instance = ogs_sbi_nf_instance_find_by_service_type( service_type, requester_nf_type); if (nf_instance) OGS_SBI_SETUP_NF_INSTANCE( sess->sbi.service_type_array[service_type], nf_instance); } if (nf_instance) { r = pcf_sess_sbi_discover_and_send( OGS_SBI_SERVICE_TYPE_NBSF_MANAGEMENT, NULL, pcf_nbsf_management_build_register, sess, stream, nf_instance); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); } else { r = pcf_sess_sbi_discover_only(sess, stream, service_type); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); } return (r == OGS_OK); } else { /* Home PLMN */ r = pcf_sess_sbi_discover_and_send( OGS_SBI_SERVICE_TYPE_NUDR_DR, NULL, pcf_nudr_dr_build_query_sm_data, sess, stream, NULL); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); return (r == OGS_OK); } cleanup: ogs_assert(status); ogs_assert(strerror); ogs_error("%s", strerror); /* * TS29.512 * 4.2.2.2 SM Policy Association establishment * * If the PCF is, due to incomplete, erroneous or missing * information (e.g. QoS, RAT type, subscriber information) * not able to provision a policy decision as response to * the request for PCC rules by the SMF, the PCF may reject * the request and include in an HTTP "400 Bad Request" * response message the "cause" attribute of the ProblemDetails * data structure set to "ERROR_INITIAL_PARAMETERS". */ ogs_assert(true == ogs_sbi_server_send_error(stream, status, message, strerror, NULL, "ERROR_INITIAL_PARAMETERS")); ogs_free(strerror); return false; } bool pcf_npcf_smpolicycontrol_handle_delete(pcf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *message) { int r; int status = 0; char *strerror = NULL; pcf_ue_t *pcf_ue = NULL; pcf_app_t *app_session = NULL; OpenAPI_sm_policy_delete_data_t *SmPolicyDeleteData = NULL; ogs_assert(sess); pcf_ue = sess->pcf_ue; ogs_assert(stream); ogs_assert(message); SmPolicyDeleteData = message->SmPolicyDeleteData; if (!SmPolicyDeleteData) { strerror = ogs_msprintf("[%s:%d] No SmPolicyDeleteData", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } ogs_list_for_each(&sess->app_list, app_session) { pcf_sbi_send_policyauthorization_terminate_notify(app_session); } if (pcf_sessions_number_by_snssai_and_dnn( pcf_ue, &sess->s_nssai, sess->dnn) > 1) { ogs_sbi_message_t sendmsg; memset(&sendmsg, 0, sizeof(sendmsg)); ogs_sbi_response_t *response = ogs_sbi_build_response( &sendmsg, OGS_SBI_HTTP_STATUS_NO_CONTENT); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); } else { r = pcf_sess_sbi_discover_and_send( OGS_SBI_SERVICE_TYPE_NBSF_MANAGEMENT, NULL, pcf_nbsf_management_build_de_register, sess, stream, NULL); ogs_expect(r == OGS_OK); ogs_assert(r != OGS_ERROR); } return true; cleanup: ogs_assert(status); ogs_assert(strerror); ogs_error("%s", strerror); ogs_assert(true == ogs_sbi_server_send_error(stream, status, message, strerror, NULL, NULL)); ogs_free(strerror); return false; } bool pcf_npcf_policyauthorization_handle_create(pcf_sess_t *sess, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { bool rc; int i, j, rv, status = 0; char *strerror = NULL; pcf_ue_t *pcf_ue = NULL; pcf_app_t *app_session = NULL; ogs_sbi_client_t *client = NULL; OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL; char *fqdn = NULL; uint16_t fqdn_port = 0; ogs_sockaddr_t *addr = NULL, *addr6 = NULL; OpenAPI_app_session_context_t *AppSessionContext = NULL; OpenAPI_app_session_context_req_data_t *AscReqData = NULL; uint64_t supported_features = 0; ogs_sbi_server_t *server = NULL; ogs_sbi_header_t header; ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; ogs_session_data_t session_data; ogs_ims_data_t ims_data; ogs_media_component_t *media_component = NULL; ogs_media_sub_component_t *sub = NULL; OpenAPI_list_t *MediaComponentList = NULL; OpenAPI_map_t *MediaComponentMap = NULL; OpenAPI_media_component_t *MediaComponent = NULL; OpenAPI_list_t *SubComponentList = NULL; OpenAPI_map_t *SubComponentMap = NULL; OpenAPI_media_sub_component_t *SubComponent = NULL; OpenAPI_list_t *fDescList = NULL; OpenAPI_sm_policy_decision_t SmPolicyDecision; OpenAPI_list_t *PccRuleList = NULL; OpenAPI_map_t *PccRuleMap = NULL; OpenAPI_pcc_rule_t *PccRule = NULL; OpenAPI_list_t *QosDecisionList = NULL; OpenAPI_map_t *QosDecisionMap = NULL; OpenAPI_qos_data_t *QosData = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL, *node3 = NULL; ogs_assert(sess); pcf_ue = sess->pcf_ue; ogs_assert(stream); ogs_assert(recvmsg); server = ogs_sbi_server_from_stream(stream); ogs_assert(server); memset(&ims_data, 0, sizeof(ims_data)); memset(&session_data, 0, sizeof(ogs_session_data_t)); AppSessionContext = recvmsg->AppSessionContext; if (!AppSessionContext) { strerror = ogs_msprintf("[%s:%d] No AppSessionContext", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } AscReqData = AppSessionContext->asc_req_data; if (!AscReqData) { strerror = ogs_msprintf("[%s:%d] No AscReqData", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!AscReqData->supp_feat) { strerror = ogs_msprintf("[%s:%d] No AscReqData->suppFeat", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!AscReqData->notif_uri) { strerror = ogs_msprintf("[%s:%d] No AscReqData->notifUri", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!AscReqData->med_components) { strerror = ogs_msprintf("[%s:%d] No AscReqData->MediaCompoenent", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } rc = ogs_sbi_getaddr_from_uri(&scheme, &fqdn, &fqdn_port, &addr, &addr6, AscReqData->notif_uri); if (rc == false || scheme == OpenAPI_uri_scheme_NULL) { strerror = ogs_msprintf("[%s:%d] Invalid URI [%s]", pcf_ue->supi, sess->psi, AscReqData->notif_uri); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } supported_features = ogs_uint64_from_string(AscReqData->supp_feat); sess->policyauthorization_features &= supported_features; if (sess->policyauthorization_features != supported_features) { ogs_free(AscReqData->supp_feat); AscReqData->supp_feat = ogs_uint64_to_string(sess->policyauthorization_features); ogs_assert(AscReqData->supp_feat); } MediaComponentList = AscReqData->med_components; OpenAPI_list_for_each(MediaComponentList, node) { MediaComponentMap = node->data; if (MediaComponentMap) { MediaComponent = MediaComponentMap->value; if (MediaComponent) { if (ims_data.num_of_media_component >= OGS_ARRAY_SIZE(ims_data.media_component)) { ogs_error("OVERFLOW ims_data.num_of_media_component " "[%d:%d:%d]", ims_data.num_of_media_component, OGS_MAX_NUM_OF_MEDIA_COMPONENT, (int)OGS_ARRAY_SIZE(ims_data.media_component)); break; } media_component = &ims_data. media_component[ims_data.num_of_media_component]; media_component->media_component_number = MediaComponent->med_comp_n; media_component->media_type = MediaComponent->med_type; if (MediaComponent->mar_bw_dl) media_component->max_requested_bandwidth_dl = ogs_sbi_bitrate_from_string(MediaComponent->mar_bw_dl); if (MediaComponent->mar_bw_ul) media_component->max_requested_bandwidth_ul = ogs_sbi_bitrate_from_string(MediaComponent->mar_bw_ul); if (MediaComponent->mir_bw_dl) media_component->min_requested_bandwidth_dl = ogs_sbi_bitrate_from_string(MediaComponent->mir_bw_dl); if (MediaComponent->mir_bw_ul) media_component->min_requested_bandwidth_ul = ogs_sbi_bitrate_from_string(MediaComponent->mir_bw_ul); if (MediaComponent->rr_bw) media_component->rr_bandwidth = ogs_sbi_bitrate_from_string(MediaComponent->rr_bw); if (MediaComponent->rs_bw) media_component->rs_bandwidth = ogs_sbi_bitrate_from_string(MediaComponent->rs_bw); media_component->flow_status = MediaComponent->f_status; SubComponentList = MediaComponent->med_sub_comps; OpenAPI_list_for_each(SubComponentList, node2) { if (media_component->num_of_sub >= OGS_ARRAY_SIZE(media_component->sub)) { ogs_error("OVERFLOW media_component->num_of_sub " "[%d:%d:%d]", media_component->num_of_sub, OGS_MAX_NUM_OF_MEDIA_SUB_COMPONENT, (int)OGS_ARRAY_SIZE(media_component->sub)); break; } sub = &media_component->sub[media_component->num_of_sub]; SubComponentMap = node2->data; if (SubComponentMap) { SubComponent = SubComponentMap->value; if (SubComponent) { sub->flow_number = SubComponent->f_num; sub->flow_usage = SubComponent->flow_usage; fDescList = SubComponent->f_descs; OpenAPI_list_for_each(fDescList, node3) { ogs_flow_t *flow = NULL; if (sub->num_of_flow >= OGS_ARRAY_SIZE(sub->flow)) { ogs_error( "OVERFLOW sub->num_of_flow [%d:%d:%d]", sub->num_of_flow, OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT, (int)OGS_ARRAY_SIZE(sub->flow)); break; } flow = &sub->flow[sub->num_of_flow]; if (node3->data) { flow->description = ogs_strdup(node3->data); ogs_assert(flow->description); sub->num_of_flow++; } } media_component->num_of_sub++; } } } ims_data.num_of_media_component++; } } } app_session = pcf_app_add(sess); ogs_assert(app_session); if (app_session->notif_uri) ogs_free(app_session->notif_uri); app_session->notif_uri = ogs_strdup(AscReqData->notif_uri); ogs_assert(app_session->notif_uri); client = ogs_sbi_client_find(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC); client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6); if (!client) { strerror = ogs_msprintf("%s: ogs_sbi_client_add() failed", OGS_FUNC); status = OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR; ogs_freeaddrinfo(addr); goto cleanup; } } OGS_SBI_SETUP_CLIENT(&app_session->naf, client); ogs_free(fqdn); ogs_freeaddrinfo(addr); ogs_freeaddrinfo(addr6); rv = pcf_db_qos_data( pcf_ue->supi, sess->home.presence == true ? &sess->home.plmn_id : NULL, &sess->s_nssai, sess->dnn, &session_data); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] Cannot find SUPI in DB", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_NOT_FOUND; goto cleanup; } memset(&SmPolicyDecision, 0, sizeof(SmPolicyDecision)); PccRuleList = OpenAPI_list_create(); ogs_assert(PccRuleList); QosDecisionList = OpenAPI_list_create(); ogs_assert(QosDecisionList); for (i = 0; i < ims_data.num_of_media_component; i++) { int flow_presence = 0; ogs_pcc_rule_t *pcc_rule = NULL; ogs_pcc_rule_t *db_pcc_rule = NULL; uint8_t qos_index = 0; ogs_media_component_t *media_component = &ims_data.media_component[i]; if (media_component->media_type == OpenAPI_media_type_NULL) { strerror = ogs_msprintf("[%s:%d] Media-Type is Required", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } switch(media_component->media_type) { case OpenAPI_media_type_AUDIO: qos_index = OGS_QOS_INDEX_1; break; case OpenAPI_media_type_VIDEO: qos_index = OGS_QOS_INDEX_2; break; case OpenAPI_media_type_CONTROL: qos_index = OGS_QOS_INDEX_5; break; default: strerror = ogs_msprintf("[%s:%d] Unknown Media-Type [%d]", pcf_ue->supi, sess->psi, media_component->media_type); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } for (j = 0; j < session_data.num_of_pcc_rule; j++) { if (session_data.pcc_rule[j].qos.index == qos_index) { db_pcc_rule = &session_data.pcc_rule[j]; break; } } if (!db_pcc_rule && (media_component->media_type == OpenAPI_media_type_CONTROL)) { /* * Check for default bearer for IMS signalling * QCI 5 and ARP 1 */ if (session_data.session.qos.index != OGS_QOS_INDEX_5 || session_data.session.qos.arp.priority_level != 1) { strerror = ogs_msprintf("[%s:%d] CHECK WEBUI : " "Even the Default Bearer(QCI:%d,ARP:%d) " "cannot support IMS signalling.", pcf_ue->supi, sess->psi, session_data.session.qos.index, session_data.session.qos.arp.priority_level); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } else { continue; } } if (!db_pcc_rule) { strerror = ogs_msprintf("[%s:%d] CHECK WEBUI : " "No PCC Rule in DB [QoS Index:%d] - " "Please add PCC Rule using WEBUI", pcf_ue->supi, sess->psi, qos_index); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } for (j = 0; j < app_session->num_of_pcc_rule; j++) { if (app_session->pcc_rule[j].qos.index == qos_index) { pcc_rule = &app_session->pcc_rule[j]; break; } } if (!pcc_rule) { pcc_rule = &app_session->pcc_rule[app_session->num_of_pcc_rule]; ogs_assert(pcc_rule); pcc_rule->id = ogs_msprintf("%s-a%s", db_pcc_rule->id, app_session->app_session_id); ogs_assert(pcc_rule->id); memcpy(&pcc_rule->qos, &db_pcc_rule->qos, sizeof(ogs_qos_t)); pcc_rule->flow_status = db_pcc_rule->flow_status; pcc_rule->precedence = db_pcc_rule->precedence; /* Install Flow */ flow_presence = 1; rv = ogs_pcc_rule_install_flow_from_media( pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] install_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } app_session->num_of_pcc_rule++; } else { int count = 0; /* Check Flow */ count = ogs_pcc_rule_num_of_flow_equal_to_media( pcc_rule, media_component); if (count == -1) { strerror = ogs_msprintf("[%s:%d] matched_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } if (pcc_rule->num_of_flow != count) { /* Re-install Flow */ flow_presence = 1; rv = ogs_pcc_rule_install_flow_from_media( pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] re-install_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } } } /* Update QoS */ rv = ogs_pcc_rule_update_qos_from_media(pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] update_qos() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } /* if we failed to get QoS from IMS, apply WEBUI QoS */ if (pcc_rule->qos.mbr.downlink == 0) pcc_rule->qos.mbr.downlink = db_pcc_rule->qos.mbr.downlink; if (pcc_rule->qos.mbr.uplink == 0) pcc_rule->qos.mbr.uplink = db_pcc_rule->qos.mbr.uplink; if (pcc_rule->qos.gbr.downlink == 0) pcc_rule->qos.gbr.downlink = db_pcc_rule->qos.gbr.downlink; if (pcc_rule->qos.gbr.uplink == 0) pcc_rule->qos.gbr.uplink = db_pcc_rule->qos.gbr.uplink; /************************************************************** * Build PCC Rule & QoS Decision *************************************************************/ PccRule = ogs_sbi_build_pcc_rule(pcc_rule, flow_presence); ogs_assert(PccRule->pcc_rule_id); PccRuleMap = OpenAPI_map_create(PccRule->pcc_rule_id, PccRule); ogs_assert(PccRuleMap); OpenAPI_list_add(PccRuleList, PccRuleMap); QosData = ogs_sbi_build_qos_data(pcc_rule); ogs_assert(QosData); ogs_assert(QosData->qos_id); QosDecisionMap = OpenAPI_map_create(QosData->qos_id, QosData); ogs_assert(QosDecisionMap); OpenAPI_list_add(QosDecisionList, QosDecisionMap); } if (PccRuleList->count) SmPolicyDecision.pcc_rules = PccRuleList; if (QosDecisionList->count) SmPolicyDecision.qos_decs = QosDecisionList; memset(&sendmsg, 0, sizeof(sendmsg)); memset(&header, 0, sizeof(header)); header.service.name = (char *)OGS_SBI_SERVICE_NAME_NPCF_POLICYAUTHORIZATION; header.api.version = (char *)OGS_SBI_API_V1; header.resource.component[0] = (char *)OGS_SBI_RESOURCE_NAME_APP_SESSIONS; header.resource.component[1] = (char *)app_session->app_session_id; sendmsg.http.location = ogs_sbi_server_uri(server, &header); ogs_assert(sendmsg.http.location); sendmsg.AppSessionContext = recvmsg->AppSessionContext; response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_CREATED); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); ogs_free(sendmsg.http.location); if (PccRuleList->count || QosDecisionList->count) { ogs_assert(true == pcf_sbi_send_smpolicycontrol_update_notify( sess, &SmPolicyDecision)); } OpenAPI_list_for_each(PccRuleList, node) { PccRuleMap = node->data; if (PccRuleMap) { PccRule = PccRuleMap->value; if (PccRule) ogs_sbi_free_pcc_rule(PccRule); ogs_free(PccRuleMap); } } OpenAPI_list_free(PccRuleList); OpenAPI_list_for_each(QosDecisionList, node) { QosDecisionMap = node->data; if (QosDecisionMap) { QosData = QosDecisionMap->value; if (QosData) ogs_sbi_free_qos_data(QosData); ogs_free(QosDecisionMap); } } OpenAPI_list_free(QosDecisionList); ogs_ims_data_free(&ims_data); OGS_SESSION_DATA_FREE(&session_data); return true; cleanup: ogs_assert(status); ogs_assert(strerror); ogs_error("%s", strerror); ogs_assert(true == ogs_sbi_server_send_error(stream, status, recvmsg, strerror, NULL, NULL)); ogs_free(strerror); OpenAPI_list_for_each(PccRuleList, node) { PccRuleMap = node->data; if (PccRuleMap) { PccRule = PccRuleMap->value; if (PccRule) ogs_sbi_free_pcc_rule(PccRule); ogs_free(PccRuleMap); } } OpenAPI_list_free(PccRuleList); OpenAPI_list_for_each(QosDecisionList, node) { QosDecisionMap = node->data; if (QosDecisionMap) { QosData = QosDecisionMap->value; if (QosData) ogs_sbi_free_qos_data(QosData); ogs_free(QosDecisionMap); } } OpenAPI_list_free(QosDecisionList); ogs_ims_data_free(&ims_data); OGS_SESSION_DATA_FREE(&session_data); return false; } bool pcf_npcf_policyauthorization_handle_update( pcf_sess_t *sess, pcf_app_t *app_session, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int i, j, rv, status = 0; char *strerror = NULL; pcf_ue_t *pcf_ue = NULL; OpenAPI_app_session_context_update_data_patch_t *AppSessionContextUpdateDataPatch = NULL; OpenAPI_app_session_context_update_data_t *AscUpdateData = NULL; ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; ogs_session_data_t session_data; ogs_ims_data_t ims_data; ogs_media_component_t *media_component = NULL; ogs_media_sub_component_t *sub = NULL; OpenAPI_list_t *MediaComponentList = NULL; OpenAPI_map_t *MediaComponentMap = NULL; OpenAPI_media_component_rm_t *MediaComponent = NULL; OpenAPI_list_t *SubComponentList = NULL; OpenAPI_map_t *SubComponentMap = NULL; OpenAPI_media_sub_component_rm_t *SubComponent = NULL; OpenAPI_list_t *fDescList = NULL; OpenAPI_sm_policy_decision_t SmPolicyDecision; OpenAPI_list_t *PccRuleList = NULL; OpenAPI_map_t *PccRuleMap = NULL; OpenAPI_pcc_rule_t *PccRule = NULL; OpenAPI_list_t *QosDecisionList = NULL; OpenAPI_map_t *QosDecisionMap = NULL; OpenAPI_qos_data_t *QosData = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL, *node3 = NULL; ogs_assert(sess); pcf_ue = sess->pcf_ue; ogs_assert(app_session); ogs_assert(stream); ogs_assert(recvmsg); memset(&ims_data, 0, sizeof(ims_data)); memset(&session_data, 0, sizeof(ogs_session_data_t)); AppSessionContextUpdateDataPatch = recvmsg->AppSessionContextUpdateDataPatch; if (!AppSessionContextUpdateDataPatch) { strerror = ogs_msprintf("[%s:%d] No AppSessionContextUpdateDataPatch", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } AscUpdateData = AppSessionContextUpdateDataPatch->asc_req_data; if (!AscUpdateData) { strerror = ogs_msprintf("[%s:%d] No AscUpdateData", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (!AscUpdateData->med_components) { strerror = ogs_msprintf("[%s:%d] No AscUpdateData->MediaCompoenent", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } MediaComponentList = AscUpdateData->med_components; OpenAPI_list_for_each(MediaComponentList, node) { MediaComponentMap = node->data; if (MediaComponentMap) { MediaComponent = MediaComponentMap->value; if (MediaComponent) { if (ims_data.num_of_media_component >= OGS_ARRAY_SIZE(ims_data.media_component)) { ogs_error("OVERFLOW ims_data.num_of_media_component " "[%d:%d:%d]", ims_data.num_of_media_component, OGS_MAX_NUM_OF_MEDIA_COMPONENT, (int)OGS_ARRAY_SIZE(ims_data.media_component)); break; } media_component = &ims_data. media_component[ims_data.num_of_media_component]; media_component->media_component_number = MediaComponent->med_comp_n; media_component->media_type = MediaComponent->med_type; if (MediaComponent->mar_bw_dl) media_component->max_requested_bandwidth_dl = ogs_sbi_bitrate_from_string(MediaComponent->mar_bw_dl); if (MediaComponent->mar_bw_ul) media_component->max_requested_bandwidth_ul = ogs_sbi_bitrate_from_string(MediaComponent->mar_bw_ul); if (MediaComponent->mir_bw_dl) media_component->min_requested_bandwidth_dl = ogs_sbi_bitrate_from_string(MediaComponent->mir_bw_dl); if (MediaComponent->mir_bw_ul) media_component->min_requested_bandwidth_ul = ogs_sbi_bitrate_from_string(MediaComponent->mir_bw_ul); if (MediaComponent->rr_bw) media_component->rr_bandwidth = ogs_sbi_bitrate_from_string(MediaComponent->rr_bw); if (MediaComponent->rs_bw) media_component->rs_bandwidth = ogs_sbi_bitrate_from_string(MediaComponent->rs_bw); media_component->flow_status = MediaComponent->f_status; SubComponentList = MediaComponent->med_sub_comps; OpenAPI_list_for_each(SubComponentList, node2) { if (media_component->num_of_sub >= OGS_ARRAY_SIZE(media_component->sub)) { ogs_error("OVERFLOW media_component->num_of_sub " "[%d:%d:%d]", media_component->num_of_sub, OGS_MAX_NUM_OF_MEDIA_SUB_COMPONENT, (int)OGS_ARRAY_SIZE(media_component->sub)); break; } sub = &media_component->sub[media_component->num_of_sub]; SubComponentMap = node2->data; if (SubComponentMap) { SubComponent = SubComponentMap->value; if (SubComponent) { sub->flow_number = SubComponent->f_num; sub->flow_usage = SubComponent->flow_usage; fDescList = SubComponent->f_descs; OpenAPI_list_for_each(fDescList, node3) { ogs_flow_t *flow = NULL; if (sub->num_of_flow >= OGS_ARRAY_SIZE(sub->flow)) { ogs_error( "OVERFLOW sub->num_of_flow [%d:%d:%d]", sub->num_of_flow, OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT, (int)OGS_ARRAY_SIZE(sub->flow)); break; } flow = &sub->flow[sub->num_of_flow]; if (node3->data) { flow->description = ogs_strdup(node3->data); ogs_assert(flow->description); sub->num_of_flow++; } } media_component->num_of_sub++; } } } ims_data.num_of_media_component++; } } } rv = pcf_db_qos_data( pcf_ue->supi, sess->home.presence == true ? &sess->home.plmn_id : NULL, &sess->s_nssai, sess->dnn, &session_data); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] Cannot find SUPI in DB", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_NOT_FOUND; goto cleanup; } memset(&SmPolicyDecision, 0, sizeof(SmPolicyDecision)); PccRuleList = OpenAPI_list_create(); ogs_assert(PccRuleList); QosDecisionList = OpenAPI_list_create(); ogs_assert(QosDecisionList); for (i = 0; i < ims_data.num_of_media_component; i++) { int flow_presence = 0; ogs_pcc_rule_t *pcc_rule = NULL; ogs_pcc_rule_t *db_pcc_rule = NULL; uint8_t qos_index = 0; ogs_media_component_t *media_component = &ims_data.media_component[i]; if (media_component->media_type == OpenAPI_media_type_NULL) { strerror = ogs_msprintf("[%s:%d] Media-Type is Required", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } switch(media_component->media_type) { case OpenAPI_media_type_AUDIO: qos_index = OGS_QOS_INDEX_1; break; case OpenAPI_media_type_VIDEO: qos_index = OGS_QOS_INDEX_2; break; case OpenAPI_media_type_CONTROL: qos_index = OGS_QOS_INDEX_5; break; default: strerror = ogs_msprintf("[%s:%d] Unknown Media-Type [%d]", pcf_ue->supi, sess->psi, media_component->media_type); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } for (j = 0; j < session_data.num_of_pcc_rule; j++) { if (session_data.pcc_rule[j].qos.index == qos_index) { db_pcc_rule = &session_data.pcc_rule[j]; break; } } if (!db_pcc_rule && (media_component->media_type == OpenAPI_media_type_CONTROL)) { /* * Check for default bearer for IMS signalling * QCI 5 and ARP 1 */ if (session_data.session.qos.index != OGS_QOS_INDEX_5 || session_data.session.qos.arp.priority_level != 1) { strerror = ogs_msprintf("[%s:%d] CHECK WEBUI : " "Even the Default Bearer(QCI:%d,ARP:%d) " "cannot support IMS signalling.", pcf_ue->supi, sess->psi, session_data.session.qos.index, session_data.session.qos.arp.priority_level); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } else { continue; } } if (!db_pcc_rule) { strerror = ogs_msprintf("[%s:%d] CHECK WEBUI : " "No PCC Rule in DB [QoS Index:%d] - " "Please add PCC Rule using WEBUI", pcf_ue->supi, sess->psi, qos_index); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } for (j = 0; j < app_session->num_of_pcc_rule; j++) { if (app_session->pcc_rule[j].qos.index == qos_index) { pcc_rule = &app_session->pcc_rule[j]; break; } } if (!pcc_rule) { pcc_rule = &app_session->pcc_rule[app_session->num_of_pcc_rule]; ogs_assert(pcc_rule); pcc_rule->id = ogs_strdup(app_session->app_session_id); ogs_assert(pcc_rule->id); memcpy(&pcc_rule->qos, &db_pcc_rule->qos, sizeof(ogs_qos_t)); pcc_rule->flow_status = db_pcc_rule->flow_status; pcc_rule->precedence = db_pcc_rule->precedence; /* Install Flow */ flow_presence = 1; rv = ogs_pcc_rule_install_flow_from_media( pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] install_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } app_session->num_of_pcc_rule++; } else { int count = 0; /* Check Flow */ count = ogs_pcc_rule_num_of_flow_equal_to_media( pcc_rule, media_component); if (count == -1) { strerror = ogs_msprintf("[%s:%d] matched_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } if (pcc_rule->num_of_flow != count) { /* Re-install Flow */ flow_presence = 1; rv = ogs_pcc_rule_install_flow_from_media( pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] re-install_flow() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } } } /* Update QoS */ rv = ogs_pcc_rule_update_qos_from_media(pcc_rule, media_component); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s:%d] update_qos() failed", pcf_ue->supi, sess->psi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } /* if we failed to get QoS from IMS, apply WEBUI QoS */ if (pcc_rule->qos.mbr.downlink == 0) pcc_rule->qos.mbr.downlink = db_pcc_rule->qos.mbr.downlink; if (pcc_rule->qos.mbr.uplink == 0) pcc_rule->qos.mbr.uplink = db_pcc_rule->qos.mbr.uplink; if (pcc_rule->qos.gbr.downlink == 0) pcc_rule->qos.gbr.downlink = db_pcc_rule->qos.gbr.downlink; if (pcc_rule->qos.gbr.uplink == 0) pcc_rule->qos.gbr.uplink = db_pcc_rule->qos.gbr.uplink; /************************************************************** * Build PCC Rule & QoS Decision *************************************************************/ PccRule = ogs_sbi_build_pcc_rule(pcc_rule, flow_presence); ogs_assert(PccRule->pcc_rule_id); PccRuleMap = OpenAPI_map_create(PccRule->pcc_rule_id, PccRule); ogs_assert(PccRuleMap); OpenAPI_list_add(PccRuleList, PccRuleMap); QosData = ogs_sbi_build_qos_data(pcc_rule); ogs_assert(QosData); ogs_assert(QosData->qos_id); QosDecisionMap = OpenAPI_map_create(QosData->qos_id, QosData); ogs_assert(QosDecisionMap); OpenAPI_list_add(QosDecisionList, QosDecisionMap); } if (PccRuleList->count) SmPolicyDecision.pcc_rules = PccRuleList; if (QosDecisionList->count) SmPolicyDecision.qos_decs = QosDecisionList; memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.AppSessionContextUpdateDataPatch = recvmsg->AppSessionContextUpdateDataPatch; response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); if (PccRuleList->count || QosDecisionList->count) { ogs_assert(true == pcf_sbi_send_smpolicycontrol_update_notify( sess, &SmPolicyDecision)); } OpenAPI_list_for_each(PccRuleList, node) { PccRuleMap = node->data; if (PccRuleMap) { PccRule = PccRuleMap->value; if (PccRule) ogs_sbi_free_pcc_rule(PccRule); ogs_free(PccRuleMap); } } OpenAPI_list_free(PccRuleList); OpenAPI_list_for_each(QosDecisionList, node) { QosDecisionMap = node->data; if (QosDecisionMap) { QosData = QosDecisionMap->value; if (QosData) ogs_sbi_free_qos_data(QosData); ogs_free(QosDecisionMap); } } OpenAPI_list_free(QosDecisionList); ogs_ims_data_free(&ims_data); OGS_SESSION_DATA_FREE(&session_data); return true; cleanup: ogs_assert(status); ogs_assert(strerror); ogs_error("%s", strerror); ogs_assert(true == ogs_sbi_server_send_error(stream, status, recvmsg, strerror, NULL, NULL)); ogs_free(strerror); OpenAPI_list_for_each(PccRuleList, node) { PccRuleMap = node->data; if (PccRuleMap) { PccRule = PccRuleMap->value; if (PccRule) ogs_sbi_free_pcc_rule(PccRule); ogs_free(PccRuleMap); } } OpenAPI_list_free(PccRuleList); OpenAPI_list_for_each(QosDecisionList, node) { QosDecisionMap = node->data; if (QosDecisionMap) { QosData = QosDecisionMap->value; if (QosData) ogs_sbi_free_qos_data(QosData); ogs_free(QosDecisionMap); } } OpenAPI_list_free(QosDecisionList); ogs_ims_data_free(&ims_data); OGS_SESSION_DATA_FREE(&session_data); return false; } bool pcf_npcf_policyauthorization_handle_delete( pcf_sess_t *sess, pcf_app_t *app_session, ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int i; OpenAPI_sm_policy_decision_t SmPolicyDecision; OpenAPI_list_t *PccRuleList = NULL; OpenAPI_map_t *PccRuleMap = NULL; OpenAPI_list_t *QosDecisionList = NULL; OpenAPI_map_t *QosDecisionMap = NULL; OpenAPI_lnode_t *node = NULL; ogs_assert(true == ogs_sbi_send_http_status_no_content(stream)); ogs_assert(app_session); memset(&SmPolicyDecision, 0, sizeof(SmPolicyDecision)); PccRuleList = OpenAPI_list_create(); ogs_assert(PccRuleList); QosDecisionList = OpenAPI_list_create(); ogs_assert(QosDecisionList); for (i = 0; i < app_session->num_of_pcc_rule; i++) { ogs_pcc_rule_t *pcc_rule = &app_session->pcc_rule[i]; ogs_assert(pcc_rule); PccRuleMap = OpenAPI_map_create(pcc_rule->id, NULL); ogs_assert(PccRuleMap); OpenAPI_list_add(PccRuleList, PccRuleMap); QosDecisionMap = OpenAPI_map_create(pcc_rule->id, NULL); ogs_assert(QosDecisionMap); OpenAPI_list_add(QosDecisionList, QosDecisionMap); } if (PccRuleList->count) SmPolicyDecision.pcc_rules = PccRuleList; if (QosDecisionList->count) SmPolicyDecision.qos_decs = QosDecisionList; if (PccRuleList->count || QosDecisionList->count) { ogs_assert(true == pcf_sbi_send_smpolicycontrol_delete_notify( sess, app_session, &SmPolicyDecision)); } else { pcf_app_remove(app_session); } OpenAPI_list_for_each(PccRuleList, node) { PccRuleMap = node->data; if (PccRuleMap) { ogs_free(PccRuleMap); } } OpenAPI_list_free(PccRuleList); OpenAPI_list_for_each(QosDecisionList, node) { QosDecisionMap = node->data; if (QosDecisionMap) { ogs_free(QosDecisionMap); } } OpenAPI_list_free(QosDecisionList); return true; }