Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/pfcp/context.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 "app/ogs-app.h"
21
#include "ogs-pfcp.h"
22
23
int __ogs_pfcp_domain;
24
static ogs_pfcp_context_t self;
25
static int context_initialized = 0;
26
27
static OGS_POOL(ogs_pfcp_node_pool, ogs_pfcp_node_t);
28
29
static OGS_POOL(ogs_pfcp_far_pool, ogs_pfcp_far_t);
30
static OGS_POOL(ogs_pfcp_urr_pool, ogs_pfcp_urr_t);
31
static OGS_POOL(ogs_pfcp_qer_pool, ogs_pfcp_qer_t);
32
static OGS_POOL(ogs_pfcp_bar_pool, ogs_pfcp_bar_t);
33
34
static OGS_POOL(ogs_pfcp_pdr_pool, ogs_pfcp_pdr_t);
35
static OGS_POOL(ogs_pfcp_pdr_teid_pool, ogs_pool_id_t);
36
static ogs_pool_id_t *pdr_random_to_index;
37
38
static OGS_POOL(ogs_pfcp_rule_pool, ogs_pfcp_rule_t);
39
40
static OGS_POOL(ogs_pfcp_dev_pool, ogs_pfcp_dev_t);
41
static OGS_POOL(ogs_pfcp_subnet_pool, ogs_pfcp_subnet_t);
42
43
void ogs_pfcp_context_init(void)
44
0
{
45
0
    int i;
46
0
    ogs_assert(context_initialized == 0);
47
48
    /* Initialize SMF context */
49
0
    memset(&self, 0, sizeof(ogs_pfcp_context_t));
50
51
0
    self.local_recovery = ogs_time_ntp32_now();
52
53
0
    ogs_log_install_domain(&__ogs_pfcp_domain, "pfcp", ogs_core()->log.level);
54
55
0
    ogs_pool_init(&ogs_pfcp_node_pool, ogs_app()->pool.nf);
56
57
0
    ogs_pool_init(&ogs_pfcp_far_pool,
58
0
            ogs_app()->pool.sess * OGS_MAX_NUM_OF_FAR);
59
0
    ogs_pool_init(&ogs_pfcp_urr_pool,
60
0
            ogs_app()->pool.sess * OGS_MAX_NUM_OF_URR);
61
0
    ogs_pool_init(&ogs_pfcp_qer_pool,
62
0
            ogs_app()->pool.sess * OGS_MAX_NUM_OF_QER);
63
0
    ogs_pool_init(&ogs_pfcp_bar_pool,
64
0
            ogs_app()->pool.sess * OGS_MAX_NUM_OF_BAR);
65
66
0
    ogs_pool_init(&ogs_pfcp_pdr_pool,
67
0
            ogs_app()->pool.sess * OGS_MAX_NUM_OF_PDR);
68
0
    ogs_pool_init(&ogs_pfcp_pdr_teid_pool, ogs_pfcp_pdr_pool.size);
69
0
    ogs_pool_random_id_generate(&ogs_pfcp_pdr_teid_pool);
70
71
0
    pdr_random_to_index = ogs_calloc(
72
0
            sizeof(ogs_pool_id_t), ogs_pfcp_pdr_pool.size+1);
73
0
    ogs_assert(pdr_random_to_index);
74
0
    for (i = 0; i < ogs_pfcp_pdr_pool.size; i++)
75
0
        pdr_random_to_index[ogs_pfcp_pdr_teid_pool.array[i]] = i;
76
77
0
    ogs_pool_init(&ogs_pfcp_rule_pool,
78
0
            ogs_app()->pool.sess *
79
0
            OGS_MAX_NUM_OF_PDR * OGS_MAX_NUM_OF_FLOW_IN_PDR);
80
81
0
    ogs_pool_init(&ogs_pfcp_dev_pool, OGS_MAX_NUM_OF_DEV);
82
0
    ogs_pool_init(&ogs_pfcp_subnet_pool, OGS_MAX_NUM_OF_SUBNET);
83
84
0
    self.object_teid_hash = ogs_hash_make();
85
0
    ogs_assert(self.object_teid_hash);
86
0
    self.far_f_teid_hash = ogs_hash_make();
87
0
    ogs_assert(self.far_f_teid_hash);
88
0
    self.far_teid_hash = ogs_hash_make();
89
0
    ogs_assert(self.far_teid_hash);
90
91
0
    context_initialized = 1;
92
0
}
93
94
void ogs_pfcp_context_final(void)
95
0
{
96
0
    ogs_assert(context_initialized == 1);
97
98
0
    ogs_assert(self.object_teid_hash);
99
0
    ogs_hash_destroy(self.object_teid_hash);
100
0
    ogs_assert(self.far_f_teid_hash);
101
0
    ogs_hash_destroy(self.far_f_teid_hash);
102
0
    ogs_assert(self.far_teid_hash);
103
0
    ogs_hash_destroy(self.far_teid_hash);
104
105
0
    ogs_pfcp_dev_remove_all();
106
0
    ogs_pfcp_subnet_remove_all();
107
108
0
    ogs_pool_final(&ogs_pfcp_dev_pool);
109
0
    ogs_pool_final(&ogs_pfcp_subnet_pool);
110
0
    ogs_pool_final(&ogs_pfcp_rule_pool);
111
112
0
    ogs_pool_final(&ogs_pfcp_pdr_pool);
113
0
    ogs_pool_final(&ogs_pfcp_pdr_teid_pool);
114
0
    ogs_free(pdr_random_to_index);
115
116
0
    ogs_pool_final(&ogs_pfcp_far_pool);
117
0
    ogs_pool_final(&ogs_pfcp_urr_pool);
118
0
    ogs_pool_final(&ogs_pfcp_qer_pool);
119
0
    ogs_pool_final(&ogs_pfcp_bar_pool);
120
121
0
    ogs_pfcp_node_remove_all(&self.pfcp_peer_list);
122
123
0
    ogs_pool_final(&ogs_pfcp_node_pool);
124
125
0
    context_initialized = 0;
126
0
}
127
128
ogs_pfcp_context_t *ogs_pfcp_self(void)
129
0
{
130
0
    return &self;
131
0
}
132
133
static int ogs_pfcp_context_prepare(void)
134
0
{
135
0
    self.pfcp_port = OGS_PFCP_UDP_PORT;
136
137
0
    self.tun_ifname = "ogstun";
138
139
0
    return OGS_OK;
140
0
}
141
142
static int ogs_pfcp_check_subnet_overlapping(void)
143
0
{
144
0
    ogs_pfcp_subnet_t *subnet = NULL;
145
0
    ogs_pfcp_subnet_t *next_subnet = NULL;
146
0
    char buf1[OGS_ADDRSTRLEN];
147
0
    char buf2[OGS_ADDRSTRLEN];
148
0
    int rv = OGS_OK;
149
150
0
    ogs_list_for_each(&self.subnet_list, subnet){
151
0
        for (next_subnet = ogs_list_next(subnet); (next_subnet);
152
0
                next_subnet = ogs_list_next(next_subnet)) {
153
0
            if ((strlen(subnet->dnn) == 0 ||
154
0
                 strlen(next_subnet->dnn) == 0 ||
155
0
                (strcmp(subnet->dnn, next_subnet->dnn)) == 0) &&
156
0
                subnet->gw.family == next_subnet->gw.family) {
157
0
                uint32_t *addr1 = subnet->sub.sub;
158
0
                uint32_t *addr2 = next_subnet->sub.sub;
159
0
                uint32_t mask[4];
160
0
                int i;
161
                /* Get smaller subnet mask for IPv4 or IPv6 */
162
0
                for (i = 0; i < 4 ; i++) {
163
0
                    mask[i] = (subnet->sub.mask[i] & next_subnet->sub.mask[i]);
164
0
                }
165
                /* Compare masked subnets if they overlap */
166
0
                if (subnet->gw.family == AF_INET) {
167
0
                    if ((addr1[0] & mask[0]) == (addr2[0] & mask[0])) {
168
0
                        ogs_error("Overlapping subnets in SMF configuration file: %s/%d and %s/%d",
169
0
                                OGS_INET_NTOP(&subnet->gw.sub[0], buf1),
170
0
                                subnet->prefixlen,
171
0
                                OGS_INET_NTOP(&next_subnet->gw.sub[0], buf2),
172
0
                                next_subnet->prefixlen);
173
0
                        rv = OGS_ERROR;
174
0
                    }
175
0
                } else if (subnet->gw.family == AF_INET6) {
176
0
                    if (((addr1[0] & mask[0]) == (addr2[0] & mask[0])) &&
177
0
                        ((addr1[1] & mask[1]) == (addr2[1] & mask[1])) &&
178
0
                        ((addr1[2] & mask[2]) == (addr2[2] & mask[2])) &&
179
0
                        ((addr1[3] & mask[3]) == (addr2[3] & mask[3]))) {
180
0
                        ogs_error("Overlapping subnets in SMF configuration file: %s/%d and %s/%d",
181
0
                                OGS_INET6_NTOP(&subnet->gw.sub[0], buf1),
182
0
                                subnet->prefixlen,
183
0
                                OGS_INET6_NTOP(&next_subnet->gw.sub[0], buf2),
184
0
                                next_subnet->prefixlen);
185
0
                        rv = OGS_ERROR;
186
0
                    }
187
0
                } else {
188
0
                    ogs_error("Invalid family in subnet configuration [%d]",
189
0
                            subnet->gw.family);
190
0
                    rv = OGS_ERROR;
191
0
                    ogs_assert_if_reached();
192
0
                }
193
0
            }
194
0
        }
195
0
    }
196
197
0
    return rv;
198
0
}
199
200
static int ogs_pfcp_context_validation(const char *local)
201
0
{
202
0
    if (ogs_list_first(&self.pfcp_list) == NULL &&
203
0
        ogs_list_first(&self.pfcp_list6) == NULL) {
204
0
        ogs_error("No %s.pfcp.address: in '%s'", local, ogs_app()->file);
205
0
        return OGS_ERROR;
206
0
    }
207
0
    if (ogs_pfcp_check_subnet_overlapping() != OGS_OK)
208
0
        return OGS_ERROR;
209
210
0
    return OGS_OK;
211
0
}
212
213
int ogs_pfcp_context_parse_config(const char *local, const char *remote)
214
0
{
215
0
    int rv;
216
0
    yaml_document_t *document = NULL;
217
0
    ogs_yaml_iter_t root_iter;
218
0
    int idx = 0;
219
220
0
    document = ogs_app()->document;
221
0
    ogs_assert(document);
222
223
0
    rv = ogs_pfcp_context_prepare();
224
0
    if (rv != OGS_OK) return rv;
225
226
0
    ogs_yaml_iter_init(&root_iter, document);
227
0
    while (ogs_yaml_iter_next(&root_iter)) {
228
0
        const char *root_key = ogs_yaml_iter_key(&root_iter);
229
0
        ogs_assert(root_key);
230
0
        if ((!strcmp(root_key, local)) &&
231
0
            idx++ == ogs_app()->config_section_id) {
232
0
            ogs_yaml_iter_t local_iter;
233
0
            ogs_yaml_iter_recurse(&root_iter, &local_iter);
234
0
            while (ogs_yaml_iter_next(&local_iter)) {
235
0
                const char *local_key = ogs_yaml_iter_key(&local_iter);
236
0
                ogs_assert(local_key);
237
0
                if (!strcmp(local_key, "pfcp")) {
238
0
                    ogs_yaml_iter_t pfcp_iter;
239
0
                    ogs_yaml_iter_recurse(&local_iter, &pfcp_iter);
240
0
                    while (ogs_yaml_iter_next(&pfcp_iter)) {
241
0
                        const char *pfcp_key = ogs_yaml_iter_key(&pfcp_iter);
242
0
                        ogs_assert(pfcp_key);
243
0
                        if (!strcmp(pfcp_key, "server")) {
244
0
                            ogs_yaml_iter_t server_iter, server_array;
245
0
                            ogs_yaml_iter_recurse(&pfcp_iter, &server_array);
246
0
                            do {
247
0
                                int family = AF_UNSPEC;
248
0
                                int i, num = 0;
249
0
                                const char *hostname[OGS_MAX_NUM_OF_HOSTNAME];
250
0
                                int num_of_advertise = 0;
251
0
                                const char *advertise[OGS_MAX_NUM_OF_HOSTNAME];
252
0
                                uint16_t port = self.pfcp_port;
253
0
                                const char *dev = NULL;
254
0
                                ogs_sockaddr_t *addr = NULL;
255
256
0
                                ogs_sockopt_t option;
257
0
                                bool is_option = false;
258
259
0
                                if (ogs_yaml_iter_type(&server_array) ==
260
0
                                        YAML_MAPPING_NODE) {
261
0
                                    memcpy(&server_iter, &server_array,
262
0
                                            sizeof(ogs_yaml_iter_t));
263
0
                                } else if (ogs_yaml_iter_type(&server_array) ==
264
0
                                    YAML_SEQUENCE_NODE) {
265
0
                                    if (!ogs_yaml_iter_next(&server_array))
266
0
                                        break;
267
0
                                    ogs_yaml_iter_recurse(
268
0
                                            &server_array, &server_iter);
269
0
                                } else if (ogs_yaml_iter_type(&server_array) ==
270
0
                                    YAML_SCALAR_NODE) {
271
0
                                    break;
272
0
                                } else
273
0
                                    ogs_assert_if_reached();
274
275
0
                                while (ogs_yaml_iter_next(&server_iter)) {
276
0
                                    const char *server_key =
277
0
                                        ogs_yaml_iter_key(&server_iter);
278
0
                                    ogs_assert(server_key);
279
0
                                    if (!strcmp(server_key, "family")) {
280
0
                                        const char *v =
281
0
                                            ogs_yaml_iter_value(&server_iter);
282
0
                                        if (v) family = atoi(v);
283
0
                                        if (family != AF_UNSPEC &&
284
0
                                            family != AF_INET &&
285
0
                                            family != AF_INET6) {
286
0
                                            ogs_warn("Ignore family(%d) : "
287
0
                                                "AF_UNSPEC(%d), "
288
0
                                                "AF_INET(%d), AF_INET6(%d) ",
289
0
                                                family,
290
0
                                                AF_UNSPEC, AF_INET, AF_INET6);
291
0
                                            family = AF_UNSPEC;
292
0
                                        }
293
0
                                    } else if (!strcmp(server_key, "address")) {
294
0
                                        ogs_yaml_iter_t hostname_iter;
295
0
                                        ogs_yaml_iter_recurse(&server_iter,
296
0
                                                &hostname_iter);
297
0
                                        ogs_assert(ogs_yaml_iter_type(
298
0
                                                    &hostname_iter) !=
299
0
                                                YAML_MAPPING_NODE);
300
301
0
                                        do {
302
0
                                            if (ogs_yaml_iter_type(
303
0
                                                        &hostname_iter) ==
304
0
                                                    YAML_SEQUENCE_NODE) {
305
0
                                                if (!ogs_yaml_iter_next(
306
0
                                                            &hostname_iter))
307
0
                                                    break;
308
0
                                            }
309
310
0
                                            ogs_assert(num <
311
0
                                                    OGS_MAX_NUM_OF_HOSTNAME);
312
0
                                            hostname[num++] =
313
0
                                                ogs_yaml_iter_value(
314
0
                                                        &hostname_iter);
315
0
                                        } while (ogs_yaml_iter_type(
316
0
                                                    &hostname_iter) ==
317
0
                                                YAML_SEQUENCE_NODE);
318
0
                                    } else if (!strcmp(
319
0
                                                server_key, "advertise")) {
320
0
                                        ogs_yaml_iter_t hostname_iter;
321
0
                                        ogs_yaml_iter_recurse(&server_iter,
322
0
                                                &hostname_iter);
323
0
                                        ogs_assert(ogs_yaml_iter_type(
324
0
                                                    &hostname_iter) !=
325
0
                                                YAML_MAPPING_NODE);
326
327
0
                                        do {
328
0
                                            if (ogs_yaml_iter_type(
329
0
                                                        &hostname_iter) ==
330
0
                                                    YAML_SEQUENCE_NODE) {
331
0
                                                if (!ogs_yaml_iter_next(
332
0
                                                            &hostname_iter))
333
0
                                                    break;
334
0
                                            }
335
336
0
                                            ogs_assert(num <
337
0
                                                    OGS_MAX_NUM_OF_HOSTNAME);
338
0
                                            advertise[num_of_advertise++] =
339
0
                                                ogs_yaml_iter_value(
340
0
                                                        &hostname_iter);
341
0
                                        } while (ogs_yaml_iter_type(
342
0
                                                    &hostname_iter) ==
343
0
                                                YAML_SEQUENCE_NODE);
344
0
                                    } else if (!strcmp(server_key, "port")) {
345
0
                                        const char *v =
346
0
                                            ogs_yaml_iter_value(&server_iter);
347
0
                                        if (v) {
348
0
                                            port = atoi(v);
349
0
                                            self.pfcp_port = port;
350
0
                                        }
351
0
                                    } else if (!strcmp(server_key, "dev")) {
352
0
                                        dev = ogs_yaml_iter_value(&server_iter);
353
0
                                    } else if (!strcmp(server_key, "option")) {
354
0
                                        rv = ogs_app_parse_sockopt_config(
355
0
                                                &server_iter, &option);
356
0
                                        if (rv != OGS_OK) {
357
0
                                            ogs_error("ogs_app_parse_sockopt_"
358
0
                                                    "config() failed");
359
0
                                            return rv;
360
0
                                        }
361
0
                                        is_option = true;
362
0
                                    } else if (!strcmp(server_key, "apn") ||
363
0
                                                !strcmp(server_key, "dnn")) {
364
                                        /* Skip */
365
0
                                    } else
366
0
                                        ogs_warn("unknown key `%s`",
367
0
                                                server_key);
368
0
                                }
369
370
                                /* Add address information */
371
0
                                addr = NULL;
372
0
                                for (i = 0; i < num; i++) {
373
0
                                    rv = ogs_addaddrinfo(&addr,
374
0
                                            family, hostname[i], port, 0);
375
0
                                    ogs_assert(rv == OGS_OK);
376
0
                                }
377
378
                                /* Add each address as a separate socknode */
379
0
                                if (addr) {
380
0
                                    ogs_sockaddr_t *current = addr;
381
0
                                    while (current) {
382
0
                                        if (current->ogs_sa_family ==
383
0
                                                AF_INET &&
384
0
                                            ogs_global_conf()->
385
0
                                                parameter.no_ipv4 == 0) {
386
0
                                            ogs_socknode_add(&self.pfcp_list,
387
0
                                                             AF_INET, current,
388
0
                                                             is_option ?
389
0
                                                             &option : NULL);
390
0
                                        }
391
0
                                        if (current->ogs_sa_family ==
392
0
                                                AF_INET6 &&
393
0
                                            ogs_global_conf()->
394
0
                                                parameter.no_ipv6 == 0) {
395
0
                                            ogs_socknode_add(&self.pfcp_list6,
396
0
                                                             AF_INET6, current,
397
0
                                                             is_option ?
398
0
                                                             &option : NULL);
399
0
                                        }
400
0
                                        current = current->next;
401
0
                                    }
402
0
                                    ogs_freeaddrinfo(addr);
403
0
                                }
404
405
                                /* Process advertise addresses if needed */
406
0
                                addr = NULL;
407
0
                                for (i = 0; i < num_of_advertise; i++) {
408
0
                                    rv = ogs_addaddrinfo(&addr,
409
0
                                            family, advertise[i], port, 0);
410
0
                                    ogs_assert(rv == OGS_OK);
411
0
                                }
412
413
0
                                if (addr) {
414
0
                                    if (ogs_global_conf()->
415
0
                                            parameter.no_ipv4 == 0 &&
416
0
                                        !self.pfcp_advertise) {
417
0
                                        ogs_copyaddrinfo(
418
0
                                                &self.pfcp_advertise, addr);
419
0
                                        ogs_filteraddrinfo(
420
0
                                                &self.pfcp_advertise, AF_INET);
421
0
                                    }
422
0
                                    if (ogs_global_conf()->
423
0
                                            parameter.no_ipv6 == 0 &&
424
0
                                        !self.pfcp_advertise6) {
425
0
                                        ogs_copyaddrinfo(
426
0
                                                &self.pfcp_advertise6, addr);
427
0
                                        ogs_filteraddrinfo(
428
0
                                                &self.pfcp_advertise6,
429
0
                                                AF_INET6);
430
0
                                    }
431
0
                                    ogs_freeaddrinfo(addr);
432
0
                                }
433
434
                                /* Bind to device if specified */
435
0
                                if (dev) {
436
0
                                    rv = ogs_socknode_probe(
437
0
                                            ogs_global_conf()->
438
0
                                            parameter.no_ipv4 ?
439
0
                                                NULL : &self.pfcp_list,
440
0
                                            ogs_global_conf()->
441
0
                                            parameter.no_ipv6 ?
442
0
                                                NULL : &self.pfcp_list6,
443
0
                                            dev, self.pfcp_port,
444
0
                                            is_option ? &option : NULL);
445
0
                                    ogs_assert(rv == OGS_OK);
446
0
                                }
447
448
0
                            } while (ogs_yaml_iter_type(&server_array) ==
449
0
                                    YAML_SEQUENCE_NODE);
450
0
                        } else if (!strcmp(pfcp_key, "client")) {
451
0
                            ogs_yaml_iter_t client_iter;
452
0
                            ogs_yaml_iter_recurse(&pfcp_iter, &client_iter);
453
0
                            while (ogs_yaml_iter_next(&client_iter)) {
454
0
                                const char *client_key =
455
0
                                    ogs_yaml_iter_key(&client_iter);
456
0
                                ogs_assert(client_key);
457
0
                                if (!strcmp(client_key, remote)) {
458
0
                                    ogs_yaml_iter_t remote_array, remote_iter;
459
0
                                    ogs_yaml_iter_recurse(
460
0
                                            &client_iter, &remote_array);
461
0
                                    do {
462
0
                                        ogs_pfcp_node_t *node = NULL;
463
0
                                        ogs_sockaddr_t *addr = NULL;
464
0
                                        int family = AF_UNSPEC;
465
0
                                        int i, num = 0;
466
0
                                        const char *hostname[
467
0
                                            OGS_MAX_NUM_OF_HOSTNAME];
468
0
                                        uint16_t port = self.pfcp_port;
469
0
                                        uint16_t tac[OGS_MAX_NUM_OF_TAI] = {0,};
470
0
                                        int num_of_tac = 0;
471
0
                                        const char *dnn[OGS_MAX_NUM_OF_DNN];
472
0
                                        int num_of_dnn = 0;
473
0
                                        uint32_t e_cell_id[
474
0
                                            OGS_MAX_NUM_OF_CELL_ID] = {0,};
475
0
                                        int num_of_e_cell_id = 0;
476
0
                                        uint64_t nr_cell_id[
477
0
                                            OGS_MAX_NUM_OF_CELL_ID] = {0,};
478
0
                                        int num_of_nr_cell_id = 0;
479
480
0
                                        if (ogs_yaml_iter_type(&remote_array) ==
481
0
                                                YAML_MAPPING_NODE) {
482
0
                                            memcpy(&remote_iter, &remote_array,
483
0
                                                    sizeof(ogs_yaml_iter_t));
484
0
                                        } else if (ogs_yaml_iter_type(
485
0
                                                    &remote_array) ==
486
0
                                                YAML_SEQUENCE_NODE) {
487
0
                                            if (!ogs_yaml_iter_next(
488
0
                                                        &remote_array))
489
0
                                                break;
490
0
                                            ogs_yaml_iter_recurse(&remote_array,
491
0
                                                    &remote_iter);
492
0
                                        } else if (ogs_yaml_iter_type(
493
0
                                                    &remote_array) ==
494
0
                                                YAML_SCALAR_NODE) {
495
0
                                            break;
496
0
                                        } else
497
0
                                            ogs_assert_if_reached();
498
499
0
                                        while (ogs_yaml_iter_next(
500
0
                                                    &remote_iter)) {
501
0
                                            const char *remote_key =
502
0
                                                ogs_yaml_iter_key(&remote_iter);
503
0
                                            ogs_assert(remote_key);
504
0
                                            if (!strcmp(remote_key, "family")) {
505
0
                                                const char *v =
506
0
                                                    ogs_yaml_iter_value(
507
0
                                                            &remote_iter);
508
0
                                                if (v) family = atoi(v);
509
0
                                                if (family != AF_UNSPEC &&
510
0
                                                    family != AF_INET &&
511
0
                                                    family != AF_INET6) {
512
0
                                                    ogs_warn(
513
0
                                                        "Ignore family(%d) : "
514
0
                                                        "AF_UNSPEC(%d), "
515
0
                                                        "AF_INET(%d), "
516
0
                                                        "AF_INET6(%d) ",
517
0
                                                        family, AF_UNSPEC,
518
0
                                                        AF_INET, AF_INET6);
519
0
                                                    family = AF_UNSPEC;
520
0
                                                }
521
0
                                            } else if (!strcmp(remote_key,
522
0
                                                        "address")) {
523
0
                                                ogs_yaml_iter_t hostname_iter;
524
0
                                                ogs_yaml_iter_recurse(
525
0
                                                        &remote_iter,
526
0
                                                        &hostname_iter);
527
0
                                                ogs_assert(ogs_yaml_iter_type(
528
0
                                                            &hostname_iter) !=
529
0
                                                        YAML_MAPPING_NODE);
530
531
0
                                                do {
532
0
                                                    if (ogs_yaml_iter_type(
533
0
                                                            &hostname_iter) ==
534
0
                                                        YAML_SEQUENCE_NODE) {
535
0
                                                        if (!ogs_yaml_iter_next(
536
0
                                                                &hostname_iter))
537
0
                                                            break;
538
0
                                                    }
539
540
0
                                                    ogs_assert(num <
541
0
                                                    OGS_MAX_NUM_OF_HOSTNAME);
542
0
                                                    hostname[num++] =
543
0
                                                        ogs_yaml_iter_value(
544
0
                                                            &hostname_iter);
545
0
                                                } while (ogs_yaml_iter_type(
546
0
                                                            &hostname_iter) ==
547
0
                                                        YAML_SEQUENCE_NODE);
548
0
                                            } else if (!strcmp(remote_key,
549
0
                                                        "advertise")) {
550
                                                /* Nothing in client */
551
0
                                            } else if (!strcmp(remote_key,
552
0
                                                        "port")) {
553
0
                                                const char *v =
554
0
                                                    ogs_yaml_iter_value(
555
0
                                                            &remote_iter);
556
0
                                                if (v) port = atoi(v);
557
0
                                            } else if (!strcmp(remote_key,
558
0
                                                        "tac")) {
559
0
                                                ogs_yaml_iter_t tac_iter;
560
0
                                                ogs_yaml_iter_recurse(
561
0
                                                        &remote_iter,
562
0
                                                        &tac_iter);
563
0
                                                ogs_assert(ogs_yaml_iter_type(
564
0
                                                            &tac_iter) !=
565
0
                                                        YAML_MAPPING_NODE);
566
567
0
                                                do {
568
0
                                                    const char *v = NULL;
569
570
0
                                                    ogs_assert(num_of_tac <
571
0
                                                            OGS_MAX_NUM_OF_TAI);
572
0
                                                    if (ogs_yaml_iter_type(
573
0
                                                                &tac_iter) ==
574
0
                                                        YAML_SEQUENCE_NODE) {
575
0
                                                        if (!ogs_yaml_iter_next(
576
0
                                                                    &tac_iter))
577
0
                                                            break;
578
0
                                                    }
579
580
0
                                                    v = ogs_yaml_iter_value(
581
0
                                                            &tac_iter);
582
0
                                                    if (v) {
583
0
                                                        tac[num_of_tac] =
584
0
                                                            atoi(v);
585
0
                                                        num_of_tac++;
586
0
                                                    }
587
0
                                                } while (ogs_yaml_iter_type(
588
0
                                                            &tac_iter) ==
589
0
                                                        YAML_SEQUENCE_NODE);
590
0
                                            } else if (!strcmp(
591
0
                                                        remote_key, "apn") ||
592
0
                                                    !strcmp(
593
0
                                                        remote_key, "dnn")) {
594
0
                                                ogs_yaml_iter_t dnn_iter;
595
0
                                                ogs_yaml_iter_recurse(
596
0
                                                        &remote_iter,
597
0
                                                        &dnn_iter);
598
0
                                                ogs_assert(ogs_yaml_iter_type(
599
0
                                                            &dnn_iter) !=
600
0
                                                        YAML_MAPPING_NODE);
601
602
0
                                                do {
603
0
                                                    const char *v = NULL;
604
605
0
                                                    ogs_assert(num_of_dnn <
606
0
                                                            OGS_MAX_NUM_OF_DNN);
607
0
                                                    if (ogs_yaml_iter_type(
608
0
                                                                &dnn_iter) ==
609
0
                                                        YAML_SEQUENCE_NODE) {
610
0
                                                        if (!ogs_yaml_iter_next(
611
0
                                                                    &dnn_iter))
612
0
                                                            break;
613
0
                                                    }
614
615
0
                                                    v = ogs_yaml_iter_value(
616
0
                                                            &dnn_iter);
617
0
                                                    if (v) {
618
0
                                                        dnn[num_of_dnn] = v;
619
0
                                                        num_of_dnn++;
620
0
                                                    }
621
0
                                                } while (ogs_yaml_iter_type(
622
0
                                                            &dnn_iter) ==
623
0
                                                        YAML_SEQUENCE_NODE);
624
0
                                            } else if (!strcmp(remote_key,
625
0
                                                        "e_cell_id")) {
626
0
                                                ogs_yaml_iter_t e_cell_id_iter;
627
0
                                                ogs_yaml_iter_recurse(
628
0
                                                        &remote_iter,
629
0
                                                        &e_cell_id_iter);
630
0
                                                ogs_assert(ogs_yaml_iter_type(
631
0
                                                            &e_cell_id_iter) !=
632
0
                                                        YAML_MAPPING_NODE);
633
634
0
                                                do {
635
0
                                                    const char *v = NULL;
636
637
0
                                                    ogs_assert(
638
0
                                                            num_of_e_cell_id <
639
0
                                                        OGS_MAX_NUM_OF_ENB_ID);
640
0
                                                    if (ogs_yaml_iter_type(
641
0
                                                            &e_cell_id_iter) ==
642
0
                                                        YAML_SEQUENCE_NODE) {
643
0
                                                        if (!ogs_yaml_iter_next(
644
0
                                                            &e_cell_id_iter))
645
0
                                                            break;
646
0
                                                    }
647
648
0
                                                    v = ogs_yaml_iter_value(
649
0
                                                            &e_cell_id_iter);
650
0
                                                    if (v) {
651
0
                                                        e_cell_id[
652
0
                                                            num_of_e_cell_id] =
653
0
                                                        ogs_uint64_from_string_hexadecimal(
654
0
                                                                (char*)v);
655
0
                                                        num_of_e_cell_id++;
656
0
                                                    }
657
0
                                                } while (ogs_yaml_iter_type(
658
0
                                                            &e_cell_id_iter) ==
659
0
                                                        YAML_SEQUENCE_NODE);
660
0
                                            } else if (!strcmp(remote_key,
661
0
                                                        "nr_cell_id")) {
662
0
                                                ogs_yaml_iter_t nr_cell_id_iter;
663
0
                                                ogs_yaml_iter_recurse(
664
0
                                                        &remote_iter,
665
0
                                                        &nr_cell_id_iter);
666
0
                                                ogs_assert(ogs_yaml_iter_type(
667
0
                                                            &nr_cell_id_iter) !=
668
0
                                                        YAML_MAPPING_NODE);
669
670
0
                                                do {
671
0
                                                    const char *v = NULL;
672
673
0
                                                    ogs_assert(
674
0
                                                            num_of_nr_cell_id <
675
0
                                                        OGS_MAX_NUM_OF_ENB_ID);
676
0
                                                    if (ogs_yaml_iter_type(
677
0
                                                            &nr_cell_id_iter) ==
678
0
                                                        YAML_SEQUENCE_NODE) {
679
0
                                                        if (!ogs_yaml_iter_next(
680
0
                                                            &nr_cell_id_iter))
681
0
                                                            break;
682
0
                                                    }
683
684
0
                                                    v = ogs_yaml_iter_value(
685
0
                                                            &nr_cell_id_iter);
686
0
                                                    if (v) {
687
0
                                                        nr_cell_id[
688
0
                                                            num_of_nr_cell_id] =
689
0
                                                        ogs_uint64_from_string_hexadecimal(
690
0
                                                                (char*)v);
691
0
                                                        num_of_nr_cell_id++;
692
0
                                                    }
693
0
                                                } while (ogs_yaml_iter_type(
694
0
                                                        &nr_cell_id_iter) ==
695
0
                                                        YAML_SEQUENCE_NODE);
696
0
                                            } else
697
0
                                                ogs_warn("unknown key `%s`",
698
0
                                                        remote_key);
699
0
                                        }
700
701
0
                                        addr = NULL;
702
0
                                        for (i = 0; i < num; i++) {
703
0
                                            rv = ogs_addaddrinfo(&addr, family,
704
0
                                                    hostname[i], port, 0);
705
0
                                            ogs_assert(rv == OGS_OK);
706
0
                                        }
707
708
0
                                        ogs_filter_ip_version(&addr,
709
0
                                                ogs_global_conf()->parameter.
710
0
                                                no_ipv4,
711
0
                                                ogs_global_conf()->parameter.
712
0
                                                no_ipv6,
713
0
                                                ogs_global_conf()->parameter.
714
0
                                                prefer_ipv4);
715
716
0
                                        if (addr == NULL) continue;
717
718
0
                                        node = ogs_pfcp_node_new(addr);
719
0
                                        ogs_assert(node);
720
0
                                        ogs_list_add(
721
0
                                                &self.pfcp_peer_list, node);
722
723
0
                                        node->num_of_tac = num_of_tac;
724
0
                                        if (num_of_tac != 0)
725
0
                                            memcpy(node->tac,
726
0
                                                    tac, sizeof(node->tac));
727
728
0
                                        node->num_of_dnn = num_of_dnn;
729
0
                                        if (num_of_dnn != 0)
730
0
                                            memcpy(node->dnn,
731
0
                                                    dnn, sizeof(node->dnn));
732
733
0
                                        node->num_of_e_cell_id =
734
0
                                            num_of_e_cell_id;
735
0
                                        if (num_of_e_cell_id != 0)
736
0
                                            memcpy(node->e_cell_id, e_cell_id,
737
0
                                                    sizeof(node->e_cell_id));
738
739
0
                                        node->num_of_nr_cell_id =
740
0
                                            num_of_nr_cell_id;
741
0
                                        if (num_of_nr_cell_id != 0)
742
0
                                            memcpy(node->nr_cell_id, nr_cell_id,
743
0
                                                    sizeof(node->nr_cell_id));
744
745
0
                                    } while (ogs_yaml_iter_type(
746
0
                                                &remote_array) ==
747
0
                                            YAML_SEQUENCE_NODE);
748
0
                                }
749
0
                            }
750
0
                        } else
751
0
                            ogs_warn("unknown key `%s`", pfcp_key);
752
0
                    }
753
0
                } else if (!strcmp(local_key, "session")) {
754
0
                    ogs_yaml_iter_t subnet_array, subnet_iter;
755
0
                    ogs_yaml_iter_recurse(&local_iter, &subnet_array);
756
757
0
                    do {
758
0
                        ogs_pfcp_subnet_t *subnet = NULL;
759
0
                        const char *ipstr = NULL;
760
0
                        const char *gateway = NULL;
761
0
                        const char *mask_or_numbits = NULL;
762
0
                        const char *dnn = NULL;
763
0
                        const char *dev = self.tun_ifname;
764
0
                        const char *low[OGS_MAX_NUM_OF_SUBNET_RANGE];
765
0
                        const char *high[OGS_MAX_NUM_OF_SUBNET_RANGE];
766
0
                        int i, num = 0;
767
768
0
                        memset(low, 0, sizeof(low));
769
0
                        memset(high, 0, sizeof(high));
770
771
0
                        if (ogs_yaml_iter_type(&subnet_array) ==
772
0
                                YAML_MAPPING_NODE) {
773
0
                            memcpy(&subnet_iter, &subnet_array,
774
0
                                    sizeof(ogs_yaml_iter_t));
775
0
                        } else if (ogs_yaml_iter_type(&subnet_array) ==
776
0
                                YAML_SEQUENCE_NODE) {
777
0
                            if (!ogs_yaml_iter_next(&subnet_array))
778
0
                                break;
779
0
                            ogs_yaml_iter_recurse(&subnet_array, &subnet_iter);
780
0
                        } else if (ogs_yaml_iter_type(&subnet_array) ==
781
0
                                YAML_SCALAR_NODE) {
782
0
                            break;
783
0
                        } else
784
0
                            ogs_assert_if_reached();
785
786
0
                        while (ogs_yaml_iter_next(&subnet_iter)) {
787
0
                            const char *subnet_key =
788
0
                                ogs_yaml_iter_key(&subnet_iter);
789
0
                            ogs_assert(subnet_key);
790
0
                            if (!strcmp(subnet_key, "subnet")) {
791
0
                                char *v =
792
0
                                    (char *)ogs_yaml_iter_value(&subnet_iter);
793
0
                                if (v) {
794
0
                                    ipstr = (const char *)strsep(&v, "/");
795
0
                                    if (ipstr) {
796
0
                                        mask_or_numbits = (const char *)v;
797
0
                                    }
798
0
                                }
799
0
                            } else if (!strcmp(subnet_key, "gateway")) {
800
0
                                gateway = ogs_yaml_iter_value(&subnet_iter);
801
0
                            } else if (!strcmp(subnet_key, "apn") ||
802
0
                                        !strcmp(subnet_key, "dnn")) {
803
0
                                dnn = ogs_yaml_iter_value(&subnet_iter);
804
0
                            } else if (!strcmp(subnet_key, "dev")) {
805
0
                                dev = ogs_yaml_iter_value(&subnet_iter);
806
0
                            } else if (!strcmp(subnet_key, "range")) {
807
0
                                ogs_yaml_iter_t range_iter;
808
0
                                ogs_yaml_iter_recurse(
809
0
                                        &subnet_iter, &range_iter);
810
0
                                ogs_assert(ogs_yaml_iter_type(&range_iter) !=
811
0
                                    YAML_MAPPING_NODE);
812
0
                                do {
813
0
                                    char *v = NULL;
814
815
0
                                    if (ogs_yaml_iter_type(&range_iter) ==
816
0
                                            YAML_SEQUENCE_NODE) {
817
0
                                        if (!ogs_yaml_iter_next(&range_iter))
818
0
                                            break;
819
0
                                    }
820
821
0
                                    v = (char *)
822
0
                                        ogs_yaml_iter_value(&range_iter);
823
0
                                    if (v) {
824
0
                                        ogs_assert(num <
825
0
                                                OGS_MAX_NUM_OF_SUBNET_RANGE);
826
0
                                        low[num] =
827
0
                                            (const char *)strsep(&v, "-");
828
0
                                        if (low[num] && strlen(low[num]) == 0)
829
0
                                            low[num] = NULL;
830
831
0
                                        high[num] = (const char *)v;
832
0
                                        if (high[num] && strlen(high[num]) == 0)
833
0
                                            high[num] = NULL;
834
0
                                    }
835
836
0
                                    if (low[num] || high[num]) num++;
837
0
                                } while (
838
0
                                    ogs_yaml_iter_type(&range_iter) ==
839
0
                                    YAML_SEQUENCE_NODE);
840
0
                            } else
841
0
                                ogs_warn("unknown key `%s`", subnet_key);
842
0
                        }
843
844
0
                        subnet = ogs_pfcp_subnet_add(
845
0
                                ipstr, mask_or_numbits, gateway, dnn, dev);
846
0
                        ogs_assert(subnet);
847
848
0
                        subnet->num_of_range = num;
849
0
                        for (i = 0; i < subnet->num_of_range; i++) {
850
0
                            subnet->range[i].low = low[i];
851
0
                            subnet->range[i].high = high[i];
852
0
                        }
853
854
0
                    } while (ogs_yaml_iter_type(&subnet_array) ==
855
0
                            YAML_SEQUENCE_NODE);
856
0
                }
857
0
            }
858
0
        }
859
0
    }
860
861
0
    rv = ogs_pfcp_context_validation(local);
862
0
    if (rv != OGS_OK) return rv;
863
864
0
    return OGS_OK;
865
0
}
866
867
/******************************************************************************
868
 * ogs_pfcp_node_new()
869
 *  - Initialize node_id.type to OGS_PFCP_NODE_ID_UNKNOWN
870
 *  - So the node can later be updated with a real Node ID via
871
 *    ogs_pfcp_node_merge() once we learn it from PFCP messages.
872
 ******************************************************************************/
873
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *config_addr)
874
0
{
875
0
    int rv;
876
0
    ogs_pfcp_node_t *node = NULL;
877
878
0
    ogs_pool_alloc(&ogs_pfcp_node_pool, &node);
879
0
    if (!node) {
880
0
        ogs_error("No memory: ogs_pool_alloc() failed [%s]",
881
0
                ogs_sockaddr_to_string_static(config_addr));
882
0
        return NULL;
883
0
    }
884
0
    memset(node, 0, sizeof(ogs_pfcp_node_t));
885
886
    /* Store config_addr, if any */
887
0
    node->config_addr = config_addr;
888
889
    /* If config_addr is given, copy it immediately into addr_list */
890
0
    if (config_addr) {
891
0
        rv = ogs_copyaddrinfo(&node->addr_list, config_addr);
892
0
        if (rv != OGS_OK) {
893
0
            ogs_error("ogs_copyaddrinfo() failed");
894
0
            ogs_pool_free(&ogs_pfcp_node_pool, node);
895
0
            return NULL;
896
0
        }
897
0
    }
898
899
    /*
900
     * Initialize node->node_id to UNKNOWN, meaning "no Node ID assigned yet".
901
     */
902
0
    memset(&node->node_id, 0, sizeof(node->node_id));
903
0
    node->node_id.type = OGS_PFCP_NODE_ID_UNKNOWN;
904
905
0
    ogs_list_init(&node->local_list);
906
0
    ogs_list_init(&node->remote_list);
907
908
0
    return node;
909
0
}
910
911
void ogs_pfcp_node_free(ogs_pfcp_node_t *node)
912
0
{
913
0
    ogs_assert(node);
914
915
0
    ogs_pfcp_xact_delete_all(node);
916
917
0
    ogs_freeaddrinfo(node->config_addr);
918
0
    ogs_freeaddrinfo(node->addr_list);
919
920
0
    ogs_pool_free(&ogs_pfcp_node_pool, node);
921
0
}
922
923
/******************************************************************************
924
 * ogs_pfcp_node_add()
925
 *  - Create a new PFCP node, then call ogs_pfcp_node_merge() to handle
926
 *    IPv4/IPv6 or FQDN logic.
927
 ******************************************************************************/
928
ogs_pfcp_node_t *ogs_pfcp_node_add(ogs_list_t *list,
929
    ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
930
0
{
931
0
    ogs_pfcp_node_t *node = NULL;
932
933
0
    ogs_assert(list);
934
0
    ogs_assert(node_id && from);
935
936
    /*
937
     * We only handle IPv4, IPv6, and FQDN types here. If the incoming
938
     * node_id has any other type, we treat it as invalid. This ensures
939
     * we do not merge a node with an unsupported PFCP Node ID.
940
     */
941
0
    if (node_id->type != OGS_PFCP_NODE_ID_IPV4 &&
942
0
        node_id->type != OGS_PFCP_NODE_ID_IPV6 &&
943
0
        node_id->type != OGS_PFCP_NODE_ID_FQDN) {
944
0
        ogs_error("Invalid PFCP Node Type = %d", node_id->type);
945
0
        return NULL;
946
0
    }
947
948
    /* Create node with no config_addr initially */
949
0
    node = ogs_pfcp_node_new(NULL);
950
0
    if (!node) {
951
0
        ogs_error("No memory: ogs_pfcp_node_add() failed node_id:%s from:%s",
952
0
                ogs_pfcp_node_id_to_string_static(node_id),
953
0
                ogs_sockaddr_to_string_static(from));
954
0
        return NULL;
955
0
    }
956
957
    /* Set node->node_id, reset last_dns_refresh. */
958
0
    memcpy(&node->node_id, node_id, sizeof(node->node_id));
959
0
    node->last_dns_refresh = 0;
960
961
    /* Merge addresses => fill node->addr_list if conditions are met */
962
0
    if (ogs_pfcp_node_merge(node, node_id, from) != OGS_OK) {
963
0
        ogs_error("ogs_pfcp_node_merge() failed node_id [%s] from [%s]",
964
0
                ogs_pfcp_node_id_to_string_static(node_id),
965
0
                ogs_sockaddr_to_string_static(from));
966
0
        ogs_pool_free(&ogs_pfcp_node_pool, node);
967
0
        return NULL;
968
0
    }
969
970
0
    ogs_list_add(list, node);
971
972
0
    return node;
973
0
}
974
975
/******************************************************************************
976
 * ogs_pfcp_node_find()
977
 *  - No DNS logic here. Merely finds a node by node_id (if provided) and
978
 *    checks if 'from' address is in node->addr_list.
979
 ******************************************************************************/
980
ogs_pfcp_node_t *ogs_pfcp_node_find(ogs_list_t *list,
981
    ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
982
0
{
983
0
    ogs_pfcp_node_t *cur;
984
985
0
    ogs_assert(list);
986
0
    ogs_assert(node_id || from);
987
988
0
    ogs_list_for_each(list, cur) {
989
        /*
990
         * If the node currently has a known Node ID (not UNKNOWN)
991
         * and the caller provided a node_id to match, then compare them.
992
         * If they do not match, skip this node. This allows config-based nodes
993
         * (with an UNKNOWN node_id) to be found by IP address alone,
994
         * while nodes with a definite ID must match the incoming node_id.
995
         */
996
0
        if (cur->node_id.type != OGS_PFCP_NODE_ID_UNKNOWN && node_id) {
997
0
            if (!ogs_pfcp_node_id_compare(&cur->node_id, node_id))
998
0
                continue;
999
0
        }
1000
0
        if (!from)
1001
0
            return cur;
1002
1003
        /* Check if 'from' is in cur->addr_list. */
1004
0
        if (ogs_sockaddr_check_any_match(cur->addr_list, NULL,
1005
0
                                         from, /* compare_port= */ true)) {
1006
0
            return cur;
1007
0
        }
1008
0
    }
1009
1010
    /* No match found. */
1011
0
    return NULL;
1012
0
}
1013
1014
/******************************************************************************
1015
 * ogs_pfcp_node_merge():
1016
 *  - If node_id changes to FQDN, we check last_dns_refresh.
1017
 *    => If 0, do an immediate DNS resolution (first time).
1018
 *    => If >= 300 seconds passed, do a periodic refresh.
1019
 *    => Otherwise, skip.
1020
 *  - If node_id changes to IPv4/IPv6, convert IP addresses immediately.
1021
 *  - Merge the 'from' address into addr_list if provided.
1022
 ******************************************************************************/
1023
int ogs_pfcp_node_merge(ogs_pfcp_node_t *node,
1024
    ogs_pfcp_node_id_t *node_id, ogs_sockaddr_t *from)
1025
0
{
1026
0
    ogs_sockaddr_t single;
1027
0
    ogs_sockaddr_t *tmp_list = NULL;
1028
1029
0
    ogs_assert(node);
1030
0
    ogs_assert(node_id || from);
1031
1032
0
    if (node_id) {
1033
        /*
1034
         * We only handle IPv4, IPv6, and FQDN types here. If the incoming
1035
         * node_id has any other type, we treat it as invalid. This ensures
1036
         * we do not merge a node with an unsupported PFCP Node ID.
1037
         */
1038
0
        if (node_id->type != OGS_PFCP_NODE_ID_IPV4 &&
1039
0
            node_id->type != OGS_PFCP_NODE_ID_IPV6 &&
1040
0
            node_id->type != OGS_PFCP_NODE_ID_FQDN) {
1041
0
            ogs_error("Invalid PFCP Node Type = %d", node_id->type);
1042
0
            return OGS_ERROR;
1043
0
        }
1044
1045
        /* Check if node_id is different from node->node_id. */
1046
0
        if (!ogs_pfcp_node_id_compare(&node->node_id, node_id)) {
1047
            /* Update the node's ID and reset the refresh timestamp. */
1048
0
            memcpy(&node->node_id, node_id, sizeof(node->node_id));
1049
0
            node->last_dns_refresh = 0;
1050
0
        }
1051
1052
        /* If FQDN, do a DNS lookup (immediate or periodic). */
1053
0
        if (node->node_id.type == OGS_PFCP_NODE_ID_FQDN) {
1054
/*
1055
 * We perform a DNS resolution if 'last_dns_refresh' is zero, which means
1056
 * this FQDN node has never been resolved yet (first-time resolution), or if
1057
 * at least 300 seconds have passed since the last refresh. Without checking
1058
 * '== 0', a newly created FQDN node might skip resolution if 'now' is less
1059
 * than the 300-second threshold.
1060
 */
1061
0
            ogs_time_t now = ogs_time_now();
1062
1063
/* For 300-second refresh interval in microseconds. */
1064
0
#define OGS_PFCP_NODE_DNS_REFRESH_INTERVAL \
1065
0
    ((ogs_time_t)(300) * OGS_USEC_PER_SEC)
1066
0
            if (node->last_dns_refresh == 0 ||
1067
0
                (now - node->last_dns_refresh) >=
1068
0
                  OGS_PFCP_NODE_DNS_REFRESH_INTERVAL) {
1069
1070
0
                tmp_list = ogs_pfcp_node_id_to_addrinfo(&node->node_id);
1071
0
                if (!tmp_list) {
1072
0
                    ogs_error("DNS resolution failed for FQDN [%s]",
1073
0
                              node->node_id.fqdn);
1074
0
                    return OGS_ERROR;
1075
0
                }
1076
1077
0
                ogs_freeaddrinfo(node->addr_list);
1078
0
                node->addr_list = tmp_list;
1079
0
                node->last_dns_refresh = now;
1080
0
                node->current_addr = NULL;
1081
0
                tmp_list = NULL;
1082
0
            }
1083
0
        }
1084
        /* If IPv4/IPv6, convert immediately. */
1085
0
        else if (node->node_id.type == OGS_PFCP_NODE_ID_IPV4 ||
1086
0
                 node->node_id.type == OGS_PFCP_NODE_ID_IPV6) {
1087
0
            tmp_list = ogs_pfcp_node_id_to_addrinfo(&node->node_id);
1088
0
            if (!tmp_list) {
1089
0
                ogs_error("Failed to convert node ID to address info");
1090
0
                return OGS_ERROR;
1091
0
            }
1092
0
            ogs_merge_addrinfo(&node->addr_list, tmp_list);
1093
0
            ogs_freeaddrinfo(tmp_list);
1094
0
            tmp_list = NULL;
1095
0
        }
1096
0
        else {
1097
            /* Not IPv4, IPv6, or FQDN => invalid node type. */
1098
0
            ogs_error("Invalid Node ID type [%d]", node->node_id.type);
1099
0
            return OGS_ERROR;
1100
0
        }
1101
0
    }
1102
1103
    /* Merge 'from' into addr_list if provided. */
1104
0
    if (from) {
1105
0
        memcpy(&single, from, sizeof(single));
1106
0
        single.next = NULL;
1107
0
        ogs_merge_addrinfo(&node->addr_list, &single);
1108
0
    }
1109
1110
0
    return OGS_OK;
1111
0
}
1112
1113
void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node)
1114
0
{
1115
0
    ogs_assert(list);
1116
0
    ogs_assert(node);
1117
1118
0
    ogs_list_remove(list, node);
1119
0
    ogs_pfcp_node_free(node);
1120
0
}
1121
1122
void ogs_pfcp_node_remove_all(ogs_list_t *list)
1123
0
{
1124
0
    ogs_pfcp_node_t *node = NULL, *next_node = NULL;
1125
1126
0
    ogs_assert(list);
1127
1128
0
    ogs_list_for_each_safe(list, next_node, node)
1129
0
        ogs_pfcp_node_remove(list, node);
1130
0
}
1131
1132
/******************************************************************************
1133
 * Compare two node IDs for equality. Returns true if they match, else false.
1134
 ******************************************************************************/
1135
bool ogs_pfcp_node_id_compare(
1136
        const ogs_pfcp_node_id_t *id1, const ogs_pfcp_node_id_t *id2)
1137
0
{
1138
0
    if (id1->type != id2->type)
1139
0
        return false; /* Types do not match */
1140
1141
0
    switch (id1->type) {
1142
0
        case OGS_PFCP_NODE_ID_IPV4:
1143
0
            if (id1->addr != id2->addr) return false;
1144
0
            return true;
1145
1146
0
        case OGS_PFCP_NODE_ID_IPV6:
1147
0
            if (memcmp(id1->addr6, id2->addr6, OGS_IPV6_LEN) != 0)
1148
0
                return false;
1149
0
            return true;
1150
1151
0
        case OGS_PFCP_NODE_ID_FQDN:
1152
0
            if (strcmp(id1->fqdn, id2->fqdn) != 0)
1153
0
                return false;
1154
0
            return true;
1155
1156
0
        default:
1157
0
            ogs_error("Unexpected Node Type [%d]", id1->type);
1158
0
            ogs_abort();
1159
0
            return false; /* Unknown types do not match */
1160
0
    }
1161
0
}
1162
1163
ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
1164
        char *dnn, ogs_pfcp_interface_t source_interface)
1165
0
{
1166
0
    ogs_gtpu_resource_t *resource = NULL;
1167
1168
0
    ogs_assert(list);
1169
1170
0
    ogs_list_for_each(list, resource) {
1171
0
        bool match = true;
1172
1173
0
        if (resource->info.assoni &&
1174
0
            strlen(resource->info.network_instance) &&
1175
0
            dnn && strlen(dnn) &&
1176
0
            ogs_strcasecmp(dnn, resource->info.network_instance) != 0) {
1177
0
            match = false;
1178
0
        }
1179
1180
0
        if (resource->info.assosi &&
1181
0
            resource->info.source_interface <= OGS_PFCP_INTERFACE_LI_FUNCTION &&
1182
0
            source_interface <= OGS_PFCP_INTERFACE_LI_FUNCTION &&
1183
0
            source_interface != resource->info.source_interface) {
1184
0
            match = false;
1185
0
        }
1186
1187
0
        if (match == true) return resource;
1188
0
    }
1189
1190
0
    return NULL;
1191
0
}
1192
1193
/*
1194
 * GTP-U peer nodes in gtpu_peer_list are created on demand by
1195
 * ogs_pfcp_setup_far_gtpu_node()/ogs_pfcp_setup_pdr_gtpu_node() and
1196
 * shared by all FARs/PDRs carrying the same IP. gnode->gtpu_ref_count
1197
 * counts those FARs/PDRs; when the last one is removed, the peer is
1198
 * removed from gtpu_peer_list and returned to the pool. Without this,
1199
 * a peer whose eNB/gNB was renumbered would occupy a pool entry until
1200
 * the process exits and repeated IP changes would eventually exhaust
1201
 * `global.max.gtp_peer`.
1202
 */
1203
static void gtpu_peer_release(ogs_gtp_node_t *gnode)
1204
0
{
1205
0
    ogs_assert(gnode);
1206
0
    ogs_assert(gnode->gtpu_ref_count > 0);
1207
1208
0
    if (--gnode->gtpu_ref_count == 0)
1209
0
        ogs_gtp_node_remove(&ogs_gtp_self()->gtpu_peer_list, gnode);
1210
0
}
1211
1212
int ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far)
1213
0
{
1214
0
    int rv;
1215
0
    ogs_ip_t ip;
1216
0
    ogs_gtp_node_t *gnode = NULL;
1217
1218
0
    ogs_assert(far);
1219
1220
0
    ogs_pfcp_outer_header_creation_to_ip(&far->outer_header_creation, &ip);
1221
1222
    /* No Outer Header Creation */
1223
0
    if (ip.len == 0) return OGS_DONE;
1224
1225
0
    gnode = ogs_gtp_node_find_by_ip(&ogs_gtp_self()->gtpu_peer_list, &ip);
1226
0
    if (!gnode) {
1227
0
        gnode = ogs_gtp_node_add_by_ip(
1228
0
            &ogs_gtp_self()->gtpu_peer_list, &ip, ogs_gtp_self()->gtpu_port);
1229
0
        if (!gnode) {
1230
0
            ogs_error("Cannot allocate GTP-U peer "
1231
0
                    "[FAR-ID:%u TEID:0x%x]",
1232
0
                    far->id, far->outer_header_creation.teid);
1233
0
            return OGS_ERROR;
1234
0
        }
1235
1236
0
        rv = ogs_gtp_connect(
1237
0
                ogs_gtp_self()->gtpu_sock, ogs_gtp_self()->gtpu_sock6, gnode);
1238
0
        if (rv != OGS_OK) {
1239
0
            ogs_error("Cannot connect GTP-U peer "
1240
0
                    "[FAR-ID:%u TEID:0x%x rv:%d]",
1241
0
                    far->id, far->outer_header_creation.teid, rv);
1242
            /*
1243
             * ogs_gtp_node_new() zeroes gnode->addr, and only a successful
1244
             * ogs_gtp_connect() fills it in. On failure the node stays in
1245
             * gtpu_peer_list with ogs_sa_family == 0, so the next request
1246
             * carrying the same IP address finds it through
1247
             * ogs_gtp_node_find_by_ip(), skips ogs_gtp_connect() entirely
1248
             * and reaches ogs_pfcp_far_f_teid_hash_set(), which aborts:
1249
             *
1250
             *   [pfcp] FATAL: Unknown family(0) (../lib/pfcp/context.c)
1251
             *
1252
             * OGS_SETUP_GTP_NODE() has not run yet, so no FAR references
1253
             * this node and removing it here is safe.
1254
             */
1255
0
            ogs_gtp_node_remove(&ogs_gtp_self()->gtpu_peer_list, gnode);
1256
0
            return rv;
1257
0
        }
1258
0
    }
1259
1260
    /* Update FAR can move to another peer; keep the count per pointer */
1261
0
    if (far->gnode != gnode) {
1262
0
        ogs_warn("Set FAR-ID[%u] GTP-U peer [TEID:0x%x]",
1263
0
                far->id, far->outer_header_creation.teid);
1264
0
        gnode->gtpu_ref_count++;
1265
0
        if (far->gnode)
1266
0
            gtpu_peer_release(far->gnode);
1267
0
        OGS_SETUP_GTP_NODE(far, gnode);
1268
0
    }
1269
1270
0
    return OGS_OK;
1271
0
}
1272
1273
int ogs_pfcp_setup_pdr_gtpu_node(ogs_pfcp_pdr_t *pdr)
1274
0
{
1275
0
    int rv;
1276
0
    ogs_ip_t ip;
1277
0
    ogs_gtp_node_t *gnode = NULL;
1278
1279
0
    ogs_assert(pdr);
1280
1281
    /* No F-TEID */
1282
0
    if (pdr->f_teid_len == 0) return OGS_DONE;
1283
1284
0
    rv = ogs_pfcp_f_teid_to_ip(&pdr->f_teid, &ip);
1285
0
    if (rv != OGS_OK) {
1286
0
        ogs_error("ogs_pfcp_f_teid_to_ip() failed");
1287
0
        return rv;
1288
0
    }
1289
1290
0
    gnode = ogs_gtp_node_find_by_ip(&ogs_gtp_self()->gtpu_peer_list, &ip);
1291
0
    if (!gnode) {
1292
0
        gnode = ogs_gtp_node_add_by_ip(
1293
0
            &ogs_gtp_self()->gtpu_peer_list, &ip, ogs_gtp_self()->gtpu_port);
1294
0
        if (!gnode) {
1295
0
            ogs_error("ogs_gtp_node_add_by_ip() failed");
1296
0
            return OGS_ERROR;
1297
0
        }
1298
1299
0
        rv = ogs_gtp_connect(
1300
0
                ogs_gtp_self()->gtpu_sock, ogs_gtp_self()->gtpu_sock6, gnode);
1301
0
        if (rv != OGS_OK) {
1302
0
            ogs_error("ogs_gtp_connect() failed");
1303
            /* Same rollback as ogs_pfcp_setup_far_gtpu_node() */
1304
0
            ogs_gtp_node_remove(&ogs_gtp_self()->gtpu_peer_list, gnode);
1305
0
            return rv;
1306
0
        }
1307
0
    }
1308
1309
    /* Update PDR can move to another peer; keep the count per pointer */
1310
0
    if (pdr->gnode != gnode) {
1311
0
        gnode->gtpu_ref_count++;
1312
0
        if (pdr->gnode)
1313
0
            gtpu_peer_release(pdr->gnode);
1314
0
        OGS_SETUP_GTP_NODE(pdr, gnode);
1315
0
    }
1316
1317
0
    return OGS_OK;
1318
0
}
1319
1320
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess)
1321
0
{
1322
0
    ogs_pfcp_pdr_remove_all(sess);
1323
0
    ogs_pfcp_far_remove_all(sess);
1324
0
    ogs_pfcp_urr_remove_all(sess);
1325
0
    ogs_pfcp_qer_remove_all(sess);
1326
0
    if (sess->bar) ogs_pfcp_bar_delete(sess->bar);
1327
0
}
1328
1329
static bool mark_has_id(
1330
        const uint32_t *marked_id, int num_of_marked, uint32_t id)
1331
0
{
1332
0
    int i;
1333
1334
0
    for (i = 0; i < num_of_marked; i++) {
1335
0
        if (marked_id[i] == id)
1336
0
            return true;
1337
0
    }
1338
1339
0
    return false;
1340
0
}
1341
1342
/*
1343
 * Record IDs, not object addresses: a freed pool slot may later be reused.
1344
 * This is an inventory for cleanup, not a copy of the rules' contents.
1345
 */
1346
void ogs_pfcp_sess_mark(ogs_pfcp_sess_t *sess, ogs_pfcp_sess_mark_t *mark)
1347
0
{
1348
0
    ogs_pfcp_pdr_t *pdr = NULL;
1349
0
    ogs_pfcp_far_t *far = NULL;
1350
0
    ogs_pfcp_urr_t *urr = NULL;
1351
0
    ogs_pfcp_qer_t *qer = NULL;
1352
1353
0
    ogs_assert(sess);
1354
0
    ogs_assert(mark);
1355
1356
0
    memset(mark, 0, sizeof(*mark));
1357
1358
0
    ogs_list_for_each(&sess->pdr_list, pdr) {
1359
0
        ogs_assert(mark->num_of_pdr < OGS_ARRAY_SIZE(mark->pdr_id));
1360
0
        mark->pdr_id[mark->num_of_pdr++] = pdr->id;
1361
0
    }
1362
0
    ogs_list_for_each(&sess->far_list, far) {
1363
0
        ogs_assert(mark->num_of_far < OGS_ARRAY_SIZE(mark->far_id));
1364
0
        mark->far_id[mark->num_of_far++] = far->id;
1365
0
    }
1366
0
    ogs_list_for_each(&sess->urr_list, urr) {
1367
0
        ogs_assert(mark->num_of_urr < OGS_ARRAY_SIZE(mark->urr_id));
1368
0
        mark->urr_id[mark->num_of_urr++] = urr->id;
1369
0
    }
1370
0
    ogs_list_for_each(&sess->qer_list, qer) {
1371
0
        ogs_assert(mark->num_of_qer < OGS_ARRAY_SIZE(mark->qer_id));
1372
0
        mark->qer_id[mark->num_of_qer++] = qer->id;
1373
0
    }
1374
1375
0
    mark->has_bar = (sess->bar != NULL);
1376
1377
0
    ogs_info("Mark rules [PDR:%d FAR:%d URR:%d QER:%d BAR:%d]",
1378
0
            mark->num_of_pdr, mark->num_of_far,
1379
0
            mark->num_of_urr, mark->num_of_qer, mark->has_bar);
1380
0
}
1381
1382
/*
1383
 * Remove rules whose IDs were not present at ogs_pfcp_sess_mark().
1384
 * Modification handlers reject duplicate PDR/FAR/URR/QER Create IDs first,
1385
 * so a marked ID cannot be replaced by a Create in the same request.
1386
 *
1387
 * Delete PDRs before the rules they reference. Existing PDRs cannot acquire
1388
 * new references through Update PDR, and referenced-rule Removes are rejected.
1389
 * Applied Updates and Removes are not restored; retained counts can therefore
1390
 * be smaller than the mark without indicating a cleanup failure.
1391
 * PFCPSMReq-Flags are request-local and must be cleared on surviving FARs.
1392
 * Callers log the SEIDs and the final rule counts around this cleanup.
1393
 */
1394
void ogs_pfcp_sess_clear_since_mark(
1395
        ogs_pfcp_sess_t *sess, const ogs_pfcp_sess_mark_t *mark)
1396
0
{
1397
0
    ogs_pfcp_pdr_t *pdr = NULL, *next_pdr = NULL;
1398
0
    ogs_pfcp_far_t *far = NULL, *next_far = NULL;
1399
0
    ogs_pfcp_urr_t *urr = NULL, *next_urr = NULL;
1400
0
    ogs_pfcp_qer_t *qer = NULL, *next_qer = NULL;
1401
1402
0
    ogs_assert(sess);
1403
0
    ogs_assert(mark);
1404
1405
0
    ogs_list_for_each_safe(&sess->pdr_list, next_pdr, pdr) {
1406
0
        if (!mark_has_id(mark->pdr_id, mark->num_of_pdr, pdr->id)) {
1407
0
            ogs_error("Rejected modification: remove new PDR-ID[%u]",
1408
0
                    pdr->id);
1409
0
            ogs_pfcp_pdr_remove(pdr);
1410
0
        }
1411
0
    }
1412
0
    ogs_list_for_each_safe(&sess->far_list, next_far, far) {
1413
0
        if (!mark_has_id(mark->far_id, mark->num_of_far, far->id)) {
1414
0
            ogs_error("Rejected modification: remove new FAR-ID[%u]",
1415
0
                    far->id);
1416
0
            ogs_pfcp_far_remove(far);
1417
0
        } else {
1418
            /*
1419
             * A failed flags pass skips normal End Marker processing.
1420
             * Do not carry that request's flags into the next request.
1421
             */
1422
0
            if (far->smreq_flags.value)
1423
0
                ogs_info("Rejected modification: clear FAR-ID[%u] "
1424
0
                        "request flags[0x%x]",
1425
0
                        far->id, far->smreq_flags.value);
1426
0
            far->smreq_flags.value = 0;
1427
0
        }
1428
0
    }
1429
0
    ogs_list_for_each_safe(&sess->urr_list, next_urr, urr) {
1430
0
        if (!mark_has_id(mark->urr_id, mark->num_of_urr, urr->id)) {
1431
0
            ogs_error("Rejected modification: remove new URR-ID[%u]",
1432
0
                    urr->id);
1433
0
            ogs_pfcp_urr_remove(urr);
1434
0
        }
1435
0
    }
1436
0
    ogs_list_for_each_safe(&sess->qer_list, next_qer, qer) {
1437
0
        if (!mark_has_id(mark->qer_id, mark->num_of_qer, qer->id)) {
1438
0
            ogs_error("Rejected modification: remove new QER-ID[%u]",
1439
0
                    qer->id);
1440
0
            ogs_pfcp_qer_remove(qer);
1441
0
        }
1442
0
    }
1443
1444
    /* An existing BAR may have been replaced; that change is retained. */
1445
0
    if (!mark->has_bar && sess->bar) {
1446
0
        ogs_error("Rejected modification: remove new BAR-ID[%u]",
1447
0
                sess->bar->id);
1448
0
        ogs_pfcp_bar_delete(sess->bar);
1449
0
    }
1450
0
}
1451
1452
static void pdr_log_state(ogs_pfcp_sess_t *sess, const char *reason)
1453
0
{
1454
0
    ogs_pfcp_pdr_t *pdr = NULL;
1455
1456
0
    ogs_assert(sess);
1457
0
    ogs_assert(reason);
1458
1459
0
    ogs_error("%s [PDR:%d/%d] [PDR-ID-available:%lld] "
1460
0
            "[PDR-pool-available:%lld] [PDR-TEID-pool-available:%lld]",
1461
0
            reason, ogs_list_count(&sess->pdr_list), OGS_MAX_NUM_OF_PDR,
1462
0
            (long long)sess->pdr_id_pool.avail,
1463
0
            (long long)ogs_pfcp_pdr_pool.avail,
1464
0
            (long long)ogs_pfcp_pdr_teid_pool.avail);
1465
1466
0
    ogs_list_for_each(&sess->pdr_list, pdr) {
1467
0
        ogs_error("    PDR [id:%u] [teid:0x%x] [src-if:%d] [FAR-id:%u]",
1468
0
                (unsigned)pdr->id, pdr->teid, pdr->src_if,
1469
0
                pdr->far ? (unsigned)pdr->far->id : 0);
1470
0
    }
1471
0
}
1472
1473
static int precedence_compare(ogs_pfcp_pdr_t *pdr1, ogs_pfcp_pdr_t *pdr2)
1474
0
{
1475
0
    if (pdr1->precedence == pdr2->precedence)
1476
0
        return 0;
1477
0
    else if (pdr1->precedence < pdr2->precedence)
1478
0
        return -1;
1479
0
    else
1480
0
        return 1;
1481
0
}
1482
1483
ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess)
1484
0
{
1485
0
    ogs_pfcp_pdr_t *pdr = NULL;
1486
1487
0
    ogs_assert(sess);
1488
1489
0
    ogs_pool_alloc(&ogs_pfcp_pdr_pool, &pdr);
1490
0
    if (pdr == NULL) {
1491
0
        pdr_log_state(sess, "PDR pool exhausted");
1492
0
        return NULL;
1493
0
    }
1494
0
    memset(pdr, 0, sizeof *pdr);
1495
1496
0
    pdr->obj.type = OGS_PFCP_OBJ_PDR_TYPE;
1497
0
    pdr->src_if = OGS_PFCP_INTERFACE_UNKNOWN;
1498
1499
    /* Set TEID */
1500
0
    ogs_pool_alloc(&ogs_pfcp_pdr_teid_pool, &pdr->teid_node);
1501
0
    if (pdr->teid_node == NULL) {
1502
0
        ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
1503
0
        pdr_log_state(sess, "PDR TEID pool exhausted");
1504
0
        return NULL;
1505
0
    }
1506
1507
0
    pdr->teid = *(pdr->teid_node);
1508
1509
    /* Set PDR-ID */
1510
0
    ogs_pool_alloc(&sess->pdr_id_pool, &pdr->id_node);
1511
0
    if (pdr->id_node == NULL) {
1512
0
        ogs_pool_free(&ogs_pfcp_pdr_teid_pool, pdr->teid_node);
1513
0
        ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
1514
0
        pdr_log_state(sess, "PDR ID pool exhausted");
1515
0
        return NULL;
1516
0
    }
1517
1518
0
    pdr->id = *(pdr->id_node);
1519
0
    ogs_assert(pdr->id > 0 && pdr->id <= OGS_MAX_NUM_OF_PDR);
1520
1521
0
    pdr->sess = sess;
1522
0
    ogs_list_add(&sess->pdr_list, pdr);
1523
1524
0
    return pdr;
1525
0
}
1526
1527
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
1528
        ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id)
1529
0
{
1530
0
    ogs_pfcp_pdr_t *pdr = NULL;
1531
1532
0
    ogs_assert(sess);
1533
1534
0
    ogs_list_for_each(&sess->pdr_list, pdr)
1535
0
        if (pdr->id == id) return pdr;
1536
1537
0
    return NULL;
1538
0
}
1539
1540
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
1541
        ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id)
1542
0
{
1543
0
    ogs_pfcp_pdr_t *pdr = NULL;
1544
1545
0
    ogs_assert(sess);
1546
1547
0
    pdr = ogs_pfcp_pdr_find(sess, id);
1548
0
    if (!pdr) {
1549
0
        pdr = ogs_pfcp_pdr_add(sess);
1550
0
        if (!pdr) {
1551
0
            ogs_error("ogs_pfcp_pdr_add() failed");
1552
0
            return NULL;
1553
0
        }
1554
0
        pdr->id = id;
1555
0
    }
1556
1557
0
    return pdr;
1558
0
}
1559
1560
int ogs_pfcp_pdr_swap_teid(ogs_pfcp_pdr_t *pdr)
1561
0
{
1562
0
    int i = 0;
1563
1564
0
    ogs_assert(pdr);
1565
0
    ogs_assert(pdr->f_teid_len > 0);
1566
0
    ogs_assert(!pdr->f_teid.ch);
1567
1568
    /*
1569
     * Issues #3747, #3574
1570
     *
1571
     * This code validates the F-TEID (Fully encapsulated TEID) information
1572
     * element within a PDR structure before further processing the PFCP
1573
     * message. The validation ensures that the F-TEID is present and
1574
     * within acceptable limits defined by the system.
1575
     */
1576
0
    if (pdr->f_teid.teid > 0 &&
1577
0
        pdr->f_teid.teid <= ogs_pfcp_pdr_teid_pool.size) {
1578
        /* PASS OK */
1579
0
    } else {
1580
0
        ogs_error("PDR-ID[%d] F-TEID LEN[%d] TEID[0x%x]",
1581
0
                pdr->id, pdr->f_teid_len, pdr->f_teid.teid);
1582
0
        return OGS_PFCP_CAUSE_MANDATORY_IE_INCORRECT;
1583
0
    }
1584
1585
    /* Find out the Array Index for the restored TEID. */
1586
0
    i = pdr_random_to_index[pdr->f_teid.teid];
1587
0
    ogs_assert(i < ogs_pfcp_pdr_teid_pool.size);
1588
1589
0
    ogs_assert(pdr->teid_node);
1590
    /*
1591
     * If SWAP has already done this, it will not try this again.
1592
     * This situation can occur when multiple PDRs are restored
1593
     * with the same TEID.
1594
     */
1595
0
    if (pdr->f_teid.teid == ogs_pfcp_pdr_teid_pool.array[i]) {
1596
0
        ogs_pfcp_pdr_teid_pool.array[i] = *(pdr->teid_node);
1597
0
        *(pdr->teid_node) = pdr->f_teid.teid;
1598
0
    }
1599
1600
0
    return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
1601
0
}
1602
1603
static void pdr_teid_hash_register(
1604
        ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr)
1605
0
{
1606
0
    void *object = NULL;
1607
1608
0
    ogs_assert(type == OGS_PFCP_OBJ_PDR_TYPE ||
1609
0
            type == OGS_PFCP_OBJ_SESS_TYPE);
1610
0
    ogs_assert(pdr);
1611
0
    ogs_assert(pdr->sess);
1612
0
    ogs_assert(!pdr->hash.teid.registered);
1613
1614
    /* ogs_hash keeps this key's address; only the registered PDR owns it. */
1615
0
    pdr->hash.teid.key = pdr->f_teid.teid;
1616
0
    pdr->hash.teid.type = type;
1617
0
    pdr->hash.teid.registered = true;
1618
1619
0
    object = type == OGS_PFCP_OBJ_PDR_TYPE ?
1620
0
        (void *)pdr : (void *)pdr->sess;
1621
0
    ogs_hash_set(self.object_teid_hash,
1622
0
            &pdr->hash.teid.key, sizeof(pdr->hash.teid.key), object);
1623
0
    ogs_info("Register local F-TEID[0x%x] [PDR-ID:%u type:%d]",
1624
0
            pdr->hash.teid.key, pdr->id, type);
1625
0
}
1626
1627
/*
1628
 * ogs_hash retains the address of the key instead of copying it.
1629
 * When removing or changing the registered PDR, move a shared TEID
1630
 * to a live PDR so other QFIs can still use the tunnel (#2003).
1631
 */
1632
static void pdr_teid_hash_remove(ogs_pfcp_pdr_t *pdr)
1633
0
{
1634
0
    ogs_pfcp_pdr_t *other = NULL;
1635
0
    ogs_pfcp_object_type_e type;
1636
0
    uint32_t teid;
1637
1638
0
    ogs_assert(pdr);
1639
0
    ogs_assert(pdr->sess);
1640
1641
0
    if (!pdr->hash.teid.registered)
1642
        /* New PDRs and non-owners of a shared TEID have nothing to remove. */
1643
0
        return;
1644
1645
0
    type = pdr->hash.teid.type;
1646
0
    teid = pdr->hash.teid.key;
1647
1648
0
    ogs_info("Remove local F-TEID[0x%x] registration [PDR-ID:%u]",
1649
0
            teid, pdr->id);
1650
    /* NULL removes the entry; it does not leave a NULL-valued lookup. */
1651
0
    ogs_hash_set(self.object_teid_hash,
1652
0
            &pdr->hash.teid.key, sizeof(pdr->hash.teid.key), NULL);
1653
0
    pdr->hash.teid.registered = false;
1654
1655
0
    ogs_list_for_each(&pdr->sess->pdr_list, other) {
1656
0
        if (other != pdr && !other->hash.teid.registered &&
1657
0
                other->f_teid_len &&
1658
0
                other->f_teid.teid == teid) {
1659
0
            ogs_warn("Transfer local F-TEID[0x%x] [PDR-ID:%u -> %u]",
1660
0
                    teid, pdr->id, other->id);
1661
0
            pdr_teid_hash_register(type, other);
1662
0
            break;
1663
0
        }
1664
0
    }
1665
0
}
1666
1667
uint8_t ogs_pfcp_object_teid_hash_set(
1668
        ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr)
1669
0
{
1670
0
    ogs_pfcp_object_t *object = NULL;
1671
0
    ogs_pfcp_sess_t *owner_sess = NULL;
1672
1673
0
    ogs_assert(type == OGS_PFCP_OBJ_PDR_TYPE ||
1674
0
            type == OGS_PFCP_OBJ_SESS_TYPE);
1675
0
    ogs_assert(pdr);
1676
0
    ogs_assert(pdr->sess);
1677
1678
0
    if (ogs_pfcp_self()->up_function_features.ftup && pdr->f_teid.ch) {
1679
1680
0
        ogs_pfcp_pdr_t *choosed_pdr = NULL;
1681
1682
0
        if (pdr->f_teid.chid) {
1683
0
            choosed_pdr = ogs_pfcp_pdr_find_by_choose_id(
1684
0
                    pdr->sess, pdr->f_teid.choose_id);
1685
0
            if (!choosed_pdr) {
1686
0
                pdr->chid = true;
1687
0
                pdr->choose_id = pdr->f_teid.choose_id;
1688
0
            }
1689
0
        }
1690
1691
0
        if (choosed_pdr) {
1692
0
            pdr->f_teid_len = choosed_pdr->f_teid_len;
1693
0
            memcpy(&pdr->f_teid, &choosed_pdr->f_teid, pdr->f_teid_len);
1694
1695
0
        } else {
1696
0
            ogs_gtpu_resource_t *resource = NULL;
1697
0
            resource = ogs_pfcp_find_gtpu_resource(
1698
0
                    &ogs_gtp_self()->gtpu_resource_list,
1699
0
                    pdr->dnn, pdr->src_if);
1700
0
            if (resource) {
1701
0
                if (!((resource->info.v4 && pdr->f_teid.ipv4) ||
1702
0
                      (resource->info.v6 && pdr->f_teid.ipv6))) {
1703
0
                    ogs_error("CH F-TEID address family mismatch: "
1704
0
                            "resource[v4:%d v6:%d] fteid[v4:%d v6:%d]",
1705
0
                            resource->info.v4, resource->info.v6,
1706
0
                            pdr->f_teid.ipv4, pdr->f_teid.ipv6);
1707
0
                    return OGS_PFCP_CAUSE_REQUEST_REJECTED;
1708
0
                }
1709
0
                if (OGS_OK != ogs_pfcp_user_plane_ip_resource_info_to_f_teid(
1710
0
                        &resource->info, &pdr->f_teid, &pdr->f_teid_len)) {
1711
0
                    ogs_error("user_plane_ip_resource_info_to_f_teid() "
1712
0
                            "failed in CH path");
1713
0
                    return OGS_PFCP_CAUSE_REQUEST_REJECTED;
1714
0
                }
1715
0
                if (resource->info.teidri)
1716
0
                    pdr->f_teid.teid = OGS_PFCP_GTPU_INDEX_TO_TEID(
1717
0
                            pdr->teid, resource->info.teidri,
1718
0
                            resource->info.teid_range);
1719
0
                else
1720
0
                    pdr->f_teid.teid = pdr->teid;
1721
0
            } else {
1722
0
                if (!((ogs_gtp_self()->gtpu_addr && pdr->f_teid.ipv4) ||
1723
0
                    (ogs_gtp_self()->gtpu_addr6 && pdr->f_teid.ipv6))) {
1724
0
                    ogs_error("CH F-TEID address family mismatch with local "
1725
0
                            "GTP-U address: gtpu[v4:%p v6:%p] "
1726
0
                            "fteid[v4:%d v6:%d]",
1727
0
                            ogs_gtp_self()->gtpu_addr,
1728
0
                            ogs_gtp_self()->gtpu_addr6,
1729
0
                            pdr->f_teid.ipv4, pdr->f_teid.ipv6);
1730
0
                    return OGS_PFCP_CAUSE_REQUEST_REJECTED;
1731
0
                }
1732
0
                if (OGS_OK != ogs_pfcp_sockaddr_to_f_teid(
1733
0
                        pdr->f_teid.ipv4 ?
1734
0
                            ogs_gtp_self()->gtpu_addr : NULL,
1735
0
                        pdr->f_teid.ipv6 ?
1736
0
                            ogs_gtp_self()->gtpu_addr6 : NULL,
1737
0
                        &pdr->f_teid, &pdr->f_teid_len)) {
1738
0
                    ogs_error("ogs_pfcp_sockaddr_to_f_teid() "
1739
0
                            "failed in CH path");
1740
0
                    return OGS_PFCP_CAUSE_REQUEST_REJECTED;
1741
0
                }
1742
0
                pdr->f_teid.teid = pdr->teid;
1743
0
            }
1744
0
        }
1745
0
    }
1746
1747
    /*
1748
     * Validate the new TEID before removing the old registration. A rejected
1749
     * Update can then restore its fields while its old lookup remains valid.
1750
     * Same-session sharing is allowed; another session's entry is untouched.
1751
     */
1752
0
    object = ogs_pfcp_object_find_by_teid(pdr->f_teid.teid);
1753
0
    if (object) {
1754
0
        switch (object->type) {
1755
0
        case OGS_PFCP_OBJ_PDR_TYPE:
1756
0
            owner_sess = ((ogs_pfcp_pdr_t *)object)->sess;
1757
0
            break;
1758
0
        case OGS_PFCP_OBJ_SESS_TYPE:
1759
0
            owner_sess = (ogs_pfcp_sess_t *)object;
1760
0
            break;
1761
0
        default:
1762
0
            ogs_fatal("Unknown type [%d]", object->type);
1763
0
            ogs_assert_if_reached();
1764
0
        }
1765
1766
0
        if (owner_sess != pdr->sess) {
1767
0
            ogs_error("Reject PDR-ID[%u] F-TEID[0x%x]: "
1768
0
                    "registered by another session",
1769
0
                    pdr->id, pdr->f_teid.teid);
1770
0
            return OGS_PFCP_CAUSE_REQUEST_REJECTED;
1771
0
        }
1772
1773
0
        ogs_assert(object->type == type);
1774
0
    }
1775
1776
0
    if (pdr->hash.teid.registered &&
1777
0
            pdr->hash.teid.key == pdr->f_teid.teid)
1778
0
        return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
1779
1780
0
    pdr_teid_hash_remove(pdr);
1781
1782
    /* A same-session PDR already owns this shared TEID. */
1783
0
    if (!object)
1784
0
        pdr_teid_hash_register(type, pdr);
1785
1786
0
    return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
1787
0
}
1788
1789
ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid)
1790
0
{
1791
0
    return (ogs_pfcp_object_t *)ogs_hash_get(
1792
0
            self.object_teid_hash, &teid, sizeof(teid));
1793
0
}
1794
1795
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id(
1796
        ogs_pfcp_sess_t *sess, uint8_t choose_id)
1797
0
{
1798
0
    ogs_pfcp_pdr_t *pdr = NULL;
1799
1800
0
    ogs_assert(sess);
1801
1802
0
    ogs_list_for_each(&sess->pdr_list, pdr)
1803
0
        if (pdr->chid == true && pdr->choose_id == choose_id)
1804
0
            return pdr;
1805
1806
0
    return NULL;
1807
0
}
1808
1809
void ogs_pfcp_pdr_reorder_by_precedence(
1810
        ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence)
1811
0
{
1812
0
    ogs_pfcp_sess_t *sess = NULL;
1813
1814
0
    ogs_assert(pdr);
1815
0
    sess = pdr->sess;
1816
0
    ogs_assert(sess);
1817
1818
0
    ogs_list_remove(&sess->pdr_list, pdr);
1819
1820
0
    pdr->precedence = precedence;
1821
0
    ogs_list_insert_sorted(&sess->pdr_list, pdr, precedence_compare);
1822
0
}
1823
1824
void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far)
1825
0
{
1826
0
    ogs_assert(pdr);
1827
0
    ogs_assert(far);
1828
1829
0
    pdr->far = far;
1830
0
}
1831
void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr)
1832
0
{
1833
0
    ogs_assert(pdr);
1834
0
    ogs_assert(urr);
1835
0
    ogs_assert(pdr->num_of_urr < OGS_ARRAY_SIZE(pdr->urr));
1836
0
    int i;
1837
1838
    /* Avoid storing duplicate pointers */
1839
0
    for (i = 0; i < pdr->num_of_urr; i++) {
1840
0
        if (pdr->urr[i]->id == urr->id)
1841
0
            return;
1842
0
    }
1843
1844
0
    pdr->urr[pdr->num_of_urr++] = urr;
1845
0
}
1846
void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer)
1847
0
{
1848
0
    ogs_assert(pdr);
1849
0
    ogs_assert(qer);
1850
1851
0
    pdr->qer = qer;
1852
0
}
1853
1854
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr)
1855
0
{
1856
0
    int i;
1857
1858
0
    ogs_assert(pdr);
1859
0
    ogs_assert(pdr->sess);
1860
1861
0
    pdr_teid_hash_remove(pdr);
1862
1863
0
    ogs_list_remove(&pdr->sess->pdr_list, pdr);
1864
1865
0
    ogs_pfcp_rule_remove_all(pdr);
1866
1867
0
    if (pdr->gnode) {
1868
0
        gtpu_peer_release(pdr->gnode);
1869
0
        pdr->gnode = NULL;
1870
0
    }
1871
1872
0
    if (pdr->dnn)
1873
0
        ogs_free(pdr->dnn);
1874
1875
0
    if (pdr->id_node)
1876
0
        ogs_pool_free(&pdr->sess->pdr_id_pool, pdr->id_node);
1877
1878
0
    if (pdr->ipv4_framed_routes) {
1879
0
        for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
1880
0
            if (!pdr->ipv4_framed_routes[i])
1881
0
                break;
1882
0
            ogs_free(pdr->ipv4_framed_routes[i]);
1883
0
        }
1884
0
        ogs_free(pdr->ipv4_framed_routes);
1885
0
    }
1886
1887
0
    if (pdr->ipv6_framed_routes) {
1888
0
        for (i = 0; i < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; i++) {
1889
0
            if (!pdr->ipv6_framed_routes[i])
1890
0
                break;
1891
0
            ogs_free(pdr->ipv6_framed_routes[i]);
1892
0
        }
1893
0
        ogs_free(pdr->ipv6_framed_routes);
1894
0
    }
1895
1896
0
    ogs_pool_free(&ogs_pfcp_pdr_teid_pool, pdr->teid_node);
1897
0
    ogs_pool_free(&ogs_pfcp_pdr_pool, pdr);
1898
0
}
1899
1900
void ogs_pfcp_pdr_remove_all(ogs_pfcp_sess_t *sess)
1901
0
{
1902
0
    ogs_pfcp_pdr_t *pdr = NULL, *next_pdr = NULL;
1903
1904
0
    ogs_assert(sess);
1905
0
    ogs_list_for_each_safe(&sess->pdr_list, next_pdr, pdr)
1906
0
        ogs_pfcp_pdr_remove(pdr);
1907
0
}
1908
1909
ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess)
1910
0
{
1911
0
    ogs_pfcp_far_t *far = NULL;
1912
1913
0
    ogs_assert(sess);
1914
1915
0
    ogs_pool_alloc(&ogs_pfcp_far_pool, &far);
1916
0
    if (far == NULL) {
1917
0
        ogs_error("far_pool() failed");
1918
0
        return NULL;
1919
0
    }
1920
0
    memset(far, 0, sizeof *far);
1921
1922
0
    ogs_pool_alloc(&sess->far_id_pool, &far->id_node);
1923
0
    if (far->id_node == NULL) {
1924
0
        ogs_error("far_id_pool() failed");
1925
0
        ogs_pool_free(&ogs_pfcp_far_pool, far);
1926
0
        return NULL;
1927
0
    }
1928
1929
0
    far->id = *(far->id_node);
1930
0
    ogs_assert(far->id > 0 && far->id <= OGS_MAX_NUM_OF_FAR);
1931
1932
0
    far->dst_if = OGS_PFCP_INTERFACE_UNKNOWN;
1933
1934
0
    far->sess = sess;
1935
0
    ogs_list_add(&sess->far_list, far);
1936
1937
0
    return far;
1938
0
}
1939
1940
ogs_pfcp_far_t *ogs_pfcp_far_find(
1941
        ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id)
1942
0
{
1943
0
    ogs_pfcp_far_t *far = NULL;
1944
1945
0
    ogs_assert(sess);
1946
1947
0
    ogs_list_for_each(&sess->far_list, far)
1948
0
        if (far->id == id) return far;
1949
1950
0
    return NULL;
1951
0
}
1952
1953
ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
1954
        ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id)
1955
0
{
1956
0
    ogs_pfcp_far_t *far = NULL;
1957
1958
0
    ogs_assert(sess);
1959
1960
0
    far = ogs_pfcp_far_find(sess, id);
1961
0
    if (!far) {
1962
0
        far = ogs_pfcp_far_add(sess);
1963
0
        if (!far) {
1964
0
            ogs_error("ogs_pfcp_far_add() failed");
1965
0
            return NULL;
1966
0
        }
1967
0
        far->id = id;
1968
0
    }
1969
1970
0
    return far;
1971
0
}
1972
1973
static int far_f_teid_hash_key(
1974
        ogs_pfcp_far_t *far, ogs_pfcp_far_hash_f_teid_t *key)
1975
0
{
1976
0
    int len;
1977
0
    int family;
1978
0
    ogs_gtp_node_t *gnode = NULL;
1979
0
    ogs_sockaddr_t *addr = NULL;
1980
1981
0
    ogs_assert(far);
1982
0
    ogs_assert(key);
1983
1984
0
    gnode = far->gnode;
1985
0
    ogs_assert(gnode);
1986
0
    addr = &gnode->addr;
1987
1988
0
    memset(key, 0, sizeof(*key));
1989
0
    key->teid = far->outer_header_creation.teid;
1990
0
    len = sizeof(key->teid);
1991
1992
0
    family = addr->ogs_sa_family;
1993
0
    switch (family) {
1994
0
    case AF_INET:
1995
0
        memcpy(key->addr, &addr->sin.sin_addr, OGS_IPV4_LEN);
1996
0
        len += OGS_IPV4_LEN;
1997
0
        break;
1998
0
    case AF_INET6:
1999
0
        memcpy(key->addr, &addr->sin6.sin6_addr, OGS_IPV6_LEN);
2000
0
        len += OGS_IPV6_LEN;
2001
0
        break;
2002
0
    default:
2003
0
        ogs_fatal("Unknown family(%d) [FAR-ID:%u TEID:0x%x]",
2004
0
                family, far->id, far->outer_header_creation.teid);
2005
0
        ogs_abort();
2006
0
    }
2007
2008
0
    return len;
2009
0
}
2010
2011
void ogs_pfcp_far_f_teid_hash_set(ogs_pfcp_far_t *far)
2012
0
{
2013
0
    ogs_pfcp_far_hash_f_teid_t key;
2014
0
    int len;
2015
2016
0
    ogs_assert(far);
2017
2018
0
    len = far_f_teid_hash_key(far, &key);
2019
0
    if (far->hash.f_teid.len == len &&
2020
0
            memcmp(&far->hash.f_teid.key, &key, len) == 0)
2021
0
        return;
2022
2023
    /*
2024
     * len is nonzero only for the FAR that registered the entry. Remove its
2025
     * old key before testing the new one: a collision must not leave Error
2026
     * Indications for the old tunnel pointing to an already updated FAR.
2027
     */
2028
0
    if (far->hash.f_teid.len) {
2029
0
        ogs_hash_set(self.far_f_teid_hash,
2030
0
                &far->hash.f_teid.key, far->hash.f_teid.len, NULL);
2031
0
        far->hash.f_teid.len = 0;
2032
0
    }
2033
2034
    /*
2035
     * QoS flows may share a remote tunnel. This lookup is only for Error
2036
     * Indications, so keep the first FAR without rejecting the request.
2037
     * The final GTP node pass repeats this check on every accepted
2038
     * modification, so this is expected for each additional QoS flow.
2039
     */
2040
0
    if (ogs_hash_get(self.far_f_teid_hash, &key, len))
2041
0
        return;
2042
2043
0
    memcpy(&far->hash.f_teid.key, &key, len);
2044
0
    far->hash.f_teid.len = len;
2045
0
    ogs_hash_set(self.far_f_teid_hash,
2046
0
            &far->hash.f_teid.key, len, far);
2047
0
    ogs_info("Register Error Indication F-TEID[0x%x] [FAR-ID:%u]",
2048
0
            key.teid, far->id);
2049
0
}
2050
2051
ogs_pfcp_far_t *ogs_pfcp_far_find_by_gtpu_error_indication(ogs_pkbuf_t *pkbuf)
2052
0
{
2053
0
    ogs_pfcp_far_hash_f_teid_t hashkey;
2054
0
    int hashkey_len;
2055
2056
0
    uint32_t teid;
2057
0
    uint16_t len;
2058
0
    unsigned char *p = NULL;
2059
2060
0
    ogs_assert(pkbuf);
2061
2062
0
    p = pkbuf->data;
2063
0
    ogs_assert(p);
2064
2065
    /*
2066
     * 8.3 Tunnel Endpoint Identifier Data I
2067
     *
2068
     * Octet 1 : Type = 16 (Decimal)
2069
     * Octet 2-5 : Tunnel Endpoint Identitifer Data I
2070
     */
2071
0
    if (*p != 16) {
2072
0
        ogs_error("Unknown Type [%d]", *p);
2073
0
        return NULL;
2074
0
    }
2075
0
    p += 1;
2076
2077
0
    memcpy(&teid, p, 4);
2078
0
    teid = be32toh(teid);
2079
0
    p += 4;
2080
2081
    /*
2082
     * 8.4 GTP-U Peer Address
2083
     *
2084
     * Octet 1 : Type = 133 (Decimal)
2085
     * Octet 2-3 : Length
2086
     * Octet 4-n : IPv4 or IPv6 Address
2087
     */
2088
0
    if (*p != 133) {
2089
0
        ogs_error("Unknown Type [%d]", *p);
2090
0
        return NULL;
2091
0
    }
2092
0
    p += 1;
2093
2094
0
    memcpy(&len, p, 2);
2095
0
    len = be16toh(len);
2096
0
    p += 2;
2097
2098
0
    if (len == OGS_IPV4_LEN) {
2099
0
    } else if (len == OGS_IPV6_LEN) {
2100
0
    } else {
2101
0
        ogs_error("Invalid Length [%d]", len);
2102
0
        return NULL;
2103
0
    }
2104
2105
0
    hashkey.teid = teid;
2106
0
    memcpy(hashkey.addr, p, len);
2107
0
    hashkey_len = 4 + len;
2108
2109
0
    return (ogs_pfcp_far_t *)ogs_hash_get(
2110
0
            self.far_f_teid_hash, &hashkey, hashkey_len);
2111
0
}
2112
2113
ogs_pfcp_far_t *ogs_pfcp_far_find_by_pfcp_session_report(
2114
        ogs_pfcp_sess_t *sess,
2115
        ogs_pfcp_tlv_error_indication_report_t *error_indication_report)
2116
0
{
2117
0
    ogs_pfcp_far_t *far = NULL;
2118
0
    ogs_pfcp_f_teid_t *remote_f_teid = NULL;
2119
2120
0
    uint32_t teid;
2121
0
    uint16_t len;  /* OGS_IPV4_LEN or OGS_IPV6_LEN */
2122
0
    uint32_t addr[4];
2123
2124
0
    ogs_assert(sess);
2125
0
    ogs_assert(error_indication_report);
2126
2127
0
    if (error_indication_report->presence == 0) {
2128
0
        ogs_error("No Error Indication Report");
2129
0
        return NULL;
2130
0
    }
2131
2132
0
    if (error_indication_report->remote_f_teid.presence == 0) {
2133
0
        ogs_error("No Remote F-TEID");
2134
0
        return NULL;
2135
0
    }
2136
2137
0
    remote_f_teid = error_indication_report->remote_f_teid.data;
2138
0
    ogs_assert(remote_f_teid);
2139
2140
0
    teid = be32toh(remote_f_teid->teid);
2141
0
    if (remote_f_teid->ipv4 && remote_f_teid->ipv6) {
2142
0
        ogs_error("User plane should not set both IPv4 and IPv6");
2143
0
        return NULL;
2144
0
    } else if (remote_f_teid->ipv4) {
2145
0
        len = OGS_IPV4_LEN;
2146
0
        memcpy(addr, &remote_f_teid->addr, len);
2147
0
    } else if (remote_f_teid->ipv6) {
2148
0
        len = OGS_IPV6_LEN;
2149
0
        memcpy(addr, remote_f_teid->addr6, len);
2150
0
    } else {
2151
0
        ogs_error("No IPv4 and IPv6");
2152
0
        return NULL;
2153
0
    }
2154
2155
0
    ogs_list_for_each(&sess->far_list, far) {
2156
0
        if (teid == far->outer_header_creation.teid)
2157
0
            return far;
2158
0
    }
2159
2160
0
    ogs_error("Cannot find the session context "
2161
0
            "[TEID:0x%x,LEN:%d,ADDR:%08x %08x %08x %08x]",
2162
0
            teid, len, be32toh(addr[0]), be32toh(addr[1]),
2163
0
            be32toh(addr[2]), be32toh(addr[3]));
2164
2165
0
    return NULL;
2166
0
}
2167
2168
void ogs_pfcp_far_teid_hash_set(ogs_pfcp_far_t *far)
2169
0
{
2170
0
    ogs_assert(far);
2171
2172
0
    if (far->hash.teid.len)
2173
0
        ogs_hash_set(self.far_teid_hash,
2174
0
                &far->hash.teid.key, far->hash.teid.len, NULL);
2175
2176
0
    far->hash.teid.key = far->outer_header_creation.teid;
2177
0
    far->hash.teid.len = sizeof(far->hash.teid.key);
2178
2179
0
    ogs_hash_set(self.far_teid_hash,
2180
0
            &far->hash.teid.key, far->hash.teid.len, far);
2181
0
}
2182
2183
ogs_pfcp_far_t *ogs_pfcp_far_find_by_teid(uint32_t teid)
2184
0
{
2185
0
    return (ogs_pfcp_far_t *)ogs_hash_get(
2186
0
            self.far_teid_hash, &teid, sizeof(teid));
2187
0
}
2188
2189
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far)
2190
0
{
2191
0
    int i;
2192
0
    ogs_pfcp_sess_t *sess = NULL;
2193
2194
0
    ogs_assert(far);
2195
0
    sess = far->sess;
2196
0
    ogs_assert(sess);
2197
2198
0
    ogs_list_remove(&sess->far_list, far);
2199
2200
0
    if (far->hash.teid.len)
2201
0
        ogs_hash_set(self.far_teid_hash,
2202
0
                &far->hash.teid.key, far->hash.teid.len, NULL);
2203
2204
    /*
2205
     * Unlike the PDR data-path lookup, this Error Indication mapping ends
2206
     * with its registered FAR. Unregistered sharers have len == 0, so their
2207
     * removal cannot erase another FAR's entry. There is no FAR handoff.
2208
     */
2209
0
    if (far->hash.f_teid.len) {
2210
0
        ogs_info("Remove Error Indication F-TEID[0x%x] "
2211
0
                "[FAR-ID:%u]", far->hash.f_teid.key.teid, far->id);
2212
0
        ogs_hash_set(self.far_f_teid_hash,
2213
0
                &far->hash.f_teid.key, far->hash.f_teid.len, NULL);
2214
0
    }
2215
2216
0
    if (far->gnode) {
2217
0
        gtpu_peer_release(far->gnode);
2218
0
        far->gnode = NULL;
2219
0
    }
2220
2221
0
    if (far->dnn)
2222
0
        ogs_free(far->dnn);
2223
2224
0
    for (i = 0; i < far->num_of_buffered_gtpu; i++)
2225
0
        ogs_pkbuf_free(far->buffered_gtpu[i]);
2226
2227
0
    if (far->id_node)
2228
0
        ogs_pool_free(&far->sess->far_id_pool, far->id_node);
2229
2230
0
    ogs_pool_free(&ogs_pfcp_far_pool, far);
2231
0
}
2232
2233
void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess)
2234
0
{
2235
0
    ogs_pfcp_far_t *far = NULL, *next_far = NULL;
2236
2237
0
    ogs_assert(sess);
2238
2239
0
    ogs_list_for_each_safe(&sess->far_list, next_far, far)
2240
0
        ogs_pfcp_far_remove(far);
2241
0
}
2242
2243
ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess)
2244
0
{
2245
0
    ogs_pfcp_urr_t *urr = NULL;
2246
2247
0
    ogs_assert(sess);
2248
2249
0
    ogs_pool_alloc(&ogs_pfcp_urr_pool, &urr);
2250
0
    if (urr == NULL) {
2251
0
        ogs_error("urr_pool() failed");
2252
0
        return NULL;
2253
0
    }
2254
0
    memset(urr, 0, sizeof *urr);
2255
2256
0
    ogs_pool_alloc(&sess->urr_id_pool, &urr->id_node);
2257
0
    if (urr->id_node == NULL) {
2258
0
        ogs_error("urr_id_pool() failed");
2259
0
        ogs_pool_free(&ogs_pfcp_urr_pool, urr);
2260
0
        return NULL;
2261
0
    }
2262
2263
0
    urr->id = *(urr->id_node);
2264
0
    ogs_assert(urr->id > 0 && urr->id <= OGS_MAX_NUM_OF_URR);
2265
2266
0
    urr->sess = sess;
2267
0
    ogs_list_add(&sess->urr_list, urr);
2268
2269
0
    return urr;
2270
0
}
2271
2272
ogs_pfcp_urr_t *ogs_pfcp_urr_find(
2273
        ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id)
2274
0
{
2275
0
    ogs_pfcp_urr_t *urr = NULL;
2276
2277
0
    ogs_assert(sess);
2278
2279
0
    ogs_list_for_each(&sess->urr_list, urr)
2280
0
        if (urr->id == id) return urr;
2281
2282
0
    return NULL;
2283
0
}
2284
2285
ogs_pfcp_urr_t *ogs_pfcp_urr_find_or_add(
2286
        ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id)
2287
0
{
2288
0
    ogs_pfcp_urr_t *urr = NULL;
2289
2290
0
    ogs_assert(sess);
2291
2292
0
    urr = ogs_pfcp_urr_find(sess, id);
2293
0
    if (!urr) {
2294
0
        urr = ogs_pfcp_urr_add(sess);
2295
0
        if (!urr) {
2296
0
            ogs_error("ogs_pfcp_urr_add() failed");
2297
0
            return NULL;
2298
0
        }
2299
0
        urr->id = id;
2300
0
    }
2301
2302
0
    return urr;
2303
0
}
2304
2305
void ogs_pfcp_urr_remove(ogs_pfcp_urr_t *urr)
2306
0
{
2307
0
    ogs_pfcp_sess_t *sess = NULL;
2308
2309
0
    ogs_assert(urr);
2310
0
    sess = urr->sess;
2311
0
    ogs_assert(sess);
2312
2313
0
    ogs_list_remove(&sess->urr_list, urr);
2314
2315
0
    if (urr->id_node)
2316
0
        ogs_pool_free(&urr->sess->urr_id_pool, urr->id_node);
2317
2318
0
    ogs_pool_free(&ogs_pfcp_urr_pool, urr);
2319
0
}
2320
2321
void ogs_pfcp_urr_remove_all(ogs_pfcp_sess_t *sess)
2322
0
{
2323
0
    ogs_pfcp_urr_t *urr = NULL, *next_urr = NULL;
2324
2325
0
    ogs_assert(sess);
2326
2327
0
    ogs_list_for_each_safe(&sess->urr_list, next_urr, urr)
2328
0
        ogs_pfcp_urr_remove(urr);
2329
0
}
2330
2331
ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess)
2332
0
{
2333
0
    ogs_pfcp_qer_t *qer = NULL;
2334
2335
0
    ogs_assert(sess);
2336
2337
0
    ogs_pool_alloc(&ogs_pfcp_qer_pool, &qer);
2338
0
    if (qer == NULL) {
2339
0
        ogs_error("qer_pool() failed");
2340
0
        return NULL;
2341
0
    }
2342
0
    memset(qer, 0, sizeof *qer);
2343
2344
0
    ogs_pool_alloc(&sess->qer_id_pool, &qer->id_node);
2345
0
    if (qer->id_node == NULL) {
2346
0
        ogs_error("qer_id_pool() failed");
2347
0
        ogs_pool_free(&ogs_pfcp_qer_pool, qer);
2348
0
        return NULL;
2349
0
    }
2350
2351
0
    qer->id = *(qer->id_node);
2352
0
    ogs_assert(qer->id > 0 && qer->id <= OGS_MAX_NUM_OF_QER);
2353
2354
0
    qer->sess = sess;
2355
0
    ogs_list_add(&sess->qer_list, qer);
2356
2357
0
    return qer;
2358
0
}
2359
2360
ogs_pfcp_qer_t *ogs_pfcp_qer_find(
2361
        ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id)
2362
0
{
2363
0
    ogs_pfcp_qer_t *qer = NULL;
2364
2365
0
    ogs_assert(sess);
2366
2367
0
    ogs_list_for_each(&sess->qer_list, qer)
2368
0
        if (qer->id == id) return qer;
2369
2370
0
    return NULL;
2371
0
}
2372
2373
ogs_pfcp_qer_t *ogs_pfcp_qer_find_or_add(
2374
        ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id)
2375
0
{
2376
0
    ogs_pfcp_qer_t *qer = NULL;
2377
2378
0
    ogs_assert(sess);
2379
2380
0
    qer = ogs_pfcp_qer_find(sess, id);
2381
0
    if (!qer) {
2382
0
        qer = ogs_pfcp_qer_add(sess);
2383
0
        if (!qer) {
2384
0
            ogs_error("ogs_pfcp_qer_add() failed");
2385
0
            return NULL;
2386
0
        }
2387
0
        qer->id = id;
2388
0
    }
2389
2390
0
    return qer;
2391
0
}
2392
2393
void ogs_pfcp_qer_remove(ogs_pfcp_qer_t *qer)
2394
0
{
2395
0
    ogs_pfcp_sess_t *sess = NULL;
2396
2397
0
    ogs_assert(qer);
2398
0
    sess = qer->sess;
2399
0
    ogs_assert(sess);
2400
2401
0
    ogs_list_remove(&sess->qer_list, qer);
2402
2403
0
    if (qer->id_node)
2404
0
        ogs_pool_free(&qer->sess->qer_id_pool, qer->id_node);
2405
2406
0
    ogs_pool_free(&ogs_pfcp_qer_pool, qer);
2407
0
}
2408
2409
void ogs_pfcp_qer_remove_all(ogs_pfcp_sess_t *sess)
2410
0
{
2411
0
    ogs_pfcp_qer_t *qer = NULL, *next_qer = NULL;
2412
2413
0
    ogs_assert(sess);
2414
2415
0
    ogs_list_for_each_safe(&sess->qer_list, next_qer, qer)
2416
0
        ogs_pfcp_qer_remove(qer);
2417
0
}
2418
2419
ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess)
2420
0
{
2421
0
    ogs_pfcp_bar_t *bar = NULL;
2422
2423
0
    ogs_assert(sess);
2424
0
    ogs_assert(sess->bar == NULL); /* Only One BAR is supported */
2425
2426
0
    ogs_pool_alloc(&ogs_pfcp_bar_pool, &bar);
2427
0
    ogs_assert(bar);
2428
0
    memset(bar, 0, sizeof *bar);
2429
2430
0
    ogs_pool_alloc(&sess->bar_id_pool, &bar->id_node);
2431
0
    ogs_assert(bar->id_node);
2432
2433
0
    bar->id = *(bar->id_node);
2434
0
    ogs_assert(bar->id > 0 && bar->id <= OGS_MAX_NUM_OF_BAR);
2435
2436
0
    bar->sess = sess;
2437
0
    sess->bar = bar;
2438
2439
0
    return bar;
2440
0
}
2441
2442
void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar)
2443
0
{
2444
0
    ogs_pfcp_sess_t *sess = NULL;
2445
2446
0
    ogs_assert(bar);
2447
0
    sess = bar->sess;
2448
0
    ogs_assert(sess);
2449
2450
0
    if (bar->id_node)
2451
0
        ogs_pool_free(&bar->sess->bar_id_pool, bar->id_node);
2452
2453
0
    bar->sess = NULL;
2454
0
    sess->bar = NULL;
2455
2456
0
    ogs_pool_free(&ogs_pfcp_bar_pool, bar);
2457
0
}
2458
2459
ogs_pfcp_rule_t *ogs_pfcp_rule_add(ogs_pfcp_pdr_t *pdr)
2460
0
{
2461
0
    ogs_pfcp_rule_t *rule = NULL;
2462
2463
0
    ogs_assert(pdr);
2464
2465
0
    ogs_pool_alloc(&ogs_pfcp_rule_pool, &rule);
2466
0
    ogs_assert(rule);
2467
0
    memset(rule, 0, sizeof *rule);
2468
2469
0
    rule->pdr = pdr;
2470
0
    ogs_list_add(&pdr->rule_list, rule);
2471
2472
0
    return rule;
2473
0
}
2474
2475
ogs_pfcp_rule_t *ogs_pfcp_rule_find_by_sdf_filter_id(
2476
        ogs_pfcp_sess_t *sess, uint32_t sdf_filter_id)
2477
0
{
2478
0
    ogs_pfcp_pdr_t *pdr = NULL;
2479
0
    ogs_pfcp_rule_t *rule = NULL;
2480
2481
0
    ogs_assert(sess);
2482
2483
0
    ogs_list_for_each(&sess->pdr_list, pdr) {
2484
0
        ogs_list_for_each(&pdr->rule_list, rule) {
2485
0
            if (rule->bid && rule->sdf_filter_id == sdf_filter_id)
2486
0
                return rule;
2487
0
        }
2488
0
    }
2489
2490
0
    return NULL;
2491
0
}
2492
2493
void ogs_pfcp_rule_remove(ogs_pfcp_rule_t *rule)
2494
0
{
2495
0
    ogs_pfcp_pdr_t *pdr = NULL;
2496
2497
0
    ogs_assert(rule);
2498
0
    pdr = rule->pdr;
2499
0
    ogs_assert(pdr);
2500
2501
0
    ogs_list_remove(&pdr->rule_list, rule);
2502
0
    ogs_pool_free(&ogs_pfcp_rule_pool, rule);
2503
0
}
2504
2505
void ogs_pfcp_rule_remove_all(ogs_pfcp_pdr_t *pdr)
2506
0
{
2507
0
    ogs_pfcp_rule_t *rule = NULL, *next_rule = NULL;
2508
2509
0
    ogs_assert(pdr);
2510
2511
0
    ogs_list_for_each_safe(&pdr->rule_list, next_rule, rule)
2512
0
        ogs_pfcp_rule_remove(rule);
2513
0
}
2514
2515
int ogs_pfcp_ue_pool_generate(void)
2516
0
{
2517
0
    int i, rv;
2518
0
    ogs_pfcp_subnet_t *subnet = NULL;
2519
2520
0
    ogs_list_for_each(&self.subnet_list, subnet) {
2521
0
        int maxbytes = 0;
2522
0
        int lastindex = 0;
2523
0
        uint32_t start[4], end[4], broadcast[4];
2524
0
        int rangeindex, num_of_range;
2525
0
        int poolindex;
2526
0
        int inc;
2527
2528
0
        if (subnet->family == AF_INET) {
2529
0
            maxbytes = 4;
2530
0
            lastindex = 0;
2531
0
        } else if (subnet->family == AF_INET6) {
2532
0
            maxbytes = 8; /* Default Prefixlen 64bits */
2533
0
            lastindex = 1;
2534
0
        } else {
2535
            /* subnet->family might be AF_UNSPEC. So, skip it */
2536
0
            continue;
2537
0
        }
2538
2539
0
        for (i = 0; i < 4; i++) {
2540
0
            broadcast[i] = subnet->sub.sub[i] + ~subnet->sub.mask[i];
2541
0
        }
2542
2543
0
        num_of_range = subnet->num_of_range;
2544
0
        if (!num_of_range) num_of_range = 1;
2545
2546
0
        poolindex = 0;
2547
0
        for (rangeindex = 0; rangeindex < num_of_range; rangeindex++) {
2548
2549
0
            if (subnet->num_of_range &&
2550
0
                subnet->range[rangeindex].low) {
2551
0
                ogs_ipsubnet_t low;
2552
0
                rv = ogs_ipsubnet(&low, subnet->range[rangeindex].low, NULL);
2553
0
                ogs_assert(rv == OGS_OK);
2554
0
                memcpy(start, low.sub, maxbytes);
2555
0
            } else {
2556
0
                memcpy(start, subnet->sub.sub, maxbytes);
2557
0
            }
2558
2559
0
            if (subnet->num_of_range &&
2560
0
                subnet->range[rangeindex].high) {
2561
0
                ogs_ipsubnet_t high;
2562
0
                rv = ogs_ipsubnet(&high, subnet->range[rangeindex].high, NULL);
2563
0
                ogs_assert(rv == OGS_OK);
2564
0
                high.sub[lastindex] += htobe32(1);
2565
0
                memcpy(end, high.sub, maxbytes);
2566
0
            } else {
2567
0
                memcpy(end, broadcast, maxbytes);
2568
0
            }
2569
2570
0
            inc = 0;
2571
0
            while(poolindex < ogs_app()->pool.sess) {
2572
0
                ogs_pfcp_ue_ip_t *ue_ip = NULL;
2573
2574
0
                ue_ip = &subnet->pool.array[poolindex];
2575
0
                ogs_assert(ue_ip);
2576
0
                memset(ue_ip, 0, sizeof *ue_ip);
2577
0
                ue_ip->subnet = subnet;
2578
2579
0
                memcpy(ue_ip->addr, start, maxbytes);
2580
0
                ue_ip->addr[lastindex] += htobe32(inc);
2581
0
                inc++;
2582
2583
0
                if (memcmp(ue_ip->addr, end, maxbytes) == 0)
2584
0
                    break;
2585
2586
                /* Exclude Network Address */
2587
0
                if (memcmp(ue_ip->addr, subnet->sub.sub, maxbytes) == 0)
2588
0
                    continue;
2589
2590
                /* Exclude TUN IP Address */
2591
0
                if (memcmp(ue_ip->addr, subnet->gw.sub, maxbytes) == 0)
2592
0
                    continue;
2593
2594
                /* Allocate Full IPv6 Address */
2595
0
                if (lastindex == 1)
2596
0
                    ue_ip->addr[3] += htobe32(inc);
2597
2598
0
                ogs_trace("[%d] - %x:%x:%x:%x",
2599
0
                        poolindex,
2600
0
                        ue_ip->addr[0], ue_ip->addr[1],
2601
0
                        ue_ip->addr[2], ue_ip->addr[3]);
2602
2603
0
                poolindex++;
2604
0
            }
2605
0
        }
2606
0
        subnet->pool.size = subnet->pool.avail = poolindex;
2607
0
    }
2608
2609
0
    return OGS_OK;
2610
0
}
2611
2612
ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc(
2613
        uint8_t *cause_value, int family, const char *dnn, uint8_t *addr)
2614
0
{
2615
0
    ogs_pfcp_subnet_t *subnet = NULL;
2616
0
    ogs_pfcp_ue_ip_t *ue_ip = NULL;
2617
2618
0
    uint8_t zero[16];
2619
0
    size_t maxbytes = 0;
2620
2621
0
    memset(zero, 0, sizeof zero);
2622
0
    if (family == AF_INET) {
2623
0
        maxbytes = 4;
2624
0
    } else if (family == AF_INET6) {
2625
0
        maxbytes = 16;
2626
0
    } else {
2627
0
        ogs_error("Invalid family[%d]", family);
2628
0
        ogs_assert_if_reached();
2629
0
        return NULL;
2630
0
    }
2631
2632
0
    if (dnn)
2633
0
        subnet = ogs_pfcp_find_subnet_by_dnn(family, dnn);
2634
0
    else
2635
0
        subnet = ogs_pfcp_find_subnet(family);
2636
2637
0
    if (subnet == NULL) {
2638
0
        ogs_error("All IP addresses in all subnets are occupied");
2639
0
        *cause_value = OGS_PFCP_CAUSE_NO_RESOURCES_AVAILABLE;
2640
0
        return NULL;
2641
0
    }
2642
2643
    /* if assigning a static IP, do so. If not, assign dynamically! */
2644
0
    if (memcmp(addr, zero, maxbytes) != 0) {
2645
0
        ue_ip = ogs_calloc(1, sizeof(ogs_pfcp_ue_ip_t));
2646
0
        if (!ue_ip) {
2647
0
            ogs_error("All dynamic addresses are occupied");
2648
0
            *cause_value = OGS_PFCP_CAUSE_ALL_DYNAMIC_ADDRESS_ARE_OCCUPIED;
2649
0
            return NULL;
2650
0
        }
2651
2652
0
        ue_ip->subnet = subnet;
2653
0
        ue_ip->static_ip = true;
2654
0
        memcpy(ue_ip->addr, addr, maxbytes);
2655
0
    } else {
2656
0
        ogs_pool_alloc(&subnet->pool, &ue_ip);
2657
0
        if (!ue_ip) {
2658
0
            ogs_error("No resources available");
2659
0
            *cause_value = OGS_PFCP_CAUSE_NO_RESOURCES_AVAILABLE;
2660
0
            return NULL;
2661
0
        }
2662
0
    }
2663
2664
0
    return ue_ip;
2665
0
}
2666
2667
void ogs_pfcp_ue_ip_free(ogs_pfcp_ue_ip_t *ue_ip)
2668
0
{
2669
0
    ogs_pfcp_subnet_t *subnet = NULL;
2670
2671
0
    ogs_assert(ue_ip);
2672
0
    subnet = ue_ip->subnet;
2673
2674
0
    ogs_assert(subnet);
2675
2676
0
    if (ue_ip->static_ip) {
2677
0
        ogs_free(ue_ip);
2678
0
    } else {
2679
0
        ogs_pool_free(&subnet->pool, ue_ip);
2680
0
    }
2681
0
}
2682
2683
ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname)
2684
0
{
2685
0
    ogs_pfcp_dev_t *dev = NULL;
2686
2687
0
    ogs_assert(ifname);
2688
2689
0
    ogs_pool_alloc(&ogs_pfcp_dev_pool, &dev);
2690
0
    ogs_assert(dev);
2691
0
    memset(dev, 0, sizeof *dev);
2692
2693
0
    ogs_cpystrn(dev->ifname, ifname, OGS_MAX_IFNAME_LEN-1);
2694
2695
0
    ogs_list_add(&self.dev_list, dev);
2696
2697
0
    return dev;
2698
0
}
2699
2700
void ogs_pfcp_dev_remove(ogs_pfcp_dev_t *dev)
2701
0
{
2702
0
    ogs_assert(dev);
2703
2704
0
    ogs_list_remove(&self.dev_list, dev);
2705
0
    ogs_pool_free(&ogs_pfcp_dev_pool, dev);
2706
0
}
2707
2708
void ogs_pfcp_dev_remove_all(void)
2709
0
{
2710
0
    ogs_pfcp_dev_t *dev = NULL, *next_dev = NULL;
2711
2712
0
    ogs_list_for_each_safe(&self.dev_list, next_dev, dev)
2713
0
        ogs_pfcp_dev_remove(dev);
2714
0
}
2715
2716
ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname)
2717
0
{
2718
0
    ogs_pfcp_dev_t *dev = NULL;
2719
2720
0
    ogs_assert(ifname);
2721
2722
0
    ogs_list_for_each(&ogs_pfcp_self()->dev_list, dev) {
2723
0
        if (ogs_strcasecmp(dev->ifname, ifname) == 0)
2724
0
            return dev;
2725
0
    }
2726
2727
0
    return OGS_OK;
2728
0
}
2729
2730
ogs_pfcp_subnet_t *ogs_pfcp_subnet_add(
2731
        const char *ipstr, const char *mask_or_numbits,
2732
        const char *gateway, const char *dnn, const char *ifname)
2733
0
{
2734
0
    int rv;
2735
0
    ogs_pfcp_dev_t *dev = NULL;
2736
0
    ogs_pfcp_subnet_t *subnet = NULL;
2737
2738
0
    ogs_assert(ifname);
2739
2740
0
    dev = ogs_pfcp_dev_find_by_ifname(ifname);
2741
0
    if (!dev)
2742
0
        dev = ogs_pfcp_dev_add(ifname);
2743
0
    ogs_assert(dev);
2744
2745
0
    ogs_pool_alloc(&ogs_pfcp_subnet_pool, &subnet);
2746
0
    ogs_assert(subnet);
2747
0
    memset(subnet, 0, sizeof *subnet);
2748
2749
0
    subnet->family = AF_UNSPEC;
2750
0
    subnet->dev = dev;
2751
2752
0
    if (ipstr && mask_or_numbits) {
2753
0
        rv = ogs_ipsubnet(&subnet->gw, ipstr, NULL);
2754
0
        ogs_assert(rv == OGS_OK);
2755
2756
0
        rv = ogs_ipsubnet(&subnet->sub, ipstr, mask_or_numbits);
2757
0
        ogs_assert(rv == OGS_OK);
2758
2759
0
        subnet->family = subnet->gw.family;
2760
0
        subnet->prefixlen = atoi(mask_or_numbits);
2761
2762
0
        if (memcmp(subnet->gw.sub, subnet->sub.sub,
2763
0
                    sizeof(subnet->gw.sub)) != 0) {
2764
0
            char *subnet_string = NULL;
2765
2766
0
            if (subnet->family == AF_INET) {
2767
0
                subnet_string = ogs_ipv4_to_string(subnet->sub.sub[0]);
2768
0
                ogs_assert(subnet_string);
2769
0
            } else if (subnet->family == AF_INET6) {
2770
0
                subnet_string = ogs_ipv6addr_to_string(
2771
0
                        (uint8_t*)&subnet->sub.sub[0]);
2772
0
                ogs_assert(subnet_string);
2773
0
            }
2774
2775
0
            ogs_warn("Please change the configuration files of "
2776
0
                    "smf.yaml and upf.yaml as below.");
2777
0
            ogs_log_print(OGS_LOG_WARN, "\n<OLD Format>\n");
2778
0
            ogs_log_print(OGS_LOG_WARN, "smf:\n");
2779
0
            ogs_log_print(OGS_LOG_WARN, "  session:\n");
2780
0
            ogs_log_print(OGS_LOG_WARN, "    - subnet: %s/%s\n",
2781
0
                    ipstr, mask_or_numbits);
2782
0
            ogs_log_print(OGS_LOG_WARN, "\n<NEW Format>\n");
2783
0
            ogs_log_print(OGS_LOG_WARN, "smf:\n");
2784
0
            ogs_log_print(OGS_LOG_WARN, "  session:\n");
2785
0
            ogs_log_print(OGS_LOG_WARN, "    - subnet: %s/%s\n",
2786
0
                    subnet_string ? subnet_string : "Unknown", mask_or_numbits);
2787
0
            ogs_log_print(OGS_LOG_WARN, "      gateway: %s\n\n\n", ipstr);
2788
2789
0
            ogs_free(subnet_string);
2790
0
        }
2791
0
    }
2792
2793
0
    if (gateway) {
2794
0
        rv = ogs_ipsubnet(&subnet->gw, gateway, NULL);
2795
0
        ogs_assert(rv == OGS_OK);
2796
0
    }
2797
2798
0
    if (dnn)
2799
0
        ogs_cpystrn(subnet->dnn, dnn, OGS_MAX_DNN_LEN);
2800
2801
0
    ogs_pool_init(&subnet->pool, ogs_app()->pool.sess);
2802
2803
0
    ogs_list_add(&self.subnet_list, subnet);
2804
2805
0
    return subnet;
2806
0
}
2807
2808
void ogs_pfcp_subnet_remove(ogs_pfcp_subnet_t *subnet)
2809
0
{
2810
0
    ogs_assert(subnet);
2811
2812
0
    ogs_list_remove(&self.subnet_list, subnet);
2813
2814
0
    ogs_pool_final(&subnet->pool);
2815
2816
0
    ogs_pool_free(&ogs_pfcp_subnet_pool, subnet);
2817
0
}
2818
2819
void ogs_pfcp_subnet_remove_all(void)
2820
0
{
2821
0
    ogs_pfcp_subnet_t *subnet = NULL, *next_subnet = NULL;
2822
2823
0
    ogs_list_for_each_safe(&self.subnet_list, next_subnet, subnet)
2824
0
        ogs_pfcp_subnet_remove(subnet);
2825
0
}
2826
2827
ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family)
2828
0
{
2829
0
    ogs_pfcp_subnet_t *subnet = NULL;
2830
2831
0
    ogs_assert(family == AF_INET || family == AF_INET6);
2832
2833
0
    ogs_list_for_each(&self.subnet_list, subnet) {
2834
0
        if ((subnet->family == AF_UNSPEC || subnet->family == family) &&
2835
0
            (strlen(subnet->dnn) == 0) &&
2836
0
            subnet->pool.avail)
2837
0
            break;
2838
0
    }
2839
2840
0
    return subnet;
2841
0
}
2842
2843
ogs_pfcp_subnet_t *ogs_pfcp_find_subnet_by_dnn(int family, const char *dnn)
2844
0
{
2845
0
    ogs_pfcp_subnet_t *subnet = NULL;
2846
2847
0
    ogs_assert(dnn);
2848
0
    ogs_assert(family == AF_INET || family == AF_INET6);
2849
2850
0
    ogs_list_for_each(&self.subnet_list, subnet) {
2851
0
        if ((subnet->family == AF_UNSPEC || subnet->family == family) &&
2852
0
            (strlen(subnet->dnn) == 0 ||
2853
0
                (strlen(subnet->dnn) && ogs_strcasecmp(subnet->dnn, dnn) == 0)) &&
2854
0
            subnet->pool.avail)
2855
0
            break;
2856
0
    }
2857
2858
0
    return subnet;
2859
0
}
2860
2861
void ogs_pfcp_pool_init(ogs_pfcp_sess_t *sess)
2862
0
{
2863
0
    ogs_assert(sess);
2864
2865
0
    sess->obj.type = OGS_PFCP_OBJ_SESS_TYPE;
2866
2867
0
    ogs_pool_create(&sess->pdr_id_pool, OGS_MAX_NUM_OF_PDR);
2868
0
    ogs_pool_create(&sess->far_id_pool, OGS_MAX_NUM_OF_FAR);
2869
0
    ogs_pool_create(&sess->urr_id_pool, OGS_MAX_NUM_OF_URR);
2870
0
    ogs_pool_create(&sess->qer_id_pool, OGS_MAX_NUM_OF_QER);
2871
0
    ogs_pool_create(&sess->bar_id_pool, OGS_MAX_NUM_OF_BAR);
2872
2873
0
    ogs_pool_sequence_id_generate(&sess->pdr_id_pool);
2874
0
    ogs_pool_sequence_id_generate(&sess->far_id_pool);
2875
0
    ogs_pool_sequence_id_generate(&sess->urr_id_pool);
2876
0
    ogs_pool_sequence_id_generate(&sess->qer_id_pool);
2877
0
    ogs_pool_sequence_id_generate(&sess->bar_id_pool);
2878
0
}
2879
void ogs_pfcp_pool_final(ogs_pfcp_sess_t *sess)
2880
0
{
2881
0
    ogs_assert(sess);
2882
2883
0
    ogs_pool_destroy(&sess->pdr_id_pool);
2884
0
    ogs_pool_destroy(&sess->far_id_pool);
2885
0
    ogs_pool_destroy(&sess->urr_id_pool);
2886
0
    ogs_pool_destroy(&sess->qer_id_pool);
2887
0
    ogs_pool_destroy(&sess->bar_id_pool);
2888
0
}