Coverage Report

Created: 2026-11-06 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/pfcp/xact.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 *
4
 * This file is part of Open5GS.
5
 *
6
 * This program is free software: you can redistribute it and/or modify
7
 * it under the terms of the GNU Affero General Public License as published by
8
 * the Free Software Foundation, either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
 */
19
20
#include "ogs-pfcp.h"
21
#include "ogs-app.h"
22
23
#define PFCP_MIN_XACT_ID             1
24
#define PFCP_MAX_XACT_ID             0x800000
25
26
typedef enum {
27
    PFCP_XACT_UNKNOWN_STAGE,
28
    PFCP_XACT_INITIAL_STAGE,
29
    PFCP_XACT_INTERMEDIATE_STAGE,
30
    PFCP_XACT_FINAL_STAGE,
31
} ogs_pfcp_xact_stage_t;
32
33
static int ogs_pfcp_xact_initialized = 0;
34
static uint32_t g_xact_id = 0;
35
36
static OGS_POOL(pool, ogs_pfcp_xact_t);
37
38
static ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create(
39
        ogs_pfcp_node_t *node, uint32_t sqn);
40
static ogs_pfcp_xact_stage_t ogs_pfcp_xact_get_stage(
41
        uint8_t type, uint32_t xid);
42
static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type);
43
44
static void response_timeout(void *data);
45
static void holding_timeout(void *data);
46
static void delayed_commit_timeout(void *data);
47
48
int ogs_pfcp_xact_init(void)
49
0
{
50
0
    ogs_assert(ogs_pfcp_xact_initialized == 0);
51
52
0
    ogs_pool_init(&pool, ogs_app()->pool.xact);
53
54
0
    g_xact_id = 0;
55
56
0
    ogs_pfcp_xact_initialized = 1;
57
58
0
    return OGS_OK;
59
0
}
60
61
void ogs_pfcp_xact_final(void)
62
0
{
63
0
    ogs_assert(ogs_pfcp_xact_initialized == 1);
64
65
0
    ogs_pool_final(&pool);
66
67
0
    ogs_pfcp_xact_initialized = 0;
68
0
}
69
70
ogs_pfcp_xact_t *ogs_pfcp_xact_local_create(ogs_pfcp_node_t *node,
71
        void (*cb)(ogs_pfcp_xact_t *xact, void *data), void *data)
72
0
{
73
0
    ogs_pfcp_xact_t *xact = NULL;
74
75
0
    ogs_assert(node);
76
77
0
    ogs_pool_id_calloc(&pool, &xact);
78
0
    if (!xact) {
79
0
        ogs_error("Maximum number of xact[%lld] reached",
80
0
                    (long long)ogs_app()->pool.xact);
81
0
        return NULL;
82
0
    }
83
0
    xact->index = ogs_pool_index(&pool, xact);
84
85
0
    xact->org = OGS_PFCP_LOCAL_ORIGINATOR;
86
0
    xact->xid = OGS_NEXT_ID(g_xact_id, PFCP_MIN_XACT_ID, PFCP_MAX_XACT_ID);
87
0
    xact->node = node;
88
0
    xact->cb = cb;
89
0
    xact->data = data;
90
91
    /* Link before allocating timers so failure cleanup can unlink safely. */
92
0
    ogs_list_add(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
93
0
            &xact->node->local_list : &xact->node->remote_list, xact);
94
95
0
    xact->tm_response = ogs_timer_add(
96
0
            ogs_app()->timer_mgr, response_timeout,
97
0
            OGS_UINT_TO_POINTER(xact->id));
98
0
    if (!xact->tm_response) {
99
0
        ogs_error("Maximum number of xact->tm_response[%lld] reached",
100
0
                    (long long)ogs_app()->pool.timer);
101
0
        ogs_pfcp_xact_delete(xact);
102
0
        return NULL;
103
0
    }
104
0
    xact->response_rcount =
105
0
        ogs_local_conf()->time.message.pfcp.n1_response_rcount;
106
107
0
    xact->tm_holding = ogs_timer_add(
108
0
            ogs_app()->timer_mgr, holding_timeout,
109
0
            OGS_UINT_TO_POINTER(xact->id));
110
0
    if (!xact->tm_holding) {
111
0
        ogs_error("Maximum number of xact->tm_holding[%lld] reached",
112
0
                    (long long)ogs_app()->pool.timer);
113
0
        ogs_pfcp_xact_delete(xact);
114
0
        return NULL;
115
0
    }
116
0
    xact->holding_rcount =
117
0
        ogs_local_conf()->time.message.pfcp.n1_holding_rcount;
118
119
0
    xact->tm_delayed_commit = ogs_timer_add(
120
0
            ogs_app()->timer_mgr, delayed_commit_timeout,
121
0
            OGS_UINT_TO_POINTER(xact->id));
122
0
    if (!xact->tm_delayed_commit) {
123
0
        ogs_error("Maximum number of xact->tm_delayed_commit[%lld] reached",
124
0
                    (long long)ogs_app()->pool.timer);
125
0
        ogs_pfcp_xact_delete(xact);
126
0
        return NULL;
127
0
    }
128
129
0
    ogs_list_init(&xact->pdr_to_create_list);
130
131
0
    ogs_debug("[%d] %s Create  peer %s",
132
0
            xact->xid,
133
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
134
0
            ogs_sockaddr_to_string_static(node->addr_list));
135
136
0
    return xact;
137
0
}
138
139
static ogs_pfcp_xact_t *ogs_pfcp_xact_remote_create(
140
        ogs_pfcp_node_t *node, uint32_t sqn)
141
0
{
142
0
    ogs_pfcp_xact_t *xact = NULL;
143
144
0
    ogs_assert(node);
145
146
0
    ogs_pool_id_calloc(&pool, &xact);
147
0
    if (!xact) {
148
0
        ogs_error("Maximum number of xact[%lld] reached",
149
0
                    (long long)ogs_app()->pool.xact);
150
0
        return NULL;
151
0
    }
152
0
    xact->index = ogs_pool_index(&pool, xact);
153
154
0
    xact->org = OGS_PFCP_REMOTE_ORIGINATOR;
155
0
    xact->xid = OGS_PFCP_SQN_TO_XID(sqn);
156
0
    xact->node = node;
157
158
    /* Link before allocating timers so failure cleanup can unlink safely. */
159
0
    ogs_list_add(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
160
0
            &xact->node->local_list : &xact->node->remote_list, xact);
161
162
0
    xact->tm_response = ogs_timer_add(
163
0
            ogs_app()->timer_mgr, response_timeout,
164
0
            OGS_UINT_TO_POINTER(xact->id));
165
0
    if (!xact->tm_response) {
166
0
        ogs_error("Maximum number of xact->tm_response[%lld] reached",
167
0
                    (long long)ogs_app()->pool.timer);
168
0
        ogs_pfcp_xact_delete(xact);
169
0
        return NULL;
170
0
    }
171
0
    xact->response_rcount =
172
0
        ogs_local_conf()->time.message.pfcp.n1_response_rcount;
173
174
0
    xact->tm_holding = ogs_timer_add(
175
0
            ogs_app()->timer_mgr, holding_timeout,
176
0
            OGS_UINT_TO_POINTER(xact->id));
177
0
    if (!xact->tm_holding) {
178
0
        ogs_error("Maximum number of xact->tm_holding[%lld] reached",
179
0
                    (long long)ogs_app()->pool.timer);
180
0
        ogs_pfcp_xact_delete(xact);
181
0
        return NULL;
182
0
    }
183
0
    xact->holding_rcount =
184
0
        ogs_local_conf()->time.message.pfcp.n1_holding_rcount;
185
186
0
    xact->tm_delayed_commit = ogs_timer_add(
187
0
            ogs_app()->timer_mgr, delayed_commit_timeout,
188
0
            OGS_UINT_TO_POINTER(xact->id));
189
0
    if (!xact->tm_delayed_commit) {
190
0
        ogs_error("Maximum number of xact->tm_delayed_commit[%lld] reached",
191
0
                    (long long)ogs_app()->pool.timer);
192
0
        ogs_pfcp_xact_delete(xact);
193
0
        return NULL;
194
0
    }
195
196
0
    ogs_debug("[%d] %s Create  peer %s",
197
0
            xact->xid,
198
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
199
0
            ogs_sockaddr_to_string_static(node->addr_list));
200
201
0
    return xact;
202
0
}
203
204
void ogs_pfcp_xact_delete_all(ogs_pfcp_node_t *node)
205
0
{
206
0
    ogs_pfcp_xact_t *xact = NULL, *next_xact = NULL;
207
208
0
    ogs_list_for_each_safe(&node->local_list, next_xact, xact)
209
0
        ogs_pfcp_xact_delete(xact);
210
0
    ogs_list_for_each_safe(&node->remote_list, next_xact, xact)
211
0
        ogs_pfcp_xact_delete(xact);
212
0
}
213
214
ogs_pfcp_xact_t *ogs_pfcp_xact_find_by_id(ogs_pool_id_t id)
215
0
{
216
0
    return ogs_pool_find_by_id(&pool, id);
217
0
}
218
219
int ogs_pfcp_xact_update_tx(ogs_pfcp_xact_t *xact,
220
        ogs_pfcp_header_t *hdesc, ogs_pkbuf_t *pkbuf)
221
0
{
222
0
    ogs_pfcp_xact_stage_t stage;
223
0
    ogs_pfcp_header_t *h = NULL;
224
0
    int pfcp_hlen = 0;
225
226
0
    ogs_assert(xact);
227
0
    ogs_assert(xact->node);
228
0
    ogs_assert(hdesc);
229
0
    ogs_assert(pkbuf);
230
231
0
    ogs_debug("[%d] %s UPD TX-%d  peer %s",
232
0
            xact->xid,
233
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
234
0
            hdesc->type,
235
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
236
237
0
    stage = ogs_pfcp_xact_get_stage(hdesc->type, xact->xid);
238
0
    if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) {
239
0
        switch (stage) {
240
0
        case PFCP_XACT_INITIAL_STAGE:
241
0
            if (xact->step != 0) {
242
0
                ogs_error("invalid step[%d] type[%d]", xact->step, hdesc->type);
243
0
                ogs_pkbuf_free(pkbuf);
244
0
                return OGS_ERROR;
245
0
            }
246
0
            break;
247
248
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
249
0
            ogs_expect(0);
250
0
            ogs_pkbuf_free(pkbuf);
251
0
            return OGS_ERROR;
252
253
0
        case PFCP_XACT_FINAL_STAGE:
254
0
            if (xact->step != 2) {
255
0
                ogs_error("invalid step[%d] type[%d]", xact->step, hdesc->type);
256
0
                ogs_pkbuf_free(pkbuf);
257
0
                return OGS_ERROR;
258
0
            }
259
0
            break;
260
261
0
        default:
262
0
            ogs_assert_if_reached();
263
0
            break;
264
0
        }
265
0
    } else if (xact->org == OGS_PFCP_REMOTE_ORIGINATOR) {
266
0
        switch (stage) {
267
0
        case PFCP_XACT_INITIAL_STAGE:
268
0
            ogs_expect(0);
269
0
            ogs_pkbuf_free(pkbuf);
270
0
            return OGS_ERROR;
271
272
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
273
0
        case PFCP_XACT_FINAL_STAGE:
274
0
            if (xact->step != 1) {
275
0
                ogs_error("invalid step[%d] type[%d]", xact->step, hdesc->type);
276
0
                ogs_pkbuf_free(pkbuf);
277
0
                return OGS_ERROR;
278
0
            }
279
0
            break;
280
281
0
        default:
282
0
            ogs_error("invalid stage[%d] type[%d]", stage, hdesc->type);
283
0
            ogs_pkbuf_free(pkbuf);
284
0
            return OGS_ERROR;
285
0
        }
286
0
    } else {
287
0
        ogs_error("invalid org[%d] type[%d]", xact->org, hdesc->type);
288
0
        ogs_pkbuf_free(pkbuf);
289
0
        return OGS_ERROR;
290
0
    }
291
292
0
    if (hdesc->type >= OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE) {
293
0
        pfcp_hlen = OGS_PFCP_HEADER_LEN;
294
0
    } else {
295
0
        pfcp_hlen = OGS_PFCP_HEADER_LEN - OGS_PFCP_SEID_LEN;
296
0
    }
297
298
0
    ogs_pkbuf_push(pkbuf, pfcp_hlen);
299
0
    h = (ogs_pfcp_header_t *)pkbuf->data;
300
0
    memset(h, 0, pfcp_hlen);
301
302
0
    h->version = OGS_PFCP_VERSION;
303
0
    h->type = hdesc->type;
304
305
0
    if (h->type >= OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE) {
306
0
        h->seid_presence = 1;
307
0
        h->seid = htobe64(hdesc->seid);
308
0
        h->sqn = OGS_PFCP_XID_TO_SQN(xact->xid);
309
0
    } else {
310
0
        h->seid_presence = 0;
311
0
        h->sqn_only = OGS_PFCP_XID_TO_SQN(xact->xid);
312
0
    }
313
0
    h->length = htobe16(pkbuf->len - 4);
314
315
    /* Save Message type and packet of this step */
316
0
    xact->seq[xact->step].type = h->type;
317
0
    xact->seq[xact->step].pkbuf = pkbuf;
318
319
    /* Step */
320
0
    xact->step++;
321
322
0
    return OGS_OK;
323
0
}
324
325
static int ogs_pfcp_xact_update_rx(ogs_pfcp_xact_t *xact, uint8_t type)
326
0
{
327
0
    ogs_pfcp_xact_stage_t stage;
328
329
0
    ogs_debug("[%d] %s UPD RX-%d  peer %s",
330
0
            xact->xid,
331
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
332
0
            type,
333
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
334
335
0
    stage = ogs_pfcp_xact_get_stage(type, xact->xid);
336
0
    if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) {
337
0
        switch (stage) {
338
0
        case PFCP_XACT_INITIAL_STAGE:
339
0
            ogs_expect(0);
340
0
            return OGS_ERROR;
341
342
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
343
0
            if (xact->seq[1].type == type) {
344
0
                ogs_pkbuf_t *pkbuf = NULL;
345
346
0
                if (xact->step != 2 && xact->step != 3) {
347
0
                    ogs_error("invalid step[%d] type[%d]", xact->step, type);
348
0
                    ogs_pkbuf_free(pkbuf);
349
0
                    return OGS_ERROR;
350
0
                }
351
352
0
                pkbuf = xact->seq[2].pkbuf;
353
0
                if (pkbuf) {
354
0
                    if (xact->tm_holding)
355
0
                        ogs_timer_start(xact->tm_holding,
356
0
                                ogs_local_conf()->time.message.
357
0
                                    pfcp.t1_holding_duration);
358
359
0
                    ogs_warn("[%d] %s Request Duplicated. Retransmit!"
360
0
                            " for step %d type %d peer %s",
361
0
                            xact->xid,
362
0
                            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
363
0
                                "LOCAL " : "REMOTE",
364
0
                            xact->step, type,
365
0
                            ogs_sockaddr_to_string_static(
366
0
                                xact->node->addr_list));
367
0
                    ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
368
0
                } else {
369
0
                    ogs_warn("[%d] %s Request Duplicated. Discard!"
370
0
                            " for step %d type %d peer %s",
371
0
                            xact->xid,
372
0
                            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
373
0
                                "LOCAL " : "REMOTE",
374
0
                            xact->step, type,
375
0
                            ogs_sockaddr_to_string_static(
376
0
                                xact->node->addr_list));
377
0
                }
378
379
0
                return OGS_RETRY;
380
0
            }
381
382
0
            if (xact->step != 1) {
383
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
384
0
                return OGS_ERROR;
385
0
            }
386
387
0
            if (xact->tm_holding)
388
0
                ogs_timer_start(xact->tm_holding,
389
0
                        ogs_local_conf()->time.message.pfcp.
390
0
                        t1_holding_duration);
391
392
0
            break;
393
394
0
        case PFCP_XACT_FINAL_STAGE:
395
0
            if (xact->step != 1) {
396
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
397
0
                return OGS_ERROR;
398
0
            }
399
0
            break;
400
401
0
        default:
402
0
            ogs_error("invalid stage[%d]", stage);
403
0
            return OGS_ERROR;
404
0
        }
405
0
    } else if (xact->org == OGS_PFCP_REMOTE_ORIGINATOR) {
406
0
        switch (stage) {
407
0
        case PFCP_XACT_INITIAL_STAGE:
408
0
            if (xact->seq[0].type == type) {
409
0
                ogs_pkbuf_t *pkbuf = NULL;
410
411
0
                if (xact->step != 1 && xact->step != 2) {
412
0
                    ogs_error("invalid step[%d] type[%d]", xact->step, type);
413
0
                    return OGS_ERROR;
414
0
                }
415
416
0
                pkbuf = xact->seq[1].pkbuf;
417
0
                if (pkbuf) {
418
0
                    if (xact->tm_holding)
419
0
                        ogs_timer_start(xact->tm_holding,
420
0
                                ogs_local_conf()->time.message.
421
0
                                    pfcp.t1_holding_duration);
422
423
0
                    ogs_warn("[%d] %s Request Duplicated. Retransmit!"
424
0
                            " for step %d type %d peer %s",
425
0
                            xact->xid,
426
0
                            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
427
0
                                "LOCAL " : "REMOTE",
428
0
                            xact->step, type,
429
0
                            ogs_sockaddr_to_string_static(
430
0
                                xact->node->addr_list));
431
0
                    ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
432
0
                } else {
433
0
                    ogs_warn("[%d] %s Request Duplicated. Discard!"
434
0
                            " for step %d type %d peer %s",
435
0
                            xact->xid,
436
0
                            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
437
0
                                "LOCAL " : "REMOTE",
438
0
                            xact->step, type,
439
0
                            ogs_sockaddr_to_string_static(
440
0
                                xact->node->addr_list));
441
0
                }
442
443
0
                return OGS_RETRY;
444
0
            }
445
446
0
            if (xact->step != 0) {
447
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
448
0
                return OGS_ERROR;
449
0
            }
450
0
            if (xact->tm_holding)
451
0
                ogs_timer_start(xact->tm_holding,
452
0
                        ogs_local_conf()->time.message.pfcp.
453
0
                        t1_holding_duration);
454
455
0
            break;
456
457
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
458
0
            ogs_expect(0);
459
0
            return OGS_ERROR;
460
461
0
        case PFCP_XACT_FINAL_STAGE:
462
0
            if (xact->step != 2) {
463
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
464
0
                return OGS_ERROR;
465
0
            }
466
467
            /* continue */
468
0
            break;
469
470
0
        default:
471
0
            ogs_error("invalid stage[%d]", stage);
472
0
            return OGS_ERROR;
473
0
        }
474
0
    } else {
475
0
        ogs_error("invalid org[%d]", xact->org);
476
0
        return OGS_ERROR;
477
0
    }
478
479
0
    if (xact->tm_response)
480
0
        ogs_timer_stop(xact->tm_response);
481
482
    /* Save Message type of this step */
483
0
    xact->seq[xact->step].type = type;
484
485
    /* Step */
486
0
    xact->step++;
487
488
0
    return OGS_OK;
489
0
}
490
491
int ogs_pfcp_xact_commit(ogs_pfcp_xact_t *xact)
492
0
{
493
0
    uint8_t type;
494
0
    ogs_pkbuf_t *pkbuf = NULL;
495
0
    ogs_pfcp_xact_stage_t stage;
496
497
0
    ogs_assert(xact);
498
0
    ogs_assert(xact->node);
499
500
0
    ogs_debug("[%d] %s Commit  peer %s",
501
0
            xact->xid,
502
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
503
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
504
505
0
    type = xact->seq[xact->step-1].type;
506
0
    stage = ogs_pfcp_xact_get_stage(type, xact->xid);
507
508
0
    if (xact->org == OGS_PFCP_LOCAL_ORIGINATOR) {
509
0
        switch (stage) {
510
0
        case PFCP_XACT_INITIAL_STAGE:
511
0
            if (xact->step != 1) {
512
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
513
0
                ogs_pfcp_xact_delete(xact);
514
0
                return OGS_ERROR;
515
0
            }
516
517
0
            if (xact->tm_response)
518
0
                ogs_timer_start(xact->tm_response,
519
0
                        ogs_local_conf()->time.message.pfcp.t1_response_duration);
520
521
0
            break;
522
523
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
524
0
            ogs_expect(0);
525
0
            ogs_pfcp_xact_delete(xact);
526
0
            return OGS_ERROR;
527
528
0
        case PFCP_XACT_FINAL_STAGE:
529
0
            if (xact->step != 2 && xact->step != 3) {
530
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
531
0
                ogs_pfcp_xact_delete(xact);
532
0
                return OGS_ERROR;
533
0
            }
534
0
            if (xact->step == 2) {
535
0
                ogs_pfcp_xact_delete(xact);
536
0
                return OGS_OK;
537
0
            }
538
539
0
            break;
540
541
0
        default:
542
0
            ogs_error("invalid stage[%d] type[%d]", stage, type);
543
0
            ogs_pfcp_xact_delete(xact);
544
0
            return OGS_ERROR;
545
0
        }
546
0
    } else if (xact->org == OGS_PFCP_REMOTE_ORIGINATOR) {
547
0
        switch (stage) {
548
0
        case PFCP_XACT_INITIAL_STAGE:
549
0
            ogs_expect(0);
550
0
            ogs_pfcp_xact_delete(xact);
551
0
            return OGS_ERROR;
552
553
0
        case PFCP_XACT_INTERMEDIATE_STAGE:
554
0
            if (xact->step != 2) {
555
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
556
0
                ogs_pfcp_xact_delete(xact);
557
0
                return OGS_ERROR;
558
0
            }
559
0
            if (xact->tm_response)
560
0
                ogs_timer_start(xact->tm_response,
561
0
                        ogs_local_conf()->time.message.pfcp.
562
0
                        t1_response_duration);
563
564
0
            break;
565
566
0
        case PFCP_XACT_FINAL_STAGE:
567
0
            if (xact->step != 2 && xact->step != 3) {
568
0
                ogs_error("invalid step[%d] type[%d]", xact->step, type);
569
0
                ogs_pfcp_xact_delete(xact);
570
0
                return OGS_ERROR;
571
0
            }
572
0
            if (xact->step == 3) {
573
0
                ogs_pfcp_xact_delete(xact);
574
0
                return OGS_OK;
575
0
            }
576
577
0
            break;
578
579
0
        default:
580
0
            ogs_error("invalid stage[%d] type[%d]", stage, type);
581
0
            ogs_pfcp_xact_delete(xact);
582
0
            return OGS_ERROR;
583
0
        }
584
0
    } else {
585
0
        ogs_error("invalid org[%d] type[%d]", xact->org, type);
586
0
        ogs_pfcp_xact_delete(xact);
587
0
        return OGS_ERROR;
588
0
    }
589
590
0
    pkbuf = xact->seq[xact->step-1].pkbuf;
591
0
    ogs_assert(pkbuf);
592
593
0
    ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
594
595
0
    return OGS_OK;
596
0
}
597
598
void ogs_pfcp_xact_delayed_commit(ogs_pfcp_xact_t *xact, ogs_time_t duration)
599
0
{
600
0
    ogs_assert(xact);
601
0
    ogs_assert(duration);
602
0
    ogs_assert(xact->tm_delayed_commit);
603
604
0
    ogs_timer_start(xact->tm_delayed_commit, duration);
605
0
}
606
607
static void response_timeout(void *data)
608
0
{
609
0
    ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
610
0
    ogs_pfcp_xact_t *xact = NULL;
611
612
0
    ogs_assert(data);
613
0
    xact_id = OGS_POINTER_TO_UINT(data);
614
0
    ogs_assert(xact_id >= OGS_MIN_POOL_ID && xact_id <= OGS_MAX_POOL_ID);
615
616
0
    xact = ogs_pfcp_xact_find_by_id(xact_id);
617
0
    if (!xact) {
618
0
        ogs_error("PFCP Transaction has already been removed [%d]", xact_id);
619
0
        return;;
620
0
    }
621
0
    ogs_assert(xact->node);
622
623
0
    ogs_debug("[%d] %s Response Timeout "
624
0
            "for step %d type %d peer %s",
625
0
            xact->xid,
626
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
627
0
            xact->step, xact->seq[xact->step-1].type,
628
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
629
630
0
    if (--xact->response_rcount > 0) {
631
0
        ogs_pkbuf_t *pkbuf = NULL;
632
633
0
        if (xact->tm_response)
634
0
            ogs_timer_start(xact->tm_response,
635
0
                    ogs_local_conf()->time.message.pfcp.t1_response_duration);
636
637
0
        pkbuf = xact->seq[xact->step-1].pkbuf;
638
0
        ogs_assert(pkbuf);
639
640
0
        ogs_expect(OGS_OK == ogs_pfcp_sendto(xact->node, pkbuf));
641
0
    } else {
642
0
        ogs_warn("[%d] %s No Reponse. Give up! "
643
0
                "for step %d type %d peer %s",
644
0
                xact->xid,
645
0
                xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
646
0
                xact->step, xact->seq[xact->step-1].type,
647
0
                ogs_sockaddr_to_string_static(xact->node->addr_list));
648
649
0
        if (xact->cb)
650
0
            xact->cb(xact, xact->data);
651
652
0
        ogs_pfcp_xact_delete(xact);
653
0
    }
654
0
}
655
656
static void holding_timeout(void *data)
657
0
{
658
0
    ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
659
0
    ogs_pfcp_xact_t *xact = NULL;
660
661
0
    ogs_assert(data);
662
0
    xact_id = OGS_POINTER_TO_UINT(data);
663
0
    ogs_assert(xact_id >= OGS_MIN_POOL_ID && xact_id <= OGS_MAX_POOL_ID);
664
665
0
    xact = ogs_pfcp_xact_find_by_id(xact_id);
666
0
    if (!xact) {
667
0
        ogs_error("PFCP Transaction has already been removed [%d]", xact_id);
668
0
        return;;
669
0
    }
670
0
    ogs_assert(xact->node);
671
672
0
    ogs_debug("[%d] %s Holding Timeout "
673
0
            "for step %d type %d peer %s",
674
0
            xact->xid,
675
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
676
0
            xact->step, xact->seq[xact->step-1].type,
677
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
678
679
0
    if (--xact->holding_rcount > 0) {
680
0
        if (xact->tm_holding)
681
0
            ogs_timer_start(xact->tm_holding,
682
0
                    ogs_local_conf()->time.message.pfcp.t1_holding_duration);
683
0
    } else {
684
0
        ogs_debug("[%d] %s Delete Transaction "
685
0
                "for step %d type %d peer %s",
686
0
                xact->xid,
687
0
                xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
688
0
                xact->step, xact->seq[xact->step-1].type,
689
0
                ogs_sockaddr_to_string_static(xact->node->addr_list));
690
0
        ogs_pfcp_xact_delete(xact);
691
0
    }
692
0
}
693
694
static void delayed_commit_timeout(void *data)
695
0
{
696
0
    ogs_pool_id_t xact_id = OGS_INVALID_POOL_ID;
697
0
    ogs_pfcp_xact_t *xact = NULL;
698
699
0
    ogs_assert(data);
700
0
    xact_id = OGS_POINTER_TO_UINT(data);
701
0
    ogs_assert(xact_id >= OGS_MIN_POOL_ID && xact_id <= OGS_MAX_POOL_ID);
702
703
0
    xact = ogs_pfcp_xact_find_by_id(xact_id);
704
0
    if (!xact) {
705
0
        ogs_error("PFCP Transaction has already been removed [%d]", xact_id);
706
0
        return;;
707
0
    }
708
0
    ogs_assert(xact->node);
709
710
0
    ogs_debug("[%d] %s Delayed Send Timeout "
711
0
            "for step %d type %d peer %s",
712
0
            xact->xid,
713
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
714
0
            xact->step, xact->seq[xact->step-1].type,
715
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
716
717
0
    ogs_pfcp_xact_commit(xact);
718
0
}
719
720
int ogs_pfcp_xact_receive(
721
        ogs_pfcp_node_t *node, ogs_pfcp_header_t *h, ogs_pfcp_xact_t **xact)
722
0
{
723
0
    int rv;
724
725
0
    uint8_t type;
726
0
    uint32_t sqn, xid;
727
0
    ogs_pfcp_xact_stage_t stage;
728
0
    ogs_list_t *list = NULL;
729
0
    ogs_pfcp_xact_t *new = NULL;
730
731
0
    ogs_assert(node);
732
0
    ogs_assert(h);
733
734
0
    type = h->type;
735
0
    sqn = h->sqn;
736
0
    xid = OGS_PFCP_SQN_TO_XID(sqn);
737
0
    stage = ogs_pfcp_xact_get_stage(type, xid);
738
739
0
    switch (stage) {
740
0
    case PFCP_XACT_INITIAL_STAGE:
741
0
        list = &node->remote_list;
742
0
        break;
743
0
    case PFCP_XACT_INTERMEDIATE_STAGE:
744
0
        list = &node->local_list;
745
0
        break;
746
0
    case PFCP_XACT_FINAL_STAGE:
747
0
        list = &node->local_list;
748
0
        break;
749
0
    default:
750
0
        ogs_error("[%d] Unexpected type %u from PFCP peer %s",
751
0
                xid, type, ogs_sockaddr_to_string_static(node->addr_list));
752
0
        return OGS_ERROR;
753
0
    }
754
755
0
    ogs_assert(list);
756
0
    ogs_list_for_each(list, new) {
757
0
        if (new->xid == xid) {
758
0
            ogs_debug("[%d] %s Find    peer %s",
759
0
                new->xid,
760
0
                new->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
761
0
                ogs_sockaddr_to_string_static(node->addr_list));
762
0
            break;
763
0
        }
764
0
    }
765
766
0
    if (!new) {
767
0
        ogs_debug("[%d] Cannot find new type %u from PFCP peer %s",
768
0
                xid, type, ogs_sockaddr_to_string_static(node->addr_list));
769
0
        new = ogs_pfcp_xact_remote_create(node, sqn);
770
0
        if (!new) {
771
0
            ogs_error("[%d] No PFCP transaction resource for type %u "
772
0
                    "from peer %s", xid, type,
773
0
                    ogs_sockaddr_to_string_static(node->addr_list));
774
0
            return OGS_ERROR;
775
0
        }
776
0
    }
777
778
0
    ogs_debug("[%d] %s Receive peer %s",
779
0
            new->xid,
780
0
            new->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
781
0
            ogs_sockaddr_to_string_static(node->addr_list));
782
783
0
    rv = ogs_pfcp_xact_update_rx(new, type);
784
0
    if (rv == OGS_ERROR) {
785
0
        ogs_error("ogs_pfcp_xact_update_rx() failed");
786
0
        ogs_pfcp_xact_delete(new);
787
0
        return rv;
788
0
    } else if (rv == OGS_RETRY) {
789
0
        return rv;
790
0
    }
791
792
0
    *xact = new;
793
0
    return rv;
794
0
}
795
796
static ogs_pfcp_xact_stage_t ogs_pfcp_xact_get_stage(uint8_t type, uint32_t xid)
797
0
{
798
0
    ogs_pfcp_xact_stage_t stage = PFCP_XACT_UNKNOWN_STAGE;
799
800
0
    switch (type) {
801
0
    case OGS_PFCP_HEARTBEAT_REQUEST_TYPE:
802
0
    case OGS_PFCP_ASSOCIATION_SETUP_REQUEST_TYPE:
803
0
    case OGS_PFCP_ASSOCIATION_UPDATE_REQUEST_TYPE:
804
0
    case OGS_PFCP_ASSOCIATION_RELEASE_REQUEST_TYPE:
805
0
    case OGS_PFCP_SESSION_ESTABLISHMENT_REQUEST_TYPE:
806
0
    case OGS_PFCP_SESSION_MODIFICATION_REQUEST_TYPE:
807
0
    case OGS_PFCP_SESSION_DELETION_REQUEST_TYPE:
808
0
    case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE:
809
0
        stage = PFCP_XACT_INITIAL_STAGE;
810
0
        break;
811
0
    case OGS_PFCP_HEARTBEAT_RESPONSE_TYPE:
812
0
    case OGS_PFCP_ASSOCIATION_SETUP_RESPONSE_TYPE:
813
0
    case OGS_PFCP_ASSOCIATION_UPDATE_RESPONSE_TYPE:
814
0
    case OGS_PFCP_ASSOCIATION_RELEASE_RESPONSE_TYPE:
815
0
    case OGS_PFCP_VERSION_NOT_SUPPORTED_RESPONSE_TYPE:
816
0
    case OGS_PFCP_SESSION_ESTABLISHMENT_RESPONSE_TYPE:
817
0
    case OGS_PFCP_SESSION_MODIFICATION_RESPONSE_TYPE:
818
0
    case OGS_PFCP_SESSION_DELETION_RESPONSE_TYPE:
819
0
    case OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE:
820
0
        stage = PFCP_XACT_FINAL_STAGE;
821
0
        break;
822
823
0
    default:
824
0
        ogs_error("Not implemented PFCPv2 Message Type(%d)", type);
825
0
        break;
826
0
    }
827
828
0
    return stage;
829
0
}
830
831
int ogs_pfcp_xact_delete(ogs_pfcp_xact_t *xact)
832
0
{
833
0
    ogs_assert(xact);
834
0
    ogs_assert(xact->node);
835
836
0
    ogs_debug("[%d] %s Delete  peer %s",
837
0
            xact->xid,
838
0
            xact->org == OGS_PFCP_LOCAL_ORIGINATOR ? "LOCAL " : "REMOTE",
839
0
            ogs_sockaddr_to_string_static(xact->node->addr_list));
840
841
0
    if (xact->seq[0].pkbuf)
842
0
        ogs_pkbuf_free(xact->seq[0].pkbuf);
843
0
    if (xact->seq[1].pkbuf)
844
0
        ogs_pkbuf_free(xact->seq[1].pkbuf);
845
0
    if (xact->seq[2].pkbuf)
846
0
        ogs_pkbuf_free(xact->seq[2].pkbuf);
847
848
0
    if (xact->tm_response)
849
0
        ogs_timer_delete(xact->tm_response);
850
0
    if (xact->tm_holding)
851
0
        ogs_timer_delete(xact->tm_holding);
852
0
    if (xact->tm_delayed_commit)
853
0
        ogs_timer_delete(xact->tm_delayed_commit);
854
855
0
    ogs_list_remove(xact->org == OGS_PFCP_LOCAL_ORIGINATOR ?
856
0
            &xact->node->local_list : &xact->node->remote_list, xact);
857
0
    ogs_pool_id_free(&pool, xact);
858
859
0
    return OGS_OK;
860
0
}