Coverage Report

Created: 2023-09-25 07:12

/src/open5gs/lib/proto/types.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019-2022 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-proto.h"
21
22
0
#define PLMN_ID_DIGIT1(x) (((x) / 100) % 10)
23
0
#define PLMN_ID_DIGIT2(x) (((x) / 10) % 10)
24
0
#define PLMN_ID_DIGIT3(x) ((x) % 10)
25
26
uint32_t ogs_plmn_id_hexdump(void *plmn_id)
27
0
{
28
0
    uint32_t hex;
29
0
    ogs_assert(plmn_id);
30
0
    memcpy(&hex, plmn_id, sizeof(ogs_plmn_id_t));
31
0
    hex = be32toh(hex) >> 8;
32
0
    return hex;
33
0
}
34
35
uint16_t ogs_plmn_id_mcc(ogs_plmn_id_t *plmn_id)
36
0
{
37
0
    return plmn_id->mcc1 * 100 + plmn_id->mcc2 * 10 + plmn_id->mcc3;
38
0
}
39
uint16_t ogs_plmn_id_mnc(ogs_plmn_id_t *plmn_id)
40
0
{
41
0
    return plmn_id->mnc1 == 0xf ? plmn_id->mnc2 * 10 + plmn_id->mnc3 :
42
0
        plmn_id->mnc1 * 100 + plmn_id->mnc2 * 10 + plmn_id->mnc3;
43
0
}
44
uint16_t ogs_plmn_id_mnc_len(ogs_plmn_id_t *plmn_id)
45
0
{
46
0
    return plmn_id->mnc1 == 0xf ? 2 : 3;
47
0
}
48
49
void *ogs_plmn_id_build(ogs_plmn_id_t *plmn_id, 
50
        uint16_t mcc, uint16_t mnc, uint16_t mnc_len)
51
0
{
52
0
    plmn_id->mcc1 = PLMN_ID_DIGIT1(mcc);
53
0
    plmn_id->mcc2 = PLMN_ID_DIGIT2(mcc);
54
0
    plmn_id->mcc3 = PLMN_ID_DIGIT3(mcc);
55
56
0
    if (mnc_len == 2)
57
0
        plmn_id->mnc1 = 0xf;
58
0
    else
59
0
        plmn_id->mnc1 = PLMN_ID_DIGIT1(mnc);
60
61
0
    plmn_id->mnc2 = PLMN_ID_DIGIT2(mnc);
62
0
    plmn_id->mnc3 = PLMN_ID_DIGIT3(mnc);
63
64
0
    return plmn_id;
65
0
}
66
67
void *ogs_nas_from_plmn_id(
68
        ogs_nas_plmn_id_t *ogs_nas_plmn_id, ogs_plmn_id_t *plmn_id)
69
0
{
70
0
    memcpy(ogs_nas_plmn_id, plmn_id, OGS_PLMN_ID_LEN);
71
0
    if (plmn_id->mnc1 != 0xf) {
72
0
        ogs_nas_plmn_id->mnc1 = plmn_id->mnc1;
73
0
        ogs_nas_plmn_id->mnc2 = plmn_id->mnc2;
74
0
        ogs_nas_plmn_id->mnc3 = plmn_id->mnc3;
75
0
    }
76
0
    return ogs_nas_plmn_id;
77
0
}
78
void *ogs_nas_to_plmn_id(
79
        ogs_plmn_id_t *plmn_id, ogs_nas_plmn_id_t *ogs_nas_plmn_id)
80
0
{
81
0
    memcpy(plmn_id, ogs_nas_plmn_id, OGS_PLMN_ID_LEN);
82
0
    if (plmn_id->mnc1 != 0xf) {
83
0
        plmn_id->mnc1 = ogs_nas_plmn_id->mnc1;
84
0
        plmn_id->mnc2 = ogs_nas_plmn_id->mnc2;
85
0
        plmn_id->mnc3 = ogs_nas_plmn_id->mnc3;
86
0
    }
87
0
    return plmn_id;
88
0
}
89
90
char *ogs_serving_network_name_from_plmn_id(ogs_plmn_id_t *plmn_id)
91
0
{
92
0
    ogs_assert(plmn_id);
93
0
    return ogs_msprintf("5G:mnc%03d.mcc%03d.3gppnetwork.org",
94
0
            ogs_plmn_id_mnc(plmn_id), ogs_plmn_id_mcc(plmn_id));
95
0
}
96
97
char *ogs_plmn_id_mcc_string(ogs_plmn_id_t *plmn_id)
98
0
{
99
0
    ogs_assert(plmn_id);
100
0
    return ogs_msprintf("%03d", ogs_plmn_id_mcc(plmn_id));
101
0
}
102
103
char *ogs_plmn_id_mnc_string(ogs_plmn_id_t *plmn_id)
104
0
{
105
0
    ogs_assert(plmn_id);
106
0
    if (ogs_plmn_id_mnc_len(plmn_id) == 2)
107
0
        return ogs_msprintf("%02d", ogs_plmn_id_mnc(plmn_id));
108
0
    else
109
0
        return ogs_msprintf("%03d", ogs_plmn_id_mnc(plmn_id));
110
0
}
111
112
char *ogs_plmn_id_to_string(ogs_plmn_id_t *plmn_id, char *buf)
113
0
{
114
0
    ogs_assert(plmn_id);
115
0
    ogs_assert(buf);
116
117
0
    if (ogs_plmn_id_mnc_len(plmn_id) == 2)
118
0
        ogs_snprintf(buf, OGS_PLMNIDSTRLEN, "%03d%02d",
119
0
                ogs_plmn_id_mcc(plmn_id), ogs_plmn_id_mnc(plmn_id));
120
0
    else
121
0
        ogs_snprintf(buf, OGS_PLMNIDSTRLEN, "%03d%03d",
122
0
                ogs_plmn_id_mcc(plmn_id), ogs_plmn_id_mnc(plmn_id));
123
124
0
    return buf;
125
0
}
126
127
uint32_t ogs_amf_id_hexdump(ogs_amf_id_t *amf_id)
128
0
{
129
0
    uint32_t hex;
130
131
0
    ogs_assert(amf_id);
132
133
0
    memcpy(&hex, amf_id, sizeof(ogs_amf_id_t));
134
0
    hex = be32toh(hex) >> 8;
135
136
0
    return hex;
137
0
}
138
139
ogs_amf_id_t *ogs_amf_id_from_string(ogs_amf_id_t *amf_id, const char *hex)
140
0
{
141
0
    char hexbuf[sizeof(ogs_amf_id_t)];
142
143
0
    ogs_assert(amf_id);
144
0
    ogs_assert(hex);
145
146
0
    ogs_hex_from_string(hex, hexbuf, sizeof(hexbuf));
147
148
0
    amf_id->region = hexbuf[0];
149
0
    amf_id->set1 = hexbuf[1];
150
0
    amf_id->set2 = (hexbuf[2] & 0xc0) >> 6;
151
0
    amf_id->pointer = hexbuf[2] & 0x3f;
152
153
0
    return amf_id;
154
0
}
155
156
0
#define OGS_AMFIDSTRLEN    (sizeof(ogs_amf_id_t)*2+1)
157
char *ogs_amf_id_to_string(ogs_amf_id_t *amf_id)
158
0
{
159
0
    char *str = NULL;
160
0
    ogs_assert(amf_id);
161
162
0
    str = ogs_calloc(1, OGS_AMFIDSTRLEN);
163
0
    if (!str) {
164
0
        ogs_error("ogs_calloc() failed");
165
0
        return NULL;
166
0
    }
167
168
0
    ogs_hex_to_ascii(amf_id, sizeof(ogs_amf_id_t), str, OGS_AMFIDSTRLEN);
169
170
0
    return str;
171
0
}
172
173
uint8_t ogs_amf_region_id(ogs_amf_id_t *amf_id)
174
0
{
175
0
    ogs_assert(amf_id);
176
0
    return amf_id->region;
177
0
}
178
uint16_t ogs_amf_set_id(ogs_amf_id_t *amf_id)
179
0
{
180
0
    ogs_assert(amf_id);
181
0
    return (amf_id->set1 << 2) + amf_id->set2;
182
0
}
183
uint8_t ogs_amf_pointer(ogs_amf_id_t *amf_id)
184
0
{
185
0
    ogs_assert(amf_id);
186
0
    return amf_id->pointer;
187
0
}
188
189
ogs_amf_id_t *ogs_amf_id_build(ogs_amf_id_t *amf_id,
190
        uint8_t region, uint16_t set, uint8_t pointer)
191
0
{
192
0
    amf_id->region = region;
193
0
    amf_id->set1 = set >> 2;
194
0
    amf_id->set2 = set & 0x3;
195
0
    amf_id->pointer = pointer;
196
197
0
    return amf_id;
198
0
}
199
200
char *ogs_id_get_type(char *str)
201
0
{
202
0
    char *token, *p, *tmp;
203
0
    char *type = NULL;
204
205
0
    ogs_assert(str);
206
0
    tmp = ogs_strdup(str);
207
0
    if (!tmp) {
208
0
        ogs_error("ogs_strdup[%s] failed", str);
209
0
        goto cleanup;
210
0
    }
211
212
0
    p = tmp;
213
0
    token = strsep(&p, "-");
214
0
    if (!token) {
215
0
        ogs_error("strsep[%s] failed", str);
216
0
        goto cleanup;
217
0
    }
218
0
    type = ogs_strdup(token);
219
0
    if (!type) {
220
0
        ogs_error("ogs_strdup[%s:%s] failed", str, token);
221
0
        goto cleanup;
222
0
    }
223
224
0
cleanup:
225
0
    if (tmp)
226
0
        ogs_free(tmp);
227
0
    return type;
228
0
}
229
230
char *ogs_id_get_value(char *str)
231
0
{
232
0
    char *token, *p, *tmp;
233
0
    char *ueid = NULL;
234
235
0
    ogs_assert(str);
236
0
    tmp = ogs_strdup(str);
237
0
    if (!tmp) {
238
0
        ogs_error("ogs_strdup[%s] failed", str);
239
0
        goto cleanup;
240
0
    }
241
242
0
    p = tmp;
243
0
    token = strsep(&p, "-");
244
0
    if (!token) {
245
0
        ogs_error("strsep[%s] failed", str);
246
0
        goto cleanup;
247
0
    }
248
0
    token = strsep(&p, "-");
249
0
    if (!token) {
250
0
        ogs_error("strsep[%s] failed", str);
251
0
        goto cleanup;
252
0
    }
253
0
    ueid = ogs_strdup(token);
254
0
    if (!ueid) {
255
0
        ogs_error("ogs_strdup[%s:%s] failed", str, token);
256
0
        goto cleanup;
257
0
    }
258
259
0
cleanup:
260
0
    if (tmp)
261
0
        ogs_free(tmp);
262
0
    return ueid;
263
0
}
264
265
char *ogs_s_nssai_sd_to_string(ogs_uint24_t sd)
266
0
{
267
0
    char *string = NULL;
268
269
0
    if (sd.v == OGS_S_NSSAI_NO_SD_VALUE)
270
0
        return NULL;
271
272
0
    string = ogs_uint24_to_0string(sd);
273
0
    ogs_expect(string);
274
275
0
    return string;
276
0
}
277
278
ogs_uint24_t ogs_s_nssai_sd_from_string(const char *hex)
279
0
{
280
0
    ogs_uint24_t sd;
281
282
0
    sd.v = OGS_S_NSSAI_NO_SD_VALUE;
283
0
    if (hex == NULL)
284
0
        return sd;
285
286
0
    return ogs_uint24_from_string((char *)hex);
287
0
}
288
289
int ogs_fqdn_build(char *dst, char *src, int length)
290
0
{
291
0
    int i = 0, j = 0;
292
293
0
    for (i = 0, j = 0; i < length; i++, j++) {
294
0
        if (src[i] == '.') {
295
0
            dst[i-j] = j;
296
0
            j = -1;
297
0
        } else {
298
0
            dst[i+1] = src[i];
299
0
        }
300
0
    }
301
0
    dst[i-j] = j;
302
303
0
    return length+1;
304
0
}
305
306
int ogs_fqdn_parse(char *dst, char *src, int length)
307
0
{
308
0
    int i = 0, j = 0;
309
0
    uint8_t len = 0;
310
311
0
    while (i+1 < length) {
312
0
        len = src[i++];
313
0
        if ((j + len + 1) > length) {
314
0
            ogs_error("Invalid FQDN encoding[len:%d] + 1 > length[%d]",
315
0
                    len, length);
316
0
            ogs_log_hexdump(OGS_LOG_ERROR, (unsigned char *)src, length);
317
0
            return 0;
318
0
        }
319
0
        memcpy(&dst[j], &src[i], len);
320
321
0
        i += len;
322
0
        j += len;
323
        
324
0
        if (i+1 < length)
325
0
            dst[j++] = '.';
326
0
        else
327
0
            dst[j] = 0;
328
0
    }
329
330
0
    return j;
331
0
}
332
333
/* 8.13 Protocol Configuration Options (PCO) 
334
 * 10.5.6.3 Protocol configuration options in 3GPP TS 24.008 */
335
int ogs_pco_parse(ogs_pco_t *pco, unsigned char *data, int data_len)
336
0
{
337
0
    ogs_pco_t *source = (ogs_pco_t *)data;
338
0
    int size = 0;
339
0
    int i = 0;
340
341
0
    ogs_assert(pco);
342
0
    ogs_assert(data);
343
0
    ogs_assert(data_len);
344
345
0
    memset(pco, 0, sizeof(ogs_pco_t));
346
347
0
    pco->ext = source->ext;
348
0
    pco->configuration_protocol = source->configuration_protocol;
349
0
    size++;
350
351
0
    while(size < data_len && i < OGS_MAX_NUM_OF_PROTOCOL_OR_CONTAINER_ID) {
352
0
        ogs_pco_id_t *id = &pco->ids[i];
353
0
        ogs_assert(size + sizeof(id->id) <= data_len);
354
0
        memcpy(&id->id, data + size, sizeof(id->id));
355
0
        id->id = be16toh(id->id);
356
0
        size += sizeof(id->id);
357
358
0
        ogs_assert(size + sizeof(id->len) <= data_len);
359
0
        memcpy(&id->len, data + size, sizeof(id->len));
360
0
        size += sizeof(id->len);
361
362
0
        id->data = data + size;
363
0
        size += id->len;
364
365
0
        i++;
366
0
    }
367
0
    pco->num_of_id = i;
368
0
    ogs_assert(size == data_len);
369
    
370
0
    return size;
371
0
}
372
int ogs_pco_build(unsigned char *data, int data_len, ogs_pco_t *pco)
373
0
{
374
0
    ogs_pco_t target;
375
0
    int size = 0;
376
0
    int i = 0;
377
378
0
    ogs_assert(pco);
379
0
    ogs_assert(data);
380
0
    ogs_assert(data_len);
381
382
0
    memcpy(&target, pco, sizeof(ogs_pco_t));
383
384
0
    ogs_assert(size + 1 <= data_len);
385
0
    memcpy(data + size, &target, 1);
386
0
    size += 1;
387
388
0
    ogs_assert(target.num_of_id <= OGS_MAX_NUM_OF_PROTOCOL_OR_CONTAINER_ID);
389
0
    for (i = 0; i < target.num_of_id; i++) {
390
0
        ogs_pco_id_t *id = &target.ids[i];
391
392
0
        ogs_assert(size + sizeof(id->id) <= data_len);
393
0
        id->id = htobe16(id->id);
394
0
        memcpy(data + size, &id->id, sizeof(id->id));
395
0
        size += sizeof(id->id);
396
397
0
        ogs_assert(size + sizeof(id->len) <= data_len);
398
0
        memcpy(data + size, &id->len, sizeof(id->len));
399
0
        size += sizeof(id->len);
400
401
0
        ogs_assert(size + id->len <= data_len);
402
0
        memcpy(data + size, id->data, id->len);
403
0
        size += id->len;
404
0
    }
405
406
0
    return size;
407
0
}
408
409
int ogs_ip_to_sockaddr(ogs_ip_t *ip, uint16_t port, ogs_sockaddr_t **list)
410
0
{
411
0
    ogs_sockaddr_t *addr = NULL, *addr6 = NULL;
412
413
0
    ogs_assert(ip);
414
0
    ogs_assert(list);
415
416
0
    addr = ogs_calloc(1, sizeof(ogs_sockaddr_t));
417
0
    if (!addr) {
418
0
        ogs_error("ogs_calloc() failed");
419
0
        return OGS_ERROR;
420
0
    }
421
0
    addr->ogs_sa_family = AF_INET;
422
0
    addr->ogs_sin_port = htobe16(port);
423
424
0
    addr6 = ogs_calloc(1, sizeof(ogs_sockaddr_t));
425
0
    if (!addr6) {
426
0
        ogs_error("ogs_calloc() failed");
427
0
        ogs_free(addr);
428
0
        return OGS_ERROR;
429
0
    }
430
0
    addr6->ogs_sa_family = AF_INET6;
431
0
    addr6->ogs_sin_port = htobe16(port);
432
433
0
    if (ip->ipv4 && ip->ipv6) {
434
0
        addr->next = addr6;
435
436
0
        addr->sin.sin_addr.s_addr = ip->addr;
437
0
        memcpy(addr6->sin6.sin6_addr.s6_addr, ip->addr6, OGS_IPV6_LEN);
438
439
0
        *list = addr;
440
0
    } else if (ip->ipv4) {
441
0
        addr->sin.sin_addr.s_addr = ip->addr;
442
0
        ogs_free(addr6);
443
444
0
        *list = addr;
445
0
    } else if (ip->ipv6) {
446
0
        memcpy(addr6->sin6.sin6_addr.s6_addr, ip->addr6, OGS_IPV6_LEN);
447
0
        ogs_free(addr);
448
449
0
        *list = addr6;
450
0
    } else {
451
0
        ogs_error("No IPv4 and IPv6");
452
0
        ogs_free(addr);
453
0
        ogs_free(addr6);
454
0
        return OGS_ERROR;
455
0
    }
456
457
0
    return OGS_OK;
458
0
}
459
460
int ogs_sockaddr_to_ip(
461
        ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6, ogs_ip_t *ip)
462
0
{
463
0
    if (!ip) {
464
0
        ogs_error("No IP");
465
0
        return OGS_ERROR;
466
0
    }
467
0
    if (!addr && !addr6) {
468
0
        ogs_error("No Address");
469
0
        return OGS_ERROR;
470
0
    }
471
472
0
    memset(ip, 0, sizeof(ogs_ip_t));
473
474
0
    if (addr && addr6) {
475
0
        ip->ipv4 = 1;
476
0
        ip->ipv6 = 1;
477
0
        ip->len = OGS_IPV4V6_LEN;
478
0
        ip->addr = addr->sin.sin_addr.s_addr;
479
0
        memcpy(ip->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
480
0
    } else if (addr) {
481
0
        ip->ipv4 = 1;
482
0
        ip->len = OGS_IPV4_LEN;
483
0
        ip->addr = addr->sin.sin_addr.s_addr;
484
0
    } else if (addr6) {
485
0
        ip->ipv6 = 1;
486
0
        ip->len = OGS_IPV6_LEN;
487
0
        memcpy(ip->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
488
0
    } else
489
0
        ogs_assert_if_reached();
490
491
0
    return OGS_OK;
492
0
}
493
494
char *ogs_ipv4_to_string(uint32_t addr)
495
0
{
496
0
    char *buf = NULL;
497
498
0
    buf = ogs_calloc(1, OGS_ADDRSTRLEN);
499
0
    if (!buf) {
500
0
        ogs_error("ogs_calloc() failed");
501
0
        return NULL;
502
0
    }
503
504
0
    return (char*)OGS_INET_NTOP(&addr, buf);
505
0
}
506
507
char *ogs_ipv6addr_to_string(uint8_t *addr6)
508
0
{
509
0
    char *buf = NULL;
510
0
    ogs_assert(addr6);
511
512
0
    buf = ogs_calloc(1, OGS_ADDRSTRLEN);
513
0
    if (!buf) {
514
0
        ogs_error("ogs_calloc() failed");
515
0
        return NULL;
516
0
    }
517
518
0
    return (char *)OGS_INET6_NTOP(addr6, buf);
519
0
}
520
521
char *ogs_ipv6prefix_to_string(uint8_t *addr6, uint8_t prefixlen)
522
0
{
523
0
    char *buf = NULL;
524
0
    uint8_t tmp[OGS_IPV6_LEN];
525
0
    ogs_assert(addr6);
526
527
0
    memset(tmp, 0, OGS_IPV6_LEN);
528
0
    memcpy(tmp, addr6, prefixlen >> 3);
529
530
0
    buf = ogs_calloc(1, OGS_ADDRSTRLEN);
531
0
    if (!buf) {
532
0
        ogs_error("ogs_calloc() failed");
533
0
        return NULL;
534
0
    }
535
536
0
    if (OGS_INET6_NTOP(tmp, buf) == NULL) {
537
0
        ogs_fatal("Invalid IPv6 address");
538
0
        ogs_log_hexdump(OGS_LOG_FATAL, addr6, OGS_IPV6_LEN);
539
0
        ogs_assert_if_reached();
540
0
    }
541
0
    return ogs_mstrcatf(buf, "/%d", prefixlen);
542
0
}
543
544
int ogs_ipv4_from_string(uint32_t *addr, char *string)
545
0
{
546
0
    int rv;
547
0
    ogs_sockaddr_t tmp;
548
549
0
    ogs_assert(addr);
550
0
    ogs_assert(string);
551
552
0
    rv = ogs_inet_pton(AF_INET, string, &tmp);
553
0
    if (rv != OGS_OK) {
554
0
        ogs_error("Invalid IPv4 string = %s", string);
555
0
        return OGS_ERROR;
556
0
    }
557
558
0
    *addr = tmp.sin.sin_addr.s_addr;
559
560
0
    return OGS_OK;
561
0
}
562
563
int ogs_ipv6addr_from_string(uint8_t *addr6, char *string)
564
0
{
565
0
    int rv;
566
0
    ogs_sockaddr_t tmp;
567
568
0
    ogs_assert(addr6);
569
0
    ogs_assert(string);
570
571
0
    rv = ogs_inet_pton(AF_INET6, string, &tmp);
572
0
    if (rv != OGS_OK) {
573
0
        ogs_error("Invalid IPv6 string = %s", string);
574
0
        return OGS_ERROR;
575
0
    }
576
577
0
    memcpy(addr6, tmp.sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
578
579
0
    return OGS_OK;
580
0
}
581
582
int ogs_ipv6prefix_from_string(uint8_t *addr6, uint8_t *prefixlen, char *string)
583
0
{
584
0
    int rv;
585
0
    ogs_sockaddr_t tmp;
586
0
    char *v = NULL, *pv = NULL, *ipstr = NULL, *mask_or_numbits = NULL;
587
588
0
    ogs_assert(addr6);
589
0
    ogs_assert(prefixlen);
590
0
    ogs_assert(string);
591
0
    pv = v = ogs_strdup(string);
592
0
    if (!v) {
593
0
        ogs_error("ogs_strdup() failed");
594
0
        return OGS_ERROR;
595
0
    }
596
597
0
    ipstr = strsep(&v, "/");
598
0
    if (ipstr)
599
0
        mask_or_numbits = v;
600
601
0
    if (!ipstr || !mask_or_numbits) {
602
0
        ogs_error("Invalid IPv6 Prefix string = %s", v);
603
0
        ogs_free(v);
604
0
        return OGS_ERROR;
605
0
    }
606
607
0
    rv = ogs_inet_pton(AF_INET6, ipstr, &tmp);
608
0
    if (rv != OGS_OK) {
609
0
        ogs_error("ogs_inet_pton() failed");
610
0
        return rv;
611
0
    }
612
613
0
    memcpy(addr6, tmp.sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
614
0
    *prefixlen = atoi(mask_or_numbits);
615
616
0
    ogs_free(pv);
617
0
    return OGS_OK;
618
0
}
619
620
int ogs_sockaddr_to_user_plane_ip_resource_info(
621
    ogs_sockaddr_t *addr, ogs_sockaddr_t *addr6,
622
    ogs_user_plane_ip_resource_info_t *info)
623
0
{
624
0
    ogs_assert(addr || addr6);
625
0
    ogs_assert(info);
626
627
0
    if (addr) {
628
0
        info->v4 = 1;
629
0
        info->addr = addr->sin.sin_addr.s_addr;
630
0
    }
631
0
    if (addr6) {
632
0
        info->v6 = 1;
633
0
        memcpy(info->addr6, addr6->sin6.sin6_addr.s6_addr, OGS_IPV6_LEN);
634
0
    }
635
636
0
    return OGS_OK;
637
0
}
638
639
int ogs_user_plane_ip_resource_info_to_sockaddr(
640
    ogs_user_plane_ip_resource_info_t *info,
641
    ogs_sockaddr_t **addr, ogs_sockaddr_t **addr6)
642
0
{
643
0
    ogs_assert(addr && addr6);
644
0
    ogs_assert(info);
645
646
0
    *addr = NULL;
647
0
    *addr6 = NULL;
648
649
0
    if (info->v4) {
650
0
        *addr = ogs_calloc(1, sizeof(**addr));
651
0
        ogs_assert(*addr);
652
0
        (*addr)->sin.sin_addr.s_addr = info->addr;
653
0
        (*addr)->ogs_sa_family = AF_INET;
654
0
    }
655
656
0
    if (info->v6) {
657
0
        *addr6 = ogs_calloc(1, sizeof(**addr6));
658
0
        ogs_assert(*addr6);
659
0
        memcpy((*addr6)->sin6.sin6_addr.s6_addr, info->addr6, OGS_IPV6_LEN);
660
0
        (*addr6)->ogs_sa_family = AF_INET6;
661
0
    }
662
663
0
    return OGS_OK;
664
0
}
665
666
ogs_slice_data_t *ogs_slice_find_by_s_nssai(
667
        ogs_slice_data_t *slice_data, int num_of_slice_data,
668
        ogs_s_nssai_t *s_nssai)
669
0
{
670
0
    int i;
671
672
0
    ogs_assert(slice_data);
673
0
    ogs_assert(num_of_slice_data);
674
0
    ogs_assert(s_nssai);
675
676
    /* Compare S-NSSAI */
677
0
    for (i = 0; i < num_of_slice_data; i++) {
678
0
        if (s_nssai->sst == slice_data[i].s_nssai.sst &&
679
0
                s_nssai->sd.v == slice_data[i].s_nssai.sd.v) {
680
0
            return slice_data + i;
681
0
        }
682
0
    }
683
684
0
    return NULL;
685
0
}
686
687
void ogs_subscription_data_free(ogs_subscription_data_t *subscription_data)
688
0
{
689
0
    int i, j;
690
691
0
    ogs_assert(subscription_data);
692
693
0
    if (subscription_data->imsi)
694
0
        ogs_free(subscription_data->imsi);
695
0
    if (subscription_data->mme_host)
696
0
        ogs_free(subscription_data->mme_host);
697
0
    if (subscription_data->mme_realm)
698
0
        ogs_free(subscription_data->mme_realm);
699
700
0
    for (i = 0; i < subscription_data->num_of_slice; i++) {
701
0
        ogs_slice_data_t *slice_data = &subscription_data->slice[i];
702
703
0
        for (j = 0; j < slice_data->num_of_session; j++) {
704
0
            if (slice_data->session[j].name)
705
0
                ogs_free(slice_data->session[j].name);
706
0
        }
707
708
0
        slice_data->num_of_session = 0;
709
0
    }
710
711
0
    subscription_data->num_of_slice = 0;
712
713
0
    subscription_data->num_of_msisdn = 0;
714
0
}
715
716
void ogs_session_data_free(ogs_session_data_t *session_data)
717
0
{
718
0
    int i;
719
720
0
    ogs_assert(session_data);
721
722
0
    if (session_data->session.name)
723
0
        ogs_free(session_data->session.name);
724
725
0
    for (i = 0; i < session_data->num_of_pcc_rule; i++)
726
0
        OGS_PCC_RULE_FREE(&session_data->pcc_rule[i]);
727
0
}
728
729
void ogs_ims_data_free(ogs_ims_data_t *ims_data)
730
0
{
731
0
    int i, j, k;
732
733
0
    ogs_assert(ims_data);
734
735
0
    for (i = 0; i < ims_data->num_of_media_component; i++) {
736
0
        ogs_media_component_t *media_component = &ims_data->media_component[i];
737
738
0
        for (j = 0; j < media_component->num_of_sub; j++) {
739
0
            ogs_media_sub_component_t *sub = &media_component->sub[j];
740
741
0
            for (k = 0; k < sub->num_of_flow; k++) {
742
0
                ogs_flow_t *flow = &sub->flow[k];
743
744
0
                if (flow->description) {
745
0
                    ogs_free(flow->description);
746
0
                } else
747
0
                    ogs_assert_if_reached();
748
0
            }
749
0
        }
750
0
    }
751
0
}
752
753
static int flow_rx_to_gx(ogs_flow_t *rx_flow, ogs_flow_t *gx_flow)
754
0
{
755
0
    int len;
756
0
    char *from_str, *to_str;
757
758
0
    ogs_assert(rx_flow);
759
0
    ogs_assert(gx_flow);
760
761
0
    if (!strncmp(rx_flow->description,
762
0
                "permit out", strlen("permit out"))) {
763
0
        gx_flow->direction = OGS_FLOW_DOWNLINK_ONLY;
764
0
        gx_flow->description = ogs_strdup(rx_flow->description);
765
0
        ogs_assert(gx_flow->description);
766
767
0
    } else if (!strncmp(rx_flow->description,
768
0
                "permit in", strlen("permit in"))) {
769
0
        gx_flow->direction = OGS_FLOW_UPLINK_ONLY;
770
771
        /* 'permit in' should be changed
772
         * 'permit out' in Gx Diameter */
773
0
        len = strlen(rx_flow->description)+2;
774
0
        gx_flow->description = ogs_calloc(1, len);
775
0
        ogs_assert(gx_flow->description);
776
0
        strcpy(gx_flow->description, "permit out");
777
0
        from_str = strstr(&rx_flow->description[strlen("permit in")], "from");
778
0
        ogs_assert(from_str);
779
0
        to_str = strstr(&rx_flow->description[strlen("permit in")], "to");
780
0
        ogs_assert(to_str);
781
0
        strncat(gx_flow->description,
782
0
            &rx_flow->description[strlen("permit in")],
783
0
            strlen(rx_flow->description) -
784
0
                strlen("permit in") - strlen(from_str));
785
0
        strcat(gx_flow->description, "from");
786
0
        strcat(gx_flow->description, &to_str[strlen("to")]);
787
0
        strcat(gx_flow->description, " to");
788
0
        strncat(gx_flow->description, &from_str[strlen("from")],
789
0
                strlen(from_str) - strlen(to_str) - strlen("from") - 1);
790
0
        ogs_assert(len == strlen(gx_flow->description)+1);
791
0
    } else {
792
0
        ogs_error("Invalid Flow Descripton : [%s]", rx_flow->description);
793
0
        return OGS_ERROR;
794
0
    }
795
796
0
    return OGS_OK;
797
0
}
798
799
int ogs_pcc_rule_num_of_flow_equal_to_media(
800
        ogs_pcc_rule_t *pcc_rule, ogs_media_component_t *media_component)
801
0
{
802
0
    int rv;
803
0
    int i, j, k;
804
0
    int matched = 0;
805
0
    int new = 0;
806
807
0
    ogs_assert(pcc_rule);
808
0
    ogs_assert(media_component);
809
810
0
    for (i = 0; i < media_component->num_of_sub; i++) {
811
0
        ogs_media_sub_component_t *sub = &media_component->sub[i];
812
813
0
        for (j = 0; j < sub->num_of_flow; j++) {
814
0
            new++;
815
0
        }
816
0
    }
817
818
0
    if (new == 0) {
819
        /* No new flow in Media-Component */
820
0
        return pcc_rule->num_of_flow;
821
0
    }
822
823
0
    for (i = 0; i < media_component->num_of_sub; i++) {
824
0
        ogs_media_sub_component_t *sub = &media_component->sub[i];
825
826
0
        for (j = 0; j < sub->num_of_flow &&
827
0
                    j < OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT; j++) {
828
0
            ogs_flow_t gx_flow;
829
0
            ogs_flow_t *rx_flow = &sub->flow[j];
830
831
0
            rv = flow_rx_to_gx(rx_flow, &gx_flow);
832
0
            if (rv != OGS_OK) {
833
0
                ogs_error("flow reformatting error");
834
0
                return OGS_ERROR;
835
0
            }
836
837
0
            for (k = 0; k < pcc_rule->num_of_flow; k++) {
838
0
                if (gx_flow.direction == pcc_rule->flow[k].direction &&
839
0
                    !strcmp(gx_flow.description,
840
0
                        pcc_rule->flow[k].description)) {
841
0
                    matched++;
842
0
                    break;
843
0
                }
844
0
            }
845
846
0
            OGS_FLOW_FREE(&gx_flow);
847
0
        }
848
0
    }
849
850
0
    return matched;
851
0
}
852
853
int ogs_pcc_rule_install_flow_from_media(
854
        ogs_pcc_rule_t *pcc_rule, ogs_media_component_t *media_component)
855
0
{
856
0
    int rv;
857
0
    int i, j;
858
859
0
    ogs_assert(pcc_rule);
860
0
    ogs_assert(media_component);
861
862
    /* Remove Flow from PCC Rule */
863
0
    for (i = 0; i < pcc_rule->num_of_flow; i++) {
864
0
        OGS_FLOW_FREE(&pcc_rule->flow[i]);
865
0
    }
866
0
    pcc_rule->num_of_flow = 0;
867
868
0
    for (i = 0; i < media_component->num_of_sub; i++) {
869
0
        ogs_media_sub_component_t *sub = &media_component->sub[i];
870
871
        /* Copy Flow to PCC Rule */
872
0
        for (j = 0; j < sub->num_of_flow &&
873
0
                    j < OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT; j++) {
874
0
            ogs_flow_t *rx_flow = NULL;
875
0
            ogs_flow_t *gx_flow = NULL;
876
877
0
            if (pcc_rule->num_of_flow < OGS_MAX_NUM_OF_FLOW_IN_PCC_RULE) {
878
0
                rx_flow = &sub->flow[j];
879
0
                gx_flow = &pcc_rule->flow[pcc_rule->num_of_flow];
880
881
0
                rv = flow_rx_to_gx(rx_flow, gx_flow);
882
0
                if (rv != OGS_OK) {
883
0
                    ogs_error("flow reformatting error");
884
0
                    return OGS_ERROR;
885
0
                }
886
887
0
                pcc_rule->num_of_flow++;
888
0
            } else {
889
0
                ogs_error("Overflow: Number of Flow");
890
0
                return OGS_ERROR;
891
0
            }
892
0
        }
893
0
    }
894
895
0
    return OGS_OK;
896
0
}
897
898
int ogs_pcc_rule_update_qos_from_media(
899
        ogs_pcc_rule_t *pcc_rule, ogs_media_component_t *media_component)
900
0
{
901
0
    int rv;
902
0
    int i, j;
903
904
0
    ogs_assert(pcc_rule);
905
0
    ogs_assert(media_component);
906
907
0
    pcc_rule->qos.mbr.downlink = 0;
908
0
    pcc_rule->qos.mbr.uplink = 0;
909
0
    pcc_rule->qos.gbr.downlink = 0;
910
0
    pcc_rule->qos.gbr.uplink = 0;
911
912
0
    for (i = 0; i < media_component->num_of_sub; i++) {
913
0
        ogs_media_sub_component_t *sub = &media_component->sub[i];
914
915
0
        for (j = 0; j < sub->num_of_flow &&
916
0
                    j < OGS_MAX_NUM_OF_FLOW_IN_MEDIA_SUB_COMPONENT; j++) {
917
0
            ogs_flow_t gx_flow;
918
0
            ogs_flow_t *rx_flow = &sub->flow[j];
919
920
0
            rv = flow_rx_to_gx(rx_flow, &gx_flow);
921
0
            if (rv != OGS_OK) {
922
0
                ogs_error("flow reformatting error");
923
0
                return OGS_ERROR;
924
0
            }
925
926
0
            if (gx_flow.direction == OGS_FLOW_DOWNLINK_ONLY) {
927
0
                if (sub->flow_usage == OGS_FLOW_USAGE_RTCP) {
928
0
                    if (media_component->rr_bandwidth &&
929
0
                        media_component->rs_bandwidth) {
930
0
                        pcc_rule->qos.mbr.downlink +=
931
0
                            (media_component->rr_bandwidth +
932
0
                            media_component->rs_bandwidth);
933
0
                    } else if (media_component->max_requested_bandwidth_dl) {
934
0
                        if (media_component->rr_bandwidth &&
935
0
                            !media_component->rs_bandwidth) {
936
0
                            pcc_rule->qos.mbr.downlink +=
937
0
                                ogs_max(0.05 *
938
0
                                    media_component->max_requested_bandwidth_dl,
939
0
                                    media_component->rr_bandwidth);
940
0
                        }
941
0
                        if (!media_component->rr_bandwidth &&
942
0
                            media_component->rs_bandwidth) {
943
0
                            pcc_rule->qos.mbr.downlink +=
944
0
                                ogs_max(0.05 *
945
0
                                    media_component->max_requested_bandwidth_dl,
946
0
                                    media_component->rs_bandwidth);
947
0
                        }
948
0
                        if (!media_component->rr_bandwidth &&
949
0
                            !media_component->rs_bandwidth) {
950
0
                            pcc_rule->qos.mbr.downlink +=
951
0
                                0.05 *
952
0
                                    media_component->max_requested_bandwidth_dl;
953
0
                        }
954
0
                    }
955
0
                } else {
956
0
                    if (gx_flow.description) {
957
0
                        pcc_rule->qos.mbr.downlink +=
958
0
                            media_component->max_requested_bandwidth_dl;
959
0
                        pcc_rule->qos.gbr.downlink +=
960
0
                            media_component->min_requested_bandwidth_dl;
961
0
                    }
962
0
                }
963
0
            } else if (gx_flow.direction == OGS_FLOW_UPLINK_ONLY) {
964
0
                if (sub->flow_usage == OGS_FLOW_USAGE_RTCP) {
965
0
                    if (media_component->rr_bandwidth &&
966
0
                        media_component->rs_bandwidth) {
967
0
                        pcc_rule->qos.mbr.uplink +=
968
0
                            (media_component->rr_bandwidth +
969
0
                            media_component->rs_bandwidth);
970
0
                    } else if (media_component->max_requested_bandwidth_ul) {
971
0
                        if (media_component->rr_bandwidth &&
972
0
                            !media_component->rs_bandwidth) {
973
0
                            pcc_rule->qos.mbr.uplink +=
974
0
                                ogs_max(0.05 *
975
0
                                    media_component->max_requested_bandwidth_ul,
976
0
                                    media_component->rr_bandwidth);
977
0
                        }
978
0
                        if (!media_component->rr_bandwidth &&
979
0
                            media_component->rs_bandwidth) {
980
0
                            pcc_rule->qos.mbr.uplink +=
981
0
                                ogs_max(0.05 *
982
0
                                    media_component->max_requested_bandwidth_ul,
983
0
                                    media_component->rs_bandwidth);
984
0
                        }
985
0
                        if (!media_component->rr_bandwidth &&
986
0
                            !media_component->rs_bandwidth) {
987
0
                            pcc_rule->qos.mbr.uplink +=
988
0
                                0.05 *
989
0
                                    media_component->max_requested_bandwidth_ul;
990
0
                        }
991
0
                    }
992
0
                } else {
993
0
                    if (gx_flow.description) {
994
0
                        pcc_rule->qos.mbr.uplink +=
995
0
                            media_component->max_requested_bandwidth_ul;
996
0
                        pcc_rule->qos.gbr.uplink +=
997
0
                            media_component->min_requested_bandwidth_ul;
998
0
                    }
999
0
                }
1000
0
            } else
1001
0
                ogs_assert_if_reached();
1002
1003
0
            OGS_FLOW_FREE(&gx_flow);
1004
0
        }
1005
0
    }
1006
1007
0
    if (pcc_rule->qos.mbr.downlink == 0) {
1008
0
        pcc_rule->qos.mbr.downlink +=
1009
0
            media_component->max_requested_bandwidth_dl;
1010
0
        pcc_rule->qos.mbr.downlink +=
1011
0
            (media_component->rr_bandwidth + media_component->rs_bandwidth);
1012
0
    }
1013
1014
0
    if (pcc_rule->qos.mbr.uplink == 0) {
1015
0
        pcc_rule->qos.mbr.uplink +=
1016
0
            media_component->max_requested_bandwidth_ul;
1017
0
        pcc_rule->qos.mbr.uplink +=
1018
0
            (media_component->rr_bandwidth + media_component->rs_bandwidth);
1019
0
    }
1020
1021
0
    if (pcc_rule->qos.gbr.downlink == 0)
1022
0
        pcc_rule->qos.gbr.downlink = pcc_rule->qos.mbr.downlink;
1023
0
    if (pcc_rule->qos.gbr.uplink == 0)
1024
0
        pcc_rule->qos.gbr.uplink = pcc_rule->qos.mbr.uplink;
1025
1026
0
    return OGS_OK;
1027
0
}