/* * 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-app.h" static ogs_app_global_conf_t global_conf; static ogs_app_local_conf_t local_conf; static OGS_POOL(policy_conf_pool, ogs_app_policy_conf_t); static OGS_POOL(slice_conf_pool, ogs_app_slice_conf_t); static OGS_POOL(session_conf_pool, ogs_app_session_conf_t); static int initialized = 0; int ogs_app_config_init(void) { ogs_assert(initialized == 0); memset(&global_conf, 0, sizeof(ogs_app_global_conf_t)); memset(&local_conf, 0, sizeof(ogs_app_local_conf_t)); ogs_pool_init(&policy_conf_pool, OGS_MAX_NUM_OF_PLMN); ogs_pool_init(&slice_conf_pool, OGS_MAX_NUM_OF_SLICE); ogs_pool_init(&session_conf_pool, OGS_MAX_NUM_OF_SLICE*OGS_MAX_NUM_OF_SESS); initialized = 1; return OGS_OK; } void ogs_app_config_final(void) { ogs_assert(initialized == 1); ogs_app_policy_conf_remove_all(); ogs_pool_final(&policy_conf_pool); ogs_pool_final(&slice_conf_pool); ogs_pool_final(&session_conf_pool); initialized = 0; } static void recalculate_pool_size(void) { ogs_app()->pool.packet = global_conf.max.ue * OGS_MAX_NUM_OF_PACKET_BUFFER; #define MAX_NUM_OF_TUNNEL 3 /* Num of Tunnel per Bearer */ ogs_app()->pool.sess = global_conf.max.ue * OGS_MAX_NUM_OF_SESS; ogs_app()->pool.bearer = ogs_app()->pool.sess * OGS_MAX_NUM_OF_BEARER; ogs_app()->pool.tunnel = ogs_app()->pool.bearer * MAX_NUM_OF_TUNNEL; #define POOL_NUM_PER_UE 16 ogs_app()->pool.timer = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.message = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.event = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.socket = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.xact = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.stream = global_conf.max.ue * POOL_NUM_PER_UE; ogs_app()->pool.nf = global_conf.max.peer; #define NF_SERVICE_PER_NF_INSTANCE 16 ogs_app()->pool.nf_service = ogs_app()->pool.nf * NF_SERVICE_PER_NF_INSTANCE; ogs_app()->pool.subscription = ogs_app()->pool.nf * NF_SERVICE_PER_NF_INSTANCE; ogs_app()->pool.gtp_node = ogs_app()->pool.nf; if (global_conf.max.gtp_peer) ogs_app()->pool.gtp_node = global_conf.max.gtp_peer; /* Num of TAI-LAI Mapping Table */ ogs_app()->pool.csmap = ogs_app()->pool.nf; #define MAX_NUM_OF_IMPU 8 ogs_app()->pool.impi = global_conf.max.ue; ogs_app()->pool.impu = ogs_app()->pool.impi * MAX_NUM_OF_IMPU; } ogs_app_global_conf_t *ogs_global_conf(void) { return &global_conf; } ogs_app_local_conf_t *ogs_local_conf(void) { return &local_conf; } static int global_conf_prepare(void) { global_conf.sockopt.no_delay = true; #define MAX_NUM_OF_UE 1024 /* Num of UEs */ #define MAX_NUM_OF_PEER 64 /* Num of Peer */ global_conf.max.ue = MAX_NUM_OF_UE; global_conf.max.peer = MAX_NUM_OF_PEER; ogs_pkbuf_default_init(&global_conf.pkbuf_config); recalculate_pool_size(); return OGS_OK; } static int global_conf_validation(void) { if (global_conf.parameter.no_ipv4 == 1 && global_conf.parameter.no_ipv6 == 1) { ogs_error("Both `no_ipv4` and `no_ipv6` set to `true` in `%s`", ogs_app()->file); return OGS_ERROR; } return OGS_OK; } int ogs_app_parse_global_conf(ogs_yaml_iter_t *parent) { int rv; ogs_yaml_iter_t global_iter; ogs_assert(parent); rv = global_conf_prepare(); if (rv != OGS_OK) return rv; ogs_yaml_iter_recurse(parent, &global_iter); while (ogs_yaml_iter_next(&global_iter)) { const char *global_key = ogs_yaml_iter_key(&global_iter); ogs_assert(global_key); if (!strcmp(global_key, "parameter")) { ogs_yaml_iter_t parameter_iter; ogs_yaml_iter_recurse(&global_iter, ¶meter_iter); while (ogs_yaml_iter_next(¶meter_iter)) { const char *parameter_key = ogs_yaml_iter_key(¶meter_iter); ogs_assert(parameter_key); if (!strcmp(parameter_key, "no_hss")) { global_conf.parameter.no_hss = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_mme")) { global_conf.parameter.no_mme = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_sgwu")) { global_conf.parameter.no_sgwu = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_sgwc")) { global_conf.parameter.no_sgwc = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_sgw")) { global_conf.parameter.no_sgw = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_pgw")) { global_conf.parameter.no_pgw = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_pcrf")) { global_conf.parameter.no_pcrf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_nrf")) { global_conf.parameter.no_nrf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_scp")) { global_conf.parameter.no_scp = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_sepp")) { global_conf.parameter.no_sepp = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_amf")) { global_conf.parameter.no_amf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_smf")) { global_conf.parameter.no_smf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_upf")) { global_conf.parameter.no_upf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_ausf")) { global_conf.parameter.no_ausf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_udm")) { global_conf.parameter.no_udm = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_pcf")) { global_conf.parameter.no_pcf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_nssf")) { global_conf.parameter.no_nssf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_bsf")) { global_conf.parameter.no_bsf = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_udr")) { global_conf.parameter.no_udr = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_ipv4")) { global_conf.parameter.no_ipv4 = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_ipv6")) { global_conf.parameter.no_ipv6 = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "prefer_ipv4")) { global_conf.parameter.prefer_ipv4 = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "multicast")) { global_conf.parameter.multicast = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "use_openair")) { global_conf.parameter.use_openair = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_ipv4v6_local_addr_in_packet_filter")) { global_conf.parameter. no_ipv4v6_local_addr_in_packet_filter = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_pfcp_rr_select")) { global_conf.parameter.no_pfcp_rr_select = ogs_yaml_iter_bool(¶meter_iter); } else if (!strcmp(parameter_key, "no_time_zone_information")) { global_conf.parameter.no_time_zone_information = ogs_yaml_iter_bool(¶meter_iter); } else ogs_warn("unknown key `%s`", parameter_key); } } else if (!strcmp(global_key, "sockopt")) { ogs_yaml_iter_t sockopt_iter; ogs_yaml_iter_recurse(&global_iter, &sockopt_iter); while (ogs_yaml_iter_next(&sockopt_iter)) { const char *sockopt_key = ogs_yaml_iter_key(&sockopt_iter); ogs_assert(sockopt_key); if (!strcmp(sockopt_key, "no_delay")) { global_conf.sockopt.no_delay = ogs_yaml_iter_bool(&sockopt_iter); } else if (!strcmp(sockopt_key, "linger")) { const char *v = ogs_yaml_iter_value(&sockopt_iter); if (v) global_conf.sockopt.l_linger = atoi(v); global_conf.sockopt.l_onoff = true; } else ogs_warn("unknown key `%s`", sockopt_key); } } else if (!strcmp(global_key, "max")) { ogs_yaml_iter_t max_iter; ogs_yaml_iter_recurse(&global_iter, &max_iter); while (ogs_yaml_iter_next(&max_iter)) { const char *max_key = ogs_yaml_iter_key(&max_iter); ogs_assert(max_key); if (!strcmp(max_key, "ue")) { const char *v = ogs_yaml_iter_value(&max_iter); if (v) global_conf.max.ue = atoi(v); } else if (!strcmp(max_key, "peer") || !strcmp(max_key, "enb")) { const char *v = ogs_yaml_iter_value(&max_iter); if (v) global_conf.max.peer = atoi(v); } else if (!strcmp(max_key, "gtp_peer") || !strcmp(max_key, "enb")) { const char *v = ogs_yaml_iter_value(&max_iter); if (v) global_conf.max.gtp_peer = atoi(v); } else ogs_warn("unknown key `%s`", max_key); } recalculate_pool_size(); } else if (!strcmp(global_key, "pool")) { ogs_yaml_iter_t pool_iter; ogs_yaml_iter_recurse(&global_iter, &pool_iter); while (ogs_yaml_iter_next(&pool_iter)) { const char *pool_key = ogs_yaml_iter_key(&pool_iter); ogs_assert(pool_key); if (!strcmp(pool_key, "128")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_128_pool = atoi(v); } else if (!strcmp(pool_key, "256")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_256_pool = atoi(v); } else if (!strcmp(pool_key, "512")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_512_pool = atoi(v); } else if (!strcmp(pool_key, "1024")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_1024_pool = atoi(v); } else if (!strcmp(pool_key, "2048")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_2048_pool = atoi(v); } else if (!strcmp(pool_key, "8192")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_8192_pool = atoi(v); } else if (!strcmp(pool_key, "32768")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_32768_pool = atoi(v); } else if (!strcmp(pool_key, "big")) { const char *v = ogs_yaml_iter_value(&pool_iter); if (v) global_conf.pkbuf_config.cluster_big_pool = atoi(v); } else ogs_warn("unknown key `%s`", pool_key); } } } rv = global_conf_validation(); if (rv != OGS_OK) return rv; return OGS_OK; } static void regenerate_all_timer_duration(void) { ogs_assert(local_conf.time.message.duration); local_conf.time.message.sbi.client_wait_duration = local_conf.time.message.duration; local_conf.time.message.sbi.connection_deadline = local_conf.time.message.sbi.client_wait_duration + ogs_time_from_sec(1); local_conf.time.message.sbi.reconnect_interval = ogs_max(ogs_time_from_sec(3), local_conf.time.message.sbi.client_wait_duration + ogs_time_from_sec(1)); local_conf.time.message.sbi.reconnect_interval_in_exception = ogs_time_from_sec(2); #define PFCP_N1_RESPONSE_RETRY_COUNT 3 local_conf.time.message.pfcp.n1_response_rcount = PFCP_N1_RESPONSE_RETRY_COUNT; local_conf.time.message.pfcp.t1_response_duration = (local_conf.time.message.duration / (local_conf.time.message.pfcp.n1_response_rcount + 1)); ogs_assert(local_conf.time.message.pfcp.t1_response_duration); #define PFCP_N1_HOLDING_RETRY_COUNT 1 local_conf.time.message.pfcp.n1_holding_rcount = PFCP_N1_HOLDING_RETRY_COUNT; local_conf.time.message.pfcp.t1_holding_duration = local_conf.time.message.pfcp.n1_response_rcount * local_conf.time.message.pfcp.t1_response_duration; ogs_assert(local_conf.time.message.pfcp.t1_holding_duration); local_conf.time.message.pfcp.association_interval = ogs_max(ogs_time_from_sec(3), local_conf.time.message.sbi.client_wait_duration + ogs_time_from_sec(1)); local_conf.time.message.pfcp.no_heartbeat_duration = ogs_max(ogs_time_from_sec(10), local_conf.time.message.sbi.client_wait_duration + ogs_time_from_sec(1)); #define GTP_N3_RESPONSE_RETRY_COUNT 3 local_conf.time.message.gtp.n3_response_rcount = GTP_N3_RESPONSE_RETRY_COUNT; local_conf.time.message.gtp.t3_response_duration = (local_conf.time.message.duration / (local_conf.time.message.gtp.n3_response_rcount + 1)); ogs_assert(local_conf.time.message.gtp.t3_response_duration); #define GTP_N3_HOLDING_RETRY_COUNT 1 local_conf.time.message.gtp.n3_holding_rcount = GTP_N3_HOLDING_RETRY_COUNT; local_conf.time.message.gtp.t3_holding_duration = local_conf.time.message.gtp.n3_response_rcount * local_conf.time.message.gtp.t3_response_duration; ogs_assert(local_conf.time.message.gtp.t3_holding_duration); #if 0 ogs_trace("%lld, %lld, %lld, %d, %lld, %d %lld, %d, %lld, %d, %lld", (long long)local_conf.time.message.duration, (long long)local_conf.time.message.sbi.client_wait_duration, (long long)local_conf.time.message.sbi.connection_deadline, local_conf.time.message.pfcp.n1_response_rcount, (long long)local_conf.time.message.pfcp.t1_response_duration, local_conf.time.message.pfcp.n1_holding_rcount, (long long)local_conf.time.message.pfcp.t1_holding_duration, local_conf.time.message.gtp.n3_response_rcount, (long long)local_conf.time.message.gtp.t3_response_duration, local_conf.time.message.gtp.n3_holding_rcount, (long long)local_conf.time.message.gtp.t3_holding_duration); ogs_trace("%lld, %lld, %lld", (long long)local_conf.time.message.sbi.reconnect_interval, (long long)local_conf.time.message.pfcp.association_interval, (long long)local_conf.time.message.pfcp.no_heartbeat_duration); #endif } static int local_conf_prepare(void) { /* * Heartbeat Interval(e.g: 10 seconds) + No Heartbeat Margin(1 second) */ local_conf.time.nf_instance.no_heartbeat_margin = 1; /* 30 seconds */ local_conf.time.nf_instance.validity_duration = 30; /* 86400 seconds = 1 day */ local_conf.time.subscription.validity_duration = 86400; /* * Message Wait Duration : 10 seconds (Default) * * The paging retry timer is 2 seconds and the retry count is 3. * * It is recomended to set at least 9 seconds to reflect * the paging failure result to GTPv2-C or HTTP2(SBI). */ local_conf.time.message.duration = ogs_time_from_sec(10); /* * Handover Wait Duration : 300 ms (Default) * * Time to wait for AMF/MME to send UEContextReleaseCommand * to the source gNB/eNB after receiving HandoverNotify */ local_conf.time.handover.duration = ogs_time_from_msec(300); /* Size of internal metrics pool (amount of ogs_metrics_spec_t) */ ogs_app()->metrics.max_specs = 512; regenerate_all_timer_duration(); return OGS_OK; } static int local_conf_validation(void) { if (local_conf.time.nf_instance.validity_duration == 0) { ogs_error("NF Instance validity-time should not 0"); ogs_error("time:"); ogs_error(" nf_instance:"); ogs_error(" validity: 0"); return OGS_ERROR; } return OGS_OK; } int ogs_app_parse_local_conf(const char *local) { int rv; yaml_document_t *document = NULL; ogs_yaml_iter_t root_iter; document = ogs_app()->document; ogs_assert(document); rv = local_conf_prepare(); if (rv != OGS_OK) return rv; ogs_yaml_iter_init(&root_iter, document); while (ogs_yaml_iter_next(&root_iter)) { const char *root_key = ogs_yaml_iter_key(&root_iter); ogs_assert(root_key); if (!strcmp(root_key, local)) { ogs_yaml_iter_t local_iter; ogs_yaml_iter_recurse(&root_iter, &local_iter); while (ogs_yaml_iter_next(&local_iter)) { const char *local_key = ogs_yaml_iter_key(&local_iter); ogs_assert(local_key); if (!strcmp(local_key, "serving")) { ogs_yaml_iter_t serving_array, serving_iter; ogs_yaml_iter_recurse(&local_iter, &serving_array); do { const char *mnc = NULL, *mcc = NULL; ogs_assert(local_conf.num_of_serving_plmn_id < OGS_MAX_NUM_OF_PLMN); OGS_YAML_ARRAY_NEXT(&serving_array, &serving_iter); while (ogs_yaml_iter_next(&serving_iter)) { const char *serving_key = ogs_yaml_iter_key(&serving_iter); ogs_assert(serving_key); if (!strcmp(serving_key, "plmn_id")) { ogs_yaml_iter_t plmn_id_iter; ogs_yaml_iter_recurse(&serving_iter, &plmn_id_iter); while (ogs_yaml_iter_next(&plmn_id_iter)) { const char *id_key = ogs_yaml_iter_key(&plmn_id_iter); ogs_assert(id_key); if (!strcmp(id_key, "mcc")) { mcc = ogs_yaml_iter_value( &plmn_id_iter); } else if (!strcmp(id_key, "mnc")) { mnc = ogs_yaml_iter_value( &plmn_id_iter); } } if (mcc && mnc) { ogs_plmn_id_build( &local_conf.serving_plmn_id[ local_conf. num_of_serving_plmn_id], atoi(mcc), atoi(mnc), strlen(mnc)); local_conf.num_of_serving_plmn_id++; } else { ogs_error("Invalid [MCC:%s, MNC:%s]", mcc, mnc); } } else ogs_warn("unknown key `%s`", serving_key); } } while (ogs_yaml_iter_type(&serving_array) == YAML_SEQUENCE_NODE); } else if (!strcmp(local_key, "time")) { ogs_yaml_iter_t time_iter; ogs_yaml_iter_recurse(&local_iter, &time_iter); while (ogs_yaml_iter_next(&time_iter)) { const char *time_key = ogs_yaml_iter_key(&time_iter); ogs_assert(time_key); if (!strcmp(time_key, "nf_instance")) { ogs_yaml_iter_t sbi_iter; ogs_yaml_iter_recurse(&time_iter, &sbi_iter); while (ogs_yaml_iter_next(&sbi_iter)) { const char *sbi_key = ogs_yaml_iter_key(&sbi_iter); ogs_assert(sbi_key); if (!strcmp(sbi_key, "heartbeat")) { const char *v = ogs_yaml_iter_value( &sbi_iter); if (v) local_conf.time.nf_instance. heartbeat_interval = atoi(v); } else if (!strcmp(sbi_key, "validity")) { const char *v = ogs_yaml_iter_value(&sbi_iter); if (v) local_conf.time.nf_instance. validity_duration = atoi(v); } else ogs_warn("unknown key `%s`", sbi_key); } } else if (!strcmp(time_key, "subscription")) { ogs_yaml_iter_t sbi_iter; ogs_yaml_iter_recurse(&time_iter, &sbi_iter); while (ogs_yaml_iter_next(&sbi_iter)) { const char *sbi_key = ogs_yaml_iter_key(&sbi_iter); ogs_assert(sbi_key); if (!strcmp(sbi_key, "validity")) { const char *v = ogs_yaml_iter_value(&sbi_iter); if (v) local_conf.time.subscription. validity_duration = atoi(v); } else ogs_warn("unknown key `%s`", sbi_key); } } else if (!strcmp(time_key, "message")) { ogs_yaml_iter_t msg_iter; ogs_yaml_iter_recurse(&time_iter, &msg_iter); while (ogs_yaml_iter_next(&msg_iter)) { const char *msg_key = ogs_yaml_iter_key(&msg_iter); ogs_assert(msg_key); if (!strcmp(msg_key, "duration")) { const char *v = ogs_yaml_iter_value(&msg_iter); if (v) { local_conf.time.message.duration = ogs_time_from_msec(atoll(v)); regenerate_all_timer_duration(); } } else ogs_warn("unknown key `%s`", msg_key); } } else if (!strcmp(time_key, "handover")) { ogs_yaml_iter_t msg_iter; ogs_yaml_iter_recurse(&time_iter, &msg_iter); while (ogs_yaml_iter_next(&msg_iter)) { const char *msg_key = ogs_yaml_iter_key(&msg_iter); ogs_assert(msg_key); if (!strcmp(msg_key, "duration")) { const char *v = ogs_yaml_iter_value(&msg_iter); if (v) { local_conf.time.handover.duration = ogs_time_from_msec(atoll(v)); } } else ogs_warn("unknown key `%s`", msg_key); } } else if (!strcmp(time_key, "t3502")) { /* handle config in amf */ } else if (!strcmp(time_key, "t3512")) { /* handle config in amf */ } else if (!strcmp(time_key, "t3402")) { /* handle config in mme */ } else if (!strcmp(time_key, "t3412")) { /* handle config in mme */ } else if (!strcmp(time_key, "t3423")) { /* handle config in mme */ } else ogs_warn("unknown key `%s`", time_key); } } } } } rv = local_conf_validation(); if (rv != OGS_OK) return rv; return OGS_OK; } int ogs_app_parse_sockopt_config( ogs_yaml_iter_t *parent, ogs_sockopt_t *option) { ogs_yaml_iter_t sockopt_iter; ogs_assert(parent); ogs_assert(option); ogs_sockopt_init(option); ogs_yaml_iter_recurse(parent, &sockopt_iter); while (ogs_yaml_iter_next(&sockopt_iter)) { const char *sockopt_key = ogs_yaml_iter_key(&sockopt_iter); ogs_assert(sockopt_key); if (!strcmp(sockopt_key, "sctp")) { ogs_yaml_iter_t sctp_iter; ogs_yaml_iter_recurse(&sockopt_iter, &sctp_iter); while (ogs_yaml_iter_next(&sctp_iter)) { const char *sctp_key = ogs_yaml_iter_key(&sctp_iter); ogs_assert(sctp_key); if (!strcmp(sctp_key, "spp_hbinterval")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.spp_hbinterval = atoi(v); } else if (!strcmp(sctp_key, "spp_sackdelay")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.spp_sackdelay = atoi(v); } else if (!strcmp(sctp_key, "srto_initial")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.srto_initial = atoi(v); } else if (!strcmp(sctp_key, "srto_min")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.srto_min = atoi(v); } else if (!strcmp(sctp_key, "srto_max")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.srto_max = atoi(v); } else if (!strcmp(sctp_key, "sinit_num_ostreams")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.sinit_num_ostreams = atoi(v); } else if (!strcmp(sctp_key, "sinit_max_instreams")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.sinit_max_instreams = atoi(v); } else if (!strcmp(sctp_key, "sinit_max_attempts")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.sinit_max_attempts = atoi(v); } else if (!strcmp(sctp_key, "sinit_max_init_timeo")) { const char *v = ogs_yaml_iter_value(&sctp_iter); if (v) option->sctp.sinit_max_init_timeo = atoi(v); } else { ogs_error("unknown key `%s`", sctp_key); return OGS_ERROR; } } } else if (!strcmp(sockopt_key, "sctp_nodelay")) { option->sctp_nodelay = ogs_yaml_iter_bool(&sockopt_iter); } else if (!strcmp(sockopt_key, "tcp_nodelay")) { option->tcp_nodelay = ogs_yaml_iter_bool(&sockopt_iter); } else if (!strcmp(sockopt_key, "so_linger")) { ogs_yaml_iter_t so_linger_iter; ogs_yaml_iter_recurse(&sockopt_iter, &so_linger_iter); while (ogs_yaml_iter_next(&so_linger_iter)) { const char *so_linger_key = ogs_yaml_iter_key(&so_linger_iter); ogs_assert(so_linger_key); if (!strcmp(so_linger_key, "l_onoff")) { option->so_linger.l_onoff = ogs_yaml_iter_bool(&so_linger_iter); } else if (!strcmp(so_linger_key, "l_linger")) { const char *v = ogs_yaml_iter_value(&so_linger_iter); if (v) option->so_linger.l_linger = atoi(v); } else { ogs_error("unknown key `%s`", so_linger_key); return OGS_ERROR; } } } else if (!strcmp(sockopt_key, "so_bindtodevice")) { option->so_bindtodevice = ogs_yaml_iter_value(&sockopt_iter); } else { ogs_error("unknown key `%s`", sockopt_key); return OGS_ERROR; } } return OGS_OK; } static int parse_br_conf(ogs_yaml_iter_t *parent, ogs_bitrate_t *br) { ogs_yaml_iter_t br_iter; ogs_yaml_iter_recurse(parent, &br_iter); while (ogs_yaml_iter_next(&br_iter)) { const char *br_key = ogs_yaml_iter_key(&br_iter); ogs_assert(br_key); if (!strcmp(br_key, OGS_DOWNLINK_STRING)) { uint8_t unit = 0; int n; ogs_yaml_iter_t downlink_iter; ogs_yaml_iter_recurse(&br_iter, &downlink_iter); while (ogs_yaml_iter_next(&downlink_iter)) { const char *downlink_key = ogs_yaml_iter_key(&downlink_iter); ogs_assert(downlink_key); if (!strcmp(downlink_key, OGS_VALUE_STRING)) { const char *v = ogs_yaml_iter_value(&downlink_iter); if (v) br->downlink = atoi(v); } else if (!strcmp(downlink_key, OGS_UNIT_STRING)) { const char *v = ogs_yaml_iter_value(&downlink_iter); if (v) { unit = atoi(v); if (unit == 0 || unit == 1 || unit == 2 || unit == 3 || unit == 4) { } else { ogs_error("Unknown Unit [%d]", unit); return OGS_ERROR; } } } else ogs_warn("unknown key `%s`", downlink_key); } for (n = 0; n < unit; n++) br->downlink *= 1000; } else if (!strcmp(br_key, OGS_UPLINK_STRING)) { uint8_t unit = 0; int n; ogs_yaml_iter_t uplink_iter; ogs_yaml_iter_recurse(&br_iter, &uplink_iter); while (ogs_yaml_iter_next(&uplink_iter)) { const char *uplink_key = ogs_yaml_iter_key(&uplink_iter); ogs_assert(uplink_key); if (!strcmp(uplink_key, OGS_VALUE_STRING)) { const char *v = ogs_yaml_iter_value(&uplink_iter); if (v) br->uplink = atoi(v); } else if (!strcmp(uplink_key, OGS_UNIT_STRING)) { const char *v = ogs_yaml_iter_value(&uplink_iter); if (v) { unit = atoi(v); if (unit == 0 || unit == 1 || unit == 2 || unit == 3 || unit == 4) { } else { ogs_error("Unknown Unit [%d]", unit); return OGS_ERROR; } } } else ogs_warn("unknown key `%s`", uplink_key); } for (n = 0; n < unit; n++) br->uplink *= 1000; } else ogs_warn("unknown key `%s`", br_key); } return OGS_OK; } static int parse_qos_conf(ogs_yaml_iter_t *parent, ogs_qos_t *qos) { int rv; ogs_yaml_iter_t qos_iter; ogs_assert(parent); ogs_assert(qos); ogs_yaml_iter_recurse(parent, &qos_iter); while (ogs_yaml_iter_next(&qos_iter)) { const char *qos_key = ogs_yaml_iter_key(&qos_iter); ogs_assert(qos_key); if (!strcmp(qos_key, OGS_INDEX_STRING)) { const char *v = ogs_yaml_iter_value(&qos_iter); if (v) { uint8_t index = atoi(v); if (index == 1 || index == 2 || index == 3 || index == 4 || index == 65 || index == 66 || index == 67 || index == 75 || index == 71 || index == 72 || index == 73 || index == 74 || index == 76 || index == 5 || index == 6 || index == 7 || index == 8 || index == 9 || index == 69 || index == 70 || index == 79 || index == 80 || index == 82 || index == 83 || index == 84 || index == 85 || index == 86) qos->index = index; else { ogs_error("Unknown QCI [%d]", index); return OGS_ERROR; } } } else if (!strcmp(qos_key, OGS_ARP_STRING)) { ogs_yaml_iter_t arp_iter; ogs_yaml_iter_recurse(&qos_iter, &arp_iter); while (ogs_yaml_iter_next(&arp_iter)) { const char *arp_key = ogs_yaml_iter_key(&arp_iter); ogs_assert(arp_key); if (!strcmp(arp_key, OGS_PRIORITY_LEVEL_STRING)) { const char *v = ogs_yaml_iter_value(&arp_iter); if (v) { uint8_t priority_level = atoi(v); if (priority_level >= 1 && priority_level <= 15) qos->arp.priority_level = priority_level; else { ogs_error("Unknown Priority Level [%d]", priority_level); return OGS_ERROR; } } } else if (!strcmp(arp_key, OGS_PRE_EMPTION_CAPABILITY_STRING)) { const char *v = ogs_yaml_iter_value(&arp_iter); if (v) { uint8_t pre_emption_capability = atoi(v); if (pre_emption_capability == OGS_5GC_PRE_EMPTION_DISABLED || pre_emption_capability == OGS_5GC_PRE_EMPTION_ENABLED) qos->arp.pre_emption_capability = pre_emption_capability; else { ogs_error("Unknown Preemption Capability [%d]", pre_emption_capability); return OGS_ERROR; } } } else if (!strcmp(arp_key, OGS_PRE_EMPTION_VULNERABILITY_STRING)) { const char *v = ogs_yaml_iter_value(&arp_iter); if (v) { uint8_t pre_emption_vulnerability = atoi(v); if (pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_DISABLED || pre_emption_vulnerability == OGS_5GC_PRE_EMPTION_ENABLED) qos->arp.pre_emption_vulnerability = pre_emption_vulnerability; else { ogs_error("Unknown Preemption Vulnerablility [%d]", pre_emption_vulnerability); return OGS_ERROR; } } } else ogs_warn("unknown key `%s`", arp_key); } } else if (!strcmp(qos_key, OGS_MBR_STRING)) { rv = parse_br_conf(&qos_iter, &qos->mbr); if (rv != OGS_OK) { ogs_error("parse_br_conf() failed"); return rv; } } else if (!strcmp(qos_key, OGS_GBR_STRING)) { rv = parse_br_conf(&qos_iter, &qos->gbr); if (rv != OGS_OK) { ogs_error("parse_br_conf() failed"); return rv; } } } return OGS_OK; } static int session_conf_prepare(ogs_app_slice_conf_t *slice_conf) { ogs_assert(slice_conf); return OGS_OK; } static int session_conf_validation(ogs_app_slice_conf_t *slice_conf) { int rv, j, k; ogs_app_session_conf_t *session_conf = NULL; ogs_assert(slice_conf); ogs_list_for_each(&slice_conf->sess_list, session_conf) { ogs_session_data_t *session_data = &session_conf->data; ogs_info("NAME[%s]", session_data->session.name); ogs_info("QCI[%d]", session_data->session.qos.index); ogs_info("ARP[%d:%d:%d]", session_data->session.qos.arp.priority_level, session_data->session.qos.arp.pre_emption_capability, session_data->session.qos.arp.pre_emption_vulnerability); ogs_info("AMBR[Downlink:%lld:Uplink:%lld]", (long long)session_data->session.ambr.downlink, (long long)session_data->session.ambr.uplink); for (j = 0; j < session_data->num_of_pcc_rule; j++) { ogs_info("PCC_RULE[%d]", j+1); ogs_info(" ID[%s]", session_data->pcc_rule[j].id); ogs_info(" NAME[%s]", session_data->pcc_rule[j].name); ogs_info(" QCI[%d]", session_data->pcc_rule[j].qos.index); ogs_info(" ARP[%d:%d:%d]", session_data->pcc_rule[j].qos.arp.priority_level, session_data->pcc_rule[j].qos.arp. pre_emption_capability, session_data->pcc_rule[j].qos.arp. pre_emption_vulnerability); ogs_info(" MBR[Downlink:%lld:Uplink:%lld]", (long long)session_data->pcc_rule[j].qos.mbr.downlink, (long long)session_data->pcc_rule[j].qos.mbr.uplink); ogs_info(" GBR[Downlink:%lld:Uplink:%lld]", (long long)session_data->pcc_rule[j].qos.gbr.downlink, (long long)session_data->pcc_rule[j].qos.gbr.uplink); ogs_info(" NUM_OF_FLOW [%d]", session_data->pcc_rule[j].num_of_flow); for (k = 0; k < session_data->pcc_rule[j].num_of_flow; k++) { ogs_info(" DIRECTION[%d]", session_data->pcc_rule[j].flow[k].direction); ogs_info(" DESCRIPTION[%s]", session_data->pcc_rule[j].flow[k].description); } } rv = ogs_check_br_conf(&session_data->session.ambr); if (rv != OGS_OK) { ogs_error("check_br_conf(AMBR) failed"); return rv; } rv = ogs_check_qos_conf(&session_data->session.qos); if (rv != OGS_OK) { ogs_error("check_qos_conf(SESS) failed"); return rv; } } return OGS_OK; } int ogs_app_parse_session_conf( ogs_yaml_iter_t *parent, ogs_app_slice_conf_t *slice_conf) { int rv; ogs_yaml_iter_t session_array, session_iter; ogs_assert(parent); ogs_assert(slice_conf); rv = session_conf_prepare(slice_conf); if (rv != OGS_OK) return rv; ogs_yaml_iter_recurse(parent, &session_array); do { const char *name = NULL; ogs_app_session_conf_t *session_conf = NULL; ogs_session_data_t *session_data = NULL; OGS_YAML_ARRAY_NEXT(&session_array, &session_iter); while (ogs_yaml_iter_next(&session_iter)) { const char *session_key = ogs_yaml_iter_key(&session_iter); ogs_assert(session_key); if (!strcmp(session_key, OGS_NAME_STRING)) { name = (char *)ogs_yaml_iter_value(&session_iter); } } if (name) { session_conf = ogs_app_session_conf_add(slice_conf, (char *)name); if (!session_conf) { ogs_error("ogs_app_session_conf_add() failed [DNN:%s]", name); return OGS_ERROR; } } else { ogs_error("No APN/DNN"); return OGS_ERROR; } session_data = &session_conf->data; OGS_YAML_ARRAY_RECURSE(&session_array, &session_iter); while (ogs_yaml_iter_next(&session_iter)) { const char *session_key = ogs_yaml_iter_key(&session_iter); ogs_assert(session_key); if (!strcmp(session_key, OGS_TYPE_STRING)) { const char *v = ogs_yaml_iter_value(&session_iter); if (v) { uint8_t session_type = atoi(v); if (session_type == OGS_PDU_SESSION_TYPE_IPV4 || session_type == OGS_PDU_SESSION_TYPE_IPV6 || session_type == OGS_PDU_SESSION_TYPE_IPV4V6 || session_type == OGS_PDU_SESSION_TYPE_UNSTRUCTURED || session_type == OGS_PDU_SESSION_TYPE_ETHERNET) session_data->session.session_type = session_type; else { ogs_error("Unknown Session Type [%d]", session_type); return OGS_ERROR; } } } else if (!strcmp(session_key, OGS_AMBR_STRING)) { rv = parse_br_conf(&session_iter, &session_data->session.ambr); if (rv != OGS_OK) { ogs_error("parse_qos_conf() failed"); return rv; } } else if (!strcmp(session_key, OGS_QOS_STRING)) { rv = parse_qos_conf(&session_iter, &session_data->session.qos); if (rv != OGS_OK) { ogs_error("parse_qos_conf() failed"); return rv; } } else if (!strcmp(session_key, OGS_PCC_RULE_STRING)) { int pcc_rule_index = 0; ogs_yaml_iter_t pcc_rule_array, pcc_rule_iter; ogs_yaml_iter_recurse(&session_iter, &pcc_rule_array); do { ogs_pcc_rule_t *pcc_rule = NULL; ogs_assert(session_data->num_of_pcc_rule < OGS_MAX_NUM_OF_PCC_RULE); pcc_rule = &session_data-> pcc_rule[session_data->num_of_pcc_rule]; OGS_YAML_ARRAY_NEXT(&pcc_rule_array, &pcc_rule_iter); while (ogs_yaml_iter_next(&pcc_rule_iter)) { const char *pcc_rule_key = ogs_yaml_iter_key(&pcc_rule_iter); ogs_assert(pcc_rule_key); if (!strcmp(pcc_rule_key, OGS_QOS_STRING)) { rv = parse_qos_conf(&pcc_rule_iter, &pcc_rule->qos); if (rv != OGS_OK) { ogs_error("parse_qos_conf() failed"); return rv; } } else if (!strcmp(pcc_rule_key, OGS_FLOW_STRING)) { ogs_yaml_iter_t flow_array, flow_iter; ogs_yaml_iter_recurse( &pcc_rule_iter, &flow_array); do { ogs_flow_t *flow = NULL; ogs_assert(pcc_rule->num_of_flow < OGS_MAX_NUM_OF_FLOW_IN_PCC_RULE); flow = &pcc_rule->flow[pcc_rule->num_of_flow]; OGS_YAML_ARRAY_NEXT(&flow_array, &flow_iter); while (ogs_yaml_iter_next(&flow_iter)) { const char *flow_key = ogs_yaml_iter_key(&flow_iter); ogs_assert(flow_key); if (!strcmp(flow_key, OGS_DIRECTION_STRING)) { const char *v = ogs_yaml_iter_value(&flow_iter); if (v) { uint8_t direction = atoi(v); if (direction == OGS_FLOW_DOWNLINK_ONLY || direction == OGS_FLOW_UPLINK_ONLY) flow->direction = direction; else { ogs_error( "Unknown Direction [%d]", direction); return OGS_ERROR; } } } else if (!strcmp(flow_key, OGS_DESCRIPTION_STRING)) { const char *v = (char *)ogs_yaml_iter_value( &flow_iter); if (v) { flow->description = ogs_strdup(v); ogs_assert(flow->description); } } } if (flow->direction && flow->description) pcc_rule->num_of_flow++; } while (ogs_yaml_iter_type(&flow_array) == YAML_SEQUENCE_NODE); } else ogs_warn("unknown key `%s`", pcc_rule_key); } if (pcc_rule->qos.index && pcc_rule->qos.arp.priority_level && pcc_rule->qos.arp.pre_emption_capability && pcc_rule->qos.arp.pre_emption_vulnerability) { /* EPC: Charing-Rule-Name */ ogs_assert(!pcc_rule->name); pcc_rule->name = ogs_msprintf("%s-g%d", session_data->session.name, pcc_rule_index+1); ogs_assert(pcc_rule->name); /* 5GC: PCC-Rule-Id */ ogs_assert(!pcc_rule->id); pcc_rule->id = ogs_msprintf("%s-n%d", session_data->session.name, pcc_rule_index+1); ogs_assert(pcc_rule->id); pcc_rule->precedence = pcc_rule_index+1; pcc_rule_index++; session_data->num_of_pcc_rule++; } else ogs_warn("Mandatory is MISSING - " "QCI[%d], ARP[%d:%d:%d]", pcc_rule->qos.index, pcc_rule->qos.arp.priority_level, pcc_rule->qos.arp. pre_emption_capability, pcc_rule->qos.arp. pre_emption_vulnerability); } while (ogs_yaml_iter_type(&pcc_rule_array) == YAML_SEQUENCE_NODE); } } } while (ogs_yaml_iter_type(&session_array) == YAML_SEQUENCE_NODE); rv = session_conf_validation(slice_conf); if (rv != OGS_OK) return rv; return OGS_OK; } ogs_app_policy_conf_t *ogs_app_policy_conf_add(ogs_plmn_id_t *plmn_id) { ogs_app_policy_conf_t *policy_conf = NULL; ogs_assert(plmn_id); ogs_pool_alloc(&policy_conf_pool, &policy_conf); if (!policy_conf) { ogs_error("Maximum number of policy_conf[%d] reached", OGS_MAX_NUM_OF_PLMN); return NULL; } memset(policy_conf, 0, sizeof *policy_conf); memcpy(&policy_conf->plmn_id, plmn_id, sizeof(ogs_plmn_id_t)); ogs_list_init(&policy_conf->slice_list); ogs_list_add(&local_conf.policy_list, policy_conf); ogs_info("POLICY config added [%d]", ogs_list_count(&local_conf.policy_list)); return policy_conf; } ogs_app_policy_conf_t *ogs_app_policy_conf_find_by_plmn_id( ogs_plmn_id_t *plmn_id) { ogs_app_policy_conf_t *policy_conf = NULL; ogs_assert(plmn_id); ogs_list_for_each(&local_conf.policy_list, policy_conf) { if (memcmp(&policy_conf->plmn_id, plmn_id, sizeof(ogs_plmn_id_t)) == 0) break; } return policy_conf; } void ogs_app_policy_conf_remove(ogs_app_policy_conf_t *policy_conf) { ogs_assert(policy_conf); ogs_list_remove(&local_conf.policy_list, policy_conf); ogs_app_slice_conf_remove_all(policy_conf); ogs_pool_free(&policy_conf_pool, policy_conf); ogs_info("POLICY config removed [%d]", ogs_list_count(&local_conf.policy_list)); } void ogs_app_policy_conf_remove_all(void) { ogs_app_policy_conf_t *policy_conf = NULL, *next_conf = NULL;; ogs_list_for_each_safe(&local_conf.policy_list, next_conf, policy_conf) ogs_app_policy_conf_remove(policy_conf); } ogs_app_slice_conf_t *ogs_app_slice_conf_add( ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai) { ogs_app_slice_conf_t *slice_conf = NULL; ogs_assert(policy_conf); ogs_assert(s_nssai); ogs_assert(s_nssai->sst); ogs_pool_alloc(&slice_conf_pool, &slice_conf); if (!slice_conf) { ogs_error("Maximum number of slice_conf[%d] reached", OGS_MAX_NUM_OF_SLICE); return NULL; } memset(slice_conf, 0, sizeof *slice_conf); slice_conf->data.s_nssai.sst = s_nssai->sst; slice_conf->data.s_nssai.sd.v = s_nssai->sd.v; ogs_list_init(&slice_conf->sess_list); ogs_list_add(&policy_conf->slice_list, slice_conf); slice_conf->policy_conf = policy_conf; ogs_info("SLICE config added [%d]", ogs_list_count(&policy_conf->slice_list)); return slice_conf; } ogs_app_slice_conf_t *ogs_app_slice_conf_find_by_s_nssai( ogs_app_policy_conf_t *policy_conf, ogs_s_nssai_t *s_nssai) { ogs_app_slice_conf_t *slice_conf = NULL; ogs_assert(policy_conf); ogs_assert(s_nssai); ogs_assert(s_nssai->sst); ogs_list_for_each(&policy_conf->slice_list, slice_conf) { if (slice_conf->data.s_nssai.sst == s_nssai->sst && slice_conf->data.s_nssai.sd.v == s_nssai->sd.v) break; } return slice_conf; } void ogs_app_slice_conf_remove(ogs_app_slice_conf_t *slice_conf) { ogs_app_policy_conf_t *policy_conf = NULL; ogs_assert(slice_conf); policy_conf = slice_conf->policy_conf; ogs_assert(policy_conf); ogs_list_remove(&policy_conf->slice_list, slice_conf); ogs_app_session_conf_remove_all(slice_conf); ogs_pool_free(&slice_conf_pool, slice_conf); ogs_info("SLICE config removed [%d]", ogs_list_count(&policy_conf->slice_list)); } void ogs_app_slice_conf_remove_all(ogs_app_policy_conf_t *policy_conf) { ogs_app_slice_conf_t *slice_conf = NULL, *next_conf = NULL;; ogs_assert(policy_conf); ogs_list_for_each_safe(&policy_conf->slice_list, next_conf, slice_conf) ogs_app_slice_conf_remove(slice_conf); } int ogs_app_check_policy_conf(void) { ogs_app_policy_conf_t *policy_conf = NULL; ogs_list_for_each(&ogs_local_conf()->policy_list, policy_conf) { ogs_app_slice_conf_t *slice_conf = NULL; bool default_indicator = false; ogs_list_for_each(&policy_conf->slice_list, slice_conf) { if (slice_conf->data.default_indicator == true) default_indicator = true; if (ogs_list_count(&slice_conf->sess_list) == 0) { ogs_error("At least 1 Session is required"); return OGS_ERROR; } } if (default_indicator == false) { ogs_error("At least 1 Default S-NSSAI is required"); return OGS_ERROR; } } return OGS_OK; } ogs_app_session_conf_t *ogs_app_session_conf_add( ogs_app_slice_conf_t *slice_conf, char *name) { ogs_app_session_conf_t *session_conf = NULL; ogs_assert(slice_conf); ogs_assert(name); ogs_pool_alloc(&session_conf_pool, &session_conf); if (!session_conf) { ogs_error("Maximum number of session_conf[%d] reached", OGS_MAX_NUM_OF_SLICE*OGS_MAX_NUM_OF_SESS); return NULL; } memset(session_conf, 0, sizeof *session_conf); session_conf->data.session.name = ogs_strdup(name); if (!session_conf->data.session.name) { ogs_error("No memory for DNN[%s]", name); ogs_pool_free(&session_conf_pool, session_conf); return NULL; } ogs_list_add(&slice_conf->sess_list, session_conf); session_conf->slice_conf = slice_conf; ogs_info("SESSION config added [%d]", ogs_list_count(&slice_conf->sess_list)); return session_conf; } ogs_app_session_conf_t *ogs_app_session_conf_find_by_dnn( ogs_app_slice_conf_t *slice_conf, char *name) { ogs_app_session_conf_t *session_conf = NULL; ogs_assert(slice_conf); ogs_assert(name); ogs_list_for_each(&slice_conf->sess_list, session_conf) { ogs_assert(session_conf->data.session.name); if (strcmp(session_conf->data.session.name, name) == 0) break; } return session_conf; } void ogs_app_session_conf_remove(ogs_app_session_conf_t *session_conf) { ogs_app_slice_conf_t *slice_conf = NULL; ogs_assert(session_conf); slice_conf = session_conf->slice_conf; ogs_assert(slice_conf); ogs_list_remove(&slice_conf->sess_list, session_conf); OGS_SESSION_DATA_FREE(&session_conf->data); ogs_pool_free(&session_conf_pool, session_conf); ogs_info("SESSION config removed [%d]", ogs_list_count(&slice_conf->sess_list)); } void ogs_app_session_conf_remove_all(ogs_app_slice_conf_t *slice_conf) { ogs_app_session_conf_t *session_conf = NULL, *next_conf = NULL;; ogs_assert(slice_conf); ogs_list_for_each_safe(&slice_conf->sess_list, next_conf, session_conf) ogs_app_session_conf_remove(session_conf); } int ogs_app_config_session_data( ogs_plmn_id_t *plmn_id, ogs_s_nssai_t *s_nssai, char *dnn, ogs_session_data_t *session_data) { ogs_app_policy_conf_t *policy_conf = NULL; ogs_app_slice_conf_t *slice_conf = NULL; ogs_app_session_conf_t *session_conf = NULL; ogs_assert(dnn); ogs_assert(session_data); if (plmn_id) { policy_conf = ogs_app_policy_conf_find_by_plmn_id(plmn_id); if (!policy_conf) { ogs_error("No POLICY [MCC:%03d,MNC:%03d]", ogs_plmn_id_mcc(plmn_id), ogs_plmn_id_mnc(plmn_id)); return OGS_ERROR; } } else { policy_conf = ogs_list_first(&ogs_local_conf()->policy_list); if (!policy_conf) { ogs_error("No default POLICY for EPC"); return OGS_ERROR; } } if (s_nssai) { slice_conf = ogs_app_slice_conf_find_by_s_nssai(policy_conf, s_nssai); if (!slice_conf) { ogs_error("No SLICE [SST:%d, SD:0x%x]", s_nssai->sst, s_nssai->sd.v); return OGS_ERROR; } } else { slice_conf = ogs_list_first(&policy_conf->slice_list); if (!slice_conf) { ogs_error("No default SLICE for EPC"); return OGS_ERROR; } } session_conf = ogs_app_session_conf_find_by_dnn(slice_conf, dnn); if (!session_conf) { ogs_error("No SESSION [%s]", dnn); return OGS_ERROR; } OGS_STORE_SESSION_DATA(session_data, &session_conf->data); return OGS_OK; }