/* * Copyright (C) 2019,2020 by Sukchan Lee * * This file is part of Open5GS. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "sbi-path.h" #include "nudr-handler.h" bool udr_nudr_dr_handle_subscription_authentication( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int rv; ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; ogs_dbi_auth_info_t auth_info; char k_string[OGS_KEYSTRLEN(OGS_KEY_LEN)]; char opc_string[OGS_KEYSTRLEN(OGS_KEY_LEN)]; char amf_string[OGS_KEYSTRLEN(OGS_AMF_LEN)]; char sqn_string[OGS_KEYSTRLEN(OGS_SQN_LEN)]; char sqn[OGS_SQN_LEN]; char *supi = NULL; OpenAPI_authentication_subscription_t AuthenticationSubscription; OpenAPI_sequence_number_t SequenceNumber; OpenAPI_list_t *PatchItemList = NULL; OpenAPI_lnode_t *node = NULL; ogs_assert(stream); ogs_assert(recvmsg); supi = recvmsg->h.resource.component[1]; if (!supi) { ogs_error("No SUPI"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No SUPI", NULL)); return false; } if (strncmp(supi, OGS_ID_SUPI_TYPE_IMSI, strlen(OGS_ID_SUPI_TYPE_IMSI)) != 0) { ogs_error("[%s] Unknown SUPI Type", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, recvmsg, "Unknwon SUPI Type", supi)); return false; } rv = ogs_dbi_auth_info(supi, &auth_info); if (rv != OGS_OK) { ogs_warn("[%s] Cannot find SUPI in DB", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_NOT_FOUND, recvmsg, "Cannot find SUPI Type", supi)); return false; } SWITCH(recvmsg->h.resource.component[3]) CASE(OGS_SBI_RESOURCE_NAME_AUTHENTICATION_SUBSCRIPTION) SWITCH(recvmsg->h.method) CASE(OGS_SBI_HTTP_METHOD_GET) memset(&AuthenticationSubscription, 0, sizeof(AuthenticationSubscription)); AuthenticationSubscription.authentication_method = OpenAPI_auth_method_5G_AKA; ogs_hex_to_ascii(auth_info.k, sizeof(auth_info.k), k_string, sizeof(k_string)); AuthenticationSubscription.enc_permanent_key = k_string; ogs_hex_to_ascii(auth_info.amf, sizeof(auth_info.amf), amf_string, sizeof(amf_string)); AuthenticationSubscription.authentication_management_field = amf_string; if (!auth_info.use_opc) milenage_opc(auth_info.k, auth_info.op, auth_info.opc); ogs_hex_to_ascii(auth_info.opc, sizeof(auth_info.opc), opc_string, sizeof(opc_string)); AuthenticationSubscription.enc_opc_key = opc_string; ogs_uint64_to_buffer(auth_info.sqn, OGS_SQN_LEN, sqn); ogs_hex_to_ascii(sqn, sizeof(sqn), sqn_string, sizeof(sqn_string)); memset(&SequenceNumber, 0, sizeof(SequenceNumber)); SequenceNumber.sqn = sqn_string; AuthenticationSubscription.sequence_number = &SequenceNumber; memset(&sendmsg, 0, sizeof(sendmsg)); ogs_assert(AuthenticationSubscription.authentication_method); sendmsg.AuthenticationSubscription = &AuthenticationSubscription; response = ogs_sbi_build_response( &sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); return true; CASE(OGS_SBI_HTTP_METHOD_PATCH) char *sqn_string = NULL; uint8_t sqn_ms[OGS_SQN_LEN]; uint64_t sqn = 0; PatchItemList = recvmsg->PatchItemList; if (!PatchItemList) { ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No PatchItemList Array", NULL)); return false; } OpenAPI_list_for_each(PatchItemList, node) { if (node->data) { OpenAPI_patch_item_t *patch_item = node->data; if (OpenAPI_IsString(patch_item->value)) sqn_string = cJSON_GetStringValue(patch_item->value->json); else ogs_error("Non-string value in patch not implemented"); } } if (!sqn_string) { ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No PatchItemList", NULL)); return false; } ogs_ascii_to_hex(sqn_string, strlen(sqn_string), sqn_ms, sizeof(sqn_ms)); sqn = ogs_buffer_to_uint64(sqn_ms, OGS_SQN_LEN); rv = ogs_dbi_update_sqn(supi, sqn); if (rv != OGS_OK) { ogs_fatal("[%s] Cannot update SQN", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, recvmsg, "Cannot update SQN", supi)); return false; } rv = ogs_dbi_increment_sqn(supi); if (rv != OGS_OK) { ogs_fatal("[%s] Cannot increment SQN", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, recvmsg, "Cannot increment SQN", supi)); return false; } memset(&sendmsg, 0, sizeof(sendmsg)); 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)); return true; DEFAULT ogs_error("Invalid HTTP method [%s]", recvmsg->h.method); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, recvmsg, "Invalid HTTP method", recvmsg->h.method)); END break; CASE(OGS_SBI_RESOURCE_NAME_AUTHENTICATION_STATUS) SWITCH(recvmsg->h.method) CASE(OGS_SBI_HTTP_METHOD_PUT) CASE(OGS_SBI_HTTP_METHOD_DELETE) OpenAPI_auth_event_t *AuthEvent = NULL; AuthEvent = recvmsg->AuthEvent; if (!AuthEvent && !strcmp(recvmsg->h.method, OGS_SBI_HTTP_METHOD_PUT)) { ogs_error("[%s] No AuthEvent", supi); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No AuthEvent", supi)); return false; } memset(&sendmsg, 0, sizeof(sendmsg)); rv = ogs_dbi_increment_sqn(supi); if (rv != OGS_OK) { ogs_fatal("[%s] Cannot increment SQN", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_INTERNAL_SERVER_ERROR, recvmsg, "Cannot increment SQN", supi)); return false; } 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)); return true; DEFAULT ogs_error("Invalid HTTP method [%s]", recvmsg->h.method); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, recvmsg, "Invalid HTTP method", recvmsg->h.method)); END break; DEFAULT ogs_error("Invalid resource name [%s]", recvmsg->h.resource.component[3]); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, recvmsg, "Unknown resource name", recvmsg->h.resource.component[3])); END return false; } bool udr_nudr_dr_handle_subscription_context( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; char *supi = NULL; ogs_assert(stream); ogs_assert(recvmsg); supi = recvmsg->h.resource.component[1]; if (!supi) { ogs_error("No SUPI"); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No SUPI", NULL)); return false; } if (strncmp(supi, OGS_ID_SUPI_TYPE_IMSI, strlen(OGS_ID_SUPI_TYPE_IMSI)) != 0) { ogs_error("[%s] Unknown SUPI Type", supi); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_FORBIDDEN, recvmsg, "Unknwon SUPI Type", supi)); return false; } SWITCH(recvmsg->h.resource.component[3]) CASE(OGS_SBI_RESOURCE_NAME_AMF_3GPP_ACCESS) SWITCH(recvmsg->h.method) CASE(OGS_SBI_HTTP_METHOD_PUT) OpenAPI_amf3_gpp_access_registration_t *Amf3GppAccessRegistration; Amf3GppAccessRegistration = recvmsg->Amf3GppAccessRegistration; if (!Amf3GppAccessRegistration) { ogs_error("[%s] No Amf3GppAccessRegistration", supi); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No Amf3GppAccessRegistration", supi)); return false; } memset(&sendmsg, 0, sizeof(sendmsg)); 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)); return true; CASE(OGS_SBI_HTTP_METHOD_PATCH) OpenAPI_list_t *PatchItemList; PatchItemList = recvmsg->PatchItemList; if (!PatchItemList) { ogs_error("[%s] No PatchItemList", supi); ogs_assert(true == ogs_sbi_server_send_error( stream, OGS_SBI_HTTP_STATUS_BAD_REQUEST, recvmsg, "No PatchItemList", supi)); return false; } /* TODO: parse PatchItemList */ memset(&sendmsg, 0, sizeof(sendmsg)); 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)); return true; DEFAULT ogs_error("Invalid HTTP method [%s]", recvmsg->h.method); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, recvmsg, "Invalid HTTP method", recvmsg->h.method)); END break; DEFAULT ogs_error("Invalid resource name [%s]", recvmsg->h.resource.component[3]); ogs_assert(true == ogs_sbi_server_send_error(stream, OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED, recvmsg, "Unknown resource name", recvmsg->h.resource.component[3])); END return false; } bool udr_nudr_dr_handle_subscription_provisioned( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int rv, status = 0; char *strerror = NULL; ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; ogs_subscription_data_t subscription_data; ogs_slice_data_t *slice_data = NULL; char *supi = NULL; ogs_assert(stream); ogs_assert(recvmsg); memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); supi = recvmsg->h.resource.component[1]; if (!supi) { strerror = ogs_msprintf("No SUPI"); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (strncmp(supi, OGS_ID_SUPI_TYPE_IMSI, strlen(OGS_ID_SUPI_TYPE_IMSI)) != 0) { strerror = ogs_msprintf("[%s] Unknown SUPI Type", supi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } rv = ogs_dbi_subscription_data(supi, &subscription_data); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s] Cannot find SUPI in DB", supi); status = OGS_SBI_HTTP_STATUS_NOT_FOUND; goto cleanup; } if (!subscription_data.ambr.uplink && !subscription_data.ambr.downlink) { strerror = ogs_msprintf("[%s] No UE-AMBR", supi); status = OGS_SBI_HTTP_STATUS_NOT_FOUND; goto cleanup; } SWITCH(recvmsg->h.resource.component[4]) CASE(OGS_SBI_RESOURCE_NAME_AM_DATA) int i; OpenAPI_access_and_mobility_subscription_data_t AccessAndMobilitySubscriptionData; OpenAPI_list_t *GpsiList = NULL; OpenAPI_ambr_rm_t SubscribedUeAmbr; OpenAPI_nssai_t NSSAI; OpenAPI_list_t *DefaultSingleNssaiList = NULL; OpenAPI_list_t *SingleNssaiList = NULL; OpenAPI_snssai_t *Snssai = NULL; OpenAPI_lnode_t *node = NULL; GpsiList = OpenAPI_list_create(); for (i = 0; i < subscription_data.num_of_msisdn; i++) { char *gpsi = ogs_msprintf("%s-%s", OGS_ID_GPSI_TYPE_MSISDN, subscription_data.msisdn[i].bcd); ogs_assert(gpsi); OpenAPI_list_add(GpsiList, gpsi); } SubscribedUeAmbr.uplink = ogs_sbi_bitrate_to_string( subscription_data.ambr.uplink, OGS_SBI_BITRATE_KBPS); SubscribedUeAmbr.downlink = ogs_sbi_bitrate_to_string( subscription_data.ambr.downlink, OGS_SBI_BITRATE_KBPS); memset(&NSSAI, 0, sizeof(NSSAI)); DefaultSingleNssaiList = OpenAPI_list_create(); for (i = 0; i < subscription_data.num_of_slice; i++) { slice_data = &subscription_data.slice[i]; if (slice_data->default_indicator == false) continue; Snssai = ogs_calloc(1, sizeof(*Snssai)); ogs_assert(Snssai); Snssai->sst = slice_data->s_nssai.sst; Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd); OpenAPI_list_add(DefaultSingleNssaiList, Snssai); } if (DefaultSingleNssaiList->count) { NSSAI.default_single_nssais = DefaultSingleNssaiList; } SingleNssaiList = OpenAPI_list_create(); for (i = 0; i < subscription_data.num_of_slice; i++) { slice_data = &subscription_data.slice[i]; if (slice_data->default_indicator == true) continue; Snssai = ogs_calloc(1, sizeof(*Snssai)); ogs_assert(Snssai); Snssai->sst = slice_data->s_nssai.sst; Snssai->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd); OpenAPI_list_add(SingleNssaiList, Snssai); } if (DefaultSingleNssaiList->count) { if (SingleNssaiList->count) { NSSAI.single_nssais = SingleNssaiList; } } else { if (SingleNssaiList->count) { ogs_fatal("No Default S-NSSAI"); ogs_assert_if_reached(); } } memset(&AccessAndMobilitySubscriptionData, 0, sizeof(AccessAndMobilitySubscriptionData)); if (GpsiList->count) AccessAndMobilitySubscriptionData.gpsis = GpsiList; AccessAndMobilitySubscriptionData.subscribed_ue_ambr = &SubscribedUeAmbr; if (DefaultSingleNssaiList->count) AccessAndMobilitySubscriptionData.nssai = &NSSAI; memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.AccessAndMobilitySubscriptionData = &AccessAndMobilitySubscriptionData; response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); OpenAPI_list_for_each(GpsiList, node) { if (node->data) ogs_free(node->data); } OpenAPI_list_free(GpsiList); ogs_free(SubscribedUeAmbr.uplink); ogs_free(SubscribedUeAmbr.downlink); OpenAPI_list_for_each(DefaultSingleNssaiList, node) { OpenAPI_snssai_t *Snssai = node->data; if (Snssai) { if (Snssai->sd) ogs_free(Snssai->sd); ogs_free(Snssai); } } OpenAPI_list_free(DefaultSingleNssaiList); OpenAPI_list_for_each(SingleNssaiList, node) { OpenAPI_snssai_t *Snssai = node->data; if (Snssai) { if (Snssai->sd) ogs_free(Snssai->sd); ogs_free(Snssai); } } OpenAPI_list_free(SingleNssaiList); break; CASE(OGS_SBI_RESOURCE_NAME_SMF_SELECTION_SUBSCRIPTION_DATA) int i, j; OpenAPI_smf_selection_subscription_data_t SmfSelectionSubscriptionData; OpenAPI_list_t *SubscribedSnssaiInfoList = NULL; OpenAPI_map_t *SubscribedSnssaiInfoMap = NULL; OpenAPI_snssai_info_t *SubscribedSnssaiInfo = NULL; OpenAPI_list_t *DnnInfoList = NULL; OpenAPI_dnn_info_t *DnnInfo = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL; memset(&SmfSelectionSubscriptionData, 0, sizeof(SmfSelectionSubscriptionData)); SubscribedSnssaiInfoList = OpenAPI_list_create(); ogs_assert(SubscribedSnssaiInfoList); for (i = 0; i < subscription_data.num_of_slice; i++) { if (i >= OGS_MAX_NUM_OF_SLICE) { ogs_warn("Ignore max slice count overflow [%d>=%d]", subscription_data.num_of_slice, OGS_MAX_NUM_OF_SLICE); break; } slice_data = &subscription_data.slice[i]; DnnInfoList = OpenAPI_list_create(); ogs_assert(DnnInfoList); for (j = 0; j < slice_data->num_of_session; j++) { ogs_session_t *session = NULL; if (j >= OGS_MAX_NUM_OF_SESS) { ogs_warn("Ignore max session count overflow [%d>=%d]", slice_data->num_of_session, OGS_MAX_NUM_OF_SESS); break; } session = &slice_data->session[j]; ogs_assert(session); ogs_assert(session->name); DnnInfo = ogs_calloc(1, sizeof(*DnnInfo)); ogs_assert(DnnInfo); DnnInfo->dnn = session->name; /* 0-index DNN becomes the default DNN */ if (j == 0) { DnnInfo->is_default_dnn_indicator = true; DnnInfo->default_dnn_indicator = true; } OpenAPI_list_add(DnnInfoList, DnnInfo); } SubscribedSnssaiInfo = ogs_calloc(1, sizeof(*SubscribedSnssaiInfo)); ogs_assert(SubscribedSnssaiInfo); if (DnnInfoList->count) SubscribedSnssaiInfo->dnn_infos = DnnInfoList; else OpenAPI_list_free(DnnInfoList); SubscribedSnssaiInfoMap = OpenAPI_map_create( ogs_sbi_s_nssai_to_string(&slice_data->s_nssai), SubscribedSnssaiInfo); ogs_assert(SubscribedSnssaiInfoMap); ogs_assert(SubscribedSnssaiInfoMap->key); OpenAPI_list_add(SubscribedSnssaiInfoList, SubscribedSnssaiInfoMap); } if (SubscribedSnssaiInfoList->count) SmfSelectionSubscriptionData.subscribed_snssai_infos = SubscribedSnssaiInfoList; else OpenAPI_list_free(SubscribedSnssaiInfoList); memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.SmfSelectionSubscriptionData = &SmfSelectionSubscriptionData; response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); SubscribedSnssaiInfoList = SmfSelectionSubscriptionData.subscribed_snssai_infos; OpenAPI_list_for_each(SubscribedSnssaiInfoList, node) { SubscribedSnssaiInfoMap = node->data; if (SubscribedSnssaiInfoMap) { SubscribedSnssaiInfo = SubscribedSnssaiInfoMap->value; if (SubscribedSnssaiInfo) { DnnInfoList = SubscribedSnssaiInfo->dnn_infos; if (DnnInfoList) { OpenAPI_list_for_each(DnnInfoList, node2) { DnnInfo = node2->data; if (DnnInfo) { ogs_free(DnnInfo); } } OpenAPI_list_free(DnnInfoList); } ogs_free(SubscribedSnssaiInfo); } if (SubscribedSnssaiInfoMap->key) ogs_free(SubscribedSnssaiInfoMap->key); ogs_free(SubscribedSnssaiInfoMap); } } OpenAPI_list_free(SubscribedSnssaiInfoList); break; CASE(OGS_SBI_RESOURCE_NAME_SM_DATA) int i; OpenAPI_session_management_subscription_data_t SessionManagementSubscriptionData; OpenAPI_snssai_t singleNSSAI; OpenAPI_list_t *dnnConfigurationList = NULL; OpenAPI_map_t *dnnConfigurationMap = NULL; OpenAPI_dnn_configuration_t *dnnConfiguration = NULL; OpenAPI_pdu_session_types_t *pduSessionTypeList = NULL; OpenAPI_ssc_modes_t *sscModeList = NULL; OpenAPI_subscribed_default_qos_t *_5gQoSProfile = NULL; OpenAPI_ambr_t *sessionAmbr = NULL; OpenAPI_list_t *staticIpAddress = NULL; OpenAPI_ip_address_t *ipAddress = NULL; OpenAPI_lnode_t *node = NULL, *node2 = NULL; if (!recvmsg->param.single_nssai_presence) { strerror = ogs_msprintf("[%s] No S_NSSAI", supi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; }; slice_data = ogs_slice_find_by_s_nssai( subscription_data.slice, subscription_data.num_of_slice, &recvmsg->param.s_nssai); if (!slice_data) { strerror = ogs_msprintf("[%s] Cannot find S_NSSAI[SST:%d SD:0x%x]", supi, recvmsg->param.s_nssai.sst, recvmsg->param.s_nssai.sd.v); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } singleNSSAI.sst = slice_data->s_nssai.sst; singleNSSAI.sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd); dnnConfigurationList = OpenAPI_list_create(); for (i = 0; i < slice_data->num_of_session; i++) { ogs_session_t *session = NULL; if (i >= OGS_MAX_NUM_OF_SESS) { ogs_warn("Ignore max session count overflow [%d>=%d]", slice_data->num_of_session, OGS_MAX_NUM_OF_SESS); break; } session = &slice_data->session[i]; ogs_assert(session); ogs_assert(session->name); if (recvmsg->param.dnn && ogs_strcasecmp(recvmsg->param.dnn, session->name) != 0) continue; if (!session->qos.index) { ogs_error("No 5QI"); continue; } if (!session->qos.arp.priority_level) { ogs_error("No Priority Level"); continue; } if (!session->ambr.uplink && !session->ambr.downlink) { ogs_error("No Session-AMBR"); continue; } dnnConfiguration = ogs_calloc(1, sizeof(*dnnConfiguration)); ogs_assert(dnnConfiguration); pduSessionTypeList = ogs_calloc(1, sizeof(*pduSessionTypeList)); ogs_assert(pduSessionTypeList); pduSessionTypeList->default_session_type = session->session_type; pduSessionTypeList->allowed_session_types = OpenAPI_list_create(); ogs_assert(pduSessionTypeList->allowed_session_types); switch (pduSessionTypeList->default_session_type) { case OpenAPI_pdu_session_type_IPV4: OpenAPI_list_add(pduSessionTypeList->allowed_session_types, (void *)OpenAPI_pdu_session_type_IPV4); break; case OpenAPI_pdu_session_type_IPV6: OpenAPI_list_add(pduSessionTypeList->allowed_session_types, (void *)OpenAPI_pdu_session_type_IPV6); break; case OpenAPI_pdu_session_type_IPV4V6: OpenAPI_list_add(pduSessionTypeList->allowed_session_types, (void *)OpenAPI_pdu_session_type_IPV4); OpenAPI_list_add(pduSessionTypeList->allowed_session_types, (void *)OpenAPI_pdu_session_type_IPV6); OpenAPI_list_add(pduSessionTypeList->allowed_session_types, (void *)OpenAPI_pdu_session_type_IPV4V6); break; default: ogs_fatal("Unsupported PDN_TYPE[%d]", pduSessionTypeList->default_session_type); ogs_assert_if_reached(); } dnnConfiguration->pdu_session_types = pduSessionTypeList; sscModeList = ogs_calloc(1, sizeof(*sscModeList)); ogs_assert(sscModeList); sscModeList->default_ssc_mode = OpenAPI_ssc_mode_SSC_MODE_1; sscModeList->allowed_ssc_modes = OpenAPI_list_create(); ogs_assert(sscModeList->allowed_ssc_modes); OpenAPI_list_add(sscModeList->allowed_ssc_modes, (void *)OpenAPI_ssc_mode_SSC_MODE_1); OpenAPI_list_add(sscModeList->allowed_ssc_modes, (void *)OpenAPI_ssc_mode_SSC_MODE_2); OpenAPI_list_add(sscModeList->allowed_ssc_modes, (void *)OpenAPI_ssc_mode_SSC_MODE_3); dnnConfiguration->ssc_modes = sscModeList; _5gQoSProfile = ogs_calloc(1, sizeof(*_5gQoSProfile)); ogs_assert(_5gQoSProfile); _5gQoSProfile->_5qi = session->qos.index; _5gQoSProfile->is_priority_level = true; _5gQoSProfile->priority_level = session->qos.arp.priority_level; _5gQoSProfile->arp = ogs_calloc(1, sizeof(OpenAPI_arp_t)); ogs_assert(_5gQoSProfile->arp); _5gQoSProfile->arp->priority_level = session->qos.arp.priority_level; if (session->qos.arp.pre_emption_capability == OGS_5GC_PRE_EMPTION_ENABLED) _5gQoSProfile->arp->preempt_cap = OpenAPI_preemption_capability_MAY_PREEMPT; else if (session->qos.arp.pre_emption_capability == OGS_5GC_PRE_EMPTION_DISABLED) _5gQoSProfile->arp->preempt_cap = OpenAPI_preemption_capability_NOT_PREEMPT; ogs_assert(_5gQoSProfile->arp->preempt_cap); if (session->qos.arp.pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_ENABLED) _5gQoSProfile->arp->preempt_vuln = OpenAPI_preemption_vulnerability_PREEMPTABLE; else if (session->qos.arp.pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_DISABLED) _5gQoSProfile->arp->preempt_vuln = OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE; ogs_assert(_5gQoSProfile->arp->preempt_vuln); dnnConfiguration->_5g_qos_profile = _5gQoSProfile; ogs_assert(session->ambr.uplink || session->ambr.downlink); sessionAmbr = ogs_calloc(1, sizeof(*sessionAmbr)); ogs_assert(sessionAmbr); sessionAmbr->uplink = ogs_sbi_bitrate_to_string( session->ambr.uplink, OGS_SBI_BITRATE_KBPS); sessionAmbr->downlink = ogs_sbi_bitrate_to_string( session->ambr.downlink, OGS_SBI_BITRATE_KBPS); dnnConfiguration->session_ambr = sessionAmbr; staticIpAddress = OpenAPI_list_create(); ogs_assert(staticIpAddress); if (session->ue_ip.ipv4 || session->ue_ip.ipv6) { ipAddress = ogs_calloc(1, sizeof(*ipAddress)); ogs_assert(ipAddress); if (session->ue_ip.ipv4) { ipAddress->ipv4_addr = ogs_ipv4_to_string(session->ue_ip.addr); ogs_assert(ipAddress->ipv4_addr); } if (session->ue_ip.ipv6) { ipAddress->ipv6_addr = ogs_ipv6addr_to_string(session->ue_ip.addr6); ogs_assert(ipAddress->ipv6_addr); } if (ipAddress->ipv4_addr || ipAddress->ipv6_addr) OpenAPI_list_add(staticIpAddress, ipAddress); else ogs_free(ipAddress); } if (staticIpAddress->count) dnnConfiguration->static_ip_address = staticIpAddress; else OpenAPI_list_free(staticIpAddress); dnnConfigurationMap = OpenAPI_map_create( session->name, dnnConfiguration); ogs_assert(dnnConfigurationMap); OpenAPI_list_add(dnnConfigurationList, dnnConfigurationMap); } memset(&SessionManagementSubscriptionData, 0, sizeof(SessionManagementSubscriptionData)); SessionManagementSubscriptionData.single_nssai = &singleNSSAI; if (dnnConfigurationList->count) SessionManagementSubscriptionData.dnn_configurations = dnnConfigurationList; memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.SessionManagementSubscriptionDataList = OpenAPI_list_create(); ogs_assert(sendmsg.SessionManagementSubscriptionDataList); OpenAPI_list_add(sendmsg.SessionManagementSubscriptionDataList, &SessionManagementSubscriptionData); response = ogs_sbi_build_response(&sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); OpenAPI_list_free(sendmsg.SessionManagementSubscriptionDataList); if (singleNSSAI.sd) ogs_free(singleNSSAI.sd); OpenAPI_list_for_each(dnnConfigurationList, node) { dnnConfigurationMap = node->data; if (dnnConfigurationMap) { dnnConfiguration = dnnConfigurationMap->value; if (dnnConfiguration) { pduSessionTypeList = dnnConfiguration->pdu_session_types; if (pduSessionTypeList) { if (pduSessionTypeList->allowed_session_types) OpenAPI_list_free( pduSessionTypeList->allowed_session_types); ogs_free(pduSessionTypeList); } sscModeList = dnnConfiguration->ssc_modes;; if (sscModeList) { if (sscModeList->allowed_ssc_modes) OpenAPI_list_free(sscModeList->allowed_ssc_modes); ogs_free(sscModeList); } _5gQoSProfile = dnnConfiguration->_5g_qos_profile; if (_5gQoSProfile) { if (_5gQoSProfile->arp) ogs_free(_5gQoSProfile->arp); ogs_free(_5gQoSProfile); } sessionAmbr = dnnConfiguration->session_ambr; if (sessionAmbr) { if (sessionAmbr->uplink) ogs_free(sessionAmbr->uplink); if (sessionAmbr->downlink) ogs_free(sessionAmbr->downlink); ogs_free(sessionAmbr); } staticIpAddress = dnnConfiguration->static_ip_address; if (staticIpAddress) { OpenAPI_list_for_each(staticIpAddress, node2) { if (node2->data) { ipAddress = node2->data; if (ipAddress) { if (ipAddress->ipv4_addr) ogs_free(ipAddress->ipv4_addr); if (ipAddress->ipv6_addr) ogs_free(ipAddress->ipv6_addr); ogs_free(ipAddress); } } } OpenAPI_list_free(staticIpAddress); } ogs_free(dnnConfiguration); } ogs_free(dnnConfigurationMap); } } OpenAPI_list_free(dnnConfigurationList); break; DEFAULT strerror = ogs_msprintf("Invalid resource name [%s]", recvmsg->h.resource.component[3]); status = OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED; goto cleanup; END ogs_subscription_data_free(&subscription_data); return true; cleanup: ogs_assert(strerror); ogs_assert(status); ogs_error("%s", strerror); ogs_assert(true == ogs_sbi_server_send_error(stream, status, recvmsg, strerror, NULL)); ogs_free(strerror); ogs_subscription_data_free(&subscription_data); return false; } bool udr_nudr_dr_handle_policy_data( ogs_sbi_stream_t *stream, ogs_sbi_message_t *recvmsg) { int rv, i, status = 0; char *strerror = NULL; ogs_sbi_message_t sendmsg; ogs_sbi_response_t *response = NULL; ogs_subscription_data_t subscription_data; ogs_slice_data_t *slice_data = NULL; ogs_assert(stream); ogs_assert(recvmsg); memset(&subscription_data, 0, sizeof(ogs_subscription_data_t)); SWITCH(recvmsg->h.resource.component[1]) CASE(OGS_SBI_RESOURCE_NAME_UES) char *supi = recvmsg->h.resource.component[2]; if (!supi) { strerror = ogs_msprintf("No SUPI"); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } if (strncmp(supi, OGS_ID_SUPI_TYPE_IMSI, strlen(OGS_ID_SUPI_TYPE_IMSI)) != 0) { strerror = ogs_msprintf("[%s] Unknown SUPI Type", supi); status = OGS_SBI_HTTP_STATUS_FORBIDDEN; goto cleanup; } SWITCH(recvmsg->h.method) CASE(OGS_SBI_HTTP_METHOD_GET) OpenAPI_lnode_t *node = NULL, *node2 = NULL; rv = ogs_dbi_subscription_data(supi, &subscription_data); if (rv != OGS_OK) { strerror = ogs_msprintf("[%s] Cannot find SUPI in DB", supi); status = OGS_SBI_HTTP_STATUS_NOT_FOUND; goto cleanup; } SWITCH(recvmsg->h.resource.component[3]) CASE(OGS_SBI_RESOURCE_NAME_AM_DATA) OpenAPI_am_policy_data_t AmPolicyData; memset(&AmPolicyData, 0, sizeof(AmPolicyData)); memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.AmPolicyData = &AmPolicyData; response = ogs_sbi_build_response( &sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); break; CASE(OGS_SBI_RESOURCE_NAME_SM_DATA) OpenAPI_sm_policy_data_t SmPolicyData; OpenAPI_list_t *SmPolicySnssaiDataList = NULL; OpenAPI_map_t *SmPolicySnssaiDataMap = NULL; OpenAPI_sm_policy_snssai_data_t *SmPolicySnssaiData = NULL; OpenAPI_snssai_t *sNSSAI = NULL; OpenAPI_list_t *SmPolicyDnnDataList = NULL; OpenAPI_map_t *SmPolicyDnnDataMap = NULL; OpenAPI_sm_policy_dnn_data_t *SmPolicyDnnData = NULL; if (!recvmsg->param.snssai_presence) { strerror = ogs_msprintf("[%s] No S_NSSAI", supi); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } slice_data = ogs_slice_find_by_s_nssai( subscription_data.slice, subscription_data.num_of_slice, &recvmsg->param.s_nssai); if (!slice_data) { strerror = ogs_msprintf( "[%s] Cannot find S_NSSAI[SST:%d SD:0x%x]", supi, recvmsg->param.s_nssai.sst, recvmsg->param.s_nssai.sd.v); status = OGS_SBI_HTTP_STATUS_BAD_REQUEST; goto cleanup; } sNSSAI = ogs_calloc(1, sizeof(*sNSSAI)); ogs_assert(sNSSAI); sNSSAI->sst = slice_data->s_nssai.sst; sNSSAI->sd = ogs_s_nssai_sd_to_string(slice_data->s_nssai.sd); SmPolicyDnnDataList = OpenAPI_list_create(); ogs_assert(SmPolicyDnnDataList); slice_data = &subscription_data.slice[0]; for (i = 0; i < slice_data->num_of_session; i++) { ogs_session_t *session = NULL; if (i >= OGS_MAX_NUM_OF_SESS) { ogs_warn("Ignore max session count overflow [%d>=%d]", slice_data->num_of_session, OGS_MAX_NUM_OF_SESS); break; } session = &slice_data->session[i]; ogs_assert(session); ogs_assert(session->name); if (recvmsg->param.dnn && ogs_strcasecmp(recvmsg->param.dnn, session->name) != 0) continue; SmPolicyDnnData = ogs_calloc(1, sizeof(*SmPolicyDnnData)); ogs_assert(SmPolicyDnnData); SmPolicyDnnData->dnn = session->name; SmPolicyDnnDataMap = OpenAPI_map_create( session->name, SmPolicyDnnData); ogs_assert(SmPolicyDnnDataMap); OpenAPI_list_add(SmPolicyDnnDataList, SmPolicyDnnDataMap); } SmPolicySnssaiData = ogs_calloc(1, sizeof(*SmPolicySnssaiData)); ogs_assert(SmPolicySnssaiData); SmPolicySnssaiData->snssai = sNSSAI; if (SmPolicyDnnDataList->count) SmPolicySnssaiData->sm_policy_dnn_data = SmPolicyDnnDataList; else OpenAPI_list_free(SmPolicyDnnDataList); SmPolicySnssaiDataMap = OpenAPI_map_create( ogs_sbi_s_nssai_to_string(&recvmsg->param.s_nssai), SmPolicySnssaiData); ogs_assert(SmPolicySnssaiDataMap); ogs_assert(SmPolicySnssaiDataMap->key); SmPolicySnssaiDataList = OpenAPI_list_create(); ogs_assert(SmPolicySnssaiDataList); OpenAPI_list_add(SmPolicySnssaiDataList, SmPolicySnssaiDataMap); memset(&SmPolicyData, 0, sizeof(SmPolicyData)); if (SmPolicySnssaiDataList->count) SmPolicyData.sm_policy_snssai_data = SmPolicySnssaiDataList; else OpenAPI_list_free(SmPolicySnssaiDataList); memset(&sendmsg, 0, sizeof(sendmsg)); sendmsg.SmPolicyData = &SmPolicyData; response = ogs_sbi_build_response( &sendmsg, OGS_SBI_HTTP_STATUS_OK); ogs_assert(response); ogs_assert(true == ogs_sbi_server_send_response(stream, response)); SmPolicySnssaiDataList = SmPolicyData.sm_policy_snssai_data; OpenAPI_list_for_each(SmPolicySnssaiDataList, node) { SmPolicySnssaiDataMap = node->data; if (SmPolicySnssaiDataMap) { SmPolicySnssaiData = SmPolicySnssaiDataMap->value; if (SmPolicySnssaiData) { sNSSAI = SmPolicySnssaiData->snssai; if (sNSSAI) { if (sNSSAI->sd) ogs_free(sNSSAI->sd); ogs_free(sNSSAI); } SmPolicyDnnDataList = SmPolicySnssaiData->sm_policy_dnn_data; if (SmPolicyDnnDataList) { OpenAPI_list_for_each( SmPolicyDnnDataList, node2) { SmPolicyDnnDataMap = node2->data; if (SmPolicyDnnDataMap) { SmPolicyDnnData = SmPolicyDnnDataMap->value; if (SmPolicyDnnData) { ogs_free(SmPolicyDnnData); } ogs_free(SmPolicyDnnDataMap); } } OpenAPI_list_free(SmPolicyDnnDataList); } ogs_free(SmPolicySnssaiData); } if (SmPolicySnssaiDataMap->key) ogs_free(SmPolicySnssaiDataMap->key); ogs_free(SmPolicySnssaiDataMap); } } OpenAPI_list_free(SmPolicySnssaiDataList); break; DEFAULT strerror = ogs_msprintf("Invalid resource name [%s]", recvmsg->h.resource.component[3]); status = OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED; goto cleanup; END break; DEFAULT strerror = ogs_msprintf("Invalid HTTP method [%s]", recvmsg->h.method); status = OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED; goto cleanup; END break; DEFAULT strerror = ogs_msprintf("Invalid resource name [%s]", recvmsg->h.resource.component[1]); status = OGS_SBI_HTTP_STATUS_MEHTOD_NOT_ALLOWED; goto cleanup; END ogs_subscription_data_free(&subscription_data); return true; cleanup: ogs_assert(strerror); ogs_assert(status); ogs_error("%s", strerror); ogs_assert(true == ogs_sbi_server_send_error(stream, status, recvmsg, strerror, NULL)); ogs_free(strerror); ogs_subscription_data_free(&subscription_data); return false; }