Coverage Report

Created: 2026-11-06 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/sbi/conv.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019-2023 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
#include "yuarel.h"
22
23
static int parse_scheme_output(
24
        char *_protection_scheme_id, char *_scheme_output,
25
        ogs_datum_t *ecckey, ogs_datum_t *cipher_text, uint8_t *mactag)
26
0
{
27
0
    uint8_t protection_scheme_id;
28
0
    size_t scheme_output_size;
29
0
    uint8_t *scheme_output = NULL;
30
0
    uint8_t *p = NULL;
31
32
0
    ogs_assert(_protection_scheme_id);
33
0
    ogs_assert(_scheme_output);
34
0
    ogs_assert(ecckey);
35
0
    ogs_assert(mactag);
36
0
    ogs_assert(cipher_text);
37
38
0
    protection_scheme_id = atoi(_protection_scheme_id);
39
0
    if (protection_scheme_id == OGS_PROTECTION_SCHEME_PROFILE_A) {
40
0
        ecckey->size = OGS_ECCKEY_LEN;
41
0
    } else if (protection_scheme_id == OGS_PROTECTION_SCHEME_PROFILE_B) {
42
0
        ecckey->size = OGS_ECCKEY_LEN+1;
43
0
    } else {
44
0
        ogs_fatal("Invalid protection scheme id [%s]", _protection_scheme_id);
45
0
        ogs_assert_if_reached();
46
47
0
        return OGS_ERROR;
48
0
    }
49
50
0
    cipher_text->size = OGS_MSIN_LEN;
51
52
0
    scheme_output_size = strlen(_scheme_output)/2;
53
0
    if (scheme_output_size <
54
0
            ecckey->size + cipher_text->size + OGS_MACTAG_LEN) {
55
0
        ogs_error("Not enough length [%zu]", strlen(_scheme_output));
56
0
        return OGS_ERROR;
57
0
    }
58
59
0
    scheme_output = ogs_calloc(1, scheme_output_size);
60
0
    ogs_assert(scheme_output);
61
62
0
    ogs_ascii_to_hex(_scheme_output, strlen(_scheme_output),
63
0
            scheme_output, scheme_output_size);
64
65
0
    p = scheme_output;
66
0
    ecckey->data = ogs_memdup(p, ecckey->size);
67
0
    ogs_assert(ecckey->data);
68
69
0
    p += ecckey->size;
70
0
    cipher_text->data = ogs_memdup(p, cipher_text->size);
71
0
    ogs_assert(cipher_text->data);
72
73
0
    p += cipher_text->size;
74
0
    memcpy(mactag, p, OGS_MACTAG_LEN);
75
76
0
    ogs_free(scheme_output);
77
78
0
    return OGS_OK;
79
0
}
80
81
char *ogs_supi_from_suci(const char *suci)
82
0
{
83
0
#define MAX_SUCI_TOKEN 16
84
0
    char *array[MAX_SUCI_TOKEN];
85
0
    char *p, *tmp;
86
0
    int i;
87
0
    char *supi = NULL;
88
89
0
    ogs_assert(suci);
90
0
    tmp = ogs_strdup(suci);
91
0
    if (!tmp) {
92
0
        ogs_error("ogs_strdup() failed");
93
0
        return NULL;
94
0
    }
95
96
    /* Clang scan-build SA: Branch condition evaluates to a garbage value: If array "array" is not fully populated
97
     * in the while loop below then later access in the following switch-case may check uninitialized values.
98
     * Initialize "array" to NULL pointers to fix the issue. */
99
0
    for (i = 0; i < MAX_SUCI_TOKEN; i++) {
100
0
        array[i] = NULL;
101
0
    }
102
103
0
    p = tmp;
104
0
    i = 0;
105
0
    while((i < MAX_SUCI_TOKEN) && (array[i++] = strsep(&p, "-"))) {
106
        /* Empty Body */
107
0
    }
108
109
0
    SWITCH(array[0])
110
0
    CASE("suci")
111
0
        SWITCH(array[1])
112
0
        CASE("0")   /* SUPI format : IMSI */
113
0
            if (array[2] && array[3] && array[5] && array[6] && array[7]) {
114
0
                uint8_t protection_scheme_id = atoi(array[5]);
115
0
                uint8_t home_network_pki_value = atoi(array[6]);
116
117
0
                if (protection_scheme_id == OGS_PROTECTION_SCHEME_NULL) {
118
0
                    supi = ogs_msprintf("imsi-%s%s%s",
119
0
                            array[2], array[3], array[7]);
120
0
                } else if (protection_scheme_id ==
121
0
                            OGS_PROTECTION_SCHEME_PROFILE_A ||
122
0
                        protection_scheme_id ==
123
0
                            OGS_PROTECTION_SCHEME_PROFILE_B) {
124
125
0
                    ogs_datum_t pubkey;
126
0
                    ogs_datum_t cipher_text;
127
0
                    ogs_datum_t plain_text;
128
0
                    char *plain_bcd;
129
0
                    uint8_t mactag1[OGS_MACTAG_LEN], mactag2[OGS_MACTAG_LEN];
130
131
0
                    uint8_t z[OGS_ECCKEY_LEN];
132
133
0
                    uint8_t ek[OGS_KEY_LEN];
134
0
                    uint8_t icb[OGS_IVEC_LEN];
135
0
                    uint8_t mk[OGS_SHA256_DIGEST_SIZE];
136
137
0
                    if (home_network_pki_value <
138
0
                            OGS_HOME_NETWORK_PKI_VALUE_MIN ||
139
0
                        home_network_pki_value >
140
0
                            OGS_HOME_NETWORK_PKI_VALUE_MAX) {
141
0
                        ogs_error("Invalid HNET PKI Value [%s]", array[6]);
142
0
                        break;
143
0
                    }
144
145
0
                    if (!ogs_sbi_self()->hnet[home_network_pki_value].avail) {
146
0
                        ogs_error("HNET PKI Value Not Avaiable [%s]", array[6]);
147
0
                        break;
148
0
                    }
149
150
0
                    if (ogs_sbi_self()->hnet[home_network_pki_value].scheme
151
0
                            != protection_scheme_id) {
152
0
                        ogs_error("Scheme Not Matched [%d != %d]",
153
0
                            ogs_sbi_self()->hnet[home_network_pki_value].scheme,
154
0
                            protection_scheme_id);
155
0
                        break;
156
0
                    }
157
158
0
                    if (parse_scheme_output(
159
0
                            array[5], array[7],
160
0
                            &pubkey, &cipher_text, mactag1) != OGS_OK) {
161
0
                        ogs_error("parse_scheme_output[%s] failed", array[7]);
162
0
                        break;
163
0
                    }
164
165
0
                    if (protection_scheme_id ==
166
0
                            OGS_PROTECTION_SCHEME_PROFILE_A) {
167
0
                        curve25519_donna(z,
168
0
                            ogs_sbi_self()->hnet[home_network_pki_value].key,
169
0
                            pubkey.data);
170
0
                    } else if (protection_scheme_id ==
171
0
                            OGS_PROTECTION_SCHEME_PROFILE_B) {
172
0
                        if (ecdh_shared_secret(
173
0
                                pubkey.data,
174
0
                                ogs_sbi_self()->
175
0
                                    hnet[home_network_pki_value].key,
176
0
                                z) != 1) {
177
0
                            ogs_error("ecdh_shared_secret() failed");
178
0
                            ogs_log_hexdump(OGS_LOG_ERROR,
179
0
                                    pubkey.data, OGS_ECCKEY_LEN);
180
0
                            ogs_log_hexdump(OGS_LOG_ERROR,
181
0
                                ogs_sbi_self()->
182
0
                                    hnet[home_network_pki_value].key,
183
0
                                    OGS_ECCKEY_LEN);
184
0
                            goto cleanup;
185
0
                        }
186
0
                    } else
187
0
                        ogs_assert_if_reached();
188
189
0
                    ogs_kdf_ansi_x963(
190
0
                        z, OGS_ECCKEY_LEN, pubkey.data, pubkey.size,
191
0
                        ek, icb, mk);
192
193
0
                    ogs_hmac_sha256(
194
0
                            mk, OGS_SHA256_DIGEST_SIZE,
195
0
                            cipher_text.data, cipher_text.size,
196
0
                            mactag2, OGS_MACTAG_LEN);
197
198
0
                    if (memcmp(mactag1, mactag2, OGS_MACTAG_LEN) != 0) {
199
0
                        ogs_error("MAC-tag not matched");
200
0
                        ogs_log_hexdump(OGS_LOG_ERROR, mactag1, OGS_MACTAG_LEN);
201
0
                        ogs_log_hexdump(OGS_LOG_ERROR, mactag2, OGS_MACTAG_LEN);
202
0
                        goto cleanup;
203
0
                    }
204
205
0
                    plain_text.size = cipher_text.size;
206
0
                    plain_text.data = ogs_calloc(1, plain_text.size);
207
0
                    ogs_assert(plain_text.data);
208
209
0
                    ogs_aes_ctr128_encrypt(
210
0
                            ek, icb, cipher_text.data, cipher_text.size,
211
0
                            plain_text.data);
212
213
0
                    plain_bcd = ogs_calloc(1, plain_text.size*2+1);
214
0
                    ogs_assert(plain_bcd);
215
216
0
                    ogs_buffer_to_bcd(plain_text.data, plain_text.size,
217
0
                        plain_bcd, plain_text.size*2+1);
218
219
0
                    supi = ogs_msprintf("imsi-%s%s%s",
220
0
                            array[2], array[3], plain_bcd);
221
0
                    ogs_assert(supi);
222
223
0
                    if (plain_text.data)
224
0
                        ogs_free(plain_text.data);
225
0
                    ogs_free(plain_bcd);
226
0
cleanup:
227
0
                    if (pubkey.data)
228
0
                        ogs_free(pubkey.data);
229
0
                    if (cipher_text.data)
230
0
                        ogs_free(cipher_text.data);
231
0
                } else {
232
0
                    ogs_error("Invalid Protection Scheme [%s]", array[5]);
233
0
                }
234
0
            }
235
0
            break;
236
0
        DEFAULT
237
0
            ogs_error("Not implemented [%s]", array[1]);
238
0
            break;
239
0
        END
240
0
        break;
241
0
    DEFAULT
242
0
        ogs_error("Not implemented [%s]", array[0]);
243
0
        break;
244
0
    END
245
246
0
    ogs_free(tmp);
247
0
    return supi;
248
0
}
249
250
char *ogs_supi_from_supi_or_suci(const char *supi_or_suci)
251
0
{
252
0
    char *type = NULL;
253
0
    char *supi = NULL;
254
255
0
    ogs_assert(supi_or_suci);
256
0
    type = ogs_id_get_type(supi_or_suci);
257
0
    if (!type) {
258
0
        ogs_error("ogs_id_get_type[%s] failed", supi_or_suci);
259
0
        goto cleanup;
260
0
    }
261
0
    SWITCH(type)
262
0
    CASE("imsi")
263
0
        supi = ogs_strdup(supi_or_suci);
264
0
        ogs_expect(supi);
265
0
        break;
266
0
    CASE("suci")
267
0
        supi = ogs_supi_from_suci(supi_or_suci);
268
0
        ogs_expect(supi);
269
0
        break;
270
0
    DEFAULT
271
0
        ogs_error("Not implemented [%s]", type);
272
0
        break;
273
0
    END
274
275
0
cleanup:
276
0
    if (type)
277
0
        ogs_free(type);
278
0
    return supi;
279
0
}
280
281
char *ogs_uridup(
282
        OpenAPI_uri_scheme_e scheme,
283
        const char *fqdn,
284
        const ogs_sockaddr_t *addr,
285
        const ogs_sockaddr_t *addr6,
286
        uint16_t port,
287
        const ogs_sbi_header_t *h)
288
0
{
289
0
    char buf[OGS_ADDRSTRLEN];
290
0
    char uri[OGS_HUGE_LEN];
291
0
    char *p, *last;
292
0
    int i;
293
294
0
    ogs_assert(scheme);
295
0
    ogs_assert(fqdn || addr || addr6);
296
297
0
    p = uri;
298
0
    last = uri + OGS_HUGE_LEN;
299
300
    /* HTTP scheme is selected based on TLS information */
301
0
    if (scheme == OpenAPI_uri_scheme_https)
302
0
        p = ogs_slprintf(p, last, "https://");
303
0
    else if (scheme == OpenAPI_uri_scheme_http)
304
0
        p = ogs_slprintf(p, last, "http://");
305
0
    else {
306
0
        ogs_fatal("Invalid scheme [%d]", scheme);
307
0
        ogs_assert_if_reached();
308
0
    }
309
310
    /* Hostname/IP address */
311
0
    if (fqdn)
312
0
        p = ogs_slprintf(p, last, "%s", fqdn);
313
0
    else if (addr6) {
314
0
        p = ogs_slprintf(p, last, "[%s]", OGS_ADDR(addr6, buf));
315
0
    } else if (addr) {
316
0
        p = ogs_slprintf(p, last, "%s", OGS_ADDR(addr, buf));
317
0
    } else
318
0
        ogs_assert_if_reached();
319
320
    /* Port number */
321
0
    if (port)
322
0
        p = ogs_slprintf(p, last, ":%d", port);
323
324
    /* API */
325
0
    if (h) {
326
0
        ogs_assert(h->service.name);
327
0
        p = ogs_slprintf(p, last, "/%s", h->service.name);
328
0
        ogs_assert(h->api.version);
329
0
        p = ogs_slprintf(p, last, "/%s", h->api.version);
330
331
        /* Resource */
332
0
        ogs_assert(h->resource.component[0]);
333
0
        for (i = 0; i < OGS_SBI_MAX_NUM_OF_RESOURCE_COMPONENT &&
334
0
                            h->resource.component[i]; i++)
335
0
            p = ogs_slprintf(p, last, "/%s", h->resource.component[i]);
336
0
    }
337
338
0
    return ogs_strdup(uri);
339
0
}
340
341
char *ogs_sbi_server_uri(
342
        const ogs_sbi_server_t *server,
343
        const ogs_sbi_header_t *h)
344
0
{
345
0
    ogs_sockaddr_t *advertise = NULL;
346
347
0
    ogs_assert(server);
348
349
0
    advertise = server->advertise;
350
0
    if (!advertise)
351
0
        advertise = server->node.addr;
352
0
    ogs_assert(advertise);
353
354
0
    return ogs_sbi_sockaddr_uri(server->scheme, advertise, h);
355
0
}
356
357
uint16_t ogs_sbi_uri_port_from_scheme_and_addr(
358
        OpenAPI_uri_scheme_e scheme,
359
        const ogs_sockaddr_t *addr)
360
0
{
361
0
    uint16_t port = 0;
362
363
0
    ogs_assert(scheme);
364
0
    ogs_assert(addr);
365
366
0
    if (scheme == OpenAPI_uri_scheme_https &&
367
0
        OGS_PORT(addr) == OGS_SBI_HTTPS_PORT) {
368
        /* No Port in URI */
369
0
    } else if (scheme == OpenAPI_uri_scheme_http &&
370
0
        OGS_PORT(addr) == OGS_SBI_HTTP_PORT) {
371
        /* No Port in URI */
372
0
    } else {
373
0
        port = OGS_PORT(addr);
374
0
    }
375
376
0
    return port;
377
0
}
378
379
char *ogs_sbi_sockaddr_uri(
380
        OpenAPI_uri_scheme_e scheme,
381
        const ogs_sockaddr_t *sa_list,
382
        const ogs_sbi_header_t *h)
383
0
{
384
0
    int rv;
385
0
    char *hostname = NULL;
386
0
    ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
387
0
    uint16_t port = 0;
388
0
    char *uri = NULL;
389
390
0
    ogs_assert(scheme);
391
0
    ogs_assert(sa_list);
392
393
0
    hostname = ogs_gethostname(sa_list);
394
395
0
    rv = ogs_copyaddrinfo(&addr, sa_list);
396
0
    ogs_assert(rv == OGS_OK);
397
0
    rv = ogs_copyaddrinfo(&addr6, addr);
398
0
    ogs_assert(rv == OGS_OK);
399
400
0
    rv = ogs_filteraddrinfo(&addr, AF_INET);
401
0
    ogs_assert(rv == OGS_OK);
402
0
    rv = ogs_filteraddrinfo(&addr6, AF_INET6);
403
0
    ogs_assert(rv == OGS_OK);
404
405
0
    if (addr6)
406
0
        port = ogs_sbi_uri_port_from_scheme_and_addr(scheme, addr6);
407
0
    else if (addr)
408
0
        port = ogs_sbi_uri_port_from_scheme_and_addr(scheme, addr);
409
410
0
    uri = ogs_uridup(scheme, hostname, addr, addr6, port, h);
411
412
0
    ogs_freeaddrinfo(addr);
413
0
    ogs_freeaddrinfo(addr6);
414
415
0
    return uri;
416
0
}
417
418
char *ogs_sbi_client_uri(
419
        const ogs_sbi_client_t *client,
420
        const ogs_sbi_header_t *h)
421
0
{
422
0
    uint16_t port = 0;
423
424
0
    ogs_assert(client);
425
426
0
    if (client->fqdn) {
427
0
        port = client->fqdn_port;
428
0
    } else {
429
0
        if (client->addr6) {
430
0
            port = ogs_sbi_uri_port_from_scheme_and_addr(
431
0
                    client->scheme, client->addr6);
432
0
        } else if (client->addr) {
433
0
            port = ogs_sbi_uri_port_from_scheme_and_addr(
434
0
                    client->scheme, client->addr);
435
0
        }
436
0
    }
437
438
0
    return ogs_uridup(
439
0
            client->scheme, client->fqdn, client->addr, client->addr6, port, h);
440
0
}
441
442
char *ogs_sbi_client_apiroot(const ogs_sbi_client_t *client)
443
0
{
444
0
    return ogs_sbi_client_uri(client, NULL);
445
0
}
446
447
/**
448
 * Returns a url-decoded version of str
449
 * IMPORTANT: be sure to free() the returned string after use
450
 * Thanks Geek Hideout!
451
 * http://www.geekhideout.com/urlcode.shtml
452
 */
453
char *ogs_sbi_url_encode(const char *str)
454
0
{
455
0
    if (str != NULL) {
456
0
        char *pstr = (char *)str;
457
0
        char *buf = ogs_malloc(strlen(str) * 3 + 1);
458
0
        char *pbuf = buf;
459
0
        ogs_assert(buf);
460
0
        while (*pstr) {
461
462
0
            if (*pstr == '"' ||
463
0
                *pstr == '(' ||
464
0
                *pstr == ')' ||
465
0
                *pstr == ',' ||
466
0
                *pstr == '/' ||
467
0
                *pstr == ':' ||
468
0
                *pstr == ';' ||
469
0
                *pstr == '<' ||
470
0
                *pstr == '=' ||
471
0
                *pstr == '>' ||
472
0
                *pstr == '?' ||
473
0
                *pstr == '@' ||
474
0
                *pstr == '[' ||
475
0
                *pstr == '\\' ||
476
0
                *pstr == ']' ||
477
0
                *pstr == '{' ||
478
0
                *pstr == '}') {
479
0
                *pbuf++ = '%';
480
0
                *pbuf++ = ogs_to_hex(*pstr >> 4);
481
0
                *pbuf++ = ogs_to_hex(*pstr & 15);
482
0
            } else
483
0
                *pbuf++ = *pstr;
484
485
0
            pstr++;
486
0
        }
487
0
        *pbuf = '\0';
488
0
        return buf;
489
0
    } else {
490
0
        return NULL;
491
0
    }
492
0
}
493
494
char *ogs_sbi_url_decode(const char *str)
495
302k
{
496
302k
    if (str != NULL) {
497
230k
        char *pstr = (char *)str;
498
230k
        char *buf = ogs_malloc(strlen(str) + 1);
499
230k
        char *pbuf = buf;
500
230k
        ogs_assert(buf);
501
2.79M
        while (*pstr) {
502
2.56M
            if (*pstr == '%') {
503
5.91k
                if (isxdigit((unsigned char)pstr[1]) &&
504
5.91k
                        isxdigit((unsigned char)pstr[2])) {
505
4.14k
                    *pbuf++ = ogs_from_hex(pstr[1]) << 4 |
506
4.14k
                                ogs_from_hex(pstr[2]);
507
4.14k
                    pstr += 2;
508
4.14k
                }
509
2.56M
            } else if (*pstr == '+') {
510
482
                *pbuf++ = ' ';
511
2.56M
            } else {
512
2.56M
                *pbuf++ = * pstr;
513
2.56M
            }
514
2.56M
            pstr++;
515
2.56M
        }
516
230k
        *pbuf = '\0';
517
230k
        return buf;
518
230k
    } else {
519
71.1k
        return NULL;
520
71.1k
    }
521
302k
}
522
523
char *ogs_sbi_parse_uri(char *uri, const char *delim, char **saveptr)
524
301k
{
525
301k
    char *item = NULL;
526
527
301k
    item = ogs_sbi_url_decode(ogs_strtok_r(uri, delim, saveptr));
528
301k
    if (!item) {
529
71.1k
        return NULL;
530
71.1k
    }
531
532
230k
    return item;
533
301k
}
534
535
bool ogs_sbi_getaddr_from_uri(
536
        OpenAPI_uri_scheme_e *scheme,
537
        char **fqdn, uint16_t *fqdn_port,
538
        ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6,
539
        char *uri)
540
0
{
541
0
    int rv;
542
0
    ogs_sockaddr_t tmp;
543
0
    struct yuarel yuarel;
544
0
    char *p = NULL;
545
0
    int port = 0;
546
547
0
    ogs_assert(fqdn);
548
0
    ogs_assert(fqdn_port);
549
0
    ogs_assert(addr);
550
0
    ogs_assert(addr6);
551
0
    ogs_assert(uri);
552
553
0
    p = ogs_strdup(uri);
554
555
0
    rv = yuarel_parse(&yuarel, p);
556
0
    if (rv != OGS_OK) {
557
0
        ogs_free(p);
558
0
        ogs_error("yuarel_parse() failed [%s]", uri);
559
0
        return false;
560
0
    }
561
562
0
    if (!yuarel.scheme) {
563
0
        ogs_error("No http.scheme found [%s]", uri);
564
0
        ogs_free(p);
565
0
        return false;
566
0
    }
567
568
0
    if (strcmp(yuarel.scheme, "https") == 0) {
569
0
        *scheme = OpenAPI_uri_scheme_https;
570
0
    } else if (strcmp(yuarel.scheme, "http") == 0) {
571
0
        *scheme = OpenAPI_uri_scheme_http;
572
0
    } else {
573
0
        ogs_error("Invalid http.scheme [%s:%s]", yuarel.scheme, uri);
574
0
        ogs_free(p);
575
0
        return false;
576
0
    }
577
578
0
    if (!yuarel.host) {
579
0
        ogs_error("No http.host found [%s]", uri);
580
0
        ogs_free(p);
581
0
        return false;
582
0
    }
583
584
0
    if (yuarel.port) port = yuarel.port;
585
586
0
    if (ogs_inet_pton(AF_INET, yuarel.host, &tmp) == OGS_OK ||
587
0
        ogs_inet_pton(AF_INET6, yuarel.host, &tmp) == OGS_OK) {
588
589
0
        *fqdn = NULL;
590
0
        *fqdn_port = 0;
591
592
0
        rv = ogs_getaddrinfo(addr, AF_UNSPEC, yuarel.host, port, 0);
593
0
        if (rv != OGS_OK) {
594
0
            ogs_error("ogs_getaddrinfo() failed [%s]", uri);
595
0
            ogs_free(p);
596
0
            return false;
597
0
        }
598
599
0
        rv = ogs_copyaddrinfo(addr6, *addr);
600
0
        ogs_assert(rv == OGS_OK);
601
602
0
        rv = ogs_filteraddrinfo(addr, AF_INET);
603
0
        ogs_assert(rv == OGS_OK);
604
0
        rv = ogs_filteraddrinfo(addr6, AF_INET6);
605
0
        ogs_assert(rv == OGS_OK);
606
607
0
    } else {
608
609
0
        *addr = NULL;
610
0
        *addr6 = NULL;
611
612
0
        *fqdn = ogs_strdup(yuarel.host);
613
0
        ogs_assert(*fqdn);
614
0
        *fqdn_port = port;
615
616
0
    }
617
618
0
    ogs_free(p);
619
0
    return true;
620
0
}
621
622
bool ogs_sbi_getpath_from_uri(char **path, const char *uri)
623
0
{
624
0
    int rv;
625
0
    struct yuarel yuarel;
626
0
    char *p = NULL;
627
628
0
    ogs_assert(uri);
629
630
0
    p = ogs_strdup(uri);
631
632
0
    rv = yuarel_parse(&yuarel, p);
633
0
    if (rv != OGS_OK) {
634
0
        ogs_error("yuarel_parse() failed [%s]", uri);
635
0
        ogs_free(p);
636
0
        return false;
637
0
    }
638
639
0
    if (!yuarel.scheme) {
640
0
        ogs_error("No http.scheme found [%s]", uri);
641
0
        ogs_free(p);
642
0
        return false;
643
0
    }
644
645
0
    if (strcmp(yuarel.scheme, "https") == 0) {
646
647
0
    } else if (strcmp(yuarel.scheme, "http") == 0) {
648
649
0
    } else {
650
0
        ogs_error("Invalid http.scheme [%s:%s]", yuarel.scheme, uri);
651
0
        ogs_free(p);
652
0
        return false;
653
0
    }
654
655
0
    if (!yuarel.host) {
656
0
        ogs_error("No http.host found [%s]", uri);
657
0
        ogs_free(p);
658
0
        return false;
659
0
    }
660
661
0
    if (!yuarel.path) {
662
0
        ogs_error("No http.path found [%s]", uri);
663
0
        ogs_free(p);
664
0
        return false;
665
0
    }
666
667
0
    *path = ogs_strdup(yuarel.path);
668
0
    ogs_assert(*path);
669
670
0
    ogs_free(p);
671
0
    return true;
672
0
}
673
674
char *ogs_sbi_client_resolve(
675
        OpenAPI_uri_scheme_e scheme,
676
        char *fqdn, uint16_t fqdn_port,
677
        const char **resolve, int num_of_resolve)
678
0
{
679
0
    int i;
680
0
    uint16_t port;
681
0
    char *result = NULL;
682
683
0
    ogs_assert(scheme);
684
0
    ogs_assert(fqdn);
685
0
    ogs_assert(resolve);
686
0
    ogs_assert(resolve[0]);
687
0
    ogs_assert(num_of_resolve);
688
689
0
    port = fqdn_port;
690
0
    if (!port) {
691
0
        if (scheme == OpenAPI_uri_scheme_https)
692
0
            port = OGS_SBI_HTTPS_PORT;
693
0
        else if (scheme == OpenAPI_uri_scheme_http)
694
0
            port = OGS_SBI_HTTP_PORT;
695
0
        else
696
0
            ogs_assert_if_reached();
697
0
    }
698
699
0
    result = ogs_msprintf("%s:%d:%s", fqdn, port, resolve[0]);
700
0
    if (!result) {
701
0
        ogs_error("ogs_msprintf() failed");
702
0
        return NULL;
703
0
    }
704
705
0
    for (i = 1; i < num_of_resolve; i++) {
706
0
        ogs_assert(resolve[i]);
707
0
        result = ogs_mstrcatf(result, ",%s", resolve[i]);
708
0
        if (!result) {
709
0
            ogs_error("ogs_mstrcatf() failed");
710
0
            ogs_free(result);
711
0
            return NULL;
712
0
        }
713
0
    }
714
715
0
    return result;
716
0
}
717
718
char *ogs_sbi_bitrate_to_string(uint64_t bitrate, int unit)
719
0
{
720
0
    if (unit == OGS_SBI_BITRATE_KBPS) {
721
0
        return ogs_msprintf("%lld Kbps",
722
0
                (long long)bitrate / 1000);
723
0
    } else if (unit == OGS_SBI_BITRATE_MBPS) {
724
0
        return ogs_msprintf("%lld Mbps",
725
0
                (long long)bitrate / 1000 / 1000);
726
0
    } else if (unit == OGS_SBI_BITRATE_GBPS) {
727
0
        return ogs_msprintf("%lld Gbps",
728
0
                (long long)bitrate / 1000 / 1000 / 1000);
729
0
    } else if (unit == OGS_SBI_BITRATE_TBPS) {
730
0
        return ogs_msprintf("%lld Tbps",
731
0
                (long long)bitrate / 1000 / 1000 / 1000 / 1000);
732
0
    }
733
734
0
    return ogs_msprintf("%lld bps", (long long)bitrate);
735
0
}
736
737
uint64_t ogs_sbi_bitrate_from_string(const char *str)
738
0
{
739
0
    const char *unit = NULL;
740
0
    double bitrate = 0;
741
0
    ogs_assert(str);
742
0
    uint64_t mul = 1;
743
744
0
    unit = strrchr(str, ' ');
745
0
    bitrate = atof(str);
746
747
0
    if (!unit) {
748
0
        ogs_error("No Unit [%s]", str);
749
0
        return bitrate;
750
0
    }
751
752
0
    SWITCH(unit+1)
753
0
    CASE("Kbps")
754
0
        mul = 1000ul;
755
0
        break;
756
0
    CASE("Mbps")
757
0
        mul = 1000ul * 1000ul;
758
0
        break;
759
0
    CASE("Gbps")
760
0
        mul = 1000ul * 1000ul * 1000ul;
761
0
        break;
762
0
    CASE("Tbps")
763
0
        mul = 1000ul * 1000ul * 1000ul * 1000ul;
764
0
        break;
765
0
    DEFAULT
766
0
    END
767
768
0
    if (bitrate >= (INT64_MAX / mul))
769
0
        return INT64_MAX;
770
0
    else
771
0
        bitrate *= mul;
772
773
0
    return (uint64_t) bitrate;
774
0
}
775
776
0
#define MAX_TIMESTR_LEN 128
777
778
int ogs_strftimezone(char *str, size_t size, int tm_gmtoff)
779
0
{
780
0
    uint8_t off_sign;
781
0
    int off;
782
0
    int len;
783
784
0
    ogs_assert(str);
785
0
    ogs_assert(size);
786
787
0
    off_sign = '+';
788
0
    off = tm_gmtoff;
789
0
    if (tm_gmtoff < 0) {
790
0
        off_sign = '-';
791
0
        off = -off;
792
0
    }
793
794
0
    len = ogs_snprintf(str, size, "%c%02d:%02d",
795
0
            off_sign, off / 3600, (off % 3600) / 60);
796
0
    if (len != 6) {
797
0
        ogs_fatal("Unknown tm_gmtoff[%d:%d], len[%d], str[%s]",
798
0
                tm_gmtoff, off, len, str);
799
0
        ogs_assert_if_reached();
800
0
    }
801
802
0
    return len;
803
0
}
804
805
#define USE_MILLISECONDS_IN_RFC3339 0
806
807
char *ogs_sbi_localtime_string(ogs_time_t timestamp)
808
0
{
809
0
    struct tm tm;
810
811
0
    char datetime[MAX_TIMESTR_LEN];
812
0
    char timezone[MAX_TIMESTR_LEN];
813
0
    int len;
814
815
0
    ogs_localtime(ogs_time_sec(timestamp), &tm);
816
0
    ogs_strftime(datetime, sizeof datetime, "%Y-%m-%dT%H:%M:%S", &tm);
817
818
0
    len = ogs_strftimezone(timezone, MAX_TIMESTR_LEN, tm.tm_gmtoff);
819
0
    ogs_assert(len == 6);
820
821
#if USE_MILLISECONDS_IN_RFC3339
822
    return ogs_msprintf("%s.%03lld%s",
823
            datetime, (long long)ogs_time_msec(timestamp), timezone);
824
#else
825
0
    return ogs_msprintf("%s.%06lld%s",
826
0
            datetime, (long long)ogs_time_usec(timestamp), timezone);
827
0
#endif
828
0
}
829
830
char *ogs_sbi_gmtime_string(ogs_time_t timestamp)
831
0
{
832
0
    struct tm tm;
833
834
0
    char datetime[MAX_TIMESTR_LEN];
835
836
0
    ogs_gmtime(ogs_time_sec(timestamp), &tm);
837
0
    ogs_strftime(datetime, sizeof datetime, "%Y-%m-%dT%H:%M:%S", &tm);
838
839
#if USE_MILLISECONDS_IN_RFC3339
840
    return ogs_msprintf("%s.%03lldZ",
841
            datetime, (long long)ogs_time_msec(timestamp));
842
#else
843
0
    return ogs_msprintf("%s.%06lldZ",
844
0
            datetime, (long long)ogs_time_usec(timestamp));
845
0
#endif
846
0
}
847
848
char *ogs_sbi_timezone_string(int tm_gmtoff)
849
0
{
850
0
    char timezone[MAX_TIMESTR_LEN];
851
0
    int len;
852
853
0
    len = ogs_strftimezone(timezone, MAX_TIMESTR_LEN, tm_gmtoff);
854
0
    ogs_assert(len == 6);
855
856
0
    return ogs_msprintf("%s", timezone);
857
0
}
858
859
bool ogs_sbi_time_from_string(ogs_time_t *timestamp, const char *str)
860
0
{
861
0
    int rv, i, j, k;
862
0
    struct tm tm;
863
0
    bool is_subsecs, is_time, timezone_found;
864
0
    char seconds[MAX_TIMESTR_LEN];
865
0
    char subsecs[MAX_TIMESTR_LEN];
866
0
    ogs_time_t usecs;
867
868
0
    ogs_assert(str);
869
0
    ogs_assert(timestamp);
870
871
0
    memset(seconds, 0, sizeof seconds);
872
0
    memset(subsecs, 0, sizeof subsecs);
873
874
0
    is_subsecs = false;
875
0
    is_time = false;
876
0
    timezone_found = false;
877
0
    i = 0; j = 0, k = 0;
878
0
    while(str[i]) {
879
0
        if (is_subsecs == false && str[i] == '.')
880
0
            is_subsecs = true;
881
0
        else if (is_subsecs == false && str[i] == 'T')
882
0
            is_time = true;
883
0
        else if (is_subsecs == true && (str[i] < '0' || str[i] > '9'))
884
0
            is_subsecs = false;
885
886
0
        if (is_time == true && (str[i] == '+' || str[i] == '-'))
887
0
            timezone_found = true;
888
889
0
        if (is_subsecs == false) {
890
0
            if (str[i] == ':' && i >= 3 &&
891
0
                    (str[i-3] == '+' || str[i-3] == '-')) {
892
                /* remove ':' character in timezone string range */
893
0
            } else {
894
0
                if (j >= MAX_TIMESTR_LEN - 1) {
895
0
                    ogs_error("Too long time string [%d]", (int)strlen(str));
896
0
                    return false;
897
0
                }
898
0
                seconds[j++] = str[i];
899
0
            }
900
0
        } else {
901
0
            if (k >= MAX_TIMESTR_LEN - 1) {
902
0
                ogs_error("Too long time string [%d]", (int)strlen(str));
903
0
                return false;
904
0
            }
905
0
            subsecs[k++] = str[i];
906
0
        }
907
908
0
        i++;
909
0
    }
910
911
0
    memset(&tm, 0, sizeof(tm));
912
0
    if (timezone_found == true)
913
0
        ogs_strptime(seconds, "%Y-%m-%dT%H:%M:%S%z", &tm);
914
0
    else
915
0
        ogs_strptime(seconds, "%Y-%m-%dT%H:%M:%S", &tm);
916
#if USE_MATH
917
    usecs = (ogs_time_t)floor(atof(subsecs) * 1000000.0 + 0.5);
918
#else
919
0
    usecs = (ogs_time_t)((atof(subsecs) * 10000000 + 5) / 10);
920
0
#endif
921
922
0
    rv = ogs_time_from_gmt(timestamp, &tm, usecs);
923
0
    if (rv != OGS_OK) {
924
0
        ogs_error("Cannot convert time [%s]", str);
925
0
        return false;
926
0
    }
927
928
0
    return true;
929
0
}
930
931
int ogs_sbi_rfc7231_string(char *date_str, ogs_time_t time)
932
0
{
933
0
    const char ogs_month_snames[12][4] = {
934
0
        "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
935
0
        "Aug", "Sep", "Oct", "Nov", "Dec"
936
0
    };
937
0
    const char ogs_day_snames[7][4] = {
938
0
        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
939
0
    };
940
941
0
    struct tm gmt;
942
0
    const char *s;
943
0
    int real_year;
944
945
0
    ogs_time_t sec = ogs_time_sec(time);
946
0
    ogs_time_t msec = ogs_time_msec(time);
947
948
0
    ogs_assert(date_str);
949
950
0
    ogs_gmtime(sec, &gmt);
951
952
    /* example: "Sun, 04 Aug 2019 08:49:37.845 GMT" */
953
    /*           123456789012345678901234567890123  */
954
955
0
    s = &ogs_day_snames[gmt.tm_wday][0];
956
0
    *date_str++ = *s++;
957
0
    *date_str++ = *s++;
958
0
    *date_str++ = *s++;
959
0
    *date_str++ = ',';
960
0
    *date_str++ = ' ';
961
0
    *date_str++ = gmt.tm_mday / 10 + '0';
962
0
    *date_str++ = gmt.tm_mday % 10 + '0';
963
0
    *date_str++ = ' ';
964
0
    s = &ogs_month_snames[gmt.tm_mon][0];
965
0
    *date_str++ = *s++;
966
0
    *date_str++ = *s++;
967
0
    *date_str++ = *s++;
968
0
    *date_str++ = ' ';
969
0
    real_year = 1900 + gmt.tm_year;
970
    /* This routine isn't y10k ready. */
971
0
    *date_str++ = real_year / 1000 + '0';
972
0
    *date_str++ = real_year % 1000 / 100 + '0';
973
0
    *date_str++ = real_year % 100 / 10 + '0';
974
0
    *date_str++ = real_year % 10 + '0';
975
0
    *date_str++ = ' ';
976
0
    *date_str++ = gmt.tm_hour / 10 + '0';
977
0
    *date_str++ = gmt.tm_hour % 10 + '0';
978
0
    *date_str++ = ':';
979
0
    *date_str++ = gmt.tm_min / 10 + '0';
980
0
    *date_str++ = gmt.tm_min % 10 + '0';
981
0
    *date_str++ = ':';
982
0
    *date_str++ = gmt.tm_sec / 10 + '0';
983
0
    *date_str++ = gmt.tm_sec % 10 + '0';
984
0
    *date_str++ = '.';
985
0
    *date_str++ = msec / 100 + '0';
986
0
    *date_str++ = msec % 100 / 10 + '0';
987
0
    *date_str++ = msec % 10 + '0';
988
0
    *date_str++ = ' ';
989
0
    *date_str++ = 'G';
990
0
    *date_str++ = 'M';
991
0
    *date_str++ = 'T';
992
0
    *date_str++ = 0;
993
994
0
    return OGS_OK;
995
0
}
996
997
char *ogs_sbi_s_nssai_to_json(const ogs_s_nssai_t *s_nssai)
998
0
{
999
0
    cJSON *item = NULL;
1000
0
    OpenAPI_snssai_t sNSSAI;
1001
1002
0
    char *v = NULL;
1003
1004
0
    ogs_assert(s_nssai);
1005
1006
0
    sNSSAI.sst = s_nssai->sst;
1007
0
    sNSSAI.sd = ogs_s_nssai_sd_to_string(s_nssai->sd);
1008
1009
0
    item = OpenAPI_snssai_convertToJSON(&sNSSAI);
1010
0
    if (!item) {
1011
0
        ogs_error("OpenAPI_snssai_convertToJSON() failed");
1012
0
        return NULL;
1013
0
    }
1014
0
    if (sNSSAI.sd) ogs_free(sNSSAI.sd);
1015
1016
0
    v = cJSON_PrintUnformatted(item);
1017
0
    ogs_expect(v);
1018
0
    cJSON_Delete(item);
1019
1020
0
    return v;
1021
0
}
1022
1023
bool ogs_sbi_s_nssai_from_json(ogs_s_nssai_t *s_nssai, const char *str)
1024
30
{
1025
30
    bool rc = false;
1026
1027
30
    cJSON *item = NULL;
1028
30
    OpenAPI_snssai_t *sNSSAI = NULL;
1029
1030
30
    ogs_assert(s_nssai);
1031
30
    ogs_assert(str);
1032
1033
30
    item = cJSON_Parse(str);
1034
30
    if (item) {
1035
6
        sNSSAI = OpenAPI_snssai_parseFromJSON(item);
1036
6
        if (sNSSAI) {
1037
2
            s_nssai->sst = sNSSAI->sst;
1038
2
            s_nssai->sd = ogs_s_nssai_sd_from_string(sNSSAI->sd);
1039
2
            OpenAPI_snssai_free(sNSSAI);
1040
2
            rc = true;
1041
2
        }
1042
6
        cJSON_Delete(item);
1043
6
    }
1044
1045
30
    return rc;
1046
30
}
1047
1048
char *ogs_sbi_s_nssai_to_string(const ogs_s_nssai_t *s_nssai)
1049
0
{
1050
0
    ogs_assert(s_nssai);
1051
1052
0
    if (s_nssai->sd.v != OGS_S_NSSAI_NO_SD_VALUE) {
1053
0
        return ogs_msprintf("%d-%06x", s_nssai->sst, s_nssai->sd.v);
1054
0
    } else {
1055
0
        return ogs_msprintf("%d", s_nssai->sst);
1056
0
    }
1057
0
}
1058
1059
bool ogs_sbi_s_nssai_from_string(ogs_s_nssai_t *s_nssai, const char *str)
1060
0
{
1061
0
    bool rc = false;
1062
0
    char *token, *p, *tofree;
1063
0
    char *sst = NULL;
1064
0
    char *sd = NULL;
1065
1066
0
    ogs_assert(s_nssai);
1067
0
    ogs_assert(str);
1068
1069
0
    tofree = p = ogs_strdup(str);
1070
0
    if (!p) {
1071
0
        ogs_error("ogs_strdup[%s] failed", str);
1072
0
        goto cleanup;
1073
0
    }
1074
1075
0
    token = strsep(&p, "-");
1076
0
    if (!token) {
1077
0
        ogs_error("strsep[%s] failed", str);
1078
0
        goto cleanup;
1079
0
    }
1080
1081
0
    sst = ogs_strdup(token);
1082
0
    if (!sst) {
1083
0
        ogs_error("ogs_strdup[%s:%s] failed", str, token);
1084
0
        goto cleanup;
1085
0
    }
1086
1087
0
    s_nssai->sst = atoi(sst);
1088
0
    s_nssai->sd.v = OGS_S_NSSAI_NO_SD_VALUE;
1089
1090
0
    if (p) {
1091
0
        sd = ogs_strdup(p);
1092
0
        if (!sd) {
1093
0
            ogs_error("ogs_strdup[%s:%s] failed", str, token);
1094
0
            goto cleanup;
1095
0
        }
1096
0
        s_nssai->sd = ogs_uint24_from_string_hexadecimal(sd);
1097
0
    }
1098
1099
0
    rc = true;
1100
1101
0
cleanup:
1102
0
    if (tofree)
1103
0
        ogs_free(tofree);
1104
0
    if (sst)
1105
0
        ogs_free(sst);
1106
0
    if (sd)
1107
0
        ogs_free(sd);
1108
1109
0
    return rc;
1110
0
}
1111
1112
OpenAPI_plmn_id_t *ogs_sbi_build_plmn_id(const ogs_plmn_id_t *plmn_id)
1113
0
{
1114
0
    OpenAPI_plmn_id_t *PlmnId = NULL;
1115
1116
0
    ogs_assert(plmn_id);
1117
1118
0
    PlmnId = ogs_calloc(1, sizeof(*PlmnId));
1119
0
    if (!PlmnId) {
1120
0
        ogs_error("ogs_calloc() failed");
1121
0
        return NULL;
1122
0
    }
1123
1124
0
    PlmnId->mcc = ogs_plmn_id_mcc_string(plmn_id);
1125
0
    if (!PlmnId->mcc) {
1126
0
        ogs_error("ogs_plmn_id_mcc_string() failed");
1127
0
        ogs_sbi_free_plmn_id(PlmnId);
1128
0
        return NULL;
1129
0
    }
1130
0
    PlmnId->mnc = ogs_plmn_id_mnc_string(plmn_id);
1131
0
    if (!PlmnId->mnc) {
1132
0
        ogs_error("ogs_plmn_id_mnc_string() failed");
1133
0
        ogs_sbi_free_plmn_id(PlmnId);
1134
0
        return NULL;
1135
0
    }
1136
1137
0
    return PlmnId;
1138
0
}
1139
1140
bool ogs_sbi_parse_plmn_id(
1141
        ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_t *PlmnId)
1142
35
{
1143
35
    ogs_assert(plmn_id);
1144
35
    ogs_assert(PlmnId);
1145
35
    ogs_assert(PlmnId->mcc);
1146
35
    ogs_assert(PlmnId->mnc);
1147
1148
35
    ogs_plmn_id_build(plmn_id,
1149
35
            atoi(PlmnId->mcc), atoi(PlmnId->mnc), strlen(PlmnId->mnc));
1150
1151
35
    return true;
1152
35
}
1153
1154
void ogs_sbi_free_plmn_id(OpenAPI_plmn_id_t *PlmnId)
1155
25
{
1156
25
    ogs_assert(PlmnId);
1157
1158
25
    if (PlmnId->mcc)
1159
25
        ogs_free(PlmnId->mcc);
1160
25
    if (PlmnId->mnc)
1161
25
        ogs_free(PlmnId->mnc);
1162
1163
25
    ogs_free(PlmnId);
1164
25
}
1165
1166
OpenAPI_list_t *ogs_sbi_build_plmn_list(
1167
        const ogs_plmn_id_t *plmn_list, int num_of_plmn_list)
1168
0
{
1169
0
    OpenAPI_list_t *PlmnList = NULL;
1170
0
    OpenAPI_plmn_id_t *PlmnId = NULL;
1171
0
    int i;
1172
1173
0
    ogs_assert(plmn_list);
1174
0
    ogs_assert(num_of_plmn_list);
1175
1176
0
    PlmnList = OpenAPI_list_create();
1177
0
    ogs_assert(PlmnList);
1178
1179
0
    for (i = 0; i < num_of_plmn_list; i++) {
1180
0
        PlmnId = ogs_sbi_build_plmn_id(plmn_list + i);
1181
0
        ogs_assert(PlmnId);
1182
1183
0
        OpenAPI_list_add(PlmnList, PlmnId);
1184
0
    }
1185
1186
0
    return PlmnList;
1187
0
}
1188
1189
int ogs_sbi_parse_plmn_list(
1190
        ogs_plmn_id_t *plmn_list, const OpenAPI_list_t *PlmnList)
1191
12
{
1192
12
    OpenAPI_plmn_id_t *PlmnId = NULL;
1193
12
    OpenAPI_lnode_t *node = NULL;
1194
12
    int num_of_plmn_list = 0;
1195
1196
12
    ogs_assert(plmn_list);
1197
12
    ogs_assert(PlmnList);
1198
1199
12
    num_of_plmn_list = 0;
1200
25
    OpenAPI_list_for_each(PlmnList, node) {
1201
25
        PlmnId = node->data;
1202
25
        if (PlmnId) {
1203
25
            ogs_assert(PlmnId->mcc);
1204
25
            ogs_assert(PlmnId->mnc);
1205
1206
25
            if (num_of_plmn_list >= OGS_MAX_NUM_OF_PLMN) {
1207
0
                ogs_warn("Exceeded maximum PLMN list size (%d)",
1208
0
                        OGS_MAX_NUM_OF_PLMN);
1209
0
                break;
1210
0
            }
1211
1212
25
            ogs_plmn_id_build(plmn_list + num_of_plmn_list,
1213
25
                    atoi(PlmnId->mcc), atoi(PlmnId->mnc), strlen(PlmnId->mnc));
1214
1215
25
            num_of_plmn_list++;
1216
25
        }
1217
25
    }
1218
1219
12
    return num_of_plmn_list;
1220
12
}
1221
1222
void ogs_sbi_free_plmn_list(OpenAPI_list_t *PlmnList)
1223
16
{
1224
16
    OpenAPI_plmn_id_t *PlmnId = NULL;
1225
16
    OpenAPI_lnode_t *node = NULL;
1226
1227
16
    ogs_assert(PlmnList);
1228
1229
25
    OpenAPI_list_for_each(PlmnList, node) {
1230
25
        PlmnId = node->data;
1231
25
        if (PlmnId)
1232
25
            ogs_sbi_free_plmn_id(PlmnId);
1233
25
    }
1234
16
    OpenAPI_list_free(PlmnList);
1235
16
}
1236
1237
/**
1238
 * Compares an ogs_plmn_id_t structure with an OpenAPI_plmn_id_t structure.
1239
 *
1240
 * @param plmn_list The PLMN-ID in ogs_plmn_id_t format.
1241
 * @param PlmnList The PLMN-ID in OpenAPI_plmn_id_t format.
1242
 * @return true if the PLMN-IDs are equal; otherwise, false.
1243
 */
1244
bool ogs_sbi_compare_plmn_list(
1245
        const ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_t *PlmnId)
1246
0
{
1247
0
    ogs_plmn_id_t temp_plmn_id;
1248
1249
0
    ogs_assert(plmn_id);
1250
0
    ogs_assert(PlmnId);
1251
0
    ogs_assert(PlmnId->mcc);
1252
0
    ogs_assert(PlmnId->mnc);
1253
1254
    /* Convert OpenAPI_plmn_id_t to ogs_plmn_id_t */
1255
0
    ogs_sbi_parse_plmn_id(&temp_plmn_id, PlmnId);
1256
1257
    /* Compare MCC and MNC values */
1258
0
    if (ogs_plmn_id_mcc(plmn_id) == ogs_plmn_id_mcc(&temp_plmn_id) &&
1259
0
        ogs_plmn_id_mnc(plmn_id) == ogs_plmn_id_mnc(&temp_plmn_id)) {
1260
0
        return true;
1261
0
    }
1262
1263
0
    return false;
1264
0
}
1265
1266
OpenAPI_plmn_id_nid_t *ogs_sbi_build_plmn_id_nid(const ogs_plmn_id_t *plmn_id)
1267
0
{
1268
0
    OpenAPI_plmn_id_nid_t *PlmnIdNid = NULL;
1269
1270
0
    ogs_assert(plmn_id);
1271
1272
0
    PlmnIdNid = ogs_calloc(1, sizeof(*PlmnIdNid));
1273
0
    if (!PlmnIdNid) {
1274
0
        ogs_error("ogs_calloc() failed");
1275
0
        return NULL;
1276
0
    }
1277
1278
0
    PlmnIdNid->mcc = ogs_plmn_id_mcc_string(plmn_id);
1279
0
    if (!PlmnIdNid->mcc) {
1280
0
        ogs_error("ogs_plmn_id_mcc_string() failed");
1281
0
        ogs_sbi_free_plmn_id_nid(PlmnIdNid);
1282
0
        return NULL;
1283
0
    }
1284
0
    PlmnIdNid->mnc = ogs_plmn_id_mnc_string(plmn_id);
1285
0
    if (!PlmnIdNid->mnc) {
1286
0
        ogs_error("ogs_plmn_id_mnc_string() failed");
1287
0
        ogs_sbi_free_plmn_id_nid(PlmnIdNid);
1288
0
        return NULL;
1289
0
    }
1290
1291
0
    return PlmnIdNid;
1292
0
}
1293
1294
bool ogs_sbi_parse_plmn_id_nid(
1295
        ogs_plmn_id_t *plmn_id, const OpenAPI_plmn_id_nid_t *PlmnIdNid)
1296
12
{
1297
12
    ogs_assert(plmn_id);
1298
12
    ogs_assert(PlmnIdNid);
1299
12
    ogs_assert(PlmnIdNid->mcc);
1300
12
    ogs_assert(PlmnIdNid->mnc);
1301
1302
12
    ogs_plmn_id_build(plmn_id,
1303
12
            atoi(PlmnIdNid->mcc), atoi(PlmnIdNid->mnc), strlen(PlmnIdNid->mnc));
1304
1305
12
    return true;
1306
12
}
1307
1308
void ogs_sbi_free_plmn_id_nid(OpenAPI_plmn_id_nid_t *PlmnIdNid)
1309
0
{
1310
0
    ogs_assert(PlmnIdNid);
1311
1312
0
    if (PlmnIdNid->mcc)
1313
0
        ogs_free(PlmnIdNid->mcc);
1314
0
    if (PlmnIdNid->mnc)
1315
0
        ogs_free(PlmnIdNid->mnc);
1316
0
    if (PlmnIdNid->nid)
1317
0
        ogs_free(PlmnIdNid->nid);
1318
1319
0
    ogs_free(PlmnIdNid);
1320
0
}
1321
1322
OpenAPI_guami_t *ogs_sbi_build_guami(const ogs_guami_t *guami)
1323
0
{
1324
0
    OpenAPI_guami_t *Guami = NULL;
1325
1326
0
    ogs_assert(guami);
1327
1328
0
    Guami = ogs_calloc(1, sizeof(*Guami));
1329
0
    if (!Guami) {
1330
0
        ogs_error("ogs_calloc() failed");
1331
0
        return NULL;
1332
0
    }
1333
1334
0
    Guami->plmn_id = ogs_sbi_build_plmn_id_nid(&guami->plmn_id);
1335
0
    if (!Guami->plmn_id) {
1336
0
        ogs_error("ogs_sbi_build_plmn_id_nid() failed");
1337
0
        ogs_sbi_free_guami(Guami);
1338
0
        return NULL;
1339
0
    }
1340
0
    Guami->amf_id = ogs_amf_id_to_string(&guami->amf_id);
1341
0
    if (!Guami->amf_id) {
1342
0
        ogs_error("ogs_amf_id_to_string() failed");
1343
0
        ogs_sbi_free_guami(Guami);
1344
0
        return NULL;
1345
0
    }
1346
1347
0
    return Guami;
1348
0
}
1349
1350
bool ogs_sbi_parse_guami(ogs_guami_t *guami, const OpenAPI_guami_t *Guami)
1351
42
{
1352
42
    ogs_assert(guami);
1353
42
    ogs_assert(Guami);
1354
42
    ogs_assert(Guami->amf_id);
1355
42
    ogs_assert(Guami->plmn_id);
1356
1357
42
    if (!ogs_amf_id_from_string(&guami->amf_id, Guami->amf_id)) {
1358
30
        ogs_error("Invalid GUAMI AMF ID [%s]", Guami->amf_id);
1359
30
        return false;
1360
30
    }
1361
12
    ogs_sbi_parse_plmn_id_nid(&guami->plmn_id, Guami->plmn_id);
1362
1363
12
    return true;
1364
42
}
1365
1366
void ogs_sbi_free_guami(OpenAPI_guami_t *Guami)
1367
0
{
1368
0
    ogs_assert(Guami);
1369
1370
0
    if (Guami->plmn_id)
1371
0
        ogs_sbi_free_plmn_id_nid(Guami->plmn_id);
1372
0
    if (Guami->amf_id)
1373
0
        ogs_free(Guami->amf_id);
1374
0
    ogs_free(Guami);
1375
0
}
1376
1377
OpenAPI_nr_location_t *ogs_sbi_build_nr_location(
1378
    const ogs_5gs_tai_t *tai, const ogs_nr_cgi_t *nr_cgi)
1379
0
{
1380
0
    OpenAPI_nr_location_t *NrLocation = NULL;
1381
0
    OpenAPI_tai_t *Tai = NULL;
1382
0
    OpenAPI_ncgi_t *Ncgi = NULL;
1383
1384
0
    ogs_assert(tai);
1385
0
    ogs_assert(nr_cgi);
1386
1387
0
    NrLocation = ogs_calloc(1, sizeof(*NrLocation));
1388
0
    if (!NrLocation) {
1389
0
        ogs_error("ogs_calloc() failed");
1390
0
        return NULL;
1391
0
    }
1392
1393
0
    NrLocation->tai = Tai = ogs_calloc(1, sizeof(*Tai));
1394
0
    if (!Tai) {
1395
0
        ogs_error("ogs_calloc() failed");
1396
0
        ogs_sbi_free_nr_location(NrLocation);
1397
0
        return NULL;
1398
0
    }
1399
0
    Tai->plmn_id = ogs_sbi_build_plmn_id(&tai->plmn_id);
1400
0
    if (!Tai->plmn_id) {
1401
0
        ogs_error("ogs_sbi_build_plmn_id() failed");
1402
0
        ogs_sbi_free_nr_location(NrLocation);
1403
0
        return NULL;
1404
0
    }
1405
0
    Tai->tac = ogs_uint24_to_0string(tai->tac);
1406
0
    if (!Tai->tac) {
1407
0
        ogs_error("ogs_uint24_to_0string() failed");
1408
0
        ogs_sbi_free_nr_location(NrLocation);
1409
0
        return NULL;
1410
0
    }
1411
1412
0
    NrLocation->ncgi = Ncgi = ogs_calloc(1, sizeof(*Ncgi));
1413
0
    if (!Ncgi) {
1414
0
        ogs_error("ogs_calloc() failed");
1415
0
        ogs_sbi_free_nr_location(NrLocation);
1416
0
        return NULL;
1417
0
    }
1418
0
    Ncgi->plmn_id = ogs_sbi_build_plmn_id(&nr_cgi->plmn_id);
1419
0
    if (!Ncgi->plmn_id) {
1420
0
        ogs_error("ogs_sbi_build_plmn_id() failed");
1421
0
        ogs_sbi_free_nr_location(NrLocation);
1422
0
        return NULL;
1423
0
    }
1424
0
    Ncgi->nr_cell_id = ogs_uint36_to_0string(nr_cgi->cell_id);
1425
0
    if (!Ncgi->nr_cell_id) {
1426
0
        ogs_error("ogs_uint36_to_0string() failed");
1427
0
        ogs_sbi_free_nr_location(NrLocation);
1428
0
        return NULL;
1429
0
    }
1430
1431
0
    return NrLocation;
1432
0
}
1433
1434
bool ogs_sbi_parse_nr_location(ogs_5gs_tai_t *tai, ogs_nr_cgi_t *nr_cgi,
1435
        const OpenAPI_nr_location_t *NrLocation)
1436
0
{
1437
0
    OpenAPI_tai_t *Tai = NULL;
1438
0
    OpenAPI_ncgi_t *Ncgi = NULL;
1439
1440
0
    ogs_assert(tai);
1441
0
    ogs_assert(nr_cgi);
1442
0
    ogs_assert(NrLocation);
1443
1444
0
    Tai = NrLocation->tai;
1445
0
    if (Tai) {
1446
0
        if (Tai->plmn_id)
1447
0
            ogs_sbi_parse_plmn_id(&tai->plmn_id, Tai->plmn_id);
1448
0
        if (Tai->tac)
1449
0
            tai->tac = ogs_uint24_from_string_hexadecimal(Tai->tac);
1450
0
    }
1451
1452
0
    Ncgi = NrLocation->ncgi;
1453
0
    if (Ncgi) {
1454
0
        if (Ncgi->plmn_id)
1455
0
            ogs_sbi_parse_plmn_id(&nr_cgi->plmn_id, Ncgi->plmn_id);
1456
0
        if (Ncgi->nr_cell_id)
1457
0
            nr_cgi->cell_id = ogs_uint64_from_string_hexadecimal(
1458
0
                    Ncgi->nr_cell_id);
1459
1460
0
    }
1461
1462
0
    return true;
1463
0
}
1464
1465
void ogs_sbi_free_nr_location(OpenAPI_nr_location_t *NrLocation)
1466
0
{
1467
0
    OpenAPI_tai_t *Tai = NULL;
1468
0
    OpenAPI_ncgi_t *Ncgi = NULL;
1469
1470
0
    ogs_assert(NrLocation);
1471
1472
0
    Tai = NrLocation->tai;
1473
0
    if (Tai) {
1474
0
        if (Tai->plmn_id)
1475
0
            ogs_sbi_free_plmn_id(Tai->plmn_id);
1476
0
        if (Tai->tac)
1477
0
            ogs_free(Tai->tac);
1478
0
        ogs_free(Tai);
1479
0
    }
1480
1481
0
    Ncgi = NrLocation->ncgi;
1482
0
    if (Ncgi) {
1483
0
        if (Ncgi->plmn_id)
1484
0
            ogs_sbi_free_plmn_id(Ncgi->plmn_id);
1485
0
        if (Ncgi->nr_cell_id)
1486
0
            ogs_free(Ncgi->nr_cell_id);
1487
0
        ogs_free(Ncgi);
1488
0
    }
1489
1490
0
    ogs_free(NrLocation);
1491
0
}
1492
1493
OpenAPI_pcc_rule_t *ogs_sbi_build_pcc_rule(
1494
        const ogs_pcc_rule_t *pcc_rule, int flow_presence)
1495
0
{
1496
0
    OpenAPI_pcc_rule_t *PccRule = NULL;
1497
0
    OpenAPI_list_t *FlowInformationList = NULL;
1498
0
    OpenAPI_flow_information_t *FlowInformation = NULL;
1499
1500
0
    int i;
1501
1502
0
    ogs_assert(pcc_rule);
1503
1504
0
    PccRule = ogs_calloc(1, sizeof(*PccRule));
1505
0
    ogs_assert(PccRule);
1506
1507
    /*
1508
     * At this point, only 1 QosData is used for PccRule.
1509
     * Therefore, QoS ID uses the same value as PCC Rule ID.
1510
     */
1511
0
    PccRule->pcc_rule_id = pcc_rule->id;
1512
1513
0
    PccRule->ref_qos_data = OpenAPI_list_create();
1514
0
    ogs_assert(PccRule->ref_qos_data);
1515
1516
0
    OpenAPI_list_add(PccRule->ref_qos_data, PccRule->pcc_rule_id);
1517
1518
0
    PccRule->is_precedence = true;
1519
0
    PccRule->precedence = pcc_rule->precedence;
1520
1521
0
    if (flow_presence == 1) {
1522
0
        FlowInformationList = OpenAPI_list_create();
1523
0
        ogs_assert(FlowInformationList);
1524
1525
0
        for (i = 0; i < pcc_rule->num_of_flow; i++) {
1526
0
            const ogs_flow_t *flow = &pcc_rule->flow[i];
1527
0
            ogs_assert(flow);
1528
1529
0
            FlowInformation = ogs_calloc(1, sizeof(*FlowInformation));
1530
0
            ogs_assert(FlowInformation);
1531
1532
0
            if (flow->direction == OGS_FLOW_UPLINK_ONLY)
1533
0
                FlowInformation->flow_direction =
1534
0
                    OpenAPI_flow_direction_UPLINK;
1535
0
            else if (flow->direction == OGS_FLOW_DOWNLINK_ONLY)
1536
0
                FlowInformation->flow_direction =
1537
0
                    OpenAPI_flow_direction_DOWNLINK;
1538
0
            else if (flow->direction == OGS_FLOW_BIDIRECTIONAL)
1539
0
                FlowInformation->flow_direction =
1540
0
                    OpenAPI_flow_direction_BIDIRECTIONAL;
1541
0
            else {
1542
0
                ogs_fatal("Unsupported direction [%d]", flow->direction);
1543
0
                ogs_assert_if_reached();
1544
0
            }
1545
1546
0
            ogs_assert(flow->description);
1547
0
            FlowInformation->flow_description = flow->description;
1548
1549
0
            OpenAPI_list_add(FlowInformationList, FlowInformation);
1550
0
        }
1551
1552
0
        if (FlowInformationList->count)
1553
0
            PccRule->flow_infos = FlowInformationList;
1554
0
        else
1555
0
            OpenAPI_list_free(FlowInformationList);
1556
0
    }
1557
1558
0
    return PccRule;
1559
0
}
1560
1561
void ogs_sbi_free_pcc_rule(OpenAPI_pcc_rule_t *PccRule)
1562
0
{
1563
0
    OpenAPI_flow_information_t *FlowInformation = NULL;
1564
0
    OpenAPI_lnode_t *node = NULL;
1565
1566
0
    ogs_assert(PccRule);
1567
1568
0
    if (PccRule->ref_qos_data)
1569
0
        OpenAPI_list_free(PccRule->ref_qos_data);
1570
0
    if (PccRule->flow_infos) {
1571
0
        OpenAPI_list_for_each(PccRule->flow_infos, node) {
1572
0
            FlowInformation = node->data;
1573
0
            if (FlowInformation) ogs_free(FlowInformation);
1574
0
        }
1575
0
        OpenAPI_list_free(PccRule->flow_infos);
1576
0
    }
1577
0
    ogs_free(PccRule);
1578
0
}
1579
1580
OpenAPI_qos_data_t *ogs_sbi_build_qos_data(ogs_pcc_rule_t *pcc_rule)
1581
0
{
1582
0
    OpenAPI_qos_data_t *QosData = NULL;
1583
1584
0
    ogs_assert(pcc_rule);
1585
1586
0
    QosData = ogs_calloc(1, sizeof(*QosData));
1587
0
    ogs_assert(QosData);
1588
1589
    /*
1590
     * At this point, only 1 QosData is used for PccRule.
1591
     * Therefore, QoS ID uses the same value as PCC Rule ID.
1592
     */
1593
0
    QosData->qos_id = pcc_rule->id;
1594
1595
0
    QosData->is__5qi = true;
1596
0
    QosData->_5qi = pcc_rule->qos.index;
1597
0
    QosData->is_priority_level = true;
1598
0
    QosData->priority_level = pcc_rule->qos.arp.priority_level;
1599
1600
0
    QosData->arp = ogs_calloc(1, sizeof(OpenAPI_arp_t));
1601
0
    ogs_assert(QosData->arp);
1602
1603
0
    if (pcc_rule->qos.arp.pre_emption_capability ==
1604
0
            OGS_5GC_PRE_EMPTION_ENABLED)
1605
0
        QosData->arp->preempt_cap =
1606
0
            OpenAPI_preemption_capability_MAY_PREEMPT;
1607
0
    else if (pcc_rule->qos.arp.pre_emption_capability ==
1608
0
            OGS_5GC_PRE_EMPTION_DISABLED)
1609
0
        QosData->arp->preempt_cap =
1610
0
            OpenAPI_preemption_capability_NOT_PREEMPT;
1611
0
    ogs_assert(pcc_rule->qos.arp.pre_emption_capability);
1612
1613
0
    if (pcc_rule->qos.arp.pre_emption_vulnerability ==
1614
0
            OGS_5GC_PRE_EMPTION_ENABLED)
1615
0
        QosData->arp->preempt_vuln =
1616
0
            OpenAPI_preemption_vulnerability_PREEMPTABLE;
1617
0
    else if (pcc_rule->qos.arp.pre_emption_vulnerability ==
1618
0
            OGS_5GC_PRE_EMPTION_DISABLED)
1619
0
        QosData->arp->preempt_vuln =
1620
0
            OpenAPI_preemption_vulnerability_NOT_PREEMPTABLE;
1621
0
    ogs_assert(pcc_rule->qos.arp.pre_emption_vulnerability);
1622
0
    QosData->arp->priority_level = pcc_rule->qos.arp.priority_level;
1623
1624
0
    if (pcc_rule->qos.mbr.uplink)
1625
0
        QosData->maxbr_ul = ogs_sbi_bitrate_to_string(
1626
0
                pcc_rule->qos.mbr.uplink, OGS_SBI_BITRATE_BPS);
1627
0
    if (pcc_rule->qos.mbr.downlink)
1628
0
        QosData->maxbr_dl = ogs_sbi_bitrate_to_string(
1629
0
                pcc_rule->qos.mbr.downlink, OGS_SBI_BITRATE_BPS);
1630
1631
0
    if (pcc_rule->qos.gbr.uplink)
1632
0
        QosData->gbr_ul = ogs_sbi_bitrate_to_string(
1633
0
                pcc_rule->qos.gbr.uplink, OGS_SBI_BITRATE_BPS);
1634
0
    if (pcc_rule->qos.gbr.downlink)
1635
0
        QosData->gbr_dl = ogs_sbi_bitrate_to_string(
1636
0
                pcc_rule->qos.gbr.downlink, OGS_SBI_BITRATE_BPS);
1637
1638
0
    return QosData;
1639
0
}
1640
1641
void ogs_sbi_free_qos_data(OpenAPI_qos_data_t *QosData)
1642
0
{
1643
0
    ogs_assert(QosData);
1644
1645
0
    if (QosData->arp) ogs_free(QosData->arp);
1646
0
    if (QosData->maxbr_ul) ogs_free(QosData->maxbr_ul);
1647
0
    if (QosData->maxbr_dl) ogs_free(QosData->maxbr_dl);
1648
0
    if (QosData->gbr_ul) ogs_free(QosData->gbr_ul);
1649
0
    if (QosData->gbr_dl) ogs_free(QosData->gbr_dl);
1650
1651
    ogs_free(QosData);
1652
0
}