Coverage Report

Created: 2023-09-25 07:12

/src/open5gs/lib/gtp/context.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019 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-gtp.h"
21
22
int __ogs_gtp_domain;
23
static ogs_gtp_context_t self;
24
static int context_initialized = 0;
25
26
static OGS_POOL(pool, ogs_gtp_node_t);
27
static OGS_POOL(ogs_gtpu_resource_pool, ogs_gtpu_resource_t);
28
29
void ogs_gtp_context_init(int num_of_gtpu_resource)
30
0
{
31
0
    ogs_assert(context_initialized == 0);
32
33
    /* Initialize GTP context */
34
0
    memset(&self, 0, sizeof(ogs_gtp_context_t));
35
36
0
    ogs_log_install_domain(&__ogs_gtp_domain, "gtp", ogs_core()->log.level);
37
38
0
    ogs_pool_init(&pool, ogs_app()->pool.gtp_node);
39
0
    ogs_pool_init(&ogs_gtpu_resource_pool, num_of_gtpu_resource);
40
41
0
    context_initialized = 1;
42
0
}
43
44
void ogs_gtp_context_final(void)
45
0
{
46
0
    ogs_assert(context_initialized == 1);
47
48
0
    ogs_gtpu_resource_remove_all(&self.gtpu_resource_list);
49
0
    ogs_pool_final(&ogs_gtpu_resource_pool);
50
51
0
    ogs_gtp_node_remove_all(&self.gtpu_peer_list);
52
0
    ogs_pool_final(&pool);
53
54
0
    context_initialized = 0;
55
0
}
56
57
ogs_gtp_context_t *ogs_gtp_self(void)
58
0
{
59
0
    return &self;
60
0
}
61
62
static int ogs_gtp_context_prepare(void)
63
0
{
64
0
    self.gtpc_port = OGS_GTPV2_C_UDP_PORT;
65
0
    self.gtpu_port = OGS_GTPV1_U_UDP_PORT;
66
67
0
    return OGS_OK;
68
0
}
69
70
static int ogs_gtp_context_validation(const char *local)
71
0
{
72
0
    return OGS_OK;
73
0
}
74
75
int ogs_gtp_context_parse_config(const char *local, const char *remote)
76
0
{
77
0
    int rv;
78
0
    yaml_document_t *document = NULL;
79
0
    ogs_yaml_iter_t root_iter;
80
81
0
    document = ogs_app()->document;
82
0
    ogs_assert(document);
83
84
0
    rv = ogs_gtp_context_prepare();
85
0
    if (rv != OGS_OK) return rv;
86
87
0
    ogs_yaml_iter_init(&root_iter, document);
88
0
    while (ogs_yaml_iter_next(&root_iter)) {
89
0
        const char *root_key = ogs_yaml_iter_key(&root_iter);
90
0
        ogs_assert(root_key);
91
0
        if (!strcmp(root_key, local)) {
92
0
            ogs_yaml_iter_t local_iter;
93
0
            ogs_yaml_iter_recurse(&root_iter, &local_iter);
94
0
            while (ogs_yaml_iter_next(&local_iter)) {
95
0
                const char *local_key = ogs_yaml_iter_key(&local_iter);
96
0
                ogs_assert(local_key);
97
0
                if (!strcmp(local_key, "gtpc")) {
98
0
                    ogs_yaml_iter_t gtpc_array, gtpc_iter;
99
0
                    ogs_yaml_iter_recurse(&local_iter, &gtpc_array);
100
0
                    do {
101
0
                        int family = AF_UNSPEC;
102
0
                        int i, num = 0;
103
0
                        const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
104
0
                        uint16_t port = self.gtpc_port;
105
0
                        const char *dev = NULL;
106
0
                        ogs_sockaddr_t *addr = NULL;
107
108
0
                        ogs_sockopt_t option;
109
0
                        bool is_option = false;
110
111
0
                        if (ogs_yaml_iter_type(&gtpc_array) ==
112
0
                                YAML_MAPPING_NODE) {
113
0
                            memcpy(&gtpc_iter, &gtpc_array,
114
0
                                    sizeof(ogs_yaml_iter_t));
115
0
                        } else if (ogs_yaml_iter_type(&gtpc_array) ==
116
0
                            YAML_SEQUENCE_NODE) {
117
0
                            if (!ogs_yaml_iter_next(&gtpc_array))
118
0
                                break;
119
0
                            ogs_yaml_iter_recurse(&gtpc_array, &gtpc_iter);
120
0
                        } else if (ogs_yaml_iter_type(&gtpc_array) ==
121
0
                            YAML_SCALAR_NODE) {
122
0
                            break;
123
0
                        } else
124
0
                            ogs_assert_if_reached();
125
126
0
                        while (ogs_yaml_iter_next(&gtpc_iter)) {
127
0
                            const char *gtpc_key =
128
0
                                ogs_yaml_iter_key(&gtpc_iter);
129
0
                            ogs_assert(gtpc_key);
130
0
                            if (!strcmp(gtpc_key, "family")) {
131
0
                                const char *v = ogs_yaml_iter_value(&gtpc_iter);
132
0
                                if (v) family = atoi(v);
133
0
                                if (family != AF_UNSPEC &&
134
0
                                    family != AF_INET && family != AF_INET6) {
135
0
                                    ogs_warn("Ignore family(%d) : "
136
0
                                        "AF_UNSPEC(%d), "
137
0
                                        "AF_INET(%d), AF_INET6(%d) ",
138
0
                                        family, AF_UNSPEC, AF_INET, AF_INET6);
139
0
                                    family = AF_UNSPEC;
140
0
                                }
141
0
                            } else if (!strcmp(gtpc_key, "addr") ||
142
0
                                    !strcmp(gtpc_key, "name")) {
143
0
                                ogs_yaml_iter_t hostname_iter;
144
0
                                ogs_yaml_iter_recurse(&gtpc_iter,
145
0
                                        &hostname_iter);
146
0
                                ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
147
0
                                    YAML_MAPPING_NODE);
148
149
0
                                do {
150
0
                                    if (ogs_yaml_iter_type(&hostname_iter) ==
151
0
                                            YAML_SEQUENCE_NODE) {
152
0
                                        if (!ogs_yaml_iter_next(&hostname_iter))
153
0
                                            break;
154
0
                                    }
155
156
0
                                    ogs_assert(num < OGS_MAX_NUM_OF_HOSTNAME);
157
0
                                    hostname[num++] =
158
0
                                        ogs_yaml_iter_value(&hostname_iter);
159
0
                                } while (
160
0
                                    ogs_yaml_iter_type(&hostname_iter) ==
161
0
                                        YAML_SEQUENCE_NODE);
162
0
                            } else if (!strcmp(gtpc_key, "port")) {
163
0
                                const char *v = ogs_yaml_iter_value(&gtpc_iter);
164
0
                                if (v) port = atoi(v);
165
0
                            } else if (!strcmp(gtpc_key, "dev")) {
166
0
                                dev = ogs_yaml_iter_value(&gtpc_iter);
167
0
                            } else if (!strcmp(gtpc_key, "option")) {
168
0
                                rv = ogs_app_config_parse_sockopt(
169
0
                                        &gtpc_iter, &option);
170
0
                                if (rv != OGS_OK) return rv;
171
0
                                is_option = true;
172
0
                            } else if (!strcmp(gtpc_key, "tac")) {
173
                                /* Nothing */
174
0
                            } else if (!strcmp(gtpc_key, "e_cell_id")) {
175
                                /* Nothing */
176
0
                            } else
177
0
                                ogs_warn("unknown key `%s`", gtpc_key);
178
0
                        }
179
180
0
                        addr = NULL;
181
0
                        for (i = 0; i < num; i++) {
182
0
                            rv = ogs_addaddrinfo(&addr,
183
0
                                    family, hostname[i], port, 0);
184
0
                            ogs_assert(rv == OGS_OK);
185
0
                        }
186
187
0
                        if (addr) {
188
0
                            if (ogs_app()->parameter.no_ipv4 == 0)
189
0
                                ogs_socknode_add(
190
0
                                    &self.gtpc_list, AF_INET, addr,
191
0
                                    is_option ? &option : NULL);
192
0
                            if (ogs_app()->parameter.no_ipv6 == 0)
193
0
                                ogs_socknode_add(
194
0
                                    &self.gtpc_list6, AF_INET6, addr,
195
0
                                    is_option ? &option : NULL);
196
0
                            ogs_freeaddrinfo(addr);
197
0
                        }
198
199
0
                        if (dev) {
200
0
                            rv = ogs_socknode_probe(
201
0
                                    ogs_app()->parameter.no_ipv4 ?
202
0
                                        NULL : &self.gtpc_list,
203
0
                                    ogs_app()->parameter.no_ipv6 ?
204
0
                                        NULL : &self.gtpc_list6,
205
0
                                    dev, port,
206
0
                                    is_option ? &option : NULL);
207
0
                            ogs_assert(rv == OGS_OK);
208
0
                        }
209
210
0
                    } while (ogs_yaml_iter_type(&gtpc_array) ==
211
0
                            YAML_SEQUENCE_NODE);
212
213
0
                    if (ogs_list_empty(&self.gtpc_list) &&
214
0
                        ogs_list_empty(&self.gtpc_list6)) {
215
0
                        rv = ogs_socknode_probe(
216
0
                                ogs_app()->parameter.no_ipv4 ?
217
0
                                    NULL : &self.gtpc_list,
218
0
                                ogs_app()->parameter.no_ipv6 ?
219
0
                                    NULL : &self.gtpc_list6,
220
0
                                NULL, self.gtpc_port, NULL);
221
0
                        ogs_assert(rv == OGS_OK);
222
0
                    }
223
0
                } else if (!strcmp(local_key, "gtpu")) {
224
0
                    ogs_list_t list, list6;
225
0
                    ogs_socknode_t *node = NULL, *node6 = NULL;
226
0
                    ogs_socknode_t *iter = NULL, *next_iter = NULL;
227
228
0
                    ogs_yaml_iter_t gtpu_array, gtpu_iter;
229
0
                    ogs_yaml_iter_recurse(&local_iter, &gtpu_array);
230
231
0
                    do {
232
0
                        int family = AF_UNSPEC;
233
0
                        int i, num_of_hostname = 0;
234
0
                        const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
235
0
                        int num_of_advertise = 0;
236
0
                        const char *advertise[OGS_MAX_NUM_OF_HOSTNAME];
237
0
                        uint16_t port = self.gtpu_port;
238
0
                        const char *dev = NULL;
239
0
                        ogs_sockaddr_t *addr = NULL;
240
0
                        ogs_sockaddr_t *adv_addr = NULL;
241
0
                        ogs_sockaddr_t *adv_addr6 = NULL;
242
0
                        const char *teid_range_indication = NULL;
243
0
                        const char *teid_range = NULL;
244
0
                        const char *network_instance = NULL;
245
0
                        const char *source_interface = NULL;
246
247
0
                        ogs_sockopt_t option;
248
0
                        bool is_option = false;
249
250
0
                        if (ogs_yaml_iter_type(&gtpu_array) ==
251
0
                                YAML_MAPPING_NODE) {
252
0
                            memcpy(&gtpu_iter, &gtpu_array,
253
0
                                    sizeof(ogs_yaml_iter_t));
254
0
                        } else if (ogs_yaml_iter_type(&gtpu_array) ==
255
0
                            YAML_SEQUENCE_NODE) {
256
0
                            if (!ogs_yaml_iter_next(&gtpu_array))
257
0
                                break;
258
0
                            ogs_yaml_iter_recurse(&gtpu_array, &gtpu_iter);
259
0
                        } else if (ogs_yaml_iter_type(&gtpu_array) ==
260
0
                            YAML_SCALAR_NODE) {
261
0
                            break;
262
0
                        } else
263
0
                            ogs_assert_if_reached();
264
265
0
                        while (ogs_yaml_iter_next(&gtpu_iter)) {
266
0
                            const char *gtpu_key =
267
0
                                ogs_yaml_iter_key(&gtpu_iter);
268
0
                            ogs_assert(gtpu_key);
269
270
0
                            if (ogs_list_count(&self.gtpu_resource_list) >=
271
0
                                OGS_MAX_NUM_OF_GTPU_RESOURCE) {
272
0
                                ogs_warn("[Overflow]: Number of User Plane "
273
0
                                    "IP Resource <= %d",
274
0
                                    OGS_MAX_NUM_OF_GTPU_RESOURCE);
275
0
                                break;
276
0
                            }
277
278
0
                            if (!strcmp(gtpu_key, "family")) {
279
0
                                const char *v = ogs_yaml_iter_value(&gtpu_iter);
280
0
                                if (v) family = atoi(v);
281
0
                                if (family != AF_UNSPEC &&
282
0
                                    family != AF_INET && family != AF_INET6) {
283
0
                                    ogs_warn("Ignore family(%d)"
284
0
                                        ": AF_UNSPEC(%d), "
285
0
                                        "AF_INET(%d), AF_INET6(%d) ",
286
0
                                        family, AF_UNSPEC, AF_INET, AF_INET6);
287
0
                                    family = AF_UNSPEC;
288
0
                                }
289
0
                            } else if (!strcmp(gtpu_key, "addr") ||
290
0
                                    !strcmp(gtpu_key, "name")) {
291
0
                                ogs_yaml_iter_t hostname_iter;
292
0
                                ogs_yaml_iter_recurse(
293
0
                                        &gtpu_iter, &hostname_iter);
294
0
                                ogs_assert(ogs_yaml_iter_type(&hostname_iter) !=
295
0
                                    YAML_MAPPING_NODE);
296
297
0
                                do {
298
0
                                    if (ogs_yaml_iter_type(&hostname_iter) ==
299
0
                                            YAML_SEQUENCE_NODE) {
300
0
                                        if (!ogs_yaml_iter_next(&hostname_iter))
301
0
                                            break;
302
0
                                    }
303
304
0
                                    ogs_assert(num_of_hostname <
305
0
                                            OGS_MAX_NUM_OF_HOSTNAME);
306
0
                                    hostname[num_of_hostname++] =
307
0
                                        ogs_yaml_iter_value(&hostname_iter);
308
0
                                } while (
309
0
                                    ogs_yaml_iter_type(&hostname_iter) ==
310
0
                                        YAML_SEQUENCE_NODE);
311
0
                            } else if (!strcmp(gtpu_key, "advertise")) {
312
0
                                ogs_yaml_iter_t advertise_iter;
313
0
                                ogs_yaml_iter_recurse(
314
0
                                        &gtpu_iter, &advertise_iter);
315
0
                                ogs_assert(ogs_yaml_iter_type(
316
0
                                    &advertise_iter) != YAML_MAPPING_NODE);
317
318
0
                                do {
319
0
                                    if (ogs_yaml_iter_type(&advertise_iter) ==
320
0
                                            YAML_SEQUENCE_NODE) {
321
0
                                        if (!ogs_yaml_iter_next(
322
0
                                            &advertise_iter))
323
0
                                            break;
324
0
                                    }
325
326
0
                                    ogs_assert(num_of_advertise <
327
0
                                            OGS_MAX_NUM_OF_HOSTNAME);
328
0
                                    advertise[num_of_advertise++] =
329
0
                                        ogs_yaml_iter_value(&advertise_iter);
330
0
                                } while (
331
0
                                    ogs_yaml_iter_type(&advertise_iter) ==
332
0
                                        YAML_SEQUENCE_NODE);
333
0
                            } else if (!strcmp(gtpu_key, "port")) {
334
0
                                const char *v = ogs_yaml_iter_value(&gtpu_iter);
335
0
                                if (v) port = atoi(v);
336
0
                            } else if (!strcmp(gtpu_key, "dev")) {
337
0
                                dev = ogs_yaml_iter_value(&gtpu_iter);
338
0
                            } else if (!strcmp(gtpu_key, "option")) {
339
0
                                rv = ogs_app_config_parse_sockopt(
340
0
                                        &gtpu_iter, &option);
341
0
                                if (rv != OGS_OK) return rv;
342
0
                                is_option = true;
343
0
                            } else if (!strcmp(gtpu_key,
344
0
                                        "teid_range_indication")) {
345
0
                                teid_range_indication =
346
0
                                    ogs_yaml_iter_value(&gtpu_iter);
347
0
                            } else if (!strcmp(gtpu_key,
348
0
                                        "teid_range")) {
349
0
                                teid_range = ogs_yaml_iter_value(&gtpu_iter);
350
0
                            } else if (!strcmp(gtpu_key,
351
0
                                        "network_instance")) {
352
0
                                network_instance =
353
0
                                    ogs_yaml_iter_value(&gtpu_iter);
354
0
                            } else if (!strcmp(gtpu_key,
355
0
                                        "source_interface")) {
356
0
                                source_interface =
357
0
                                    ogs_yaml_iter_value(&gtpu_iter);
358
0
                            } else
359
0
                                ogs_warn("unknown key `%s`", gtpu_key);
360
0
                        }
361
362
0
                        addr = NULL;
363
0
                        for (i = 0; i < num_of_hostname; i++) {
364
0
                            rv = ogs_addaddrinfo(&addr,
365
0
                                    family, hostname[i], port, 0);
366
0
                            ogs_assert(rv == OGS_OK);
367
0
                        }
368
369
0
                        ogs_list_init(&list);
370
0
                        ogs_list_init(&list6);
371
372
0
                        if (addr) {
373
0
                            if (ogs_app()->parameter.no_ipv4 == 0)
374
0
                                ogs_socknode_add(
375
0
                                    &list, AF_INET, addr,
376
0
                                    is_option ? &option : NULL);
377
0
                            if (ogs_app()->parameter.no_ipv6 == 0)
378
0
                                ogs_socknode_add(
379
0
                                    &list6, AF_INET6, addr,
380
0
                                    is_option ? &option : NULL);
381
0
                            ogs_freeaddrinfo(addr);
382
0
                        }
383
384
0
                        if (dev) {
385
0
                            rv = ogs_socknode_probe(
386
0
                                ogs_app()->parameter.no_ipv4 ? NULL : &list,
387
0
                                ogs_app()->parameter.no_ipv6 ? NULL : &list6,
388
0
                                dev, port,
389
0
                                is_option ? &option : NULL);
390
0
                            ogs_assert(rv == OGS_OK);
391
0
                        }
392
393
0
                        adv_addr = NULL;
394
0
                        for (i = 0; i < num_of_advertise; i++) {
395
0
                            rv = ogs_addaddrinfo(&adv_addr,
396
0
                                    family, advertise[i], port, 0);
397
0
                            ogs_assert(rv == OGS_OK);
398
0
                        }
399
0
                        rv = ogs_copyaddrinfo(&adv_addr6, adv_addr);
400
0
                        ogs_assert(rv == OGS_OK);
401
402
0
                        rv = ogs_filteraddrinfo(&adv_addr, AF_INET);
403
0
                        ogs_assert(rv == OGS_OK);
404
0
                        rv = ogs_filteraddrinfo(&adv_addr6, AF_INET6);
405
0
                        ogs_assert(rv == OGS_OK);
406
407
                        /* Find first IPv4/IPv6 address in the list.
408
                         *
409
                         * In the following configuration,
410
                         * 127.0.0.4, 127.0.0.5 and 2001:db8:cafe::1 are ignored
411
                         * on PFCP Assocation Response message's
412
                         * user plane IP resource information.
413
                         *
414
                         * gtpu:
415
                         *   - addr:
416
                         *     - 127.0.0.3
417
                         *     - ::1
418
                         *     - 127.0.0.4
419
                         *     - 127.0.0.5
420
                         *     - 2001:db8:cafe::1
421
                         *
422
                         * To include all user plane IP resource information,
423
                         * configure as below:
424
                         *
425
                         * gtpu:
426
                         *   - addr:
427
                         *     - 127.0.0.3
428
                         *     - ::1
429
                         *   - addr: 127.0.0.4
430
                         *   - addr
431
                         *     - 127.0.0.5
432
                         *     - 2001:db8:cafe::1
433
                         */
434
0
                        node = ogs_list_first(&list);
435
0
                        node6 = ogs_list_first(&list6);
436
0
                        if (node || node6) {
437
0
                            ogs_user_plane_ip_resource_info_t info;
438
439
0
                            memset(&info, 0, sizeof(info));
440
0
                            ogs_sockaddr_to_user_plane_ip_resource_info(
441
0
                                    adv_addr ? adv_addr :
442
0
                                        node ? node->addr : NULL,
443
0
                                    adv_addr6 ? adv_addr6 :
444
0
                                        node6 ? node6->addr : NULL,
445
0
                                    &info);
446
447
0
                            if (teid_range_indication) {
448
0
                                info.teidri = atoi(teid_range_indication);
449
0
                                if (teid_range) {
450
0
                                    info.teid_range = atoi(teid_range);
451
0
                                }
452
0
                            }
453
0
                            if (network_instance) {
454
0
                                info.assoni = 1;
455
0
                                ogs_cpystrn(info.network_instance,
456
0
                                    network_instance, OGS_MAX_APN_LEN+1);
457
0
                            }
458
0
                            if (source_interface) {
459
0
                                info.assosi = 1;
460
0
                                info.source_interface = atoi(source_interface);
461
0
                            }
462
463
0
                            ogs_gtpu_resource_add(
464
0
                                &self.gtpu_resource_list, &info);
465
0
                        }
466
467
0
                        ogs_list_for_each_safe(&list, next_iter, iter)
468
0
                            ogs_list_add(&self.gtpu_list, iter);
469
0
                        ogs_list_for_each_safe(&list6, next_iter, iter)
470
0
                            ogs_list_add(&self.gtpu_list, iter);
471
472
0
                        ogs_freeaddrinfo(adv_addr);
473
0
                        ogs_freeaddrinfo(adv_addr6);
474
475
0
                    } while (ogs_yaml_iter_type(&gtpu_array) ==
476
0
                            YAML_SEQUENCE_NODE);
477
478
0
                    if (ogs_list_first(&self.gtpu_list) == NULL) {
479
0
                        ogs_list_init(&list);
480
0
                        ogs_list_init(&list6);
481
482
0
                        rv = ogs_socknode_probe(
483
0
                                ogs_app()->parameter.no_ipv4 ? NULL : &list,
484
0
                                ogs_app()->parameter.no_ipv6 ? NULL : &list6,
485
0
                                NULL, self.gtpu_port, NULL);
486
0
                        ogs_assert(rv == OGS_OK);
487
488
                        /*
489
                         * The first tuple IPv4/IPv6 are added
490
                         * in User Plane IP resource information.
491
                         *
492
                         * TEID Range, Network Instance, Source Interface
493
                         * cannot be configured in automatic IP detection.
494
                         */
495
0
                        node = ogs_list_first(&list);
496
0
                        node6 = ogs_list_first(&list6);
497
0
                        if (node || node6) {
498
0
                            ogs_user_plane_ip_resource_info_t info;
499
500
0
                            memset(&info, 0, sizeof(info));
501
0
                            ogs_sockaddr_to_user_plane_ip_resource_info(
502
0
                                    node ? node->addr : NULL,
503
0
                                    node6 ? node6->addr : NULL,
504
0
                                    &info);
505
506
0
                            ogs_gtpu_resource_add(
507
0
                                &self.gtpu_resource_list, &info);
508
0
                        }
509
510
0
                        ogs_list_for_each_safe(&list, next_iter, iter)
511
0
                            ogs_list_add(&self.gtpu_list, iter);
512
0
                        ogs_list_for_each_safe(&list6, next_iter, iter)
513
0
                            ogs_list_add(&self.gtpu_list, iter);
514
0
                    }
515
0
                }
516
0
            }
517
0
        }
518
0
    }
519
520
0
    rv = ogs_gtp_context_validation(local);
521
0
    if (rv != OGS_OK) return rv;
522
523
0
    return OGS_OK;
524
0
}
525
526
ogs_gtp_node_t *ogs_gtp_node_new(ogs_sockaddr_t *sa_list)
527
0
{
528
0
    ogs_gtp_node_t *node = NULL;
529
530
0
    ogs_assert(sa_list);
531
532
0
    ogs_pool_alloc(&pool, &node);
533
0
    if (!node) {
534
0
        ogs_error("ogs_pool_alloc() failed");
535
0
        return NULL;
536
0
    }
537
0
    memset(node, 0, sizeof(ogs_gtp_node_t));
538
539
0
    node->sa_list = sa_list;
540
541
0
    ogs_list_init(&node->local_list);
542
0
    ogs_list_init(&node->remote_list);
543
544
0
    return node;
545
0
}
546
547
void ogs_gtp_node_free(ogs_gtp_node_t *node)
548
0
{
549
0
    ogs_assert(node);
550
551
0
    ogs_gtp_xact_delete_all(node);
552
553
0
    ogs_freeaddrinfo(node->sa_list);
554
0
    ogs_pool_free(&pool, node);
555
0
}
556
557
ogs_gtp_node_t *ogs_gtp_node_add_by_f_teid(
558
        ogs_list_t *list, ogs_gtp2_f_teid_t *f_teid, uint16_t port)
559
0
{
560
0
    int rv;
561
0
    ogs_gtp_node_t *node = NULL;
562
0
    ogs_sockaddr_t *addr = NULL;
563
564
0
    ogs_assert(list);
565
0
    ogs_assert(f_teid);
566
0
    ogs_assert(port);
567
568
0
    rv = ogs_gtp2_f_teid_to_sockaddr(f_teid, port, &addr);
569
0
    if (rv != OGS_OK) {
570
0
        ogs_error("ogs_gtp2_f_teid_to_sockaddr() failed");
571
0
        return NULL;
572
0
    }
573
574
0
    rv = ogs_filter_ip_version(
575
0
            &addr,
576
0
            ogs_app()->parameter.no_ipv4,
577
0
            ogs_app()->parameter.no_ipv6,
578
0
            ogs_app()->parameter.prefer_ipv4);
579
0
    if (!addr) {
580
0
        ogs_error("ogs_filter_ip_version() failed");
581
0
        return NULL;
582
0
    }
583
584
#if 0 /* deprecated */
585
    rv = ogs_socknode_fill_scope_id_in_local(addr);
586
    ogs_assert(rv == OGS_OK);
587
#endif
588
589
0
    node = ogs_gtp_node_new(addr);
590
0
    if (!node) {
591
0
        ogs_error("ogs_gtp_node_new() failed");
592
0
        ogs_freeaddrinfo(addr);
593
0
        return NULL;
594
0
    }
595
596
0
    rv = ogs_gtp2_f_teid_to_ip(f_teid, &node->ip);
597
0
    if (rv != OGS_OK) {
598
0
        ogs_error("ogs_gtp2_f_teid_to_ip() failed");
599
0
        ogs_freeaddrinfo(addr);
600
0
        return NULL;
601
0
    }
602
603
0
    ogs_list_add(list, node);
604
605
0
    return node;
606
0
}
607
608
ogs_gtp_node_t *ogs_gtp_node_add_by_addr(ogs_list_t *list, ogs_sockaddr_t *addr)
609
0
{
610
0
    ogs_gtp_node_t *gnode = NULL;
611
0
    ogs_sockaddr_t *new = NULL;
612
613
0
    ogs_assert(list);
614
0
    ogs_assert(addr);
615
616
0
    ogs_assert(OGS_OK == ogs_copyaddrinfo(&new, addr));
617
0
    gnode = ogs_gtp_node_new(new);
618
0
    if (!gnode) {
619
0
        ogs_error("ogs_gtp_node_new() failed");
620
0
        ogs_freeaddrinfo(new);
621
0
        return NULL;
622
0
    }
623
624
0
    memcpy(&gnode->addr, new, sizeof gnode->addr);
625
626
0
    ogs_list_add(list, gnode);
627
628
0
    return gnode;
629
0
}
630
631
void ogs_gtp_node_remove(ogs_list_t *list, ogs_gtp_node_t *node)
632
0
{
633
0
    ogs_assert(node);
634
635
0
    ogs_list_remove(list, node);
636
637
0
    ogs_gtp_node_free(node);
638
0
}
639
640
void ogs_gtp_node_remove_all(ogs_list_t *list)
641
0
{
642
0
    ogs_gtp_node_t *node = NULL, *next_node = NULL;
643
644
0
    ogs_list_for_each_safe(list, next_node, node)
645
0
        ogs_gtp_node_remove(list, node);
646
0
}
647
648
ogs_gtp_node_t *ogs_gtp_node_find_by_addr(
649
        ogs_list_t *list, ogs_sockaddr_t *addr)
650
0
{
651
0
    ogs_gtp_node_t *node = NULL;
652
653
0
    ogs_assert(list);
654
0
    ogs_assert(addr);
655
656
0
    ogs_list_for_each(list, node) {
657
0
        if (ogs_sockaddr_is_equal(&node->addr, addr) == true)
658
0
            break;
659
0
    }
660
661
0
    return node;
662
0
}
663
664
ogs_gtp_node_t *ogs_gtp_node_find_by_f_teid(
665
        ogs_list_t *list, ogs_gtp2_f_teid_t *f_teid)
666
0
{
667
0
    int rv;
668
0
    ogs_gtp_node_t *node = NULL;
669
0
    ogs_ip_t ip;
670
671
0
    ogs_assert(list);
672
0
    ogs_assert(f_teid);
673
674
0
    rv = ogs_gtp2_f_teid_to_ip(f_teid, &ip);
675
0
    ogs_assert(rv == OGS_OK);
676
677
0
    ogs_list_for_each(list, node) {
678
0
        if (memcmp(&node->ip, &ip, sizeof(ip)) == 0)
679
0
            break;
680
0
    }
681
682
0
    return node;
683
0
}
684
685
ogs_gtp_node_t *ogs_gtp_node_add_by_ip(
686
        ogs_list_t *list, ogs_ip_t *ip, uint16_t port)
687
0
{
688
0
    int rv;
689
0
    ogs_gtp_node_t *node = NULL;
690
0
    ogs_sockaddr_t *addr = NULL;
691
692
0
    ogs_assert(list);
693
0
    ogs_assert(ip);
694
0
    ogs_assert(port);
695
696
0
    rv = ogs_ip_to_sockaddr(ip, port, &addr);
697
0
    if (rv != OGS_OK) {
698
0
        ogs_error("ogs_ip_to_sockaddr() failed");
699
0
        return NULL;
700
0
    }
701
702
0
    rv = ogs_filter_ip_version(
703
0
            &addr,
704
0
            ogs_app()->parameter.no_ipv4,
705
0
            ogs_app()->parameter.no_ipv6,
706
0
            ogs_app()->parameter.prefer_ipv4);
707
0
    if (!addr) {
708
0
        ogs_error("ogs_filter_ip_version() failed");
709
0
        return NULL;
710
0
    }
711
712
#if 0 /* deprecated */
713
    rv = ogs_socknode_fill_scope_id_in_local(addr);
714
    ogs_assert(rv == OGS_OK);
715
#endif
716
717
0
    node = ogs_gtp_node_new(addr);
718
0
    if (!node) {
719
0
        ogs_error("ogs_gtp_node_new() failed");
720
0
        ogs_freeaddrinfo(addr);
721
0
        return NULL;
722
0
    }
723
724
0
    memcpy(&node->ip, ip, sizeof(*ip));
725
726
0
    ogs_list_add(list, node);
727
728
0
    return node;
729
0
}
730
731
ogs_gtp_node_t *ogs_gtp_node_find_by_ip(ogs_list_t *list, ogs_ip_t *ip)
732
0
{
733
0
    ogs_gtp_node_t *node = NULL;
734
735
0
    ogs_assert(list);
736
0
    ogs_assert(ip);
737
738
0
    ogs_list_for_each(list, node) {
739
0
        if (memcmp(&node->ip, ip, sizeof(*ip)) == 0)
740
0
            break;
741
0
    }
742
743
0
    return node;
744
0
}
745
746
ogs_gtpu_resource_t *ogs_gtpu_resource_add(ogs_list_t *list,
747
        ogs_user_plane_ip_resource_info_t *info)
748
0
{
749
0
    ogs_gtpu_resource_t *resource = NULL;
750
751
0
    ogs_assert(list);
752
0
    ogs_assert(info);
753
754
0
    ogs_pool_alloc(&ogs_gtpu_resource_pool, &resource);
755
0
    ogs_assert(resource);
756
757
0
    memcpy(&resource->info, info, sizeof(*info));
758
759
0
    ogs_list_add(list, resource);
760
761
0
    return resource;
762
0
}
763
764
void ogs_gtpu_resource_remove(ogs_list_t *list,
765
        ogs_gtpu_resource_t *resource)
766
0
{
767
0
    ogs_assert(list);
768
0
    ogs_assert(resource);
769
770
0
    ogs_list_remove(list, resource);
771
772
0
    ogs_pool_free(&ogs_gtpu_resource_pool, resource);
773
0
}
774
775
void ogs_gtpu_resource_remove_all(ogs_list_t *list)
776
0
{
777
0
    ogs_gtpu_resource_t *resource = NULL, *next_resource = NULL;
778
779
0
    ogs_assert(list);
780
781
0
    ogs_list_for_each_safe(list, next_resource, resource)
782
0
        ogs_gtpu_resource_remove(list, resource);
783
0
}