Coverage Report

Created: 2026-10-16 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open5gs/lib/pfcp/build.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2019-2024 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
22
ogs_pkbuf_t *ogs_pfcp_build_heartbeat_request(uint8_t type)
23
0
{
24
0
    ogs_pfcp_message_t *pfcp_message = NULL;
25
0
    ogs_pfcp_heartbeat_request_t *req = NULL;
26
0
    ogs_pkbuf_t *pkbuf = NULL;
27
28
0
    ogs_debug("Heartbeat Request");
29
30
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
31
0
    if (!pfcp_message) {
32
0
        ogs_error("ogs_calloc() failed");
33
0
        return NULL;
34
0
    }
35
36
0
    req = &pfcp_message->pfcp_heartbeat_request;
37
38
0
    req->recovery_time_stamp.presence = 1;
39
0
    req->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
40
41
0
    pfcp_message->h.type = type;
42
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
43
0
    ogs_expect(pkbuf);
44
45
0
    ogs_free(pfcp_message);
46
47
0
    return pkbuf;
48
0
}
49
50
ogs_pkbuf_t *ogs_pfcp_build_heartbeat_response(uint8_t type)
51
0
{
52
0
    ogs_pfcp_message_t *pfcp_message = NULL;
53
0
    ogs_pfcp_heartbeat_response_t *rsp = NULL;
54
0
    ogs_pkbuf_t *pkbuf = NULL;
55
56
0
    ogs_debug("Heartbeat Response");
57
58
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
59
0
    if (!pfcp_message) {
60
0
        ogs_error("ogs_calloc() failed");
61
0
        return NULL;
62
0
    }
63
64
0
    rsp = &pfcp_message->pfcp_heartbeat_response;
65
66
0
    rsp->recovery_time_stamp.presence = 1;
67
0
    rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
68
69
0
    pfcp_message->h.type = type;
70
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
71
0
    ogs_expect(pkbuf);
72
73
0
    ogs_free(pfcp_message);
74
75
0
    return pkbuf;
76
0
}
77
78
ogs_pkbuf_t *ogs_pfcp_cp_build_association_setup_request(uint8_t type)
79
0
{
80
0
    ogs_pfcp_message_t *pfcp_message = NULL;
81
0
    ogs_pfcp_association_setup_request_t *req = NULL;
82
0
    ogs_pkbuf_t *pkbuf = NULL;
83
84
0
    ogs_pfcp_node_id_t node_id;
85
0
    int node_id_len = 0, rv;
86
87
0
    ogs_debug("Association Setup Request");
88
89
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
90
0
    if (!pfcp_message) {
91
0
        ogs_error("ogs_calloc() failed");
92
0
        return NULL;
93
0
    }
94
95
0
    req = &pfcp_message->pfcp_association_setup_request;
96
97
0
    rv = ogs_pfcp_sockaddr_to_node_id(&node_id, &node_id_len);
98
0
    if (rv != OGS_OK) {
99
0
        ogs_error("ogs_pfcp_sockaddr_to_node_id() failed");
100
0
        ogs_free(pfcp_message);
101
0
        return NULL;
102
0
    }
103
0
    req->node_id.presence = 1;
104
0
    req->node_id.data = &node_id;
105
0
    req->node_id.len = node_id_len;
106
107
0
    req->recovery_time_stamp.presence = 1;
108
0
    req->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
109
110
0
    req->cp_function_features.presence = 1;
111
0
    req->cp_function_features.u8 = ogs_pfcp_self()->cp_function_features.octet5;
112
113
0
    pfcp_message->h.type = type;
114
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
115
0
    ogs_expect(pkbuf);
116
117
0
    ogs_free(pfcp_message);
118
119
0
    return pkbuf;
120
0
}
121
122
ogs_pkbuf_t *ogs_pfcp_cp_build_association_setup_response(uint8_t type,
123
        uint8_t cause)
124
0
{
125
0
    ogs_pfcp_message_t *pfcp_message = NULL;
126
0
    ogs_pfcp_association_setup_response_t *rsp = NULL;
127
0
    ogs_pkbuf_t *pkbuf = NULL;
128
129
0
    ogs_pfcp_node_id_t node_id;
130
0
    int node_id_len = 0, rv;
131
132
0
    ogs_debug("Association Setup Response");
133
134
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
135
0
    if (!pfcp_message) {
136
0
        ogs_error("ogs_calloc() failed");
137
0
        return NULL;
138
0
    }
139
140
0
    rsp = &pfcp_message->pfcp_association_setup_response;
141
142
0
    rv = ogs_pfcp_sockaddr_to_node_id(&node_id, &node_id_len);
143
0
    if (rv != OGS_OK) {
144
0
        ogs_error("ogs_pfcp_sockaddr_to_node_id() failed");
145
0
        ogs_free(pfcp_message);
146
0
        return NULL;
147
0
    }
148
0
    rsp->node_id.presence = 1;
149
0
    rsp->node_id.data = &node_id;
150
0
    rsp->node_id.len = node_id_len;
151
152
0
    rsp->cause.presence = 1;
153
0
    rsp->cause.u8 = cause;
154
155
0
    rsp->recovery_time_stamp.presence = 1;
156
0
    rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
157
158
0
    rsp->cp_function_features.presence = 1;
159
0
    rsp->cp_function_features.u8 = ogs_pfcp_self()->cp_function_features.octet5;
160
161
0
    pfcp_message->h.type = type;
162
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
163
0
    ogs_expect(pkbuf);
164
165
0
    ogs_free(pfcp_message);
166
167
0
    return pkbuf;
168
0
}
169
170
ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_request(uint8_t type)
171
0
{
172
0
    ogs_pfcp_message_t *pfcp_message = NULL;
173
0
    ogs_pfcp_association_setup_request_t *req = NULL;
174
0
    ogs_pkbuf_t *pkbuf = NULL;
175
176
0
    ogs_pfcp_node_id_t node_id;
177
0
    int node_id_len = 0, rv;
178
179
0
    ogs_debug("Association Setup Request");
180
181
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
182
0
    if (!pfcp_message) {
183
0
        ogs_error("ogs_calloc() failed");
184
0
        return NULL;
185
0
    }
186
187
0
    req = &pfcp_message->pfcp_association_setup_request;
188
189
0
    rv = ogs_pfcp_sockaddr_to_node_id(&node_id, &node_id_len);
190
0
    if (rv != OGS_OK) {
191
0
        ogs_error("ogs_pfcp_sockaddr_to_node_id() failed");
192
0
        ogs_free(pfcp_message);
193
0
        return NULL;
194
0
    }
195
0
    req->node_id.presence = 1;
196
0
    req->node_id.data = &node_id;
197
0
    req->node_id.len = node_id_len;
198
199
0
    req->recovery_time_stamp.presence = 1;
200
0
    req->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
201
202
0
    ogs_assert(ogs_pfcp_self()->up_function_features_len);
203
0
    req->up_function_features.presence = 1;
204
0
    req->up_function_features.data = &ogs_pfcp_self()->up_function_features;
205
0
    req->up_function_features.len = ogs_pfcp_self()->up_function_features_len;
206
207
0
    pfcp_message->h.type = type;
208
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
209
0
    ogs_expect(pkbuf);
210
211
0
    ogs_free(pfcp_message);
212
213
0
    return pkbuf;
214
0
}
215
216
ogs_pkbuf_t *ogs_pfcp_up_build_association_setup_response(uint8_t type,
217
        uint8_t cause)
218
0
{
219
0
    ogs_pfcp_message_t *pfcp_message = NULL;
220
0
    ogs_pfcp_association_setup_response_t *rsp = NULL;
221
0
    ogs_pkbuf_t *pkbuf = NULL;
222
223
0
    ogs_pfcp_node_id_t node_id;
224
0
    int node_id_len = 0, rv;
225
226
0
    ogs_debug("Association Setup Response");
227
228
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
229
0
    if (!pfcp_message) {
230
0
        ogs_error("ogs_calloc() failed");
231
0
        return NULL;
232
0
    }
233
234
0
    rsp = &pfcp_message->pfcp_association_setup_response;
235
236
0
    rv = ogs_pfcp_sockaddr_to_node_id(&node_id, &node_id_len);
237
0
    if (rv != OGS_OK) {
238
0
        ogs_error("ogs_pfcp_sockaddr_to_node_id() failed");
239
0
        ogs_free(pfcp_message);
240
0
        return NULL;
241
0
    }
242
0
    rsp->node_id.presence = 1;
243
0
    rsp->node_id.data = &node_id;
244
0
    rsp->node_id.len = node_id_len;
245
246
0
    rsp->cause.presence = 1;
247
0
    rsp->cause.u8 = cause;
248
249
0
    rsp->recovery_time_stamp.presence = 1;
250
0
    rsp->recovery_time_stamp.u32 = ogs_pfcp_self()->local_recovery;
251
252
0
    ogs_assert(ogs_pfcp_self()->up_function_features_len);
253
0
    rsp->up_function_features.presence = 1;
254
0
    rsp->up_function_features.data = &ogs_pfcp_self()->up_function_features;
255
0
    rsp->up_function_features.len = ogs_pfcp_self()->up_function_features_len;
256
257
0
    pfcp_message->h.type = type;
258
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
259
0
    ogs_expect(pkbuf);
260
261
0
    ogs_free(pfcp_message);
262
263
0
    return pkbuf;
264
0
}
265
266
static struct {
267
    ogs_pfcp_f_teid_t f_teid;
268
    char dnn[OGS_MAX_DNN_LEN+1];
269
    char *sdf_filter[OGS_MAX_NUM_OF_FLOW_IN_PDR];
270
} pdrbuf[OGS_MAX_NUM_OF_PDR];
271
272
void ogs_pfcp_pdrbuf_init(void)
273
0
{
274
0
    memset(pdrbuf, 0, sizeof(pdrbuf));
275
0
}
276
277
void ogs_pfcp_pdrbuf_clear(void)
278
0
{
279
0
    int i, j;
280
0
    for (i = 0; i < OGS_MAX_NUM_OF_PDR; i++) {
281
0
        for (j = 0; j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
282
0
            if (pdrbuf[i].sdf_filter[j])
283
0
                ogs_free(pdrbuf[i].sdf_filter[j]);
284
0
        }
285
0
    }
286
0
}
287
288
void ogs_pfcp_build_create_pdr(
289
    ogs_pfcp_tlv_create_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr)
290
0
{
291
0
    ogs_pfcp_far_t *far = NULL;
292
0
    ogs_pfcp_sdf_filter_t pfcp_sdf_filter[OGS_MAX_NUM_OF_FLOW_IN_PDR];
293
0
    int j = 0;
294
0
    int len = 0;
295
296
0
    ogs_assert(message);
297
298
0
    ogs_assert(pdr);
299
300
0
    far = pdr->far;
301
0
    ogs_assert(far);
302
303
0
    message->presence = 1;
304
0
    message->pdr_id.presence = 1;
305
0
    message->pdr_id.u16 = pdr->id;
306
307
0
    if (pdr->precedence) { /* No precedence in Sxa */
308
0
        message->precedence.presence = 1;
309
0
        message->precedence.u32 = pdr->precedence;
310
0
    }
311
312
0
    message->pdi.presence = 1;
313
0
    message->pdi.source_interface.presence = 1;
314
0
    message->pdi.source_interface.u8 = pdr->src_if;
315
316
0
    if (pdr->src_if_type_presence) {
317
0
        message->pdi.source_interface_type.presence = 1;
318
0
        message->pdi.source_interface_type.u8 = pdr->src_if_type;
319
0
    }
320
321
0
    if (pdr->dnn) {
322
0
        message->pdi.network_instance.presence = 1;
323
0
        message->pdi.network_instance.len = ogs_fqdn_build(
324
0
            pdrbuf[i].dnn, pdr->dnn, strlen(pdr->dnn));
325
0
        message->pdi.network_instance.data = pdrbuf[i].dnn;
326
0
    }
327
328
0
    memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
329
0
    for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
330
0
        ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);
331
332
0
        if (pdr->flow[j].fd) {
333
0
            pfcp_sdf_filter[j].fd = 1;
334
0
            pfcp_sdf_filter[j].flow_description_len =
335
0
                    strlen(pdr->flow[j].description);
336
0
            pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
337
0
        }
338
0
        if (pdr->flow[j].bid) {
339
0
            pfcp_sdf_filter[j].bid = 1;
340
0
            pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
341
0
        }
342
343
0
        len = sizeof(ogs_pfcp_sdf_filter_t) +
344
0
                pfcp_sdf_filter[j].flow_description_len;
345
346
0
        message->pdi.sdf_filter[j].presence = 1;
347
0
        pdrbuf[i].sdf_filter[j] = ogs_calloc(1, len);
348
0
        ogs_assert(pdrbuf[i].sdf_filter[j]);
349
0
        ogs_pfcp_build_sdf_filter(&message->pdi.sdf_filter[j],
350
0
                &pfcp_sdf_filter[j], pdrbuf[i].sdf_filter[j], len);
351
0
    }
352
353
0
    if (pdr->ue_ip_addr_len) {
354
0
        message->pdi.ue_ip_address.presence = 1;
355
0
        message->pdi.ue_ip_address.data = &pdr->ue_ip_addr;
356
0
        message->pdi.ue_ip_address.len = pdr->ue_ip_addr_len;
357
0
    }
358
359
0
    for (j = 0; j < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; j++) {
360
0
        if (!pdr->ipv4_framed_routes || !pdr->ipv4_framed_routes[j])
361
0
            break;
362
0
        message->pdi.framed_route[j].presence = 1;
363
0
        message->pdi.framed_route[j].data = pdr->ipv4_framed_routes[j];
364
0
        message->pdi.framed_route[j].len = strlen(pdr->ipv4_framed_routes[j]);
365
0
        ogs_info("PFCP encode Framed-Route in PDR[%u]: %s",
366
0
                pdr->id, pdr->ipv4_framed_routes[j]);
367
0
    }
368
369
0
    for (j = 0; j < OGS_MAX_NUM_OF_FRAMED_ROUTES_IN_PDI; j++) {
370
0
        if (!pdr->ipv6_framed_routes || !pdr->ipv6_framed_routes[j])
371
0
            break;
372
0
        message->pdi.framed_ipv6_route[j].presence = 1;
373
0
        message->pdi.framed_ipv6_route[j].data = pdr->ipv6_framed_routes[j];
374
0
        message->pdi.framed_ipv6_route[j].len = strlen(pdr->ipv6_framed_routes[j]);
375
0
        ogs_info("PFCP encode Framed-IPv6-Route in PDR[%u]: %s",
376
0
                pdr->id, pdr->ipv6_framed_routes[j]);
377
0
    }
378
379
0
    if (pdr->f_teid_len) {
380
0
        int f_teid_len =
381
0
            ogs_min(pdr->f_teid_len, sizeof(pdrbuf[i].f_teid));
382
383
0
        memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, f_teid_len);
384
0
        pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid);
385
386
0
        message->pdi.local_f_teid.presence = 1;
387
0
        message->pdi.local_f_teid.data = &pdrbuf[i].f_teid;
388
0
        message->pdi.local_f_teid.len = f_teid_len;
389
0
    }
390
391
0
    if (pdr->qfi) {
392
0
        message->pdi.qfi.presence = 1;
393
0
        message->pdi.qfi.u8 = pdr->qfi;
394
0
    }
395
396
0
    if (pdr->outer_header_removal_len) {
397
0
        message->outer_header_removal.presence = 1;
398
0
        message->outer_header_removal.data = &pdr->outer_header_removal;
399
0
        message->outer_header_removal.len = pdr->outer_header_removal_len;
400
0
    }
401
402
0
    if (pdr->far) {
403
0
        message->far_id.presence = 1;
404
0
        message->far_id.u32 = pdr->far->id;
405
0
    }
406
407
0
    ogs_assert(pdr->num_of_urr <= OGS_ARRAY_SIZE(message->urr_id));
408
0
    for (i = 0; i < pdr->num_of_urr; i++) {
409
0
        message->urr_id[i].presence = 1;
410
0
        message->urr_id[i].u32 = pdr->urr[i]->id;
411
0
    }
412
413
0
    if (pdr->qer) {
414
0
        message->qer_id.presence = 1;
415
0
        message->qer_id.u32 = pdr->qer->id;
416
0
    }
417
0
}
418
419
bool ogs_pfcp_build_created_pdr(
420
    ogs_pfcp_tlv_created_pdr_t *message, int i, ogs_pfcp_pdr_t *pdr)
421
0
{
422
0
    bool pdr_presence = false;
423
424
0
    ogs_assert(message);
425
426
0
    ogs_assert(pdr);
427
428
0
    if (pdr->f_teid_len) {
429
0
        int f_teid_len =
430
0
            ogs_min(pdr->f_teid_len, sizeof(pdrbuf[i].f_teid));
431
432
0
        memcpy(&pdrbuf[i].f_teid, &pdr->f_teid, f_teid_len);
433
0
        pdrbuf[i].f_teid.teid = htobe32(pdr->f_teid.teid);
434
435
0
        message->local_f_teid.presence = 1;
436
0
        message->local_f_teid.data = &pdrbuf[i].f_teid;
437
0
        message->local_f_teid.len = f_teid_len;
438
439
0
        pdr_presence = true;
440
0
    }
441
442
0
    if (pdr_presence == true) {
443
0
        message->presence = 1;
444
0
        message->pdr_id.presence = 1;
445
0
        message->pdr_id.u16 = pdr->id;
446
0
    }
447
448
0
    return pdr_presence;
449
0
}
450
451
void ogs_pfcp_build_update_pdr(
452
    ogs_pfcp_tlv_update_pdr_t *message, int i,
453
    ogs_pfcp_pdr_t *pdr, uint64_t modify_flags)
454
0
{
455
0
    ogs_pfcp_sdf_filter_t pfcp_sdf_filter[OGS_MAX_NUM_OF_FLOW_IN_PDR];
456
0
    int j = 0;
457
0
    int len = 0;
458
459
0
    ogs_assert(message);
460
0
    ogs_assert(pdr);
461
462
0
    ogs_assert(modify_flags &
463
0
            (OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
464
0
             OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE|
465
0
             OGS_PFCP_MODIFY_EPC_TFT_UPDATE|
466
0
             OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL));
467
468
0
    message->presence = 1;
469
0
    message->pdr_id.presence = 1;
470
0
    message->pdr_id.u16 = pdr->id;
471
472
0
    if (modify_flags &
473
0
            (OGS_PFCP_MODIFY_TFT_NEW|OGS_PFCP_MODIFY_TFT_ADD|
474
0
             OGS_PFCP_MODIFY_TFT_REPLACE|OGS_PFCP_MODIFY_TFT_DELETE|
475
0
             OGS_PFCP_MODIFY_EPC_TFT_UPDATE)) {
476
0
        message->pdi.presence = 1;
477
0
        message->pdi.source_interface.presence = 1;
478
0
        message->pdi.source_interface.u8 = pdr->src_if;
479
480
0
        if (pdr->src_if_type_presence) {
481
0
            message->pdi.source_interface_type.presence = 1;
482
0
            message->pdi.source_interface_type.u8 = pdr->src_if_type;
483
0
        }
484
485
0
        memset(pfcp_sdf_filter, 0, sizeof(pfcp_sdf_filter));
486
0
        for (j = 0; j < pdr->num_of_flow && j < OGS_MAX_NUM_OF_FLOW_IN_PDR; j++) {
487
0
            ogs_assert(pdr->flow[j].fd || pdr->flow[j].bid);
488
489
0
            if (pdr->flow[j].fd) {
490
0
                pfcp_sdf_filter[j].fd = 1;
491
0
                pfcp_sdf_filter[j].flow_description_len =
492
0
                        strlen(pdr->flow[j].description);
493
0
                pfcp_sdf_filter[j].flow_description = pdr->flow[j].description;
494
0
            }
495
0
            if (pdr->flow[j].bid) {
496
0
                pfcp_sdf_filter[j].bid = 1;
497
0
                pfcp_sdf_filter[j].sdf_filter_id = pdr->flow[j].sdf_filter_id;
498
0
            }
499
500
0
            len = sizeof(ogs_pfcp_sdf_filter_t) +
501
0
                    pfcp_sdf_filter[j].flow_description_len;
502
503
0
            message->pdi.sdf_filter[j].presence = 1;
504
0
            pdrbuf[i].sdf_filter[j] = ogs_calloc(1, len);
505
0
            ogs_assert(pdrbuf[i].sdf_filter[j]);
506
0
            ogs_pfcp_build_sdf_filter(&message->pdi.sdf_filter[j],
507
0
                    &pfcp_sdf_filter[j], pdrbuf[i].sdf_filter[j], len);
508
0
        }
509
0
    }
510
0
    if (modify_flags & OGS_PFCP_MODIFY_OUTER_HEADER_REMOVAL) {
511
0
        if (pdr->outer_header_removal_len) {
512
0
            message->outer_header_removal.presence = 1;
513
0
            message->outer_header_removal.data = &pdr->outer_header_removal;
514
0
            message->outer_header_removal.len = pdr->outer_header_removal_len;
515
0
        }
516
0
    }
517
0
}
518
519
static struct {
520
    ogs_pfcp_outer_header_creation_t outer_header_creation;
521
    char dnn[OGS_MAX_DNN_LEN+1];
522
} farbuf[OGS_MAX_NUM_OF_FAR];
523
524
void ogs_pfcp_build_create_far(
525
    ogs_pfcp_tlv_create_far_t *message, int i, ogs_pfcp_far_t *far)
526
0
{
527
0
    ogs_pfcp_sess_t *sess = NULL;
528
529
0
    ogs_assert(message);
530
0
    ogs_assert(far);
531
0
    sess = far->sess;
532
0
    ogs_assert(sess);
533
534
0
    message->presence = 1;
535
0
    message->far_id.presence = 1;
536
0
    message->far_id.u32 = far->id;
537
538
0
    message->apply_action.presence = 1;
539
0
    message->apply_action.u16 = far->apply_action;
540
541
0
    if (far->apply_action & OGS_PFCP_APPLY_ACTION_FORW) {
542
0
        message->forwarding_parameters.presence = 1;
543
0
        message->forwarding_parameters.destination_interface.presence = 1;
544
0
        message->forwarding_parameters.destination_interface.u8 =
545
0
            far->dst_if;
546
547
0
        if (far->dst_if_type_presence) {
548
0
            message->forwarding_parameters.destination_interface_type.
549
0
                presence = 1;
550
0
            message->forwarding_parameters.destination_interface_type.
551
0
                u8 = far->dst_if_type;
552
0
        }
553
554
0
        if (far->dnn) {
555
0
            message->forwarding_parameters.network_instance.presence = 1;
556
0
            message->forwarding_parameters.network_instance.len =
557
0
                ogs_fqdn_build(farbuf[i].dnn, far->dnn, strlen(far->dnn));
558
0
            message->forwarding_parameters.network_instance.data =
559
0
                farbuf[i].dnn;
560
0
        }
561
562
0
        if (far->outer_header_creation_len) {
563
0
            memcpy(&farbuf[i].outer_header_creation,
564
0
                &far->outer_header_creation, far->outer_header_creation_len);
565
0
            farbuf[i].outer_header_creation.teid =
566
0
                    htobe32(far->outer_header_creation.teid);
567
568
0
            message->forwarding_parameters.outer_header_creation.presence = 1;
569
0
            message->forwarding_parameters.outer_header_creation.data =
570
0
                    &farbuf[i].outer_header_creation;
571
0
            message->forwarding_parameters.outer_header_creation.len =
572
0
                    far->outer_header_creation_len;
573
0
        }
574
0
    } else if (far->apply_action & OGS_PFCP_APPLY_ACTION_BUFF) {
575
0
        ogs_assert(sess->bar);
576
0
        message->bar_id.presence = 1;
577
0
        message->bar_id.u8 = sess->bar->id;
578
0
    }
579
0
}
580
581
void ogs_pfcp_build_update_far_deactivate(
582
        ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far)
583
0
{
584
0
    ogs_pfcp_sess_t *sess = NULL;
585
586
0
    ogs_assert(message);
587
0
    ogs_assert(far);
588
0
    sess = far->sess;
589
0
    ogs_assert(sess);
590
591
0
    message->presence = 1;
592
0
    message->far_id.presence = 1;
593
0
    message->far_id.u32 = far->id;
594
595
0
    far->apply_action =
596
0
        OGS_PFCP_APPLY_ACTION_BUFF | OGS_PFCP_APPLY_ACTION_NOCP;
597
0
    message->apply_action.presence = 1;
598
0
    message->apply_action.u16 = far->apply_action;
599
600
0
    ogs_assert(sess->bar);
601
0
    message->bar_id.presence = 1;
602
0
    message->bar_id.u8 = sess->bar->id;
603
0
}
604
605
void ogs_pfcp_build_update_far_activate(
606
        ogs_pfcp_tlv_update_far_t *message, int i, ogs_pfcp_far_t *far)
607
0
{
608
0
    ogs_assert(message);
609
0
    ogs_assert(far);
610
611
0
    message->presence = 1;
612
0
    message->far_id.presence = 1;
613
0
    message->far_id.u32 = far->id;
614
615
0
    ogs_assert(far->apply_action & OGS_PFCP_APPLY_ACTION_FORW);
616
617
0
    message->apply_action.presence = 1;
618
0
    message->apply_action.u16 = far->apply_action;
619
620
0
    message->update_forwarding_parameters.presence = 1;
621
0
    message->update_forwarding_parameters.destination_interface.presence = 1;
622
0
    message->update_forwarding_parameters.
623
0
        destination_interface.u8 = far->dst_if;
624
625
0
    if (far->dst_if_type_presence) {
626
0
        message->update_forwarding_parameters.destination_interface_type.
627
0
            presence = 1;
628
0
        message->update_forwarding_parameters.destination_interface_type.
629
0
            u8 = far->dst_if_type;
630
0
    }
631
632
0
    if (far->dnn) {
633
0
        message->update_forwarding_parameters.network_instance.presence = 1;
634
0
        message->update_forwarding_parameters.network_instance.len =
635
0
            ogs_fqdn_build(farbuf[i].dnn, far->dnn, strlen(far->dnn));
636
0
        message->update_forwarding_parameters.network_instance.data =
637
0
            farbuf[i].dnn;
638
0
    }
639
640
0
    if (far->outer_header_creation_len || far->smreq_flags.value) {
641
642
0
        if (far->outer_header_creation_len) {
643
0
            memcpy(&farbuf[i].outer_header_creation,
644
0
                &far->outer_header_creation, far->outer_header_creation_len);
645
0
            farbuf[i].outer_header_creation.teid =
646
0
                    htobe32(far->outer_header_creation.teid);
647
648
0
            message->update_forwarding_parameters.
649
0
                outer_header_creation.presence = 1;
650
0
            message->update_forwarding_parameters.
651
0
                outer_header_creation.data = &farbuf[i].outer_header_creation;
652
0
            message->update_forwarding_parameters.
653
0
                outer_header_creation.len = far->outer_header_creation_len;
654
655
0
        }
656
657
0
        if (far->smreq_flags.value) {
658
0
            message->update_forwarding_parameters.pfcpsmreq_flags.presence = 1;
659
0
            message->update_forwarding_parameters.pfcpsmreq_flags.u8 =
660
0
                far->smreq_flags.value;
661
0
        }
662
0
    }
663
0
}
664
665
static struct {
666
    ogs_pfcp_volume_threshold_t vol_threshold;
667
    ogs_pfcp_volume_quota_t vol_quota;
668
    ogs_pfcp_dropped_dl_traffic_threshold_t dropped_dl_traffic_threshold;
669
} urrbuf[OGS_MAX_NUM_OF_URR];
670
671
void ogs_pfcp_build_create_urr(
672
    ogs_pfcp_tlv_create_urr_t *message, int i, ogs_pfcp_urr_t *urr)
673
0
{
674
0
    ogs_assert(message);
675
0
    ogs_assert(urr);
676
677
0
    message->presence = 1;
678
0
    message->urr_id.presence = 1;
679
0
    message->urr_id.u32 = urr->id;
680
0
    message->measurement_method.presence = 1;
681
0
    message->measurement_method.u8 = urr->meas_method;
682
0
    message->reporting_triggers.presence = 1;
683
0
    message->reporting_triggers.u24 = (urr->rep_triggers.reptri_5 << 16)
684
0
                                    | (urr->rep_triggers.reptri_6 << 8)
685
0
                                    | (urr->rep_triggers.reptri_7);
686
0
    if (urr->meas_period) {
687
0
        message->measurement_period.presence = 1;
688
0
        message->measurement_period.u32 = urr->meas_period;
689
0
    }
690
691
0
    if (urr->vol_threshold.flags) {
692
0
        message->volume_threshold.presence = 1;
693
0
        ogs_pfcp_build_volume(
694
0
                &message->volume_threshold, &urr->vol_threshold,
695
0
                &urrbuf[i].vol_threshold, sizeof(urrbuf[i].vol_threshold));
696
0
    }
697
698
0
    if (urr->vol_quota.flags) {
699
0
        message->volume_quota.presence = 1;
700
0
        ogs_pfcp_build_volume(
701
0
                &message->volume_quota, &urr->vol_quota,
702
0
                &urrbuf[i].vol_quota, sizeof(urrbuf[i].vol_quota));
703
0
    }
704
705
0
    if (urr->event_threshold) {
706
0
        message->event_threshold.presence = 1;
707
0
        message->event_threshold.u32 = urr->event_threshold;
708
0
    }
709
710
0
    if (urr->event_quota) {
711
0
        message->event_quota.presence = 1;
712
0
        message->event_quota.u32 = urr->event_quota;
713
0
    }
714
715
0
    if (urr->time_threshold) {
716
0
        message->time_threshold.presence = 1;
717
0
        message->time_threshold.u32 = urr->time_threshold;
718
0
    }
719
720
0
    if (urr->time_quota) {
721
0
        message->time_quota.presence = 1;
722
0
        message->time_quota.u32 = urr->time_quota;
723
0
    }
724
725
0
    if (urr->quota_holding_time) {
726
0
        message->quota_holding_time.presence = 1;
727
0
        message->quota_holding_time.u32 = urr->quota_holding_time;
728
0
    }
729
730
0
    if (urr->dropped_dl_traffic_threshold.flags) {
731
0
        message->dropped_dl_traffic_threshold.presence = 1;
732
0
        ogs_pfcp_build_dropped_dl_traffic_threshold(
733
0
                &message->dropped_dl_traffic_threshold,
734
0
                &urr->dropped_dl_traffic_threshold,
735
0
                &urrbuf[i].dropped_dl_traffic_threshold,
736
0
                sizeof(urrbuf[i].dropped_dl_traffic_threshold));
737
0
    }
738
739
0
    if (urr->quota_validity_time) {
740
0
        message->quota_validity_time.presence = 1;
741
0
        message->quota_validity_time.u32 = urr->quota_validity_time;
742
0
    }
743
744
0
    if (urr->meas_info.octet5) {
745
0
        message->measurement_information.presence = 1;
746
0
        message->measurement_information.data = &urr->meas_info.octet5;
747
0
        message->measurement_information.len = 1;
748
0
    }
749
0
}
750
751
void ogs_pfcp_build_update_urr(
752
    ogs_pfcp_tlv_update_urr_t *message, int i,
753
    ogs_pfcp_urr_t *urr, uint64_t modify_flags)
754
0
{
755
0
    ogs_assert(message);
756
0
    ogs_assert(urr);
757
758
0
    ogs_assert(modify_flags &
759
0
            (OGS_PFCP_MODIFY_URR_MEAS_METHOD|
760
0
             OGS_PFCP_MODIFY_URR_REPORT_TRIGGER|
761
0
             OGS_PFCP_MODIFY_URR_VOLUME_THRESH|
762
0
             OGS_PFCP_MODIFY_URR_VOLUME_QUOTA|
763
0
             OGS_PFCP_MODIFY_URR_TIME_THRESH|
764
0
             OGS_PFCP_MODIFY_URR_TIME_QUOTA|
765
0
             OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME));
766
767
    /* Change request: Send only changed IEs */
768
0
    message->presence = 1;
769
0
    message->urr_id.presence = 1;
770
0
    message->urr_id.u32 = urr->id;
771
772
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_MEAS_METHOD) {
773
0
        message->measurement_method.presence = 1;
774
0
        message->measurement_method.u8 = urr->meas_method;
775
0
    }
776
777
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_REPORT_TRIGGER) {
778
0
        message->reporting_triggers.presence = 1;
779
0
        message->reporting_triggers.u24 = (urr->rep_triggers.reptri_5 << 16)
780
0
                                        | (urr->rep_triggers.reptri_6 << 8)
781
0
                                        | (urr->rep_triggers.reptri_7);
782
0
    }
783
784
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_VOLUME_THRESH) {
785
0
        if (urr->vol_threshold.flags) {
786
0
            message->volume_threshold.presence = 1;
787
0
            ogs_pfcp_build_volume(
788
0
                    &message->volume_threshold, &urr->vol_threshold,
789
0
                    &urrbuf[i].vol_threshold, sizeof(urrbuf[i].vol_threshold));
790
0
        }
791
0
    }
792
793
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_VOLUME_QUOTA) {
794
0
        if (urr->vol_quota.flags) {
795
0
            message->volume_quota.presence = 1;
796
0
            ogs_pfcp_build_volume(
797
0
                    &message->volume_quota, &urr->vol_quota,
798
0
                    &urrbuf[i].vol_quota, sizeof(urrbuf[i].vol_quota));
799
0
        }
800
0
    }
801
802
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_TIME_THRESH) {
803
0
        if (urr->time_threshold) {
804
0
            message->time_threshold.presence = 1;
805
0
            message->time_threshold.u32 = urr->time_threshold;
806
0
        }
807
0
    }
808
809
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_TIME_QUOTA) {
810
0
        if (urr->time_quota) {
811
0
            message->time_quota.presence = 1;
812
0
            message->time_quota.u32 = urr->time_quota;
813
0
        }
814
0
    }
815
816
0
    if (modify_flags & OGS_PFCP_MODIFY_URR_QUOTA_VALIDITY_TIME) {
817
0
        if (urr->quota_validity_time) {
818
0
            message->quota_validity_time.presence = 1;
819
0
            message->quota_validity_time.u32 = urr->quota_validity_time;
820
0
        }
821
0
    }
822
0
}
823
824
static struct {
825
    char mbr[OGS_PFCP_BITRATE_LEN];
826
    char gbr[OGS_PFCP_BITRATE_LEN];
827
} create_qer_buf[OGS_MAX_NUM_OF_QER], update_qer_buf[OGS_MAX_NUM_OF_QER];
828
829
void ogs_pfcp_build_create_qer(
830
    ogs_pfcp_tlv_create_qer_t *message, int i, ogs_pfcp_qer_t *qer)
831
0
{
832
0
    ogs_assert(message);
833
0
    ogs_assert(qer);
834
835
0
    message->presence = 1;
836
0
    message->qer_id.presence = 1;
837
0
    message->qer_id.u32 = qer->id;
838
839
0
    message->gate_status.presence = 1;
840
0
    message->gate_status.u8 = qer->gate_status.value;
841
842
0
    if (qer->mbr.uplink || qer->mbr.downlink) {
843
0
        message->maximum_bitrate.presence = 1;
844
0
        ogs_pfcp_build_bitrate(
845
0
                &message->maximum_bitrate,
846
0
                &qer->mbr, create_qer_buf[i].mbr, OGS_PFCP_BITRATE_LEN);
847
0
    }
848
0
    if (qer->gbr.uplink || qer->gbr.downlink) {
849
0
        message->guaranteed_bitrate.presence = 1;
850
0
        ogs_pfcp_build_bitrate(
851
0
                &message->guaranteed_bitrate,
852
0
                &qer->gbr, create_qer_buf[i].gbr, OGS_PFCP_BITRATE_LEN);
853
0
    }
854
855
0
    if (qer->qfi) {
856
0
        message->qos_flow_identifier.presence = 1;
857
0
        message->qos_flow_identifier.u8 = qer->qfi;
858
0
    }
859
0
}
860
861
void ogs_pfcp_build_update_qer(
862
    ogs_pfcp_tlv_update_qer_t *message, int i,
863
    ogs_pfcp_qer_t *qer, uint64_t modify_flags)
864
0
{
865
0
    ogs_assert(message);
866
0
    ogs_assert(qer);
867
868
0
    ogs_assert(modify_flags &
869
0
            (OGS_PFCP_MODIFY_QOS_MODIFY|
870
0
             OGS_PFCP_MODIFY_EPC_QOS_UPDATE));
871
872
0
    message->presence = 1;
873
0
    message->qer_id.presence = 1;
874
0
    message->qer_id.u32 = qer->id;
875
876
0
    if (modify_flags &
877
0
            (OGS_PFCP_MODIFY_QOS_MODIFY|
878
0
             OGS_PFCP_MODIFY_EPC_QOS_UPDATE)) {
879
0
        if (qer->mbr.uplink || qer->mbr.downlink) {
880
0
            message->maximum_bitrate.presence = 1;
881
0
            ogs_pfcp_build_bitrate(
882
0
                    &message->maximum_bitrate,
883
0
                    &qer->mbr, update_qer_buf[i].mbr, OGS_PFCP_BITRATE_LEN);
884
0
        }
885
0
        if (qer->gbr.uplink || qer->gbr.downlink) {
886
0
            message->guaranteed_bitrate.presence = 1;
887
0
            ogs_pfcp_build_bitrate(
888
0
                    &message->guaranteed_bitrate,
889
0
                    &qer->gbr, update_qer_buf[i].gbr, OGS_PFCP_BITRATE_LEN);
890
0
        }
891
0
    }
892
0
}
893
894
void ogs_pfcp_build_create_bar(
895
    ogs_pfcp_tlv_create_bar_t *message, ogs_pfcp_bar_t *bar)
896
0
{
897
0
    ogs_assert(message);
898
0
    ogs_assert(bar);
899
900
0
    message->presence = 1;
901
0
    message->bar_id.presence = 1;
902
0
    message->bar_id.u8 = bar->id;
903
0
}
904
905
static struct {
906
    ogs_pfcp_volume_measurement_t vol_meas;
907
} usage_report_buf;
908
909
ogs_pkbuf_t *ogs_pfcp_build_session_report_request(
910
        uint8_t type, ogs_pfcp_user_plane_report_t *report)
911
0
{
912
0
    ogs_pfcp_message_t *pfcp_message = NULL;
913
0
    ogs_pfcp_session_report_request_t *req = NULL;
914
0
    ogs_pkbuf_t *pkbuf = NULL;
915
0
    ogs_pfcp_downlink_data_service_information_t info;
916
0
    unsigned int i;
917
918
0
    ogs_assert(report);
919
920
0
    ogs_debug("PFCP session report request");
921
922
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
923
0
    if (!pfcp_message) {
924
0
        ogs_error("ogs_calloc() failed");
925
0
        return NULL;
926
0
    }
927
928
0
    req = &pfcp_message->pfcp_session_report_request;
929
930
0
    req->report_type.presence = 1;
931
0
    req->report_type.u8 = report->type.value;
932
933
0
    if (report->type.downlink_data_report) {
934
0
        int info_len = 0;
935
936
0
        req->downlink_data_report.presence = 1;
937
0
        req->downlink_data_report.pdr_id.presence = 1;
938
0
        req->downlink_data_report.pdr_id.u16 = report->downlink_data.pdr_id;
939
940
0
        memset(&info, 0, sizeof(info));
941
0
        if (report->downlink_data.qfi &&
942
0
                report->downlink_data.paging_policy_indication_value) {
943
944
0
            info_len = 3;
945
946
0
            info.qfii = 1;
947
0
            info.qfi = report->downlink_data.qfi;
948
0
            info.ppi = 1;
949
0
            info.paging_policy_indication_value =
950
0
                report->downlink_data.paging_policy_indication_value;
951
952
0
        } else if (report->downlink_data.qfi) {
953
954
0
            info_len = 2;
955
956
0
            info.qfii = 1;
957
0
            info.qfi = report->downlink_data.qfi;
958
0
        } else if (report->downlink_data.paging_policy_indication_value) {
959
960
0
            info_len = 2;
961
962
0
            info.ppi = 1;
963
0
            info.paging_policy_indication_value =
964
0
                report->downlink_data.paging_policy_indication_value;
965
0
        }
966
967
0
        if (info_len) {
968
0
            req->downlink_data_report.
969
0
                downlink_data_service_information.presence = 1;
970
0
            req->downlink_data_report.
971
0
                downlink_data_service_information.data = &info;
972
0
            req->downlink_data_report.
973
0
                downlink_data_service_information.len = info_len;
974
0
        }
975
0
    }
976
977
0
    if (report->type.usage_report) {
978
0
        ogs_assert(report->num_of_usage_report > 0);
979
0
        for (i = 0; i < report->num_of_usage_report; i++) {
980
0
            req->usage_report[i].presence = 1;
981
0
            req->usage_report[i].urr_id.presence = 1;
982
0
            req->usage_report[i].urr_id.u32 = report->usage_report[i].id;
983
0
            req->usage_report[i].ur_seqn.presence = 1;
984
0
            req->usage_report[i].ur_seqn.u32 = report->usage_report[i].seqn;
985
0
            req->usage_report[i].usage_report_trigger.presence = 1;
986
0
            req->usage_report[i].usage_report_trigger.u24 =
987
0
                (report->usage_report[i].rep_trigger.reptri_5 << 16)
988
0
                | (report->usage_report[i].rep_trigger.reptri_6 << 8)
989
0
                | (report->usage_report[i].rep_trigger.reptri_7);
990
991
0
            if (report->usage_report[i].start_time) {
992
0
                req->usage_report[i].start_time.presence = 1;
993
0
                req->usage_report[i].start_time.u32 = report->usage_report[i].start_time;
994
0
            }
995
996
0
            if (report->usage_report[i].end_time) {
997
0
                req->usage_report[i].end_time.presence = 1;
998
0
                req->usage_report[i].end_time.u32 = report->usage_report[i].end_time;
999
0
            }
1000
1001
0
            if (report->usage_report[i].vol_measurement.flags) {
1002
0
                req->usage_report[i].volume_measurement.presence = 1;
1003
0
                ogs_pfcp_build_volume_measurement(
1004
0
                        &req->usage_report[i].volume_measurement,
1005
0
                        &report->usage_report[i].vol_measurement,
1006
0
                        &usage_report_buf.vol_meas,
1007
0
                        sizeof(usage_report_buf.vol_meas));
1008
0
            }
1009
1010
0
            if (report->usage_report[i].dur_measurement) {
1011
0
                req->usage_report[i].duration_measurement.presence = 1;
1012
0
                req->usage_report[i].duration_measurement.u32 =
1013
0
                    report->usage_report[i].dur_measurement;
1014
0
            }
1015
1016
0
            if (report->usage_report[i].time_of_first_packet) {
1017
0
                req->usage_report[i].time_of_first_packet.presence = 1;
1018
0
                req->usage_report[i].time_of_first_packet.u32 =
1019
0
                    report->usage_report[i].time_of_first_packet;
1020
0
            }
1021
1022
0
            if (report->usage_report[i].time_of_last_packet) {
1023
0
                req->usage_report[i].time_of_last_packet.presence = 1;
1024
0
                req->usage_report[i].time_of_last_packet.u32 =
1025
0
                    report->usage_report[i].time_of_last_packet;
1026
0
            }
1027
0
        }
1028
0
    }
1029
1030
0
    if (report->error_indication.remote_f_teid_len) {
1031
0
        req->error_indication_report.presence = 1;
1032
0
        req->error_indication_report.remote_f_teid.presence = 1;
1033
0
        req->error_indication_report.remote_f_teid.data =
1034
0
            &report->error_indication.remote_f_teid;
1035
0
        req->error_indication_report.remote_f_teid.len =
1036
0
            report->error_indication.remote_f_teid_len;
1037
0
    }
1038
1039
0
    pfcp_message->h.type = type;
1040
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
1041
0
    ogs_expect(pkbuf);
1042
1043
0
    ogs_free(pfcp_message);
1044
1045
0
    return pkbuf;
1046
0
}
1047
1048
ogs_pkbuf_t *ogs_pfcp_build_session_report_response(
1049
        uint8_t type, uint8_t cause)
1050
0
{
1051
0
    ogs_pfcp_message_t *pfcp_message = NULL;
1052
0
    ogs_pfcp_session_report_response_t *rsp = NULL;
1053
0
    ogs_pkbuf_t *pkbuf = NULL;
1054
1055
0
    ogs_debug("PFCP session report response");
1056
1057
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
1058
0
    if (!pfcp_message) {
1059
0
        ogs_error("ogs_calloc() failed");
1060
0
        return NULL;
1061
0
    }
1062
1063
0
    rsp = &pfcp_message->pfcp_session_report_response;
1064
1065
0
    rsp->cause.presence = 1;
1066
0
    rsp->cause.u8 = cause;
1067
1068
0
    pfcp_message->h.type = type;
1069
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
1070
0
    ogs_expect(pkbuf);
1071
1072
0
    ogs_free(pfcp_message);
1073
1074
0
    return pkbuf;
1075
0
}
1076
1077
ogs_pkbuf_t *ogs_pfcp_build_session_deletion_response( uint8_t type, uint8_t cause,
1078
        ogs_pfcp_user_plane_report_t *report)
1079
0
{
1080
0
    ogs_pfcp_message_t *pfcp_message = NULL;
1081
0
    ogs_pfcp_session_deletion_response_t *rsp = NULL;
1082
0
    ogs_pkbuf_t *pkbuf = NULL;
1083
0
    unsigned int i;
1084
1085
0
    ogs_debug("PFCP session deletion response");
1086
1087
0
    pfcp_message = ogs_calloc(1, sizeof(*pfcp_message));
1088
0
    if (!pfcp_message) {
1089
0
        ogs_error("ogs_calloc() failed");
1090
0
        return NULL;
1091
0
    }
1092
1093
0
    rsp = &pfcp_message->pfcp_session_deletion_response;
1094
1095
0
    rsp->cause.presence = 1;
1096
0
    rsp->cause.u8 = cause;
1097
1098
0
    if (report->type.usage_report) {
1099
0
        ogs_assert(report->num_of_usage_report > 0);
1100
0
        for (i = 0; i < report->num_of_usage_report; i++) {
1101
0
            rsp->usage_report[i].presence = 1;
1102
0
            rsp->usage_report[i].urr_id.presence = 1;
1103
0
            rsp->usage_report[i].urr_id.u32 = report->usage_report[i].id;
1104
0
            rsp->usage_report[i].ur_seqn.presence = 1;
1105
0
            rsp->usage_report[i].ur_seqn.u32 = report->usage_report[i].seqn;
1106
0
            rsp->usage_report[i].usage_report_trigger.presence = 1;
1107
0
            rsp->usage_report[i].usage_report_trigger.u24 =
1108
0
                (report->usage_report[i].rep_trigger.reptri_5 << 16)
1109
0
                | (report->usage_report[i].rep_trigger.reptri_6 << 8)
1110
0
                | (report->usage_report[i].rep_trigger.reptri_7);
1111
1112
0
            if (report->usage_report[i].start_time) {
1113
0
                rsp->usage_report[i].start_time.presence = 1;
1114
0
                rsp->usage_report[i].start_time.u32 = report->usage_report[i].start_time;
1115
0
            }
1116
1117
0
            if (report->usage_report[i].end_time) {
1118
0
                rsp->usage_report[i].end_time.presence = 1;
1119
0
                rsp->usage_report[i].end_time.u32 = report->usage_report[i].end_time;
1120
0
            }
1121
1122
0
            if (report->usage_report[i].vol_measurement.flags) {
1123
0
                rsp->usage_report[i].volume_measurement.presence = 1;
1124
0
                ogs_pfcp_build_volume_measurement(
1125
0
                        &rsp->usage_report[i].volume_measurement,
1126
0
                        &report->usage_report[i].vol_measurement,
1127
0
                        &usage_report_buf.vol_meas,
1128
0
                        sizeof(usage_report_buf.vol_meas));
1129
0
            }
1130
1131
0
            rsp->usage_report[i].duration_measurement.presence = 1;
1132
0
            rsp->usage_report[i].duration_measurement.u32 =
1133
0
                report->usage_report[i].dur_measurement;
1134
1135
0
            if (report->usage_report[i].time_of_first_packet) {
1136
0
                rsp->usage_report[i].time_of_first_packet.presence = 1;
1137
0
                rsp->usage_report[i].time_of_first_packet.u32 =
1138
0
                    report->usage_report[i].time_of_first_packet;
1139
0
            }
1140
1141
0
            if (report->usage_report[i].time_of_last_packet) {
1142
0
                rsp->usage_report[i].time_of_last_packet.presence = 1;
1143
0
                rsp->usage_report[i].time_of_last_packet.u32 =
1144
0
                    report->usage_report[i].time_of_last_packet;
1145
0
            }
1146
0
        }
1147
0
    }
1148
0
    pfcp_message->h.type = type;
1149
0
    pkbuf = ogs_pfcp_build_msg(pfcp_message);
1150
0
    ogs_expect(pkbuf);
1151
1152
0
    ogs_free(pfcp_message);
1153
1154
0
    return pkbuf;
1155
0
}