Coverage Report

Created: 2026-11-12 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/sbi/context.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019-2025 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-sbi.h"
21
22
int __ogs_sbi_domain;
23
static ogs_sbi_context_t self;
24
static int context_initialized = 0;
25
26
static OGS_POOL(nf_instance_pool, ogs_sbi_nf_instance_t);
27
static OGS_POOL(nf_service_pool, ogs_sbi_nf_service_t);
28
static OGS_POOL(xact_pool, ogs_sbi_xact_t);
29
static OGS_POOL(subscription_spec_pool, ogs_sbi_subscription_spec_t);
30
static OGS_POOL(subscription_data_pool, ogs_sbi_subscription_data_t);
31
static OGS_POOL(nf_info_pool, ogs_sbi_nf_info_t);
32
33
void ogs_sbi_context_init(OpenAPI_nf_type_e nf_type)
34
0
{
35
0
    char nf_instance_id[OGS_UUID_FORMATTED_LENGTH + 1];
36
37
0
    ogs_assert(nf_type);
38
39
0
    ogs_assert(context_initialized == 0);
40
41
    /* Initialize SBI context */
42
0
    memset(&self, 0, sizeof(ogs_sbi_context_t));
43
44
0
    ogs_log_install_domain(&__ogs_sbi_domain, "sbi", ogs_core()->log.level);
45
46
0
    ogs_sbi_message_init(ogs_app()->pool.message, ogs_app()->pool.message);
47
0
    ogs_sbi_server_init(ogs_app()->pool.event, ogs_app()->pool.event);
48
0
    ogs_sbi_client_init(ogs_app()->pool.event, ogs_app()->pool.event);
49
50
0
    ogs_list_init(&self.nf_instance_list);
51
0
    ogs_pool_init(&nf_instance_pool, ogs_app()->pool.nf);
52
0
    ogs_pool_init(&nf_service_pool, ogs_app()->pool.nf_service);
53
54
0
    ogs_pool_init(&xact_pool, ogs_app()->pool.xact);
55
56
0
    ogs_list_init(&self.subscription_spec_list);
57
0
    ogs_pool_init(&subscription_spec_pool, ogs_app()->pool.subscription);
58
59
0
    ogs_list_init(&self.subscription_data_list);
60
0
    ogs_pool_init(&subscription_data_pool, ogs_app()->pool.subscription);
61
62
0
    ogs_pool_init(&nf_info_pool, ogs_app()->pool.nf * OGS_MAX_NUM_OF_NF_INFO);
63
64
    /* Add SELF NF-Instance */
65
0
    self.nf_instance = ogs_sbi_nf_instance_add();
66
0
    ogs_assert(self.nf_instance);
67
68
0
    ogs_uuid_get(&self.uuid);
69
0
    ogs_uuid_format(nf_instance_id, &self.uuid);
70
0
    ogs_sbi_nf_instance_set_id(self.nf_instance, nf_instance_id);
71
0
    ogs_sbi_nf_instance_set_type(self.nf_instance, nf_type);
72
73
    /* Add NRF NF-Instance */
74
0
    if (nf_type != OpenAPI_nf_type_NRF) {
75
0
        self.nrf_instance = ogs_sbi_nf_instance_add();
76
0
        ogs_assert(self.nrf_instance);
77
0
        ogs_sbi_nf_instance_set_type(self.nrf_instance, OpenAPI_nf_type_NRF);
78
0
    }
79
80
    /* Add SCP NF-Instance */
81
0
    if (nf_type != OpenAPI_nf_type_NRF) {
82
0
        self.scp_instance = ogs_sbi_nf_instance_add();
83
0
        ogs_assert(self.scp_instance);
84
0
        ogs_sbi_nf_instance_set_type(self.scp_instance, OpenAPI_nf_type_SCP);
85
0
    }
86
87
0
    context_initialized = 1;
88
0
}
89
90
void ogs_sbi_context_final(void)
91
0
{
92
0
    ogs_assert(context_initialized == 1);
93
94
0
    ogs_sbi_subscription_data_remove_all();
95
0
    ogs_pool_final(&subscription_data_pool);
96
97
0
    ogs_sbi_subscription_spec_remove_all();
98
0
    ogs_pool_final(&subscription_spec_pool);
99
100
0
    ogs_pool_final(&xact_pool);
101
102
0
    ogs_sbi_nf_instance_remove_all();
103
104
0
    ogs_pool_final(&nf_instance_pool);
105
0
    ogs_pool_final(&nf_service_pool);
106
0
    ogs_pool_final(&nf_info_pool);
107
108
0
    ogs_sbi_client_final();
109
0
    ogs_sbi_server_final();
110
0
    ogs_sbi_message_final();
111
112
0
    context_initialized = 0;
113
0
}
114
115
ogs_sbi_context_t *ogs_sbi_self(void)
116
0
{
117
0
    return &self;
118
0
}
119
120
static int ogs_sbi_context_prepare(void)
121
0
{
122
#if ENABLE_ACCEPT_ENCODING
123
    self.content_encoding = "gzip";
124
#endif
125
126
0
    self.tls.server.scheme = OpenAPI_uri_scheme_http;
127
0
    self.tls.client.scheme = OpenAPI_uri_scheme_http;
128
129
    /* Initialize delegated config with defaults */
130
0
    self.client_delegated_config.nrf.nfm  = OGS_SBI_CLIENT_DELEGATED_AUTO;
131
0
    self.client_delegated_config.nrf.disc = OGS_SBI_CLIENT_DELEGATED_AUTO;
132
0
    self.client_delegated_config.scp.next = OGS_SBI_CLIENT_DELEGATED_AUTO;
133
134
0
    return OGS_OK;
135
0
}
136
137
static int ogs_sbi_context_validation(
138
        const char *local, const char *nrf, const char *scp)
139
0
{
140
0
#define MAX_MODE 3
141
0
    int i;
142
0
    ogs_sbi_client_delegated_mode_e mode[MAX_MODE];
143
144
0
    ogs_assert(context_initialized == 1);
145
146
    /* If SMF is only used in 4G EPC, or the EIR only serves S13,
147
     * no SBI interface is required. */
148
0
    if (local && strcmp(local, "smf") != 0 && strcmp(local, "eir") != 0 &&
149
0
            ogs_sbi_server_first() == NULL) {
150
0
        ogs_error("No %s.sbi.address: in '%s'", local, ogs_app()->file);
151
0
        return OGS_ERROR;
152
0
    }
153
154
0
    mode[0] = self.client_delegated_config.nrf.nfm;
155
0
    mode[1] = self.client_delegated_config.nrf.disc;
156
0
    mode[2] = self.client_delegated_config.scp.next;
157
158
0
    for (i = 0; i < MAX_MODE; i++) {
159
0
        switch (mode[i]) {
160
0
        case OGS_SBI_CLIENT_DELEGATED_AUTO:
161
0
            if (local && strcmp(local, "nrf") == 0) {
162
                /* Skip NRF */
163
0
            } else if (local && strcmp(local, "scp") == 0) {
164
                /* Skip SCP */
165
0
            } else if (local && strcmp(local, "smf") == 0) {
166
                /* Skip SMF since SMF can run 4G */
167
0
            } else if (local && strcmp(local, "eir") == 0 &&
168
0
                    ogs_sbi_server_first() == NULL) {
169
                /* Skip EIR when it only serves S13 */
170
0
            } else {
171
0
                if (NF_INSTANCE_CLIENT(self.nrf_instance) ||
172
0
                    NF_INSTANCE_CLIENT(self.scp_instance)) {
173
0
                } else {
174
0
                    ogs_error("[%d] DELEGATED_AUTO - "
175
0
                            "Both NRF and %s are unavailable",
176
0
                            i, scp && strcmp(scp, "next_scp") == 0 ?
177
0
                                "Next-hop SCP" : "SCP");
178
0
                    return OGS_ERROR;
179
0
                }
180
0
            }
181
0
            break;
182
0
        case OGS_SBI_CLIENT_DELEGATED_YES:
183
0
            if (NF_INSTANCE_CLIENT(self.scp_instance) == NULL) {
184
0
                ogs_error("[%d] DELEGATED_YES - no %s available",
185
0
                        i, scp && strcmp(scp, "next_scp") == 0 ?
186
0
                            "Next-hop SCP" : "SCP");
187
0
                return OGS_ERROR;
188
0
            }
189
0
            break;
190
0
        case OGS_SBI_CLIENT_DELEGATED_NO:
191
0
            if (NF_INSTANCE_CLIENT(self.nrf_instance) == NULL) {
192
0
                ogs_error("[%d] DELEGATED_NO - no NRF available", i);
193
0
                return OGS_ERROR;
194
0
            }
195
0
            break;
196
0
        default:
197
0
            ogs_fatal("[%d] Invalid dicovery-config delegated [%d]",
198
0
                    i, mode[i]);
199
0
            ogs_assert_if_reached();
200
0
        }
201
0
    }
202
203
0
    if (ogs_sbi_self()->tls.server.scheme == OpenAPI_uri_scheme_https) {
204
0
        if (!ogs_sbi_self()->tls.server.private_key) {
205
0
            ogs_error("HTTPS scheme enabled but no server key");
206
0
            return OGS_ERROR;
207
0
        }
208
0
        if (!ogs_sbi_self()->tls.server.cert) {
209
0
            ogs_error("HTTPS scheme enabled but no server certificate");
210
0
            return OGS_ERROR;
211
0
        }
212
0
    }
213
214
0
    if (ogs_sbi_self()->tls.server.verify_client) {
215
0
        if (!ogs_sbi_self()->tls.server.verify_client_cacert) {
216
0
            ogs_error("CLIENT verification enabled but no CA certificate");
217
0
            return OGS_ERROR;
218
0
        }
219
0
    }
220
221
0
    return OGS_OK;
222
0
}
223
224
int ogs_sbi_context_parse_config(
225
        const char *local, const char *nrf, const char *scp)
226
0
{
227
0
    int rv;
228
0
    yaml_document_t *document = NULL;
229
0
    ogs_yaml_iter_t root_iter;
230
0
    int idx = 0;
231
232
0
    document = ogs_app()->document;
233
0
    ogs_assert(document);
234
235
0
    rv = ogs_sbi_context_prepare();
236
0
    if (rv != OGS_OK) return rv;
237
238
0
    ogs_yaml_iter_init(&root_iter, document);
239
0
    while (ogs_yaml_iter_next(&root_iter)) {
240
0
        const char *root_key = ogs_yaml_iter_key(&root_iter);
241
0
        ogs_assert(root_key);
242
0
        if (local && !strcmp(root_key, local) &&
243
0
            idx++ == ogs_app()->config_section_id) {
244
0
            ogs_yaml_iter_t local_iter;
245
0
            ogs_yaml_iter_recurse(&root_iter, &local_iter);
246
0
            while (ogs_yaml_iter_next(&local_iter)) {
247
0
                const char *local_key = ogs_yaml_iter_key(&local_iter);
248
0
                ogs_assert(local_key);
249
0
                if (!strcmp(local_key, "default")) {
250
0
                    ogs_yaml_iter_t default_iter;
251
0
                    ogs_yaml_iter_recurse(&local_iter, &default_iter);
252
0
                    while (ogs_yaml_iter_next(&default_iter)) {
253
0
                        const char *default_key =
254
0
                            ogs_yaml_iter_key(&default_iter);
255
0
                        ogs_assert(default_key);
256
0
                        if (!strcmp(default_key, "interface")) {
257
0
                           self.local_if = ogs_yaml_iter_value(&default_iter);
258
0
                        } else if (!strcmp(default_key, "tls")) {
259
0
                            ogs_yaml_iter_t tls_iter;
260
0
                            ogs_yaml_iter_recurse(&default_iter, &tls_iter);
261
0
                            while (ogs_yaml_iter_next(&tls_iter)) {
262
0
                                const char *tls_key =
263
0
                                    ogs_yaml_iter_key(&tls_iter);
264
0
                                ogs_assert(tls_key);
265
0
                                if (!strcmp(tls_key, "server")) {
266
0
                                    ogs_yaml_iter_t server_iter;
267
0
                                    ogs_yaml_iter_recurse(
268
0
                                            &tls_iter, &server_iter);
269
0
                                    while (ogs_yaml_iter_next(&server_iter)) {
270
0
                                        const char *server_key =
271
0
                                            ogs_yaml_iter_key(&server_iter);
272
0
                                        ogs_assert(server_key);
273
0
                                        if (!strcmp(server_key, "scheme")) {
274
0
                                            const char *v = ogs_yaml_iter_value(
275
0
                                                    &server_iter);
276
0
                                            if (v) {
277
0
                                                if (!ogs_strcasecmp(
278
0
                                                            v, "https"))
279
0
                                                    self.tls.server.scheme =
280
0
                                                    OpenAPI_uri_scheme_https;
281
0
                                                else if (!ogs_strcasecmp(
282
0
                                                            v, "http"))
283
0
                                                    self.tls.server.scheme =
284
0
                                                    OpenAPI_uri_scheme_http;
285
0
                                                else
286
0
                                                    ogs_warn(
287
0
                                                        "unknown scheme `%s`",
288
0
                                                        v);
289
0
                                            }
290
0
                                        } else if (!strcmp(server_key,
291
0
                                                    "private_key")) {
292
0
                                            self.tls.server.private_key =
293
0
                                                ogs_yaml_iter_value(
294
0
                                                        &server_iter);
295
0
                                        } else if (!strcmp(server_key,
296
0
                                                    "cert")) {
297
0
                                            self.tls.server.cert =
298
0
                                                ogs_yaml_iter_value(
299
0
                                                        &server_iter);
300
0
                                        } else if (!strcmp(server_key,
301
0
                                                    "sslkeylogfile")) {
302
0
                                            self.tls.server.sslkeylog =
303
0
                                                ogs_yaml_iter_value(
304
0
                                                        &server_iter);
305
0
                                        } else if (!strcmp(server_key,
306
0
                                                    "verify_client")) {
307
0
                                            self.tls.server.verify_client =
308
0
                                                ogs_yaml_iter_bool(
309
0
                                                        &server_iter);
310
0
                                        } else if (!strcmp(server_key,
311
0
                                                    "verify_client_cacert")) {
312
0
                                            self.tls.server.
313
0
                                                verify_client_cacert =
314
0
                                                    ogs_yaml_iter_value(
315
0
                                                        &server_iter);
316
0
                                        }
317
0
                                    }
318
0
                                } else if (!strcmp(tls_key, "client")) {
319
0
                                    ogs_yaml_iter_t client_iter;
320
0
                                    ogs_yaml_iter_recurse(
321
0
                                            &tls_iter, &client_iter);
322
0
                                    while (ogs_yaml_iter_next(&client_iter)) {
323
0
                                        const char *client_key =
324
0
                                            ogs_yaml_iter_key(&client_iter);
325
0
                                        ogs_assert(client_key);
326
0
                                        if (!strcmp(client_key, "scheme")) {
327
0
                                            const char *v = ogs_yaml_iter_value(
328
0
                                                    &client_iter);
329
0
                                            if (v) {
330
0
                                                if (!ogs_strcasecmp(
331
0
                                                            v, "https"))
332
0
                                                    self.tls.client.scheme =
333
0
                                                    OpenAPI_uri_scheme_https;
334
0
                                                else if (!ogs_strcasecmp(
335
0
                                                            v, "http"))
336
0
                                                    self.tls.client.scheme =
337
0
                                                    OpenAPI_uri_scheme_http;
338
0
                                                else
339
0
                                                    ogs_warn(
340
0
                                                        "unknown scheme `%s`",
341
0
                                                        v);
342
0
                                            }
343
0
                                        } else if (!strcmp(client_key,
344
0
                                                    "insecure_skip_verify")) {
345
0
                                            self.tls.client.
346
0
                                                insecure_skip_verify =
347
0
                                                    ogs_yaml_iter_bool(
348
0
                                                        &client_iter);
349
0
                                        } else if (!strcmp(client_key,
350
0
                                                    "cacert")) {
351
0
                                            self.tls.client.cacert =
352
0
                                                ogs_yaml_iter_value(
353
0
                                                        &client_iter);
354
0
                                        } else if (!strcmp(client_key,
355
0
                                                    "client_private_key")) {
356
0
                                            self.tls.client.private_key =
357
0
                                                ogs_yaml_iter_value(
358
0
                                                        &client_iter);
359
0
                                        } else if (!strcmp(client_key,
360
0
                                                    "client_cert")) {
361
0
                                            self.tls.client.cert =
362
0
                                                ogs_yaml_iter_value(
363
0
                                                        &client_iter);
364
0
                                        } else if (!strcmp(client_key,
365
0
                                                    "client_sslkeylogfile")) {
366
0
                                            self.tls.client.sslkeylog =
367
0
                                                ogs_yaml_iter_value(
368
0
                                                        &client_iter);
369
0
                                        }
370
0
                                    }
371
0
                                }
372
0
                            }
373
0
                        }
374
0
                    }
375
0
                }
376
0
            }
377
0
        }
378
0
    }
379
380
0
    idx = 0;
381
0
    ogs_yaml_iter_init(&root_iter, document);
382
0
    while (ogs_yaml_iter_next(&root_iter)) {
383
0
        const char *root_key = ogs_yaml_iter_key(&root_iter);
384
0
        ogs_assert(root_key);
385
0
        if (local && !strcmp(root_key, local) &&
386
0
            idx++ == ogs_app()->config_section_id) {
387
0
            ogs_yaml_iter_t local_iter;
388
0
            ogs_yaml_iter_recurse(&root_iter, &local_iter);
389
0
            while (ogs_yaml_iter_next(&local_iter)) {
390
0
                const char *local_key = ogs_yaml_iter_key(&local_iter);
391
0
                ogs_assert(local_key);
392
0
                if (!strcmp(local_key, "sbi")) {
393
0
                    ogs_yaml_iter_t sbi_iter;
394
0
                    ogs_yaml_iter_recurse(&local_iter, &sbi_iter);
395
0
                    while (ogs_yaml_iter_next(&sbi_iter)) {
396
0
                        const char *sbi_key = ogs_yaml_iter_key(&sbi_iter);
397
0
                        ogs_assert(sbi_key);
398
0
                        if (!strcmp(sbi_key, "server")) {
399
0
                            rv = ogs_sbi_context_parse_server_config(
400
0
                                    &sbi_iter, NULL);
401
0
                            if (rv != OGS_OK) {
402
0
                                ogs_error("ogs_sbi_context_parse_server_"
403
0
                                        "config() failed");
404
0
                                return rv;
405
0
                            }
406
0
                        } else if (!strcmp(sbi_key, "client")) {
407
0
                            ogs_yaml_iter_t client_iter;
408
0
                            ogs_yaml_iter_recurse(&sbi_iter, &client_iter);
409
0
                            while (ogs_yaml_iter_next(&client_iter)) {
410
0
                                const char *client_key =
411
0
                                    ogs_yaml_iter_key(&client_iter);
412
0
                                ogs_assert(client_key);
413
0
                                if (ogs_global_conf()->
414
0
                                        parameter.no_nrf == false &&
415
0
                                    nrf && !strcmp(client_key, nrf)) {
416
0
                                    ogs_yaml_iter_t nrf_array, nrf_iter;
417
0
                                    ogs_yaml_iter_recurse(&client_iter,
418
0
                                            &nrf_array);
419
0
                                    do {
420
0
                                        ogs_sbi_client_t *client = NULL;
421
422
0
                                        if (ogs_yaml_iter_type(&nrf_array) ==
423
0
                                                YAML_MAPPING_NODE) {
424
0
                                            memcpy(&nrf_iter, &nrf_array,
425
0
                                                    sizeof(ogs_yaml_iter_t));
426
0
                                        } else if (ogs_yaml_iter_type(
427
0
                                                    &nrf_array) ==
428
0
                                                YAML_SEQUENCE_NODE) {
429
0
                                            if (!ogs_yaml_iter_next(&nrf_array))
430
0
                                                break;
431
0
                                            ogs_yaml_iter_recurse(
432
0
                                                    &nrf_array, &nrf_iter);
433
0
                                        } else if (ogs_yaml_iter_type(
434
0
                                                    &nrf_array) ==
435
0
                                                YAML_SCALAR_NODE) {
436
0
                                            break;
437
0
                                        } else
438
0
                                            ogs_assert_if_reached();
439
440
0
                                        if (NF_INSTANCE_CLIENT(
441
0
                                                    self.nrf_instance)) {
442
0
                                            ogs_error("Only one NRF client "
443
0
                                                    "can be set");
444
0
                                            return OGS_ERROR;
445
0
                                        }
446
447
0
                                        client =
448
0
                                            ogs_sbi_context_parse_client_config(
449
0
                                                &nrf_iter);
450
0
                                        if (!client) {
451
0
                                            ogs_error("ogs_sbi_context_parse_"
452
0
                                                    "client_config() failed");
453
0
                                            return OGS_ERROR;
454
0
                                        }
455
456
0
                                        OGS_SBI_SETUP_CLIENT(
457
0
                                                self.nrf_instance, client);
458
459
0
                                    } while (ogs_yaml_iter_type(&nrf_array) ==
460
0
                                            YAML_SEQUENCE_NODE);
461
0
                                } else if (ogs_global_conf()->
462
0
                                        parameter.no_scp == false &&
463
0
                                        scp && !strcmp(client_key, scp)) {
464
0
                                    ogs_yaml_iter_t scp_array, scp_iter;
465
0
                                    ogs_yaml_iter_recurse(
466
0
                                            &client_iter, &scp_array);
467
0
                                    do {
468
0
                                        ogs_sbi_client_t *client = NULL;
469
470
0
                                        if (ogs_yaml_iter_type(&scp_array) ==
471
0
                                                YAML_MAPPING_NODE) {
472
0
                                            memcpy(&scp_iter, &scp_array,
473
0
                                                    sizeof(ogs_yaml_iter_t));
474
0
                                        } else if (ogs_yaml_iter_type(
475
0
                                                    &scp_array) ==
476
0
                                            YAML_SEQUENCE_NODE) {
477
0
                                            if (!ogs_yaml_iter_next(&scp_array))
478
0
                                                break;
479
0
                                            ogs_yaml_iter_recurse(
480
0
                                                    &scp_array, &scp_iter);
481
0
                                        } else if (ogs_yaml_iter_type(
482
0
                                                    &scp_array) ==
483
0
                                                YAML_SCALAR_NODE) {
484
0
                                            break;
485
0
                                        } else
486
0
                                            ogs_assert_if_reached();
487
488
0
                                        if (NF_INSTANCE_CLIENT(
489
0
                                                    self.scp_instance)) {
490
0
                                            ogs_error("Only one SCP client "
491
0
                                                    "can be set");
492
0
                                            return OGS_ERROR;
493
0
                                        }
494
495
0
                                        client =
496
0
                                            ogs_sbi_context_parse_client_config(
497
0
                                                &scp_iter);
498
0
                                        if (!client) {
499
0
                                            ogs_error("ogs_sbi_context_parse_"
500
0
                                                    "client_config() failed");
501
0
                                            return OGS_ERROR;
502
0
                                        }
503
504
0
                                        OGS_SBI_SETUP_CLIENT(
505
0
                                                self.scp_instance, client);
506
507
0
                                    } while (ogs_yaml_iter_type(&scp_array) ==
508
0
                                            YAML_SEQUENCE_NODE);
509
0
                                }
510
                                /* Parse delegated section */
511
0
                                else if (!strcmp(client_key, "delegated")) {
512
0
                                    ogs_yaml_iter_t delegated_iter;
513
0
                                    ogs_yaml_iter_recurse(&client_iter,
514
0
                                                          &delegated_iter);
515
516
0
                                    while (ogs_yaml_iter_next(
517
0
                                               &delegated_iter)) {
518
0
                                        const char *del_key =
519
0
                                            ogs_yaml_iter_key(
520
0
                                                &delegated_iter);
521
0
                                        if (!strcmp(del_key, "nrf")) {
522
0
                                            ogs_yaml_iter_t nrf_iter;
523
0
                                            ogs_yaml_iter_recurse(
524
0
                                                &delegated_iter, &nrf_iter);
525
0
                                            while (ogs_yaml_iter_next(
526
0
                                                       &nrf_iter)) {
527
0
                                                const char *nrf_key =
528
0
                                                    ogs_yaml_iter_key(
529
0
                                                        &nrf_iter);
530
0
                                                const char *nrf_val =
531
0
                                                    ogs_yaml_iter_value(
532
0
                                                        &nrf_iter);
533
0
                                                ogs_assert(nrf_key);
534
535
0
                                                if (!strcmp(nrf_key,"nfm")) {
536
0
                                                    if (!strcmp(nrf_val,"no")) {
537
0
                                                        self.client_delegated_config.nrf.nfm =
538
0
                                                        OGS_SBI_CLIENT_DELEGATED_NO;
539
0
                                                    } else if (!strcmp(
540
0
                                                        nrf_val,"yes")) {
541
0
                                                        self.client_delegated_config.nrf.nfm =
542
0
                                                        OGS_SBI_CLIENT_DELEGATED_YES;
543
0
                                                    } else if (!strcmp(
544
0
                                                        nrf_val,"auto")) {
545
0
                                                        self.client_delegated_config.nrf.nfm =
546
0
                                                        OGS_SBI_CLIENT_DELEGATED_AUTO;
547
0
                                                    } else {
548
0
                                                        ogs_warn("unknown "
549
0
                                                            "'nfm' `%s`",
550
0
                                                            nrf_val);
551
0
                                                    }
552
0
                                                } else if (!strcmp(
553
0
                                                           nrf_key,"disc")) {
554
0
                                                    if (!strcmp(nrf_val,"no")) {
555
0
                                                        self.client_delegated_config.nrf.disc =
556
0
                                                        OGS_SBI_CLIENT_DELEGATED_NO;
557
0
                                                    } else if (!strcmp(
558
0
                                                        nrf_val,"yes")) {
559
0
                                                        self.client_delegated_config.nrf.disc =
560
0
                                                        OGS_SBI_CLIENT_DELEGATED_YES;
561
0
                                                    } else if (!strcmp(
562
0
                                                        nrf_val,"auto")) {
563
0
                                                        self.client_delegated_config.nrf.disc =
564
0
                                                        OGS_SBI_CLIENT_DELEGATED_AUTO;
565
0
                                                    } else {
566
0
                                                        ogs_warn("unknown "
567
0
                                                            "'disc' `%s`",
568
0
                                                            nrf_val);
569
0
                                                    }
570
0
                                                } else {
571
0
                                                    ogs_warn("unknown nrf "
572
0
                                                        "delegated key `%s`",
573
0
                                                        nrf_key);
574
0
                                                }
575
0
                                            }
576
0
                                        } else if (!strcmp(del_key, "scp")) {
577
0
                                            ogs_yaml_iter_t scp_iter;
578
0
                                            ogs_yaml_iter_recurse(
579
0
                                                &delegated_iter, &scp_iter);
580
0
                                            while (ogs_yaml_iter_next(
581
0
                                                       &scp_iter)) {
582
0
                                                const char *scp_key =
583
0
                                                    ogs_yaml_iter_key(
584
0
                                                        &scp_iter);
585
0
                                                const char *scp_val =
586
0
                                                    ogs_yaml_iter_value(
587
0
                                                        &scp_iter);
588
0
                                                ogs_assert(scp_key);
589
590
0
                                                if (!strcmp(scp_key,"next")) {
591
0
                                                    if (!strcmp(scp_val,"no")) {
592
0
                                                        self.client_delegated_config.scp.next =
593
0
                                                        OGS_SBI_CLIENT_DELEGATED_NO;
594
0
                                                    } else if (!strcmp(
595
0
                                                        scp_val,"yes")) {
596
0
                                                        self.client_delegated_config.scp.next =
597
0
                                                        OGS_SBI_CLIENT_DELEGATED_YES;
598
0
                                                    } else if (!strcmp(
599
0
                                                        scp_val,"auto")) {
600
0
                                                        self.client_delegated_config.scp.next =
601
0
                                                        OGS_SBI_CLIENT_DELEGATED_AUTO;
602
0
                                                    } else {
603
0
                                                        ogs_warn("unknown "
604
0
                                                            "'next' `%s`",
605
0
                                                            scp_val);
606
0
                                                    }
607
0
                                                } else {
608
0
                                                    ogs_warn("unknown scp "
609
0
                                                        "delegated key `%s`",
610
0
                                                        scp_key);
611
0
                                                }
612
0
                                            }
613
0
                                        } else {
614
0
                                            ogs_warn("unknown delegated "
615
0
                                                "key `%s`", del_key);
616
0
                                        }
617
0
                                    }
618
0
                                }
619
0
                            }
620
0
                        } else
621
0
                            ogs_warn("unknown key `%s`", sbi_key);
622
0
                    }
623
0
                } else if (!strcmp(local_key, "service_name")) {
624
0
                    ogs_yaml_iter_t service_name_iter;
625
0
                    ogs_yaml_iter_recurse(&local_iter, &service_name_iter);
626
0
                    ogs_assert(ogs_yaml_iter_type(
627
0
                                &service_name_iter) != YAML_MAPPING_NODE);
628
629
0
                    do {
630
0
                        const char *v = NULL;
631
632
0
                        if (ogs_yaml_iter_type(&service_name_iter) ==
633
0
                                YAML_SEQUENCE_NODE) {
634
0
                            if (!ogs_yaml_iter_next(&service_name_iter))
635
0
                                break;
636
0
                        }
637
638
0
                        v = ogs_yaml_iter_value(&service_name_iter);
639
0
                        if (v && strlen(v)) {
640
0
                            OpenAPI_service_name_e name =
641
0
                                OpenAPI_service_name_FromString((char *)v);
642
0
                            if (name)
643
0
                                self.service_name[self.num_of_service_name++] =
644
0
                                    name;
645
0
                            else
646
0
                                ogs_warn("unknown service-name `%s`", v);
647
0
                        }
648
649
0
                    } while (ogs_yaml_iter_type(
650
0
                                &service_name_iter) == YAML_SEQUENCE_NODE);
651
652
0
                }
653
0
            }
654
0
        }
655
0
    }
656
657
0
    rv = ogs_sbi_context_validation(local, nrf, scp);
658
0
    if (rv != OGS_OK) return rv;
659
660
0
    return OGS_OK;
661
0
}
662
663
int ogs_sbi_context_parse_hnet_config(ogs_yaml_iter_t *root_iter)
664
0
{
665
0
    int rv;
666
0
    ogs_yaml_iter_t hnet_array, hnet_iter;
667
668
0
    ogs_assert(root_iter);
669
0
    ogs_yaml_iter_recurse(root_iter, &hnet_array);
670
0
    do {
671
0
        uint8_t id = 0, scheme = 0;
672
0
        const char *filename = NULL;
673
674
0
        if (ogs_yaml_iter_type(&hnet_array) == YAML_MAPPING_NODE) {
675
0
            memcpy(&hnet_iter, &hnet_array, sizeof(ogs_yaml_iter_t));
676
0
        } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE) {
677
0
            if (!ogs_yaml_iter_next(&hnet_array))
678
0
                break;
679
0
            ogs_yaml_iter_recurse(&hnet_array, &hnet_iter);
680
0
        } else if (ogs_yaml_iter_type(&hnet_array) == YAML_SCALAR_NODE) {
681
0
            break;
682
0
        } else
683
0
            ogs_assert_if_reached();
684
685
0
        while (ogs_yaml_iter_next(&hnet_iter)) {
686
0
            const char *hnet_key = ogs_yaml_iter_key(&hnet_iter);
687
0
            ogs_assert(hnet_key);
688
0
            if (!strcmp(hnet_key, "id")) {
689
0
                const char *v = ogs_yaml_iter_value(&hnet_iter);
690
0
                if (v) {
691
0
                    if (atoi(v) >= 1 && atoi(v) <= 254)
692
0
                        id = atoi(v);
693
0
                }
694
0
            } else if (!strcmp(hnet_key, "scheme")) {
695
0
                const char *v = ogs_yaml_iter_value(&hnet_iter);
696
0
                if (v) {
697
0
                    if (atoi(v) == 1 || atoi(v) == 2)
698
0
                        scheme = atoi(v);
699
0
                }
700
0
            } else if (!strcmp(hnet_key, "key")) {
701
0
                filename = ogs_yaml_iter_value(&hnet_iter);
702
0
            } else
703
0
                ogs_warn("unknown key `%s`", hnet_key);
704
0
        }
705
706
0
        if (id >= OGS_HOME_NETWORK_PKI_VALUE_MIN &&
707
0
            id <= OGS_HOME_NETWORK_PKI_VALUE_MAX &&
708
0
            filename) {
709
0
            if (scheme == OGS_PROTECTION_SCHEME_PROFILE_A) {
710
0
                rv = ogs_pem_decode_curve25519_key(
711
0
                        filename, self.hnet[id].key);
712
0
                if (rv == OGS_OK) {
713
0
                    self.hnet[id].avail = true;
714
0
                    self.hnet[id].scheme = scheme;
715
0
                } else {
716
0
                    ogs_error("ogs_pem_decode_curve25519_key"
717
0
                            "[%s] failed", filename);
718
0
                }
719
0
            } else if (scheme == OGS_PROTECTION_SCHEME_PROFILE_B) {
720
0
                rv = ogs_pem_decode_secp256r1_key(
721
0
                        filename, self.hnet[id].key);
722
0
                if (rv == OGS_OK) {
723
0
                    self.hnet[id].avail = true;
724
0
                    self.hnet[id].scheme = scheme;
725
0
                } else {
726
0
                    ogs_error("ogs_pem_decode_secp256r1_key[%s]"
727
0
                            " failed", filename);
728
0
                }
729
0
            } else
730
0
                ogs_error("Invalid scheme [%d]", scheme);
731
0
        } else
732
0
            ogs_error("Invalid home network configuration "
733
0
                    "[id:%d, filename:%s]", id, filename);
734
0
    } while (ogs_yaml_iter_type(&hnet_array) == YAML_SEQUENCE_NODE);
735
736
0
    return OGS_OK;
737
0
}
738
739
int ogs_sbi_context_parse_server_config(
740
        ogs_yaml_iter_t *parent, const char *interface)
741
0
{
742
0
    int rv;
743
0
    ogs_sbi_server_t *server = NULL;
744
0
    OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
745
0
    ogs_list_t list, list6;
746
0
    ogs_socknode_t *node = NULL, *node6 = NULL;
747
748
0
    ogs_assert(parent);
749
750
0
    ogs_yaml_iter_t server_iter, server_array;
751
0
    ogs_yaml_iter_recurse(parent, &server_array);
752
0
    do {
753
0
        int i, family = AF_UNSPEC;
754
0
        int num = 0;
755
0
        const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
756
0
        int num_of_advertise = 0;
757
0
        const char *advertise[OGS_MAX_NUM_OF_HOSTNAME];
758
759
0
        uint16_t port = 0;
760
0
        const char *dev = NULL;
761
0
        ogs_sockaddr_t *addr = NULL;
762
763
0
        const char *private_key = NULL, *cert = NULL, *sslkeylog = NULL;
764
765
0
        bool verify_client = false;
766
0
        const char *verify_client_cacert = NULL;
767
768
0
        ogs_sockopt_t option;
769
0
        bool is_option = false;
770
771
0
        if (ogs_yaml_iter_type(&server_array) == YAML_MAPPING_NODE) {
772
0
            memcpy(&server_iter, &server_array, sizeof(ogs_yaml_iter_t));
773
0
        } else if (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE) {
774
0
            if (!ogs_yaml_iter_next(&server_array))
775
0
                break;
776
0
            ogs_yaml_iter_recurse(&server_array, &server_iter);
777
0
        } else if (ogs_yaml_iter_type(&server_array) == YAML_SCALAR_NODE) {
778
0
            break;
779
0
        } else
780
0
            ogs_assert_if_reached();
781
782
0
        while (ogs_yaml_iter_next(&server_iter)) {
783
0
            const char *server_key = ogs_yaml_iter_key(&server_iter);
784
0
            ogs_assert(server_key);
785
0
            if (!strcmp(server_key, OGS_SBI_INTERFACE_NAME_N32F)) {
786
0
                rv = ogs_sbi_context_parse_server_config(
787
0
                        &server_iter, server_key);
788
0
                if (rv != OGS_OK) {
789
0
                    ogs_error("ogs_sbi_context_parse_server_config() "
790
0
                            "failed[key:%s]", server_key);
791
0
                    return rv;
792
0
                }
793
0
            } else if (!strcmp(server_key, "family")) {
794
0
                const char *v = ogs_yaml_iter_value(&server_iter);
795
0
                if (v) family = atoi(v);
796
0
                if (family != AF_UNSPEC && family != AF_INET &&
797
0
                    family != AF_INET6) {
798
0
                    ogs_warn("Ignore family(%d) : AF_UNSPEC(%d), "
799
0
                        "AF_INET(%d), AF_INET6(%d) ",
800
0
                        family, AF_UNSPEC, AF_INET, AF_INET6);
801
0
                    family = AF_UNSPEC;
802
0
                }
803
0
            } else if (!strcmp(server_key, "address")) {
804
0
                ogs_yaml_iter_t hostname_iter;
805
0
                ogs_yaml_iter_recurse(&server_iter, &hostname_iter);
806
0
                ogs_assert(ogs_yaml_iter_type(
807
0
                            &hostname_iter) != YAML_MAPPING_NODE);
808
809
0
                do {
810
0
                    if (ogs_yaml_iter_type(
811
0
                                &hostname_iter) == YAML_SEQUENCE_NODE) {
812
0
                        if (!ogs_yaml_iter_next(&hostname_iter))
813
0
                            break;
814
0
                    }
815
816
0
                    ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
817
0
                    hostname[num++] = ogs_yaml_iter_value(&hostname_iter);
818
0
                } while (ogs_yaml_iter_type(
819
0
                            &hostname_iter) == YAML_SEQUENCE_NODE);
820
0
            } else if (!strcmp(server_key, "advertise")) {
821
0
                ogs_yaml_iter_t advertise_iter;
822
0
                ogs_yaml_iter_recurse(&server_iter, &advertise_iter);
823
0
                ogs_assert(ogs_yaml_iter_type(
824
0
                            &advertise_iter) != YAML_MAPPING_NODE);
825
826
0
                do {
827
0
                    if (ogs_yaml_iter_type(
828
0
                                &advertise_iter) == YAML_SEQUENCE_NODE) {
829
0
                        if (!ogs_yaml_iter_next(&advertise_iter))
830
0
                            break;
831
0
                    }
832
833
0
                    ogs_assert(num_of_advertise < OGS_MAX_NUM_OF_HOSTNAME);
834
0
                    advertise[num_of_advertise++] =
835
0
                        ogs_yaml_iter_value(&advertise_iter);
836
0
                } while (ogs_yaml_iter_type(
837
0
                            &advertise_iter) == YAML_SEQUENCE_NODE);
838
0
            } else if (!strcmp(server_key, "port")) {
839
0
                const char *v = ogs_yaml_iter_value(&server_iter);
840
0
                if (v)
841
0
                    port = atoi(v);
842
0
            } else if (!strcmp(server_key, "dev")) {
843
0
                dev = ogs_yaml_iter_value(&server_iter);
844
0
            } else if (!strcmp(server_key, "scheme")) {
845
0
                const char *v = ogs_yaml_iter_value(&server_iter);
846
0
                if (v) {
847
0
                    if (!ogs_strcasecmp(v, "https"))
848
0
                        scheme = OpenAPI_uri_scheme_https;
849
0
                    else if (!ogs_strcasecmp(v, "http"))
850
0
                        scheme = OpenAPI_uri_scheme_http;
851
0
                    else
852
0
                        ogs_warn("unknown scheme `%s`", v);
853
0
                }
854
0
            } else if (!strcmp(server_key, "private_key")) {
855
0
                private_key = ogs_yaml_iter_value(&server_iter);
856
0
            } else if (!strcmp(server_key, "cert")) {
857
0
                cert = ogs_yaml_iter_value(&server_iter);
858
0
            } else if (!strcmp(server_key, "sslkeylogfile")) {
859
0
                sslkeylog = ogs_yaml_iter_value(&server_iter);
860
0
            } else if (!strcmp(server_key, "verify_client")) {
861
0
                verify_client = ogs_yaml_iter_bool(&server_iter);
862
0
            } else if (!strcmp(server_key, "verify_client_cacert")) {
863
0
                verify_client_cacert = ogs_yaml_iter_value(&server_iter);
864
0
            } else if (!strcmp(server_key, "option")) {
865
0
                rv = ogs_app_parse_sockopt_config(&server_iter, &option);
866
0
                if (rv != OGS_OK) {
867
0
                    ogs_error("ogs_app_parse_sockopt_config() failed");
868
0
                    return rv;
869
0
                }
870
0
                is_option = true;
871
0
            }
872
0
        }
873
874
0
        if (scheme == OpenAPI_uri_scheme_NULL)
875
0
            scheme = ogs_sbi_self()->tls.server.scheme;
876
877
0
        if (!port) {
878
0
            if (scheme == OpenAPI_uri_scheme_https)
879
0
                port = OGS_SBI_HTTPS_PORT;
880
0
            else if (scheme == OpenAPI_uri_scheme_http)
881
0
                port = OGS_SBI_HTTP_PORT;
882
0
            else
883
0
                ogs_assert_if_reached();
884
0
        }
885
886
0
        addr = NULL;
887
0
        for (i = 0; i < num; i++) {
888
0
            rv = ogs_addaddrinfo(&addr, family, hostname[i], port, 0);
889
0
            ogs_assert(rv == OGS_OK);
890
0
        }
891
892
0
        ogs_list_init(&list);
893
0
        ogs_list_init(&list6);
894
895
0
        if (addr) {
896
0
            if (ogs_global_conf()->parameter.no_ipv4 == 0)
897
0
                ogs_socknode_add(&list, AF_INET, addr, NULL);
898
0
            if (ogs_global_conf()->parameter.no_ipv6 == 0)
899
0
                ogs_socknode_add(&list6, AF_INET6, addr, NULL);
900
0
            ogs_freeaddrinfo(addr);
901
0
        }
902
903
0
        if (dev) {
904
0
            rv = ogs_socknode_probe(
905
0
                ogs_global_conf()->parameter.no_ipv4 ?  NULL : &list,
906
0
                ogs_global_conf()->parameter.no_ipv6 ?  NULL : &list6,
907
0
                dev, port, NULL);
908
0
            ogs_assert(rv == OGS_OK);
909
0
        }
910
911
0
        addr = NULL;
912
        /* ----- Process advertise (Host+Port Parsing Logic) ----- */
913
0
        for (i = 0; i < num_of_advertise; i++) {
914
0
            uint16_t adv_port = port; /* Default to server's port */
915
0
            char *hostbuf = NULL;
916
0
            const char *colon_pos = strchr(advertise[i], ':');
917
918
0
            if (colon_pos) {
919
                /* If a colon exists, split host and port */
920
0
                size_t host_len = colon_pos - advertise[i];
921
922
                /* Allocate memory for the host part */
923
0
                hostbuf = (char *)ogs_malloc(host_len + 1);
924
0
                ogs_assert(hostbuf);
925
926
                /* Copy the host part into hostbuf */
927
0
                memcpy(hostbuf, advertise[i], host_len);
928
0
                hostbuf[host_len] = '\0';
929
930
                /* Parse the port part */
931
0
                adv_port = (uint16_t)atoi(colon_pos + 1);
932
0
            } else {
933
                /* If no colon, treat the entire string as the host */
934
0
                hostbuf = ogs_strdup(advertise[i]);
935
0
                ogs_assert(hostbuf);
936
0
            }
937
938
            /* Add the parsed address info */
939
0
            rv = ogs_addaddrinfo(&addr, family, hostbuf, adv_port, 0);
940
0
            ogs_assert(rv == OGS_OK);
941
942
            /* Free the allocated memory */
943
0
            ogs_free(hostbuf);
944
0
        }
945
946
0
        node = ogs_list_first(&list);
947
0
        if (node) {
948
0
            server = ogs_sbi_server_add(
949
0
                    interface, scheme, node->addr, is_option ? &option : NULL);
950
0
            ogs_assert(server);
951
952
0
            if (addr && ogs_global_conf()->parameter.no_ipv4 == 0)
953
0
                ogs_sbi_server_set_advertise(server, AF_INET, addr);
954
955
0
            if (verify_client == true)
956
0
                server->verify_client = true;
957
958
0
            if (verify_client_cacert) {
959
0
                if (server->verify_client_cacert)
960
0
                    ogs_free(server->verify_client_cacert);
961
0
                server->verify_client_cacert = ogs_strdup(verify_client_cacert);
962
0
                ogs_assert(server->verify_client_cacert);
963
0
            }
964
965
0
            if (server->verify_client == true &&
966
0
                !server->verify_client_cacert) {
967
0
                ogs_error("CLIENT verification enabled but no CA certificate");
968
0
                return OGS_ERROR;
969
0
            }
970
971
0
            if (private_key) {
972
0
                if (server->private_key)
973
0
                    ogs_free(server->private_key);
974
0
                server->private_key = ogs_strdup(private_key);
975
0
                ogs_assert(server->private_key);
976
0
            }
977
0
            if (cert) {
978
0
                if (server->cert)
979
0
                    ogs_free(server->cert);
980
0
                server->cert = ogs_strdup(cert);
981
0
                ogs_assert(server->cert);
982
0
            }
983
0
            if (sslkeylog) {
984
0
                if (server->sslkeylog)
985
0
                    ogs_free(server->sslkeylog);
986
0
                server->sslkeylog = ogs_strdup(sslkeylog);
987
0
                ogs_assert(server->sslkeylog);
988
0
            }
989
990
0
            if (scheme == OpenAPI_uri_scheme_https) {
991
0
                if (!server->private_key) {
992
0
                    ogs_error("HTTPS scheme enabled but no server key");
993
0
                    return OGS_ERROR;
994
0
                }
995
0
                if (!server->cert) {
996
0
                    ogs_error("HTTPS scheme enabled but no server certificate");
997
0
                    return OGS_ERROR;
998
0
                }
999
0
            }
1000
0
        }
1001
0
        node6 = ogs_list_first(&list6);
1002
0
        if (node6) {
1003
0
            server = ogs_sbi_server_add(
1004
0
                    interface, scheme, node6->addr, is_option ? &option : NULL);
1005
0
            ogs_assert(server);
1006
1007
0
            if (addr && ogs_global_conf()->parameter.no_ipv6 == 0)
1008
0
                ogs_sbi_server_set_advertise(server, AF_INET6, addr);
1009
1010
0
            if (verify_client == true)
1011
0
                server->verify_client = true;
1012
1013
0
            if (verify_client_cacert) {
1014
0
                if (server->verify_client_cacert)
1015
0
                    ogs_free(server->verify_client_cacert);
1016
0
                server->verify_client_cacert = ogs_strdup(verify_client_cacert);
1017
0
                ogs_assert(server->verify_client_cacert);
1018
0
            }
1019
1020
0
            if (server->verify_client == true &&
1021
0
                !server->verify_client_cacert) {
1022
0
                ogs_error("CLIENT verification enabled but no CA certificate");
1023
0
                return OGS_ERROR;
1024
0
            }
1025
1026
0
            if (private_key) {
1027
0
                if (server->private_key)
1028
0
                    ogs_free(server->private_key);
1029
0
                server->private_key = ogs_strdup(private_key);
1030
0
                ogs_assert(server->private_key);
1031
0
            }
1032
0
            if (cert) {
1033
0
                if (server->cert)
1034
0
                    ogs_free(server->cert);
1035
0
                server->cert = ogs_strdup(cert);
1036
0
                ogs_assert(server->cert);
1037
0
            }
1038
0
            if (sslkeylog) {
1039
0
                if (server->sslkeylog)
1040
0
                    ogs_free(server->sslkeylog);
1041
0
                server->sslkeylog = ogs_strdup(sslkeylog);
1042
0
                ogs_assert(server->sslkeylog);
1043
0
            }
1044
1045
0
            if (scheme == OpenAPI_uri_scheme_https) {
1046
0
                if (!server->private_key) {
1047
0
                    ogs_error("HTTPS scheme enabled but no server key");
1048
0
                    return OGS_ERROR;
1049
0
                }
1050
0
                if (!server->cert) {
1051
0
                    ogs_error("HTTPS scheme enabled but no server certificate");
1052
0
                    return OGS_ERROR;
1053
0
                }
1054
0
            }
1055
0
        }
1056
1057
0
        if (addr)
1058
0
            ogs_freeaddrinfo(addr);
1059
1060
0
        ogs_socknode_remove_all(&list);
1061
0
        ogs_socknode_remove_all(&list6);
1062
1063
0
    } while (ogs_yaml_iter_type(&server_array) == YAML_SEQUENCE_NODE);
1064
1065
0
    return OGS_OK;
1066
0
}
1067
1068
ogs_sbi_client_t *ogs_sbi_context_parse_client_config(ogs_yaml_iter_t *iter)
1069
0
{
1070
0
    ogs_sbi_client_t *client = NULL;
1071
0
    const char *uri = NULL;
1072
1073
0
    int num_of_resolve = 0;
1074
0
    const char *resolve[OGS_MAX_NUM_OF_HOSTNAME];
1075
1076
0
    bool insecure_skip_verify = false;
1077
0
    const char *cacert = NULL;
1078
1079
0
    const char *client_private_key = NULL;
1080
0
    const char *client_cert = NULL;
1081
0
    const char *client_sslkeylog = NULL;
1082
0
    const char *local_if = NULL;
1083
1084
0
    bool rc;
1085
1086
0
    OpenAPI_uri_scheme_e scheme =
1087
0
        OpenAPI_uri_scheme_NULL;
1088
1089
0
    char *fqdn = NULL;
1090
0
    uint16_t fqdn_port = 0;
1091
0
    ogs_sockaddr_t *addr = NULL;
1092
0
    ogs_sockaddr_t *addr6 = NULL;
1093
1094
0
    ogs_assert(iter);
1095
1096
0
    while (ogs_yaml_iter_next(iter)) {
1097
0
        const char *key = ogs_yaml_iter_key(iter);
1098
0
        ogs_assert(key);
1099
0
        if (!strcmp(key, "uri")) {
1100
0
            uri = ogs_yaml_iter_value(iter);
1101
0
        } else if (!strcmp(key, "resolve")) {
1102
0
            ogs_yaml_iter_t resolve_iter;
1103
0
            ogs_yaml_iter_recurse(iter, &resolve_iter);
1104
0
            ogs_assert(ogs_yaml_iter_type(&resolve_iter) != YAML_MAPPING_NODE);
1105
1106
0
            do {
1107
0
                if (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE) {
1108
0
                    if (!ogs_yaml_iter_next(&resolve_iter))
1109
0
                        break;
1110
0
                }
1111
1112
0
                ogs_assert(num_of_resolve < OGS_MAX_NUM_OF_HOSTNAME);
1113
0
                resolve[num_of_resolve++] = ogs_yaml_iter_value(&resolve_iter);
1114
0
            } while (ogs_yaml_iter_type(&resolve_iter) == YAML_SEQUENCE_NODE);
1115
1116
0
        } else if (!strcmp(key, "insecure_skip_verify")) {
1117
0
            insecure_skip_verify = ogs_yaml_iter_bool(iter);
1118
0
        } else if (!strcmp(key, "cacert")) {
1119
0
            cacert = ogs_yaml_iter_value(iter);
1120
0
        } else if (!strcmp(key, "client_private_key")) {
1121
0
            client_private_key = ogs_yaml_iter_value(iter);
1122
0
        } else if (!strcmp(key, "client_cert")) {
1123
0
            client_cert = ogs_yaml_iter_value(iter);
1124
0
        } else if (!strcmp(key, "client_sslkeylogfile")) {
1125
0
            client_sslkeylog = ogs_yaml_iter_value(iter);
1126
0
        } else if (!strcmp(key, "interface")) {
1127
0
            local_if = ogs_yaml_iter_value(iter);
1128
0
        }
1129
0
    }
1130
1131
0
    if (!uri) {
1132
0
        ogs_error("URI[%s] is required", uri ? uri : "NULL");
1133
0
        return NULL;
1134
0
    }
1135
1136
0
    rc = ogs_sbi_getaddr_from_uri(
1137
0
            &scheme, &fqdn, &fqdn_port, &addr, &addr6, (char *)uri);
1138
0
    if (rc == false) {
1139
0
        if (!scheme)
1140
0
            ogs_error("Invalid Scheme in URI[%s]", uri);
1141
0
        else
1142
0
            ogs_error("Invalid URI[%s]", uri);
1143
1144
0
        return NULL;
1145
0
    }
1146
1147
0
    switch (scheme) {
1148
0
    case OpenAPI_uri_scheme_https:
1149
0
        if (!fqdn) {
1150
0
            ogs_error("HTTPS(TLS) must be set to FQDN [uri:%s]", uri);
1151
1152
0
            ogs_freeaddrinfo(addr);
1153
0
            ogs_freeaddrinfo(addr6);
1154
1155
0
            return NULL;
1156
0
        }
1157
0
        client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, NULL, NULL);
1158
0
        ogs_assert(client);
1159
0
        break;
1160
0
    case OpenAPI_uri_scheme_http:
1161
0
        client = ogs_sbi_client_add(scheme, fqdn, fqdn_port, addr, addr6);
1162
0
        ogs_assert(client);
1163
0
        break;
1164
0
    default:
1165
0
        ogs_fatal("Invalid Scheme[%d]", scheme);
1166
0
        ogs_assert_if_reached();
1167
0
    }
1168
1169
0
    if (num_of_resolve)
1170
0
        client->resolve = ogs_sbi_client_resolve(
1171
0
                scheme, fqdn, fqdn_port, resolve, num_of_resolve);
1172
1173
0
    if (insecure_skip_verify == true)
1174
0
        client->insecure_skip_verify = true;
1175
1176
0
    if (cacert) {
1177
0
        if (client->cacert)
1178
0
            ogs_free(client->cacert);
1179
0
        client->cacert = ogs_strdup(cacert);
1180
0
        ogs_assert(client->cacert);
1181
0
    }
1182
1183
0
    if (client_private_key) {
1184
0
        if (client->private_key)
1185
0
            ogs_free(client->private_key);
1186
0
        client->private_key = ogs_strdup(client_private_key);
1187
0
        ogs_assert(client->private_key);
1188
0
    }
1189
1190
0
    if (client_cert) {
1191
0
        if (client->cert)
1192
0
            ogs_free(client->cert);
1193
0
        client->cert = ogs_strdup(client_cert);
1194
0
        ogs_assert(client->cert);
1195
0
    }
1196
1197
0
    if (client_sslkeylog) {
1198
0
        if (client->sslkeylog)
1199
0
            ogs_free(client->sslkeylog);
1200
0
        client->sslkeylog = ogs_strdup(client_sslkeylog);
1201
0
        ogs_assert(client->sslkeylog);
1202
0
    }
1203
1204
0
    if (local_if) {
1205
0
        if (client->local_if)
1206
0
            ogs_free(client->local_if);
1207
0
        client->local_if = ogs_strdup(local_if);
1208
0
        ogs_assert(client->local_if);
1209
0
    }
1210
1211
0
    if ((!client_private_key && client_cert) ||
1212
0
        (client_private_key && !client_cert)) {
1213
0
        ogs_error("Either the private key or certificate is missing.");
1214
0
        ogs_sbi_client_remove(client);
1215
0
        return NULL;
1216
0
    }
1217
1218
0
    ogs_free(fqdn);
1219
0
    ogs_freeaddrinfo(addr);
1220
0
    ogs_freeaddrinfo(addr6);
1221
1222
0
    return client;
1223
0
}
1224
1225
bool ogs_sbi_nf_service_is_available(const OpenAPI_service_name_e name)
1226
0
{
1227
0
    int i;
1228
1229
0
    ogs_assert(name);
1230
1231
0
    if (self.num_of_service_name == 0)
1232
        /* If no service name is configured, all services are available */
1233
0
        return true;
1234
1235
0
    for (i = 0; i < self.num_of_service_name; i++)
1236
        /* Only services in the configuration are available */
1237
0
        if (self.service_name[i] == name)
1238
0
            return true;
1239
1240
0
    return false;
1241
0
}
1242
1243
ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_add(void)
1244
0
{
1245
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1246
1247
0
    ogs_pool_alloc(&nf_instance_pool, &nf_instance);
1248
0
    if (!nf_instance) {
1249
0
        ogs_error("OVERFLOW nf_instance_pool [pool:%llu]",
1250
0
                (unsigned long long)ogs_app()->pool.nf);
1251
0
        return NULL;
1252
0
    }
1253
0
    memset(nf_instance, 0, sizeof(ogs_sbi_nf_instance_t));
1254
1255
0
    nf_instance->pool_id = OGS_NEXT_ID(
1256
0
            nf_instance_pool.id, OGS_MIN_POOL_ID, OGS_MAX_POOL_ID);
1257
0
    ogs_hash_set(nf_instance_pool.id_hash,
1258
0
            &nf_instance->pool_id, sizeof(ogs_pool_id_t), nf_instance);
1259
1260
0
    nf_instance->time.heartbeat_interval =
1261
0
            ogs_local_conf()->time.nf_instance.heartbeat_interval;
1262
1263
0
    nf_instance->priority = OGS_SBI_DEFAULT_PRIORITY;
1264
0
    nf_instance->capacity = OGS_SBI_DEFAULT_CAPACITY;
1265
0
    nf_instance->load = OGS_SBI_DEFAULT_LOAD;
1266
1267
0
    ogs_list_add(&ogs_sbi_self()->nf_instance_list, nf_instance);
1268
1269
0
    ogs_debug("[%s] NFInstance added with Ref [%s]",
1270
0
            nf_instance->nf_type ?
1271
0
                OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL",
1272
0
            nf_instance->id);
1273
1274
0
    return nf_instance;
1275
0
}
1276
1277
void ogs_sbi_nf_instance_set_id(ogs_sbi_nf_instance_t *nf_instance, char *id)
1278
0
{
1279
0
    ogs_assert(nf_instance);
1280
0
    ogs_assert(id);
1281
1282
0
    nf_instance->id = ogs_strdup(id);
1283
0
    ogs_assert(nf_instance->id);
1284
0
}
1285
1286
void ogs_sbi_nf_instance_set_type(
1287
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e nf_type)
1288
0
{
1289
0
    ogs_assert(nf_instance);
1290
0
    ogs_assert(nf_type);
1291
1292
0
    nf_instance->nf_type = nf_type;
1293
0
}
1294
1295
void ogs_sbi_nf_instance_set_status(
1296
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_status_e nf_status)
1297
0
{
1298
0
    ogs_assert(nf_instance);
1299
0
    ogs_assert(nf_status);
1300
1301
0
    nf_instance->nf_status = nf_status;
1302
0
}
1303
1304
void ogs_sbi_nf_instance_add_allowed_nf_type(
1305
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type)
1306
0
{
1307
0
    ogs_assert(nf_instance);
1308
0
    ogs_assert(allowed_nf_type);
1309
1310
0
    if (nf_instance->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) {
1311
0
        nf_instance->allowed_nf_type[nf_instance->num_of_allowed_nf_type] =
1312
0
            allowed_nf_type;
1313
0
        nf_instance->num_of_allowed_nf_type++;
1314
0
    }
1315
0
}
1316
1317
bool ogs_sbi_nf_instance_is_allowed_nf_type(
1318
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_nf_type_e allowed_nf_type)
1319
0
{
1320
0
    int i;
1321
1322
0
    ogs_assert(nf_instance);
1323
0
    ogs_assert(allowed_nf_type);
1324
1325
0
    if (!nf_instance->num_of_allowed_nf_type) {
1326
0
        return true;
1327
0
    }
1328
1329
0
    for (i = 0; i < nf_instance->num_of_allowed_nf_type; i++) {
1330
0
        if (nf_instance->allowed_nf_type[i] == allowed_nf_type)
1331
0
            return true;
1332
0
    }
1333
1334
0
    ogs_error("Not allowed nf-type[%s] in nf-instance[%s]",
1335
0
            OpenAPI_nf_type_ToString(allowed_nf_type),
1336
0
            OpenAPI_nf_type_ToString(nf_instance->nf_type));
1337
0
    return false;
1338
0
}
1339
1340
void ogs_sbi_nf_instance_clear(ogs_sbi_nf_instance_t *nf_instance)
1341
0
{
1342
0
    int i;
1343
1344
0
    ogs_assert(nf_instance);
1345
1346
0
    if (nf_instance->fqdn)
1347
0
        ogs_free(nf_instance->fqdn);
1348
0
    nf_instance->fqdn = NULL;
1349
1350
0
    for (i = 0; i < nf_instance->num_of_ipv4; i++) {
1351
0
        if (nf_instance->ipv4[i])
1352
0
            ogs_freeaddrinfo(nf_instance->ipv4[i]);
1353
0
    }
1354
0
    nf_instance->num_of_ipv4 = 0;
1355
1356
0
    for (i = 0; i < nf_instance->num_of_ipv6; i++) {
1357
0
        if (nf_instance->ipv6[i])
1358
0
            ogs_freeaddrinfo(nf_instance->ipv6[i]);
1359
0
    }
1360
0
    nf_instance->num_of_ipv6 = 0;
1361
1362
0
    nf_instance->num_of_allowed_nf_type = 0;
1363
1364
0
    nf_instance->num_of_s_nssai = 0;
1365
0
    nf_instance->num_of_allowed_nssai = 0;
1366
0
}
1367
1368
void ogs_sbi_nf_instance_remove(ogs_sbi_nf_instance_t *nf_instance)
1369
0
{
1370
0
    ogs_assert(nf_instance);
1371
1372
0
    ogs_debug("[%s] NFInstance removed [%s]",
1373
0
            nf_instance->nf_type ?
1374
0
                OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL",
1375
0
            nf_instance->id);
1376
1377
0
    ogs_list_remove(&ogs_sbi_self()->nf_instance_list, nf_instance);
1378
1379
0
    ogs_sbi_nf_info_remove_all(&nf_instance->nf_info_list);
1380
1381
0
    ogs_sbi_nf_service_remove_all(nf_instance);
1382
1383
0
    ogs_sbi_nf_instance_clear(nf_instance);
1384
1385
0
    if (nf_instance->id) {
1386
0
        ogs_sbi_subscription_data_remove_all_by_nf_instance_id(nf_instance->id);
1387
0
        ogs_free(nf_instance->id);
1388
0
    }
1389
1390
0
    if (nf_instance->hnrf_uri)
1391
0
        ogs_free(nf_instance->hnrf_uri);
1392
1393
0
    if (nf_instance->client)
1394
0
        ogs_sbi_client_remove(nf_instance->client);
1395
1396
0
    ogs_hash_set(nf_instance_pool.id_hash,
1397
0
            &nf_instance->pool_id, sizeof(ogs_pool_id_t), NULL);
1398
0
    ogs_pool_free(&nf_instance_pool, nf_instance);
1399
0
}
1400
1401
void ogs_sbi_nf_instance_remove_all(void)
1402
0
{
1403
0
    ogs_sbi_nf_instance_t *nf_instance = NULL, *next_nf_instance = NULL;
1404
1405
0
    ogs_list_for_each_safe(
1406
0
            &ogs_sbi_self()->nf_instance_list, next_nf_instance, nf_instance)
1407
0
        ogs_sbi_nf_instance_remove(nf_instance);
1408
0
}
1409
1410
ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find(char *id)
1411
0
{
1412
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1413
1414
    /*
1415
     * This is related to Issue #3093.
1416
     *
1417
     * We want to be able to use 'ogs_sbi_nf_instance_id_find(char *id)'
1418
     * even if the 'id' is NULL as in the use case below.
1419
     *
1420
     * ogs_sbi_nf_instance_find(
1421
     *    sess->sbi.service_name_array[service_name].nf_instance_id));
1422
     *
1423
     * To do so, we changed the 'assert(id)' to 'if (!id) return NULL',
1424
     * as shown below.
1425
     */
1426
0
    if (!id) return NULL;
1427
1428
0
    ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) {
1429
0
        if (nf_instance->id && strcmp(nf_instance->id, id) == 0)
1430
0
            break;
1431
0
    }
1432
1433
0
    return nf_instance;
1434
0
}
1435
1436
ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_pool_id(ogs_pool_id_t id)
1437
0
{
1438
0
    return ogs_pool_find_by_id(&nf_instance_pool, id);
1439
0
}
1440
1441
ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_discovery_param(
1442
        OpenAPI_nf_type_e target_nf_type,
1443
        OpenAPI_nf_type_e requester_nf_type,
1444
        ogs_sbi_discovery_option_t *discovery_option)
1445
0
{
1446
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1447
1448
0
    ogs_assert(target_nf_type);
1449
0
    ogs_assert(requester_nf_type);
1450
1451
0
    ogs_list_for_each(&ogs_sbi_self()->nf_instance_list, nf_instance) {
1452
0
        if (ogs_sbi_discovery_param_is_matched(
1453
0
                    nf_instance, target_nf_type, requester_nf_type,
1454
0
                    discovery_option) == false)
1455
0
            continue;
1456
1457
0
        return nf_instance;
1458
0
    }
1459
1460
0
    return NULL;
1461
0
}
1462
1463
ogs_sbi_nf_instance_t *ogs_sbi_nf_instance_find_by_service(
1464
        OpenAPI_service_name_e service_name,
1465
        OpenAPI_nf_type_e requester_nf_type)
1466
0
{
1467
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1468
0
    ogs_sbi_discovery_option_t *discovery_option = NULL;
1469
1470
0
    OpenAPI_nf_type_e target_nf_type = OpenAPI_nf_type_NULL;
1471
1472
0
    ogs_assert(requester_nf_type);
1473
0
    ogs_assert(service_name);
1474
0
    target_nf_type = ogs_sbi_service_name_to_nf_type(service_name);
1475
0
    ogs_assert(target_nf_type);
1476
1477
0
    discovery_option = ogs_sbi_discovery_option_new();
1478
0
    ogs_assert(discovery_option);
1479
0
    ogs_sbi_discovery_option_add_service_names(discovery_option, service_name);
1480
1481
0
    nf_instance = ogs_sbi_nf_instance_find_by_discovery_param(
1482
0
            target_nf_type, requester_nf_type, discovery_option);
1483
1484
0
    ogs_sbi_discovery_option_free(discovery_option);
1485
1486
0
    return nf_instance;
1487
0
}
1488
1489
1490
ogs_sbi_nf_service_t *ogs_sbi_nf_service_add(
1491
        ogs_sbi_nf_instance_t *nf_instance,
1492
        char *id,
1493
        const OpenAPI_service_name_e name,
1494
        OpenAPI_uri_scheme_e scheme)
1495
0
{
1496
0
    ogs_sbi_nf_service_t *nf_service = NULL;
1497
1498
0
    ogs_assert(nf_instance);
1499
0
    ogs_assert(id);
1500
0
    ogs_assert(name);
1501
1502
0
    ogs_pool_alloc(&nf_service_pool, &nf_service);
1503
0
    if (!nf_service) {
1504
0
        ogs_error("OVERFLOW nf_service_pool [pool:%llu]",
1505
0
                (unsigned long long)ogs_app()->pool.nf_service);
1506
0
        return NULL;
1507
0
    }
1508
0
    memset(nf_service, 0, sizeof(ogs_sbi_nf_service_t));
1509
1510
0
    nf_service->id = ogs_strdup(id);
1511
0
    if (!nf_service->id) {
1512
0
        ogs_error("ogs_strdup() failed for nf_service->id");
1513
0
        ogs_pool_free(&nf_service_pool, nf_service);
1514
0
        return NULL;
1515
0
    }
1516
0
    nf_service->name = name;
1517
0
    if (!nf_service->name) {
1518
0
        ogs_error("ogs_strdup() failed for nf_service->name");
1519
0
        ogs_free(nf_service->id);
1520
0
        ogs_pool_free(&nf_service_pool, nf_service);
1521
0
        return NULL;
1522
0
    }
1523
0
    nf_service->scheme = scheme;
1524
0
    ogs_assert(nf_service->scheme);
1525
1526
0
    nf_service->status = OpenAPI_nf_service_status_REGISTERED;
1527
1528
0
    nf_service->priority = OGS_SBI_DEFAULT_PRIORITY;
1529
0
    nf_service->capacity = OGS_SBI_DEFAULT_CAPACITY;
1530
0
    nf_service->load = OGS_SBI_DEFAULT_LOAD;
1531
1532
0
    nf_service->nf_instance = nf_instance;
1533
1534
0
    ogs_list_add(&nf_instance->nf_service_list, nf_service);
1535
1536
0
    return nf_service;
1537
0
}
1538
1539
void ogs_sbi_nf_service_add_version(ogs_sbi_nf_service_t *nf_service,
1540
        const char *in_uri, const char *full, const char *expiry)
1541
0
{
1542
0
    ogs_assert(nf_service);
1543
1544
0
    ogs_assert(in_uri);
1545
0
    ogs_assert(full);
1546
1547
0
    if (nf_service->num_of_version < OGS_SBI_MAX_NUM_OF_SERVICE_VERSION) {
1548
0
        nf_service->version[nf_service->num_of_version].in_uri =
1549
0
            ogs_strdup(in_uri);
1550
0
        ogs_assert(nf_service->version[nf_service->num_of_version].in_uri);
1551
0
        nf_service->version[nf_service->num_of_version].full =
1552
0
            ogs_strdup(full);
1553
0
        ogs_assert(nf_service->version[nf_service->num_of_version].full);
1554
0
        if (expiry) {
1555
0
            nf_service->version[nf_service->num_of_version].expiry =
1556
0
                ogs_strdup(expiry);
1557
0
            ogs_assert(
1558
0
                nf_service->version[nf_service->num_of_version].expiry);
1559
1560
0
        }
1561
0
        nf_service->num_of_version++;
1562
0
    }
1563
0
}
1564
1565
void ogs_sbi_nf_service_add_allowed_nf_type(
1566
        ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type)
1567
0
{
1568
0
    ogs_assert(nf_service);
1569
0
    ogs_assert(allowed_nf_type);
1570
1571
0
    if (nf_service->num_of_allowed_nf_type < OGS_SBI_MAX_NUM_OF_NF_TYPE) {
1572
0
        nf_service->allowed_nf_type[nf_service->num_of_allowed_nf_type] =
1573
0
            allowed_nf_type;
1574
0
        nf_service->num_of_allowed_nf_type++;
1575
0
    }
1576
0
}
1577
1578
bool ogs_sbi_nf_service_is_allowed_nf_type(
1579
        ogs_sbi_nf_service_t *nf_service, OpenAPI_nf_type_e allowed_nf_type)
1580
0
{
1581
0
    int i;
1582
1583
0
    ogs_assert(nf_service);
1584
0
    ogs_assert(allowed_nf_type);
1585
1586
0
    if (!nf_service->num_of_allowed_nf_type) {
1587
0
        return true;
1588
0
    }
1589
1590
0
    for (i = 0; i < nf_service->num_of_allowed_nf_type; i++) {
1591
0
        if (nf_service->allowed_nf_type[i] == allowed_nf_type)
1592
0
            return true;
1593
0
    }
1594
1595
0
    ogs_error("Not allowed nf-type[%s] in nf-service[%s]",
1596
0
            OpenAPI_nf_type_ToString(allowed_nf_type),
1597
0
            OpenAPI_service_name_ToString(nf_service->name));
1598
0
    return false;
1599
0
}
1600
1601
void ogs_sbi_nf_service_clear(ogs_sbi_nf_service_t *nf_service)
1602
0
{
1603
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1604
0
    int i;
1605
1606
0
    ogs_assert(nf_service);
1607
0
    nf_instance = nf_service->nf_instance;
1608
0
    ogs_assert(nf_instance);
1609
1610
0
    if (nf_service->fqdn)
1611
0
        ogs_free(nf_service->fqdn);
1612
0
    nf_service->fqdn = NULL;
1613
1614
0
    for (i = 0; i < nf_service->num_of_version; i++) {
1615
0
        if (nf_service->version[i].in_uri)
1616
0
            ogs_free(nf_service->version[i].in_uri);
1617
0
        if (nf_service->version[i].full)
1618
0
            ogs_free(nf_service->version[i].full);
1619
0
        if (nf_service->version[i].expiry)
1620
0
            ogs_free(nf_service->version[i].expiry);
1621
0
    }
1622
0
    nf_service->num_of_version = 0;
1623
1624
0
    for (i = 0; i < nf_service->num_of_addr; i++) {
1625
0
        if (nf_service->addr[i].ipv4)
1626
0
            ogs_freeaddrinfo(nf_service->addr[i].ipv4);
1627
0
        if (nf_service->addr[i].ipv6)
1628
0
            ogs_freeaddrinfo(nf_service->addr[i].ipv6);
1629
0
    }
1630
0
    nf_service->num_of_addr = 0;
1631
1632
0
    nf_service->num_of_allowed_nf_type = 0;
1633
0
}
1634
1635
void ogs_sbi_nf_service_remove(ogs_sbi_nf_service_t *nf_service)
1636
0
{
1637
0
    ogs_sbi_nf_instance_t *nf_instance = NULL;
1638
1639
0
    ogs_assert(nf_service);
1640
0
    nf_instance = nf_service->nf_instance;
1641
0
    ogs_assert(nf_instance);
1642
1643
0
    ogs_list_remove(&nf_instance->nf_service_list, nf_service);
1644
1645
0
    ogs_assert(nf_service->id);
1646
0
    ogs_free(nf_service->id);
1647
1648
0
    ogs_sbi_nf_service_clear(nf_service);
1649
1650
0
    if (nf_service->client)
1651
0
        ogs_sbi_client_remove(nf_service->client);
1652
1653
0
    ogs_pool_free(&nf_service_pool, nf_service);
1654
0
}
1655
1656
void ogs_sbi_nf_service_remove_all(ogs_sbi_nf_instance_t *nf_instance)
1657
0
{
1658
0
    ogs_sbi_nf_service_t *nf_service = NULL, *next_nf_service = NULL;
1659
1660
0
    ogs_assert(nf_instance);
1661
1662
0
    ogs_list_for_each_safe(&nf_instance->nf_service_list,
1663
0
            next_nf_service, nf_service)
1664
0
        ogs_sbi_nf_service_remove(nf_service);
1665
0
}
1666
1667
ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_id(
1668
        ogs_sbi_nf_instance_t *nf_instance, char *id)
1669
0
{
1670
0
    ogs_sbi_nf_service_t *nf_service = NULL;
1671
1672
0
    ogs_assert(nf_instance);
1673
0
    ogs_assert(id);
1674
1675
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
1676
0
        ogs_assert(nf_service->id);
1677
0
        if (strcmp(nf_service->id, id) == 0)
1678
0
            break;
1679
0
    }
1680
1681
0
    return nf_service;
1682
0
}
1683
1684
ogs_sbi_nf_service_t *ogs_sbi_nf_service_find_by_name(
1685
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_service_name_e name)
1686
0
{
1687
0
    ogs_sbi_nf_service_t *nf_service = NULL;
1688
1689
0
    ogs_assert(nf_instance);
1690
0
    ogs_assert(name);
1691
1692
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
1693
0
        if (nf_service->name == name)
1694
0
            return nf_service;
1695
0
    }
1696
1697
0
    return NULL;
1698
0
}
1699
1700
ogs_sbi_nf_info_t *ogs_sbi_nf_info_add(
1701
        ogs_list_t *list, OpenAPI_nf_type_e nf_type)
1702
0
{
1703
0
    ogs_sbi_nf_info_t *nf_info = NULL;
1704
1705
0
    ogs_assert(list);
1706
0
    ogs_assert(nf_type);
1707
1708
0
    ogs_pool_alloc(&nf_info_pool, &nf_info);
1709
0
    if (!nf_info) {
1710
0
        ogs_error("OVERFLOW nf_info_pool [pool:%llu]",
1711
0
                (unsigned long long)(ogs_app()->pool.nf *
1712
0
                    OGS_MAX_NUM_OF_NF_INFO));
1713
0
        return NULL;
1714
0
    }
1715
0
    memset(nf_info, 0, sizeof(*nf_info));
1716
1717
0
    nf_info->nf_type = nf_type;
1718
1719
0
    ogs_list_add(list, nf_info);
1720
1721
0
    return nf_info;
1722
0
}
1723
1724
static void amf_info_free(ogs_sbi_amf_info_t *amf_info)
1725
0
{
1726
0
    ogs_assert(amf_info);
1727
1728
0
    amf_info->num_of_guami = 0;
1729
0
    amf_info->num_of_nr_tai = 0;
1730
0
    amf_info->num_of_nr_tai_range = 0;
1731
0
}
1732
1733
static void smf_info_free(ogs_sbi_smf_info_t *smf_info)
1734
0
{
1735
0
    int i, j;
1736
0
    ogs_assert(smf_info);
1737
1738
0
    for (i = 0; i < smf_info->num_of_slice; i++) {
1739
0
        for (j = 0; j < smf_info->slice[i].num_of_dnn; j++)
1740
0
            ogs_free(smf_info->slice[i].dnn[j]);
1741
0
        smf_info->slice[i].num_of_dnn = 0;
1742
0
    }
1743
0
    smf_info->num_of_slice = 0;
1744
0
    smf_info->num_of_nr_tai = 0;
1745
0
    smf_info->num_of_nr_tai_range = 0;
1746
0
}
1747
1748
static void scp_info_free(ogs_sbi_scp_info_t *scp_info)
1749
0
{
1750
0
    int i;
1751
0
    for (i = 0; i < scp_info->num_of_domain; i++) {
1752
0
        if (scp_info->domain[i].name)
1753
0
            ogs_free(scp_info->domain[i].name);
1754
0
        if (scp_info->domain[i].fqdn)
1755
0
            ogs_free(scp_info->domain[i].fqdn);
1756
0
    }
1757
0
    scp_info->num_of_domain = 0;
1758
0
}
1759
1760
static void sepp_info_free(ogs_sbi_sepp_info_t *sepp_info)
1761
0
{
1762
0
}
1763
1764
void ogs_sbi_nf_info_remove(ogs_list_t *list, ogs_sbi_nf_info_t *nf_info)
1765
0
{
1766
0
    ogs_assert(list);
1767
0
    ogs_assert(nf_info);
1768
1769
0
    ogs_list_remove(list, nf_info);
1770
1771
0
    switch(nf_info->nf_type) {
1772
0
    case OpenAPI_nf_type_AMF:
1773
0
        amf_info_free(&nf_info->amf);
1774
0
        break;
1775
0
    case OpenAPI_nf_type_SMF:
1776
0
        smf_info_free(&nf_info->smf);
1777
0
        break;
1778
0
    case OpenAPI_nf_type_SCP:
1779
0
        scp_info_free(&nf_info->scp);
1780
0
        break;
1781
0
    case OpenAPI_nf_type_SEPP:
1782
0
        sepp_info_free(&nf_info->sepp);
1783
0
        break;
1784
0
    default:
1785
0
        ogs_fatal("Not implemented NF-type[%s]",
1786
0
                OpenAPI_nf_type_ToString(nf_info->nf_type));
1787
0
        ogs_assert_if_reached();
1788
0
    }
1789
1790
0
    ogs_pool_free(&nf_info_pool, nf_info);
1791
0
}
1792
1793
void ogs_sbi_nf_info_remove_all(ogs_list_t *list)
1794
0
{
1795
0
    ogs_sbi_nf_info_t *nf_info = NULL, *next_nf_info = NULL;
1796
1797
0
    ogs_assert(list);
1798
1799
0
    ogs_list_for_each_safe(list, next_nf_info, nf_info)
1800
0
        ogs_sbi_nf_info_remove(list, nf_info);
1801
0
}
1802
1803
ogs_sbi_nf_info_t *ogs_sbi_nf_info_find(
1804
        ogs_list_t *list, OpenAPI_nf_type_e nf_type)
1805
0
{
1806
0
    ogs_sbi_nf_info_t *nf_info = NULL;
1807
1808
0
    ogs_assert(list);
1809
0
    ogs_assert(nf_type);
1810
1811
0
    ogs_list_for_each(list, nf_info) {
1812
0
        if (nf_info->nf_type == nf_type)
1813
0
            return nf_info;
1814
0
    }
1815
1816
0
    return NULL;
1817
0
}
1818
1819
bool ogs_sbi_check_amf_info_guami(
1820
        ogs_sbi_amf_info_t *amf_info, ogs_guami_t *guami)
1821
0
{
1822
0
    int i;
1823
1824
0
    ogs_assert(amf_info);
1825
0
    ogs_assert(guami);
1826
1827
0
    for (i = 0; i < amf_info->num_of_guami; i++) {
1828
0
        if ((memcmp(&amf_info->guami[i].amf_id, &guami->amf_id,
1829
0
                        sizeof(ogs_amf_id_t)) == 0) &&
1830
0
            (memcmp(&amf_info->guami[i].plmn_id, &guami->plmn_id,
1831
0
                    OGS_PLMN_ID_LEN) == 0)) {
1832
0
            return true;
1833
0
        }
1834
0
    }
1835
1836
0
    return false;
1837
0
}
1838
1839
bool ogs_sbi_check_smf_info_slice(
1840
        ogs_sbi_smf_info_t *smf_info, ogs_s_nssai_t *s_nssai, char *dnn)
1841
0
{
1842
0
    int i, j;
1843
1844
0
    ogs_assert(smf_info);
1845
0
    ogs_assert(s_nssai);
1846
0
    ogs_assert(dnn);
1847
1848
0
    for (i = 0; i < smf_info->num_of_slice; i++) {
1849
0
        if (s_nssai->sst == smf_info->slice[i].s_nssai.sst &&
1850
0
            s_nssai->sd.v == smf_info->slice[i].s_nssai.sd.v) {
1851
1852
0
            for (j = 0; j < smf_info->slice[i].num_of_dnn; j++) {
1853
0
                if (ogs_strcasecmp(dnn, smf_info->slice[i].dnn[j]) == 0)
1854
0
                    return true;
1855
0
            }
1856
0
        }
1857
0
    }
1858
1859
0
    return false;
1860
0
}
1861
bool ogs_sbi_check_smf_info_tai(
1862
        ogs_sbi_smf_info_t *smf_info, ogs_5gs_tai_t *tai)
1863
0
{
1864
0
    int i, j;
1865
1866
0
    ogs_assert(smf_info);
1867
0
    ogs_assert(tai);
1868
1869
0
    if (smf_info->num_of_nr_tai == 0 && smf_info->num_of_nr_tai_range == 0)
1870
0
        return true;
1871
1872
0
    for (i = 0; i < smf_info->num_of_nr_tai; i++) {
1873
0
        if (memcmp(&tai->plmn_id,
1874
0
                &smf_info->nr_tai[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
1875
0
            if (tai->tac.v == smf_info->nr_tai[i].tac.v)
1876
0
                return true;
1877
0
        }
1878
0
    }
1879
1880
0
    for (i = 0; i < smf_info->num_of_nr_tai_range; i++) {
1881
0
        if (memcmp(&tai->plmn_id,
1882
0
                &smf_info->nr_tai_range[i].plmn_id, OGS_PLMN_ID_LEN) == 0) {
1883
0
            for (j = 0; j < smf_info->nr_tai_range[i].num_of_tac_range; j++) {
1884
0
                if (tai->tac.v >= smf_info->nr_tai_range[i].start[j].v &&
1885
0
                    tai->tac.v <= smf_info->nr_tai_range[i].end[j].v) {
1886
0
                    return true;
1887
0
                }
1888
0
            }
1889
0
        }
1890
0
    }
1891
1892
0
    return false;
1893
0
}
1894
1895
void ogs_sbi_nf_instance_build_default(ogs_sbi_nf_instance_t *nf_instance)
1896
0
{
1897
0
    ogs_sbi_server_t *server = NULL;
1898
0
    char *hostname = NULL;
1899
1900
0
    ogs_assert(nf_instance);
1901
1902
0
    ogs_sbi_nf_instance_set_status(nf_instance, OpenAPI_nf_status_REGISTERED);
1903
1904
0
    hostname = NULL;
1905
0
    for (server = ogs_sbi_server_first();
1906
0
            server; server = ogs_sbi_server_next(server)) {
1907
0
        ogs_sockaddr_t *advertise = NULL;
1908
1909
0
        advertise = server->advertise;
1910
0
        if (!advertise)
1911
0
            advertise = server->node.addr;
1912
0
        ogs_assert(advertise);
1913
1914
        /* First FQDN is selected */
1915
0
        if (!hostname)
1916
0
            hostname = ogs_gethostname(advertise);
1917
1918
0
        if (nf_instance->num_of_ipv4 < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
1919
0
            ogs_sockaddr_t *addr = NULL;
1920
0
            ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise));
1921
0
            ogs_assert(addr);
1922
1923
0
            if (addr->ogs_sa_family == AF_INET) {
1924
0
                nf_instance->ipv4[nf_instance->num_of_ipv4] = addr;
1925
0
                nf_instance->num_of_ipv4++;
1926
0
            } else if (addr->ogs_sa_family == AF_INET6) {
1927
0
                nf_instance->ipv6[nf_instance->num_of_ipv6] = addr;
1928
0
                nf_instance->num_of_ipv6++;
1929
0
            } else
1930
0
                ogs_assert_if_reached();
1931
0
        }
1932
0
    }
1933
1934
0
    if (hostname) {
1935
0
        nf_instance->fqdn = ogs_strdup(hostname);
1936
0
        ogs_assert(nf_instance->fqdn);
1937
0
    }
1938
1939
0
    nf_instance->time.heartbeat_interval =
1940
0
            ogs_local_conf()->time.nf_instance.heartbeat_interval;
1941
1942
0
    if (ogs_local_conf()->num_of_serving_plmn_id) {
1943
0
        memcpy(nf_instance->plmn_id, ogs_local_conf()->serving_plmn_id,
1944
0
                sizeof(nf_instance->plmn_id));
1945
0
        nf_instance->num_of_plmn_id = ogs_local_conf()->num_of_serving_plmn_id;
1946
0
    }
1947
0
}
1948
1949
ogs_sbi_nf_service_t *ogs_sbi_nf_service_build_default(
1950
        ogs_sbi_nf_instance_t *nf_instance, OpenAPI_service_name_e name)
1951
0
{
1952
0
    ogs_sbi_server_t *server = NULL;
1953
0
    ogs_sbi_nf_service_t *nf_service = NULL;
1954
0
    ogs_uuid_t uuid;
1955
0
    char id[OGS_UUID_FORMATTED_LENGTH + 1];
1956
0
    char *hostname = NULL;
1957
1958
0
    OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
1959
1960
0
    ogs_assert(nf_instance);
1961
0
    ogs_assert(name);
1962
1963
0
    ogs_uuid_get(&uuid);
1964
0
    ogs_uuid_format(id, &uuid);
1965
1966
0
    server = ogs_sbi_server_first();
1967
0
    ogs_assert(server);
1968
1969
0
    scheme = server->scheme;
1970
0
    ogs_assert(scheme);
1971
1972
0
    nf_service = ogs_sbi_nf_service_add(nf_instance, id, name, scheme);
1973
0
    if (!nf_service) {
1974
0
        ogs_error("Cannot build default NF service [%s]: "
1975
0
                "nf_service_pool exhausted at startup. "
1976
0
                "Increase 'max.peer' (current pool capacity = "
1977
0
                "max.peer * 16 = %llu).",
1978
0
                OpenAPI_service_name_ToString(name),
1979
0
                (unsigned long long)ogs_app()->pool.nf_service);
1980
0
        return NULL;
1981
0
    }
1982
1983
0
    hostname = NULL;
1984
0
    for (server = ogs_sbi_server_first();
1985
0
            server; server = ogs_sbi_server_next(server)) {
1986
0
        ogs_sockaddr_t *advertise = NULL;
1987
1988
0
        advertise = server->advertise;
1989
0
        if (!advertise)
1990
0
            advertise = server->node.addr;
1991
0
        ogs_assert(advertise);
1992
1993
        /* First FQDN is selected */
1994
0
        if (!hostname)
1995
0
            hostname = ogs_gethostname(advertise);
1996
1997
0
        if (nf_service->num_of_addr < OGS_SBI_MAX_NUM_OF_IP_ADDRESS) {
1998
0
            bool is_port = true;
1999
0
            int port = 0;
2000
0
            ogs_sockaddr_t *addr = NULL;
2001
0
            ogs_assert(OGS_OK == ogs_copyaddrinfo(&addr, advertise));
2002
0
            ogs_assert(addr);
2003
2004
0
            port = OGS_PORT(addr);
2005
0
            if (nf_service->scheme == OpenAPI_uri_scheme_https) {
2006
0
                if (port == OGS_SBI_HTTPS_PORT) is_port = false;
2007
0
            } else if (nf_service->scheme == OpenAPI_uri_scheme_http) {
2008
0
                if (port == OGS_SBI_HTTP_PORT) is_port = false;
2009
0
            }
2010
2011
0
            nf_service->addr[nf_service->num_of_addr].is_port = is_port;
2012
0
            nf_service->addr[nf_service->num_of_addr].port = port;
2013
0
            if (addr->ogs_sa_family == AF_INET) {
2014
0
                nf_service->addr[nf_service->num_of_addr].ipv4 = addr;
2015
0
            } else if (addr->ogs_sa_family == AF_INET6) {
2016
0
                nf_service->addr[nf_service->num_of_addr].ipv6 = addr;
2017
0
            } else
2018
0
                ogs_assert_if_reached();
2019
2020
0
            nf_service->num_of_addr++;
2021
0
        }
2022
0
    }
2023
2024
0
    if (hostname) {
2025
0
        nf_service->fqdn = ogs_strdup(hostname);
2026
0
        ogs_assert(nf_service->fqdn);
2027
0
    }
2028
2029
0
    ogs_info("NF Service [%s]",
2030
0
            OpenAPI_service_name_ToString(nf_service->name));
2031
2032
0
    return nf_service;
2033
0
}
2034
2035
static ogs_sbi_client_t *nf_instance_find_client(
2036
        ogs_sbi_nf_instance_t *nf_instance)
2037
0
{
2038
0
    ogs_sbi_client_t *client = NULL;
2039
0
    ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
2040
0
    OpenAPI_uri_scheme_e scheme = OpenAPI_uri_scheme_NULL;
2041
2042
0
    ogs_sbi_nf_info_t *nf_info = NULL;
2043
0
    uint16_t port = 0;
2044
2045
0
    scheme = ogs_sbi_self()->tls.client.scheme;
2046
0
    ogs_assert(scheme);
2047
2048
0
    switch (nf_instance->nf_type) {
2049
0
    case OpenAPI_nf_type_SEPP:
2050
0
        nf_info = ogs_sbi_nf_info_find(
2051
0
                    &nf_instance->nf_info_list, nf_instance->nf_type);
2052
0
        if (nf_info) {
2053
0
            if (scheme == OpenAPI_uri_scheme_https)
2054
0
                port = nf_info->sepp.https.port;
2055
0
            else if (scheme == OpenAPI_uri_scheme_http)
2056
0
                port = nf_info->sepp.http.port;
2057
0
            else
2058
0
                ogs_error("Unknown scheme [%d]", scheme);
2059
0
        }
2060
0
        break;
2061
0
    case OpenAPI_nf_type_SCP:
2062
0
        nf_info = ogs_sbi_nf_info_find(
2063
0
                    &nf_instance->nf_info_list, nf_instance->nf_type);
2064
0
        if (nf_info) {
2065
0
            if (scheme == OpenAPI_uri_scheme_https)
2066
0
                port = nf_info->scp.https.port;
2067
0
            else if (scheme == OpenAPI_uri_scheme_http)
2068
0
                port = nf_info->scp.http.port;
2069
0
            else
2070
0
                ogs_error("Unknown scheme [%d]", scheme);
2071
0
        }
2072
0
        break;
2073
0
    default:
2074
0
        break;
2075
0
    }
2076
2077
    /* At this point, CLIENT selection method is very simple. */
2078
0
    if (nf_instance->num_of_ipv4) addr = nf_instance->ipv4[0];
2079
0
    if (nf_instance->num_of_ipv6) addr6 = nf_instance->ipv6[0];
2080
2081
0
    if (port) {
2082
0
        if (addr)
2083
0
            addr->ogs_sin_port = htobe16(port);
2084
0
        if (addr6)
2085
0
            addr6->ogs_sin_port = htobe16(port);
2086
0
    }
2087
2088
0
    if (nf_instance->fqdn || addr || addr6) {
2089
0
        client = ogs_sbi_client_find(
2090
0
                scheme, nf_instance->fqdn, port, addr, addr6);
2091
0
        if (!client) {
2092
0
            ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC);
2093
0
            client = ogs_sbi_client_add(
2094
0
                    scheme, nf_instance->fqdn, port, addr, addr6);
2095
0
            if (!client) {
2096
0
                ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC);
2097
0
                return NULL;
2098
0
            }
2099
0
        }
2100
0
    } else
2101
0
        ogs_error("[%s] No instance-level endpoint, "
2102
0
                "client association skipped [id:%s]",
2103
0
                OpenAPI_nf_type_ToString(nf_instance->nf_type),
2104
0
                nf_instance->id);
2105
2106
0
    return client;
2107
0
}
2108
2109
static void nf_service_associate_client(ogs_sbi_nf_service_t *nf_service)
2110
0
{
2111
0
    ogs_sbi_client_t *client = NULL;
2112
0
    ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
2113
0
    uint16_t port = 0;
2114
2115
0
    ogs_assert(nf_service->scheme);
2116
2117
    /* At this point, CLIENT selection method is very simple. */
2118
0
    if (nf_service->num_of_addr) {
2119
0
        addr = nf_service->addr[0].ipv4;
2120
0
        addr6 = nf_service->addr[0].ipv6;
2121
2122
        /*
2123
         * Added support for using custom port numbers with FQDN.
2124
         *
2125
         * This code checks if a user-defined port number is provided in the
2126
         * NFService structure. If the is_port flag is set, the port is
2127
         * assigned the specified value.
2128
         *
2129
         * This ensures that services using non-default ports can be accessed
2130
         * correctly, regardless of whether TLS is enabled or not.
2131
         */
2132
0
        if (nf_service->addr[0].is_port)
2133
0
            port = nf_service->addr[0].port;
2134
0
    }
2135
2136
0
    if (nf_service->fqdn || addr || addr6) {
2137
0
        client = ogs_sbi_client_find(
2138
0
                nf_service->scheme, nf_service->fqdn, port, addr, addr6);
2139
0
        if (!client) {
2140
0
            ogs_debug("%s: ogs_sbi_client_add()", OGS_FUNC);
2141
0
            client = ogs_sbi_client_add(
2142
0
                    nf_service->scheme, nf_service->fqdn, port, addr, addr6);
2143
0
            if (!client) {
2144
0
                ogs_error("%s: ogs_sbi_client_add() failed", OGS_FUNC);
2145
0
                return;
2146
0
            }
2147
0
        }
2148
0
    } else
2149
0
        ogs_error("[%s] No service-level endpoint, "
2150
0
                "client association skipped [id:%s]",
2151
0
                OpenAPI_service_name_ToString(nf_service->name),
2152
0
                nf_service->id);
2153
2154
0
    if (client) {
2155
0
        ogs_info("[%s] NFService associated [%s]",
2156
0
                OpenAPI_service_name_ToString(nf_service->name),
2157
0
                nf_service->id);
2158
0
        OGS_SBI_SETUP_CLIENT(nf_service, client);
2159
0
    }
2160
0
}
2161
2162
static void nf_service_associate_client_all(ogs_sbi_nf_instance_t *nf_instance)
2163
0
{
2164
0
    ogs_sbi_nf_service_t *nf_service = NULL;
2165
2166
0
    ogs_assert(nf_instance);
2167
2168
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service)
2169
0
        nf_service_associate_client(nf_service);
2170
0
}
2171
2172
bool ogs_sbi_discovery_option_is_matched(
2173
        ogs_sbi_nf_instance_t *nf_instance,
2174
        OpenAPI_nf_type_e requester_nf_type,
2175
        ogs_sbi_discovery_option_t *discovery_option)
2176
0
{
2177
0
    ogs_sbi_nf_info_t *nf_info = NULL;
2178
0
    bool smf_info_checked = false;
2179
0
    bool smf_match_found = false;
2180
0
    bool need_smf_slice = false;   /* requires both S-NSSAI and DNN */
2181
0
    bool need_smf_tai = false;     /* TAI filter present */
2182
0
    bool need_smf_any = false;     /* any SMF-specific filter */
2183
0
    int i;
2184
2185
0
    ogs_assert(nf_instance);
2186
0
    ogs_assert(requester_nf_type);
2187
0
    ogs_assert(discovery_option);
2188
2189
    /* --------------------------------------------------------------
2190
     * Step 1. Common pre-checks for all NF types
2191
     * -------------------------------------------------------------- */
2192
0
    if (discovery_option->target_nf_instance_id &&
2193
0
        nf_instance->id &&
2194
0
        strcmp(nf_instance->id,
2195
0
           discovery_option->target_nf_instance_id) != 0)
2196
0
        return false;
2197
2198
0
    if (discovery_option->num_of_service_names &&
2199
0
        ogs_sbi_discovery_option_service_names_is_matched(
2200
0
            nf_instance, requester_nf_type, discovery_option) == false)
2201
0
        return false;
2202
2203
0
    if (discovery_option->num_of_target_plmn_list &&
2204
0
        ogs_sbi_discovery_option_target_plmn_list_is_matched(
2205
0
            nf_instance, discovery_option) == false)
2206
0
        return false;
2207
2208
0
    if (nf_instance->nf_type == OpenAPI_nf_type_NRF &&
2209
0
        ogs_sbi_discovery_option_hnrf_uri_is_matched(
2210
0
            nf_instance, discovery_option) == false)
2211
0
        return false;
2212
2213
    /*
2214
     * TS 33.518 4.2.2.2.1 - Target allowed_nssai filtering
2215
     *
2216
     * If the target NF registered with allowedNssais, it may only be
2217
     * discovered for queries whose S-NSSAI falls within that set.
2218
     */
2219
0
    if (nf_instance->num_of_allowed_nssai &&
2220
0
            discovery_option->num_of_snssais) {
2221
0
        bool nssai_allowed = false;
2222
2223
0
        for (i = 0; i < discovery_option->num_of_snssais; i++) {
2224
0
            int j;
2225
0
            for (j = 0; j < nf_instance->num_of_allowed_nssai; j++) {
2226
0
                if (discovery_option->snssais[i].sst ==
2227
0
                        nf_instance->allowed_nssai[j].sst &&
2228
0
                    discovery_option->snssais[i].sd.v ==
2229
0
                        nf_instance->allowed_nssai[j].sd.v) {
2230
0
                    nssai_allowed = true;
2231
0
                    break;
2232
0
                }
2233
0
            }
2234
0
            if (nssai_allowed) break;
2235
0
        }
2236
2237
0
        if (!nssai_allowed)
2238
0
            return false;
2239
0
    }
2240
2241
    /* Determine which SMF filters are requested */
2242
0
    if (nf_instance->nf_type == OpenAPI_nf_type_SMF) {
2243
0
        need_smf_slice = (discovery_option->num_of_snssais &&
2244
0
                          discovery_option->dnn) ? true : false;
2245
0
        need_smf_tai = discovery_option->tai_presence ? true : false;
2246
2247
        /* If more SMF filters are added later, OR them here */
2248
0
        need_smf_any = (need_smf_slice || need_smf_tai) ? true : false;
2249
0
    }
2250
2251
    /* --------------------------------------------------------------
2252
     * Step 2. NF-type specific matching
2253
     * -------------------------------------------------------------- */
2254
0
    ogs_list_for_each(&nf_instance->nf_info_list, nf_info) {
2255
0
        if (nf_instance->nf_type != nf_info->nf_type) {
2256
0
            ogs_error("Invalid NF-Type [%d:%d]",
2257
0
                nf_instance->nf_type, nf_info->nf_type);
2258
0
            return false;
2259
0
        }
2260
2261
        /* --- AMF --- */
2262
0
        if (nf_info->nf_type == OpenAPI_nf_type_AMF) {
2263
0
            if (requester_nf_type == OpenAPI_nf_type_AMF &&
2264
0
                discovery_option->guami_presence &&
2265
0
                ogs_sbi_check_amf_info_guami(
2266
0
                    &nf_info->amf,
2267
0
                    &discovery_option->guami) == false)
2268
0
                return false;
2269
0
        }
2270
2271
        /* --- SMF --- */
2272
0
        else if (nf_info->nf_type == OpenAPI_nf_type_SMF) {
2273
            /* Skip expensive checks if no SMF filter is requested */
2274
0
            smf_info_checked = true;
2275
2276
            /* Slice (S-NSSAI + DNN) filter */
2277
0
            if (need_smf_slice) {
2278
0
                bool slice_ok = false;
2279
0
                for (i = 0; i < discovery_option->num_of_snssais; i++) {
2280
0
                    if (ogs_sbi_check_smf_info_slice(
2281
0
                            &nf_info->smf,
2282
0
                            &discovery_option->snssais[i],
2283
0
                            discovery_option->dnn)) {
2284
0
                        slice_ok = true;
2285
0
                        break;
2286
0
                    }
2287
0
                }
2288
0
                if (slice_ok == false)
2289
0
                    continue; /* this smfInfo does not match slice */
2290
0
            }
2291
2292
            /* TAI filter (applied after slice if present) */
2293
0
            if (need_smf_tai) {
2294
0
                if (ogs_sbi_check_smf_info_tai(
2295
0
                        &nf_info->smf,
2296
0
                        &discovery_option->tai) == false)
2297
0
                    continue; /* this smfInfo does not match TAI */
2298
0
            }
2299
2300
            /* If we reached here, all requested filters passed */
2301
0
            smf_match_found = true;
2302
0
            break; /* OR logic across smfInfo blocks */
2303
0
        }
2304
2305
        /* Other NF types: no additional checks here */
2306
0
    }
2307
2308
    /* --------------------------------------------------------------
2309
     * Step 3. Final validation for SMF
2310
     * -------------------------------------------------------------- */
2311
0
    if (nf_instance->nf_type == OpenAPI_nf_type_SMF &&
2312
0
        smf_info_checked &&
2313
0
        need_smf_any &&
2314
0
        smf_match_found == false)
2315
0
        return false;
2316
2317
0
    return true;
2318
0
}
2319
2320
bool ogs_sbi_discovery_option_service_names_is_matched(
2321
        ogs_sbi_nf_instance_t *nf_instance,
2322
        OpenAPI_nf_type_e requester_nf_type,
2323
        ogs_sbi_discovery_option_t *discovery_option)
2324
0
{
2325
0
    ogs_sbi_nf_service_t *nf_service = NULL;
2326
0
    int i;
2327
2328
0
    ogs_assert(nf_instance);
2329
0
    ogs_assert(requester_nf_type);
2330
0
    ogs_assert(discovery_option);
2331
2332
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
2333
0
        for (i = 0; i < discovery_option->num_of_service_names; i++) {
2334
0
            if (nf_service->name &&
2335
0
                discovery_option->service_names[i] &&
2336
0
                nf_service->name == discovery_option->service_names[i]) {
2337
0
                if (ogs_sbi_nf_service_is_allowed_nf_type(
2338
0
                        nf_service, requester_nf_type) == true) {
2339
0
                    return true;
2340
0
                }
2341
0
            }
2342
0
        }
2343
0
    }
2344
0
    return false;
2345
0
}
2346
2347
bool ogs_sbi_discovery_param_serving_plmn_list_is_matched(
2348
        ogs_sbi_nf_instance_t *nf_instance)
2349
0
{
2350
0
    int i, j;
2351
2352
0
    ogs_assert(nf_instance);
2353
2354
    /*
2355
     * The PLMN-ID is optional and may not be set.
2356
     *
2357
     * Does not compare if serving PLMN-ID is not set or NF-Instance is not set.
2358
     */
2359
0
    if (ogs_local_conf()->num_of_serving_plmn_id == 0 ||
2360
0
            nf_instance->num_of_plmn_id == 0)
2361
0
        return true;
2362
2363
0
    for (i = 0; i < nf_instance->num_of_plmn_id; i++) {
2364
0
        for (j = 0; j < ogs_local_conf()->num_of_serving_plmn_id; j++) {
2365
0
            if (memcmp(&nf_instance->plmn_id[i],
2366
0
                        &ogs_local_conf()->serving_plmn_id[j],
2367
0
                        OGS_PLMN_ID_LEN) == 0) {
2368
0
                return true;
2369
0
            }
2370
0
        }
2371
0
    }
2372
0
    return false;
2373
0
}
2374
2375
bool ogs_sbi_discovery_option_requester_plmn_list_is_matched(
2376
        ogs_sbi_nf_instance_t *nf_instance,
2377
        ogs_sbi_discovery_option_t *discovery_option)
2378
0
{
2379
0
    int i, j;
2380
2381
0
    ogs_assert(nf_instance);
2382
0
    ogs_assert(discovery_option);
2383
2384
0
    for (i = 0; i < nf_instance->num_of_plmn_id; i++) {
2385
0
        for (j = 0; j < discovery_option->num_of_requester_plmn_list; j++) {
2386
0
            if (memcmp(&nf_instance->plmn_id[i],
2387
0
                       &discovery_option->requester_plmn_list[j],
2388
0
                       OGS_PLMN_ID_LEN) == 0) {
2389
0
                return true;
2390
0
            }
2391
0
        }
2392
0
    }
2393
0
    return false;
2394
0
}
2395
2396
bool ogs_sbi_discovery_option_target_plmn_list_is_matched(
2397
        ogs_sbi_nf_instance_t *nf_instance,
2398
        ogs_sbi_discovery_option_t *discovery_option)
2399
0
{
2400
0
    int i, j;
2401
2402
0
    ogs_assert(nf_instance);
2403
0
    ogs_assert(discovery_option);
2404
2405
0
    for (i = 0; i < nf_instance->num_of_plmn_id; i++) {
2406
0
        for (j = 0; j < discovery_option->num_of_target_plmn_list; j++) {
2407
0
            if (memcmp(&nf_instance->plmn_id[i],
2408
0
                       &discovery_option->target_plmn_list[j],
2409
0
                       OGS_PLMN_ID_LEN) == 0) {
2410
0
                return true;
2411
0
            }
2412
0
        }
2413
0
    }
2414
0
    return false;
2415
0
}
2416
2417
bool ogs_sbi_discovery_option_hnrf_uri_is_matched(
2418
        ogs_sbi_nf_instance_t *nf_instance,
2419
        ogs_sbi_discovery_option_t *discovery_option)
2420
0
{
2421
0
    ogs_assert(nf_instance);
2422
0
    ogs_assert(discovery_option);
2423
2424
0
    if (nf_instance->hnrf_uri == NULL && discovery_option->hnrf_uri == NULL)
2425
0
        return true;
2426
0
    else if (nf_instance->hnrf_uri == NULL ||
2427
0
            discovery_option->hnrf_uri == NULL)
2428
0
        return false;
2429
2430
0
    return ogs_strcasecmp(nf_instance->hnrf_uri,
2431
0
            discovery_option->hnrf_uri) == 0;
2432
0
}
2433
2434
bool ogs_sbi_discovery_param_is_matched(
2435
        ogs_sbi_nf_instance_t *nf_instance,
2436
        OpenAPI_nf_type_e target_nf_type,
2437
        OpenAPI_nf_type_e requester_nf_type,
2438
        ogs_sbi_discovery_option_t *discovery_option)
2439
0
{
2440
0
    ogs_assert(nf_instance);
2441
0
    ogs_assert(target_nf_type);
2442
0
    ogs_assert(requester_nf_type);
2443
2444
0
    if (NF_INSTANCE_EXCLUDED_FROM_DISCOVERY(nf_instance))
2445
0
        return false;
2446
2447
0
    if (nf_instance->nf_type != target_nf_type)
2448
0
        return false;
2449
2450
    /*
2451
     * For the same PLMN, The target-plmn-list may not be included
2452
     * in discovery request.
2453
     *
2454
     * If the Serving PLMN needs to be discovered, but the target-plmn-list
2455
     * is not included, the NF of the Home PLMN can be discovered.
2456
     *
2457
     * To avoid this situation, if the target-plmn-list is not included
2458
     * and the serving PLMN is known, it is compared first.
2459
     *
2460
     * Refer to the following standard for this issue.
2461
     *
2462
     * TS29.510
2463
     * 6.2 Nnrf_NFDiscovery Service API
2464
     * 6.2.3 Resources
2465
     * Table 6.2.3.2.3.1-1: URI query parameters supported
2466
     * by the GET method on this resource
2467
     *
2468
     * NAME: target-plmn-list
2469
     * Data type: array(PlmnId)
2470
     * P: C
2471
     * Cardinality: 1..N
2472
     *
2473
     * This IE shall be included when NF services in a different PLMN,
2474
     * or NF services of specific PLMN ID(s) in a same PLMN
2475
     * comprising multiple PLMN IDs, need to be discovered.
2476
     * When included, this IE shall contain the PLMN ID of the target NF.
2477
     * If more than one PLMN ID is included, NFs from any PLMN ID present
2478
     * in the list matches the query parameter. This IE shall also
2479
     * be included in SNPN scenarios, when the entity owning
2480
     * the subscription, the Credentials Holder
2481
     * (see clause 5.30.2.9 in 3GPP TS 23.501 [2]) is a PLMN.
2482
     *
2483
     * For inter-PLMN service discovery, at most 1 PLMN ID shall
2484
     * be included in the list; it shall be included
2485
     * in the service discovery from the NF in the source PLMN sent
2486
     * to the NRF in the same PLMN, while it may be absent
2487
     * in the service discovery request sent from the source NRF
2488
     * to the target NRF. In such case, if the NRF receives more than
2489
     * 1 PLMN ID, it shall only consider the first element of the array,
2490
     * and ignore the rest.
2491
     */
2492
0
    if (!discovery_option || !discovery_option->num_of_target_plmn_list) {
2493
0
        if (ogs_sbi_discovery_param_serving_plmn_list_is_matched(
2494
0
                nf_instance) == false)
2495
0
            return false;
2496
0
    }
2497
2498
0
    if (discovery_option) {
2499
0
        if (ogs_sbi_discovery_option_is_matched(
2500
0
            nf_instance, requester_nf_type, discovery_option) == false)
2501
0
        return false;
2502
0
    }
2503
2504
0
    return true;
2505
0
}
2506
2507
void ogs_sbi_client_associate(ogs_sbi_nf_instance_t *nf_instance)
2508
0
{
2509
0
    ogs_sbi_client_t *client = NULL;
2510
2511
0
    ogs_assert(nf_instance);
2512
2513
0
    client = nf_instance_find_client(nf_instance);
2514
0
    if (client) {
2515
0
        ogs_info("[%s] NFInstance associated [%s]",
2516
0
                nf_instance->nf_type ?
2517
0
                    OpenAPI_nf_type_ToString(nf_instance->nf_type) : "NULL",
2518
0
                nf_instance->id);
2519
2520
0
        OGS_SBI_SETUP_CLIENT(nf_instance, client);
2521
0
    }
2522
2523
0
    nf_service_associate_client_all(nf_instance);
2524
0
}
2525
2526
bool nf_instance_has_usable_client(ogs_sbi_nf_instance_t *nf_instance)
2527
0
{
2528
0
    ogs_sbi_nf_service_t *nf_service = NULL;
2529
2530
0
    ogs_assert(nf_instance);
2531
2532
    /* Instance-level client */
2533
0
    if (NF_INSTANCE_CLIENT(nf_instance))
2534
0
        return true;
2535
2536
    /* Service-level clients */
2537
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
2538
0
        if (nf_service->client)
2539
0
            return true;
2540
0
    }
2541
2542
0
    return false;
2543
0
}
2544
2545
int ogs_sbi_default_client_port(OpenAPI_uri_scheme_e scheme)
2546
0
{
2547
0
    if (scheme == OpenAPI_uri_scheme_NULL)
2548
0
        scheme = ogs_sbi_self()->tls.client.scheme;
2549
2550
0
    return scheme == OpenAPI_uri_scheme_https ?
2551
0
            OGS_SBI_HTTPS_PORT : OGS_SBI_HTTP_PORT;
2552
0
}
2553
2554
ogs_sbi_client_t *ogs_sbi_client_find_by_service_name(
2555
        ogs_sbi_nf_instance_t *nf_instance, char *name, char *version)
2556
0
{
2557
0
    ogs_sbi_nf_service_t *nf_service = NULL;
2558
0
    OpenAPI_service_name_e service_name = OpenAPI_service_name_NULL;
2559
0
    int i;
2560
2561
0
    ogs_assert(nf_instance);
2562
0
    ogs_assert(name);
2563
0
    ogs_assert(version);
2564
2565
0
    service_name = OpenAPI_service_name_FromString(name);
2566
0
    if (!service_name) {
2567
0
        ogs_error("Invalid service-name[%s]", name);
2568
0
        return NULL;
2569
0
    }
2570
2571
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
2572
0
        ogs_assert(nf_service->name);
2573
0
        if (nf_service->name == service_name) {
2574
0
            for (i = 0; i < nf_service->num_of_version; i++) {
2575
0
                if (strcmp(nf_service->version[i].in_uri, version) == 0) {
2576
0
                    return nf_service->client;
2577
0
                }
2578
0
            }
2579
0
        }
2580
0
    }
2581
2582
0
    return NULL;
2583
0
}
2584
2585
ogs_sbi_client_t *ogs_sbi_client_find_by_service(
2586
        ogs_sbi_nf_instance_t *nf_instance,
2587
        OpenAPI_service_name_e service_name)
2588
0
{
2589
0
    ogs_sbi_nf_service_t *nf_service = NULL;
2590
2591
0
    ogs_assert(nf_instance);
2592
0
    ogs_assert(service_name);
2593
2594
0
    ogs_list_for_each(&nf_instance->nf_service_list, nf_service) {
2595
0
        if (nf_service->name == service_name)
2596
0
            return nf_service->client;
2597
0
    }
2598
2599
0
    return NULL;
2600
0
}
2601
2602
void ogs_sbi_object_free(ogs_sbi_object_t *sbi_object)
2603
0
{
2604
0
    int i;
2605
2606
0
    ogs_assert(sbi_object);
2607
2608
0
    if (ogs_list_count(&sbi_object->xact_list)) {
2609
0
        ogs_sbi_xact_t *xact = NULL; \
2610
0
        ogs_error("SBI running [%d]", ogs_list_count(&sbi_object->xact_list));
2611
0
        ogs_list_for_each(&sbi_object->xact_list, xact)
2612
0
            OGS_SBI_XACT_LOG(xact);
2613
0
    }
2614
2615
0
    for (i = 0; i < OGS_SBI_MAX_NUM_OF_SERVICE_NAME; i++) {
2616
0
        if (sbi_object->service_name_array[i].nf_instance_id)
2617
0
            ogs_free(sbi_object->service_name_array[i].nf_instance_id);
2618
0
    }
2619
0
    for (i = 0; i < OGS_SBI_MAX_NUM_OF_NF_TYPE; i++) {
2620
0
        if (sbi_object->nf_type_array[i].nf_instance_id)
2621
0
            ogs_free(sbi_object->nf_type_array[i].nf_instance_id);
2622
0
    }
2623
0
    if (sbi_object->home_nsmf_pdusession.nf_instance_id)
2624
0
        ogs_free(sbi_object->home_nsmf_pdusession.nf_instance_id);
2625
0
}
2626
2627
ogs_sbi_xact_t *ogs_sbi_xact_add(
2628
        ogs_pool_id_t sbi_object_id,
2629
        ogs_sbi_object_t *sbi_object,
2630
        OpenAPI_service_name_e service_name,
2631
        ogs_sbi_discovery_option_t *discovery_option,
2632
        ogs_sbi_build_f build, void *context, void *data)
2633
0
{
2634
0
    ogs_sbi_xact_t *xact = NULL;
2635
2636
0
    ogs_assert(sbi_object);
2637
2638
0
    ogs_pool_id_calloc(&xact_pool, &xact);
2639
0
    if (!xact) {
2640
0
        ogs_error("ogs_pool_id_calloc() failed");
2641
0
        return NULL;
2642
0
    }
2643
2644
0
    xact->sbi_object_id = sbi_object_id;
2645
0
    xact->sbi_object = sbi_object;
2646
0
    xact->service_name = service_name;
2647
0
    xact->requester_nf_type = NF_INSTANCE_TYPE(ogs_sbi_self()->nf_instance);
2648
0
    ogs_assert(xact->requester_nf_type);
2649
2650
    /*
2651
     * Insert one service-name in the discovery option in the function below.
2652
     *
2653
     * - ogs_sbi_xact_add()
2654
     * - ogs_sbi_send_notification_request()
2655
     */
2656
0
    if (!discovery_option) {
2657
0
        discovery_option = ogs_sbi_discovery_option_new();
2658
0
        ogs_assert(discovery_option);
2659
2660
        /* ALWAYS add Service-MAP to requester-features in Discovery Option */
2661
0
        OGS_SBI_FEATURES_SET(discovery_option->requester_features,
2662
0
                OGS_SBI_NNRF_DISC_SERVICE_MAP);
2663
0
    }
2664
2665
0
    if (!discovery_option->num_of_service_names) {
2666
0
        ogs_sbi_discovery_option_add_service_names(
2667
0
                discovery_option, service_name);
2668
0
    }
2669
0
    xact->discovery_option = discovery_option;
2670
2671
0
    xact->t_response = ogs_timer_add(
2672
0
            ogs_app()->timer_mgr, ogs_timer_sbi_client_wait_expire,
2673
0
            OGS_UINT_TO_POINTER(xact->id));
2674
0
    if (!xact->t_response) {
2675
0
        ogs_error("ogs_timer_add() failed");
2676
2677
0
        if (xact->discovery_option)
2678
0
            ogs_sbi_discovery_option_free(xact->discovery_option);
2679
0
        ogs_pool_id_free(&xact_pool, xact);
2680
2681
0
        return NULL;
2682
0
    }
2683
2684
0
    ogs_timer_start(xact->t_response,
2685
0
            ogs_local_conf()->time.message.sbi.client_wait_duration);
2686
2687
0
    if (build) {
2688
0
        xact->request = (*build)(context, data);
2689
0
        if (!xact->request) {
2690
0
            ogs_error("SBI build failed");
2691
2692
0
            if (xact->discovery_option)
2693
0
                ogs_sbi_discovery_option_free(xact->discovery_option);
2694
2695
0
            ogs_timer_delete(xact->t_response);
2696
0
            ogs_pool_id_free(&xact_pool, xact);
2697
2698
0
            return NULL;
2699
0
        }
2700
0
        if (!xact->request->h.uri) {
2701
0
            const char *service_name = NULL;
2702
2703
0
            ogs_assert(xact->service_name);
2704
0
            service_name = OpenAPI_service_name_ToString(xact->service_name);
2705
0
            ogs_assert(service_name);
2706
0
            ogs_assert(xact->request->h.service.name);
2707
2708
            /*
2709
             * Make sure the service matches
2710
             * between discover and build functions:
2711
             *
2712
             * DISCOVER : amf_ue_sbi_discover_and_send(
2713
             *              OGS_SBI_SERVICE_TYPE_NPCF_AM_POLICY_CONTROL,
2714
             * BUILD    : amf_npcf_am_policy_control_build_create()
2715
             *            message.h.service.name =
2716
             *              (char *)OGS_SBI_SERVICE_NAME_NPCF_AM_POLICY_CONTROL;
2717
             */
2718
2719
0
            if (strcmp(service_name, xact->request->h.service.name) != 0) {
2720
0
                ogs_fatal("[%s:%d] is not the same with [%s]",
2721
0
                            service_name, xact->service_name,
2722
0
                            xact->request->h.service.name);
2723
0
                ogs_assert_if_reached();
2724
0
            }
2725
0
        }
2726
0
    }
2727
2728
0
    ogs_list_add(&sbi_object->xact_list, xact);
2729
2730
0
    return xact;
2731
0
}
2732
2733
void ogs_sbi_xact_remove(ogs_sbi_xact_t *xact)
2734
0
{
2735
0
    ogs_sbi_object_t *sbi_object = NULL;
2736
2737
0
    ogs_assert(xact);
2738
2739
0
    sbi_object = xact->sbi_object;
2740
0
    ogs_assert(sbi_object);
2741
2742
0
    if (xact->discovery_option)
2743
0
        ogs_sbi_discovery_option_free(xact->discovery_option);
2744
2745
0
    ogs_assert(xact->t_response);
2746
0
    ogs_timer_delete(xact->t_response);
2747
2748
0
    if (xact->request)
2749
0
        ogs_sbi_request_free(xact->request);
2750
2751
0
    if (xact->target_apiroot)
2752
0
        ogs_free(xact->target_apiroot);
2753
2754
    /*
2755
     * Release optional user context attached to the transaction.
2756
     * The transaction owns this memory and is responsible for
2757
     * freeing it when the transaction is destroyed.
2758
     */
2759
0
    if (xact->user_data) {
2760
0
        if (xact->user_data_free)
2761
0
            xact->user_data_free(xact->user_data);
2762
0
    }
2763
2764
0
    ogs_list_remove(&sbi_object->xact_list, xact);
2765
0
    ogs_pool_id_free(&xact_pool, xact);
2766
0
}
2767
2768
void ogs_sbi_xact_remove_all(ogs_sbi_object_t *sbi_object)
2769
0
{
2770
0
    ogs_sbi_xact_t *xact = NULL, *next_xact = NULL;
2771
2772
0
    ogs_assert(sbi_object);
2773
2774
0
    ogs_list_for_each_safe(&sbi_object->xact_list, next_xact, xact)
2775
0
        ogs_sbi_xact_remove(xact);
2776
0
}
2777
2778
ogs_sbi_xact_t *ogs_sbi_xact_find_by_id(ogs_pool_id_t id)
2779
0
{
2780
0
    return ogs_pool_find_by_id(&xact_pool, id);
2781
0
}
2782
2783
ogs_sbi_subscription_spec_t *ogs_sbi_subscription_spec_add(
2784
        OpenAPI_nf_type_e nf_type, const OpenAPI_service_name_e service_name)
2785
0
{
2786
0
    ogs_sbi_subscription_spec_t *subscription_spec = NULL;
2787
2788
    /* Issue #2630 : The format of subscrCond is invalid. Must be 'oneOf'. */
2789
0
    ogs_assert(!nf_type || !service_name);
2790
2791
0
    ogs_pool_alloc(&subscription_spec_pool, &subscription_spec);
2792
0
    ogs_assert(subscription_spec);
2793
0
    memset(subscription_spec, 0, sizeof(ogs_sbi_subscription_spec_t));
2794
2795
0
    if (nf_type)
2796
0
        subscription_spec->subscr_cond.nf_type = nf_type;
2797
0
    else if (service_name)
2798
0
        subscription_spec->subscr_cond.service_name = service_name;
2799
0
    else {
2800
0
        ogs_fatal("SubscrCond must be 'oneOf'.");
2801
0
        ogs_assert_if_reached();
2802
0
    }
2803
2804
0
    ogs_list_add(&ogs_sbi_self()->subscription_spec_list, subscription_spec);
2805
2806
0
    return subscription_spec;
2807
0
}
2808
2809
void ogs_sbi_subscription_spec_remove(
2810
        ogs_sbi_subscription_spec_t *subscription_spec)
2811
0
{
2812
0
    ogs_assert(subscription_spec);
2813
2814
0
    ogs_list_remove(&ogs_sbi_self()->subscription_spec_list, subscription_spec);
2815
2816
0
    ogs_pool_free(&subscription_spec_pool, subscription_spec);
2817
0
}
2818
2819
void ogs_sbi_subscription_spec_remove_all(void)
2820
0
{
2821
0
    ogs_sbi_subscription_spec_t *subscription_spec = NULL;
2822
0
    ogs_sbi_subscription_spec_t *next_subscription_spec = NULL;
2823
2824
0
    ogs_list_for_each_safe(&ogs_sbi_self()->subscription_spec_list,
2825
0
            next_subscription_spec, subscription_spec)
2826
0
        ogs_sbi_subscription_spec_remove(subscription_spec);
2827
0
}
2828
2829
ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_add(void)
2830
0
{
2831
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
2832
2833
0
    ogs_pool_alloc(&subscription_data_pool, &subscription_data);
2834
0
    if (!subscription_data) {
2835
0
        ogs_error("OVERFLOW subscription_data_pool [pool:%llu]",
2836
0
                (unsigned long long)ogs_app()->pool.subscription);
2837
0
        return NULL;
2838
0
    }
2839
2840
0
    memset(subscription_data, 0, sizeof(ogs_sbi_subscription_data_t));
2841
2842
0
    subscription_data->pool_id = OGS_NEXT_ID(
2843
0
            subscription_data_pool.id, OGS_MIN_POOL_ID, OGS_MAX_POOL_ID);
2844
0
    ogs_hash_set(subscription_data_pool.id_hash,
2845
0
            &subscription_data->pool_id, sizeof(ogs_pool_id_t),
2846
0
            subscription_data);
2847
2848
0
    ogs_list_add(&ogs_sbi_self()->subscription_data_list, subscription_data);
2849
2850
0
    return subscription_data;
2851
0
}
2852
2853
void ogs_sbi_subscription_data_set_resource_uri(
2854
        ogs_sbi_subscription_data_t *subscription_data, char *resource_uri)
2855
0
{
2856
0
    ogs_assert(subscription_data);
2857
0
    ogs_assert(resource_uri);
2858
2859
0
    if (subscription_data->resource_uri)
2860
0
        ogs_free(subscription_data->resource_uri);
2861
0
    subscription_data->resource_uri = ogs_strdup(resource_uri);
2862
0
    ogs_assert(subscription_data->resource_uri);
2863
0
}
2864
2865
void ogs_sbi_subscription_data_set_id(
2866
        ogs_sbi_subscription_data_t *subscription_data, char *id)
2867
0
{
2868
0
    ogs_assert(subscription_data);
2869
0
    ogs_assert(id);
2870
2871
0
    if (subscription_data->id)
2872
0
        ogs_free(subscription_data->id);
2873
0
    subscription_data->id = ogs_strdup(id);
2874
0
    ogs_assert(subscription_data->id);
2875
0
}
2876
2877
void ogs_sbi_subscription_data_remove(
2878
        ogs_sbi_subscription_data_t *subscription_data)
2879
0
{
2880
0
    ogs_assert(subscription_data);
2881
2882
0
    ogs_list_remove(&ogs_sbi_self()->subscription_data_list, subscription_data);
2883
2884
0
    if (subscription_data->id)
2885
0
        ogs_free(subscription_data->id);
2886
2887
0
    if (subscription_data->notification_uri)
2888
0
        ogs_free(subscription_data->notification_uri);
2889
2890
0
    if (subscription_data->resource_uri)
2891
0
        ogs_free(subscription_data->resource_uri);
2892
2893
0
    if (subscription_data->req_nf_instance_id)
2894
0
        ogs_free(subscription_data->req_nf_instance_id);
2895
2896
0
    if (subscription_data->subscr_cond.nf_instance_id)
2897
0
        ogs_free(subscription_data->subscr_cond.nf_instance_id);
2898
2899
0
    if (subscription_data->t_validity)
2900
0
        ogs_timer_delete(subscription_data->t_validity);
2901
2902
0
    if (subscription_data->t_patch)
2903
0
        ogs_timer_delete(subscription_data->t_patch);
2904
2905
0
    if (subscription_data->client)
2906
0
        ogs_sbi_client_remove(subscription_data->client);
2907
2908
0
    ogs_hash_set(subscription_data_pool.id_hash,
2909
0
            &subscription_data->pool_id, sizeof(ogs_pool_id_t), NULL);
2910
0
    ogs_pool_free(&subscription_data_pool, subscription_data);
2911
0
}
2912
2913
void ogs_sbi_subscription_data_remove_all_by_nf_instance_id(
2914
        char *nf_instance_id)
2915
0
{
2916
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
2917
0
    ogs_sbi_subscription_data_t *next_subscription_data = NULL;
2918
2919
0
    ogs_assert(nf_instance_id);
2920
2921
0
    ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list,
2922
0
            next_subscription_data, subscription_data) {
2923
0
        if (subscription_data->req_nf_instance_id &&
2924
0
            strcmp(subscription_data->req_nf_instance_id,
2925
0
                nf_instance_id) == 0) {
2926
0
            ogs_sbi_subscription_data_remove(subscription_data);
2927
0
        }
2928
0
    }
2929
0
}
2930
2931
/*
2932
 * Send DELETE requests to NRF for all subscriptions belonging
2933
 * to the given NF instance before re-registration.
2934
 *
2935
 * This prevents subscription accumulation during repeated
2936
 * re-registration loops (e.g., heartbeat flapping).
2937
 *
2938
 * IMPORTANT:
2939
 * Local subscription_data MUST NOT be removed here.
2940
 * Cleanup is performed asynchronously in the unsubscribe
2941
 * response handler once NRF confirms deletion.
2942
 */
2943
void ogs_sbi_subscription_data_delete_and_remove_all_by_nf_instance_id(
2944
        const char *nf_instance_id)
2945
0
{
2946
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
2947
2948
0
    ogs_assert(nf_instance_id);
2949
2950
0
    ogs_list_for_each(
2951
0
            &ogs_sbi_self()->subscription_data_list, subscription_data) {
2952
2953
0
        if (!subscription_data->id) {
2954
0
            ogs_error("Skip subscription delete: id is NULL");
2955
0
            continue;
2956
0
        }
2957
2958
0
        if (!subscription_data->req_nf_instance_id) {
2959
0
            ogs_error("Skip subscription delete: req_nf_instance_id is NULL");
2960
0
            continue;
2961
0
        }
2962
2963
0
        if (!subscription_data->resource_uri) {
2964
0
            ogs_error("Skip subscription delete: resource_uri is NULL");
2965
0
            continue;
2966
0
        }
2967
2968
0
        if (strcmp(subscription_data->req_nf_instance_id,
2969
0
                   nf_instance_id) != 0) {
2970
0
            ogs_error("Skip subscription delete: nf_instance_id mismatch "
2971
0
                  "[target:%s, current:%s]",
2972
0
                  subscription_data->req_nf_instance_id, nf_instance_id);
2973
0
            continue;
2974
0
        }
2975
2976
        /*
2977
         * Prevent duplicate DELETE transmissions.
2978
         * (Simple guard using existing state field or flag placeholder)
2979
         */
2980
0
        if (subscription_data->flags & OGS_SBI_SUBSCRIPTION_DELETE_SENT) {
2981
0
            ogs_debug("[%s] Skip subscription delete: DELETE already sent",
2982
0
                    subscription_data->id);
2983
0
            continue;
2984
0
        }
2985
2986
0
        subscription_data->flags |= OGS_SBI_SUBSCRIPTION_DELETE_SENT;
2987
2988
        /*
2989
         * If we have a subscription resource identifier,
2990
         * send DELETE to NRF to cleanup remote subscription state.
2991
         *
2992
         * Typical resource:
2993
         *   /nnrf-nfm/v1/subscriptions/{subscriptionId}
2994
         */
2995
0
        ogs_info("[%s] Sending NRF subscription DELETE before "
2996
0
                "NF re-registration", subscription_data->id);
2997
2998
2999
        /* Build DELETE request */
3000
0
        ogs_nnrf_nfm_send_nf_status_unsubscribe(subscription_data);
3001
3002
        /*
3003
         * NOTE:
3004
         * Do NOT remove subscription_data here.
3005
         *
3006
         * Local cleanup is performed in the unsubscribe
3007
         * response handler once NRF confirms deletion.
3008
         *
3009
         * Removing here could lead to:
3010
         *   - Use-after-free
3011
         *   - Double free
3012
         *   - Dangling transaction context
3013
         */
3014
0
    }
3015
0
}
3016
3017
void ogs_sbi_subscription_data_remove_all(void)
3018
0
{
3019
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
3020
0
    ogs_sbi_subscription_data_t *next_subscription_data = NULL;
3021
3022
0
    ogs_list_for_each_safe(&ogs_sbi_self()->subscription_data_list,
3023
0
            next_subscription_data, subscription_data)
3024
0
        ogs_sbi_subscription_data_remove(subscription_data);
3025
0
}
3026
3027
ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_find(char *id)
3028
0
{
3029
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
3030
3031
0
    ogs_assert(id);
3032
3033
0
    ogs_list_for_each(&ogs_sbi_self()->subscription_data_list,
3034
0
            subscription_data) {
3035
0
        ogs_assert(subscription_data->id);
3036
0
        if (strcmp(subscription_data->id, id) == 0)
3037
0
            break;
3038
0
    }
3039
3040
0
    return subscription_data;
3041
0
}
3042
3043
ogs_sbi_subscription_data_t *ogs_sbi_subscription_data_find_by_pool_id(
3044
        ogs_pool_id_t id)
3045
0
{
3046
0
    return ogs_pool_find_by_id(&subscription_data_pool, id);
3047
0
}
3048
3049
bool ogs_sbi_nf_status_subscription_exists(
3050
        const char *req_nf_instance_id,
3051
        OpenAPI_nf_type_e nf_type,
3052
        OpenAPI_service_name_e service_name,
3053
        bool confirmed_only)
3054
0
{
3055
0
    ogs_sbi_subscription_data_t *subscription_data = NULL;
3056
0
    bool nf_type_present = (nf_type != OpenAPI_nf_type_NULL);
3057
0
    bool service_name_present = (service_name != OpenAPI_service_name_NULL);
3058
3059
0
    ogs_assert(req_nf_instance_id);
3060
3061
0
    ogs_list_for_each(
3062
0
            &ogs_sbi_self()->subscription_data_list, subscription_data) {
3063
0
        if (!subscription_data->req_nf_instance_id)
3064
0
            continue;
3065
3066
0
        if (strcmp(subscription_data->req_nf_instance_id,
3067
0
                    req_nf_instance_id) != 0)
3068
0
            continue;
3069
3070
0
        if (subscription_data->flags & OGS_SBI_SUBSCRIPTION_DELETE_SENT)
3071
0
            continue;
3072
3073
        /*
3074
         * confirmed_only: count a subscription only after the NRF has accepted
3075
         * it, i.e. SubscriptionId and resource URI have been assigned from the
3076
         * 201 Created response. A locally pending request is not yet a valid
3077
         * notification context.
3078
         */
3079
0
        if (confirmed_only &&
3080
0
                (!subscription_data->id || !subscription_data->resource_uri))
3081
0
            continue;
3082
3083
0
        if (nf_type_present &&
3084
0
            subscription_data->subscr_cond.nf_type != OpenAPI_nf_type_NULL &&
3085
0
            subscription_data->subscr_cond.nf_type == nf_type)
3086
0
            return true;
3087
3088
0
        if (service_name_present &&
3089
0
            subscription_data->subscr_cond.service_name !=
3090
0
                OpenAPI_service_name_NULL &&
3091
0
            subscription_data->subscr_cond.service_name == service_name)
3092
0
            return true;
3093
0
    }
3094
3095
0
    return false;
3096
0
}
3097
3098
bool ogs_sbi_supi_in_vplmn(char *supi)
3099
0
{
3100
0
    char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1];
3101
0
    bool home_network = false;
3102
0
    int i;
3103
3104
0
    ogs_assert(supi);
3105
3106
0
    if (ogs_local_conf()->num_of_serving_plmn_id == 0) {
3107
0
        return false;
3108
0
    }
3109
3110
0
    ogs_extract_digit_from_string(imsi_bcd, supi);
3111
3112
0
    for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) {
3113
0
        char buf[OGS_PLMNIDSTRLEN];
3114
0
        ogs_plmn_id_to_string(&ogs_local_conf()->serving_plmn_id[i], buf);
3115
3116
0
        if (strncmp(imsi_bcd, buf, strlen(buf)) == 0) {
3117
0
            home_network = true;
3118
0
            break;
3119
0
        }
3120
0
    }
3121
3122
0
    if (home_network == false)
3123
0
        return true;
3124
3125
0
    return false;
3126
0
}
3127
3128
bool ogs_sbi_plmn_id_in_vplmn(ogs_plmn_id_t *plmn_id)
3129
0
{
3130
0
    bool home_network = false;
3131
0
    int i;
3132
3133
0
    ogs_assert(plmn_id);
3134
3135
0
    if (ogs_local_conf()->num_of_serving_plmn_id == 0) {
3136
0
        return false;
3137
0
    }
3138
3139
0
    if (ogs_plmn_id_mcc(plmn_id) == 0) {
3140
0
        ogs_error("No MCC");
3141
0
        return false;
3142
0
    }
3143
3144
0
    if (ogs_plmn_id_mnc(plmn_id) == 0) {
3145
0
        ogs_error("No MNC");
3146
0
        return false;
3147
0
    }
3148
3149
0
    for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) {
3150
0
        if (memcmp(&ogs_local_conf()->serving_plmn_id[i],
3151
0
                    plmn_id, OGS_PLMN_ID_LEN) == 0) {
3152
0
            home_network = true;
3153
0
            break;
3154
0
        }
3155
0
    }
3156
3157
0
    if (home_network == false)
3158
0
        return true;
3159
3160
0
    return false;
3161
0
}
3162
3163
bool ogs_sbi_fqdn_in_vplmn(char *fqdn)
3164
0
{
3165
0
    bool home_network = false;
3166
0
    int i;
3167
3168
0
    ogs_assert(fqdn);
3169
3170
0
    if (ogs_local_conf()->num_of_serving_plmn_id == 0) {
3171
0
        return false;
3172
0
    }
3173
3174
0
    if (ogs_dnn_oi_from_fqdn(fqdn) == NULL) {
3175
0
        return false;
3176
0
    }
3177
3178
0
    for (i = 0; i < ogs_local_conf()->num_of_serving_plmn_id; i++) {
3179
0
        if (ogs_plmn_id_mcc_from_fqdn(fqdn) ==
3180
0
            ogs_plmn_id_mcc(&ogs_local_conf()->serving_plmn_id[i]) &&
3181
0
            ogs_plmn_id_mnc_from_fqdn(fqdn) ==
3182
0
            ogs_plmn_id_mnc(&ogs_local_conf()->serving_plmn_id[i])) {
3183
0
            home_network = true;
3184
0
            break;
3185
0
        }
3186
0
    }
3187
3188
0
    if (home_network == false)
3189
0
        return true;
3190
3191
0
    return false;
3192
0
}
3193
3194
/* OpenSSL Key Log Callback */
3195
void ogs_sbi_keylog_callback(const SSL *ssl, const char *line)
3196
0
{
3197
0
    SSL_CTX *ctx = NULL;
3198
0
    FILE *file = NULL;
3199
0
    const char *sslkeylog_file = NULL;
3200
3201
0
    ogs_assert(ssl);
3202
0
    ogs_assert(line);
3203
3204
    /* Retrieve SSL_CTX from SSL object */
3205
0
    ctx = SSL_get_SSL_CTX(ssl);
3206
0
    ogs_assert(ctx);
3207
3208
0
    sslkeylog_file = (const char *)SSL_CTX_get_app_data(ctx);
3209
0
    ogs_assert(sslkeylog_file);
3210
3211
0
    file = fopen(sslkeylog_file, "a");
3212
0
    if (file) {
3213
0
        fprintf(file, "%s\n", line);
3214
0
        fclose(file);
3215
0
    } else {
3216
0
        ogs_error("Failed to open SSL key log file: %s", sslkeylog_file);
3217
0
    }
3218
0
}