Coverage Report

Created: 2024-02-11 06:14

/src/open5gs/lib/core/ogs-tlv-msg.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
3
 * Copyright (C) 2022 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4
 *
5
 * This file is part of Open5GS.
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Affero General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
#include "ogs-core.h"
22
23
ogs_tlv_desc_t ogs_tlv_desc_more1 = {
24
    OGS_TLV_MORE, "More", 0, 1, 0, 0, { NULL } };
25
ogs_tlv_desc_t ogs_tlv_desc_more2 = {
26
    OGS_TLV_MORE, "More", 0, 2, 0, 0, { NULL } };
27
ogs_tlv_desc_t ogs_tlv_desc_more3 = {
28
    OGS_TLV_MORE, "More", 0, 3, 0, 0, { NULL } };
29
ogs_tlv_desc_t ogs_tlv_desc_more4 = {
30
    OGS_TLV_MORE, "More", 0, 4, 0, 0, { NULL } };
31
ogs_tlv_desc_t ogs_tlv_desc_more5 = {
32
    OGS_TLV_MORE, "More", 0, 5, 0, 0, { NULL } };
33
ogs_tlv_desc_t ogs_tlv_desc_more6 = {
34
    OGS_TLV_MORE, "More", 0, 6, 0, 0, { NULL } };
35
ogs_tlv_desc_t ogs_tlv_desc_more7 = {
36
    OGS_TLV_MORE, "More", 0, 7, 0, 0, { NULL } };
37
ogs_tlv_desc_t ogs_tlv_desc_more8 = {
38
    OGS_TLV_MORE, "More", 0, 8, 0, 0, { NULL } };
39
ogs_tlv_desc_t ogs_tlv_desc_more9 = {
40
    OGS_TLV_MORE, "More", 0, 9, 0, 0, { NULL } };
41
ogs_tlv_desc_t ogs_tlv_desc_more10 = {
42
    OGS_TLV_MORE, "More", 0, 10, 0, 0, { NULL } };
43
ogs_tlv_desc_t ogs_tlv_desc_more11 = {
44
    OGS_TLV_MORE, "More", 0, 11, 0, 0, { NULL } };
45
ogs_tlv_desc_t ogs_tlv_desc_more12 = {
46
    OGS_TLV_MORE, "More", 0, 12, 0, 0, { NULL } };
47
ogs_tlv_desc_t ogs_tlv_desc_more13 = {
48
    OGS_TLV_MORE, "More", 0, 13, 0, 0, { NULL } };
49
ogs_tlv_desc_t ogs_tlv_desc_more14 = {
50
    OGS_TLV_MORE, "More", 0, 14, 0, 0, { NULL } };
51
ogs_tlv_desc_t ogs_tlv_desc_more15 = {
52
    OGS_TLV_MORE, "More", 0, 15, 0, 0, { NULL } };
53
ogs_tlv_desc_t ogs_tlv_desc_more16 = {
54
    OGS_TLV_MORE, "More", 0, 16, 0, 0, { NULL } };
55
56
/* Return specific TLV mode based on its TLV description type and the msg
57
 * provided mode (used to know the type length) */
58
static uint8_t tlv_ctype2mode(ogs_tlv_type_e ctype, uint8_t msg_mode)
59
0
{
60
0
    switch(ctype) {
61
0
    case OGS_TLV_UINT8:
62
0
    case OGS_TLV_UINT16:
63
0
    case OGS_TLV_UINT24:
64
0
    case OGS_TLV_UINT32:
65
0
    case OGS_TLV_INT8:
66
0
    case OGS_TLV_INT16:
67
0
    case OGS_TLV_INT24:
68
0
    case OGS_TLV_INT32:
69
0
    case OGS_TLV_FIXED_STR:
70
0
    case OGS_TLV_VAR_STR:
71
0
    case OGS_TLV_NULL:
72
0
    case OGS_TLV_MORE:
73
0
    case OGS_TLV_COMPOUND:
74
0
    case OGS_TLV_MESSAGE:
75
0
        return msg_mode;
76
0
    case OGS_TV_UINT8:
77
0
    case OGS_TV_UINT16:
78
0
    case OGS_TV_UINT24:
79
0
    case OGS_TV_UINT32:
80
0
    case OGS_TV_INT8:
81
0
    case OGS_TV_INT16:
82
0
    case OGS_TV_INT24:
83
0
    case OGS_TV_INT32:
84
0
    case OGS_TV_FIXED_STR:
85
0
    case OGS_TV_VAR_STR:
86
0
    case OGS_TV_NULL:
87
0
    case OGS_TV_MORE:
88
0
        if (msg_mode == OGS_TLV_MODE_T2_L2)
89
0
            return OGS_TLV_MODE_T1; /* Here return OGS_TLV_MODE_T2 if ever existing */
90
0
        else
91
0
            return OGS_TLV_MODE_T1;
92
0
    default:
93
0
        ogs_assert_if_reached();
94
0
        break;
95
0
    }
96
0
}
97
98
static ogs_tlv_t *tlv_add_leaf(
99
        ogs_tlv_t *parent_tlv, ogs_tlv_t *tlv, ogs_tlv_desc_t *desc, void *msg, uint8_t msg_mode)
100
0
{
101
0
    uint8_t tlv_mode = tlv_ctype2mode(desc->ctype, msg_mode);
102
103
0
    switch (desc->ctype) {
104
0
    case OGS_TLV_UINT8:
105
0
    case OGS_TLV_INT8:
106
0
    case OGS_TV_UINT8:
107
0
    case OGS_TV_INT8:
108
0
    {
109
0
        ogs_tlv_uint8_t *v = (ogs_tlv_uint8_t *)msg;
110
0
        if (parent_tlv) {
111
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
112
0
                    desc->type, 1, desc->instance, &v->u8);
113
0
            if (!tlv) {
114
0
                ogs_error("ogs_tlv_embed()");
115
0
                return NULL;
116
0
            }
117
0
        } else {
118
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
119
0
                    desc->type, 1, desc->instance, &v->u8);
120
0
            if (!tlv) {
121
0
                ogs_error("ogs_tlv_add()");
122
0
                return NULL;
123
0
            }
124
0
        }
125
0
        break;
126
0
    }
127
0
    case OGS_TLV_UINT16:
128
0
    case OGS_TLV_INT16:
129
0
    case OGS_TV_UINT16:
130
0
    case OGS_TV_INT16:
131
0
    {
132
0
        ogs_tlv_uint16_t *v = (ogs_tlv_uint16_t *)msg;
133
134
0
        v->u16 = htobe16(v->u16);
135
136
0
        if (parent_tlv) {
137
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
138
0
                    desc->type, 2, desc->instance, &v->u16);
139
0
            if (!tlv) {
140
0
                ogs_error("ogs_tlv_embed()");
141
0
                return NULL;
142
0
            }
143
0
        } else {
144
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
145
0
                    desc->type, 2, desc->instance, &v->u16);
146
0
            if (!tlv) {
147
0
                ogs_error("ogs_tlv_add()");
148
0
                return NULL;
149
0
            }
150
0
        }
151
0
        break;
152
0
    }
153
0
    case OGS_TLV_UINT24:
154
0
    case OGS_TLV_INT24:
155
0
    case OGS_TV_UINT24:
156
0
    case OGS_TV_INT24:
157
0
    {
158
0
        ogs_tlv_uint24_t *v = (ogs_tlv_uint24_t *)msg;
159
160
0
        v->u24 = v->u24 << 8;
161
0
        v->u24 = htobe32(v->u24);
162
163
0
        if (parent_tlv) {
164
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
165
0
                    desc->type, 3, desc->instance, &v->u24);
166
0
            if (!tlv) {
167
0
                ogs_error("ogs_tlv_embed()");
168
0
                return NULL;
169
0
            }
170
0
        } else {
171
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
172
0
                    desc->type, 3, desc->instance, &v->u24);
173
0
            if (!tlv) {
174
0
                ogs_error("ogs_tlv_add()");
175
0
                return NULL;
176
0
            }
177
0
        }
178
0
        break;
179
0
    }
180
0
    case OGS_TLV_UINT32:
181
0
    case OGS_TLV_INT32:
182
0
    case OGS_TV_UINT32:
183
0
    case OGS_TV_INT32:
184
0
    {
185
0
        ogs_tlv_uint32_t *v = (ogs_tlv_uint32_t *)msg;
186
187
0
        v->u32 = htobe32(v->u32);
188
189
0
        if (parent_tlv) {
190
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
191
0
                    desc->type, 4, desc->instance, &v->u32);
192
0
            if (!tlv) {
193
0
                ogs_error("ogs_tlv_embed()");
194
0
                return NULL;
195
0
            }
196
0
        } else {
197
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
198
0
                    desc->type, 4, desc->instance, &v->u32);
199
0
            if (!tlv) {
200
0
                ogs_error("ogs_tlv_add()");
201
0
                return NULL;
202
0
            }
203
0
        }
204
0
        break;
205
0
    }
206
0
    case OGS_TLV_FIXED_STR:
207
0
    case OGS_TV_FIXED_STR:
208
0
    {
209
0
        ogs_tlv_octet_t *v = (ogs_tlv_octet_t *)msg;
210
211
0
        if (parent_tlv) {
212
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
213
0
                    desc->type, desc->length, desc->instance, v->data);
214
0
            if (!tlv) {
215
0
                ogs_error("ogs_tlv_embed()");
216
0
                return NULL;
217
0
            }
218
0
        } else {
219
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
220
0
                    desc->type, desc->length, desc->instance, v->data);
221
0
            if (!tlv) {
222
0
                ogs_error("ogs_tlv_add()");
223
0
                return NULL;
224
0
            }
225
0
        }
226
0
        break;
227
0
    }
228
0
    case OGS_TLV_VAR_STR:
229
0
    {
230
0
        ogs_tlv_octet_t *v = (ogs_tlv_octet_t *)msg;
231
232
0
        if (v->len == 0) {
233
0
            ogs_error("No TLV length - [%s] T:%d I:%d (vsz=%d)",
234
0
                    desc->name, desc->type, desc->instance, desc->vsize);
235
0
            return NULL;
236
0
        }
237
238
0
        if (parent_tlv) {
239
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
240
0
                    desc->type, v->len, desc->instance, v->data);
241
0
            if (!tlv) {
242
0
                ogs_error("ogs_tlv_embed()");
243
0
                return NULL;
244
0
            }
245
0
        } else {
246
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
247
0
                    desc->type, v->len, desc->instance, v->data);
248
0
            if (!tlv) {
249
0
                ogs_error("ogs_tlv_add()");
250
0
                return NULL;
251
0
            }
252
0
        }
253
0
        break;
254
0
    }
255
0
    case OGS_TLV_NULL:
256
0
    case OGS_TV_NULL:
257
0
    {
258
0
        if (parent_tlv) {
259
0
            tlv = ogs_tlv_embed(parent_tlv, tlv_mode,
260
0
                    desc->type, 0, desc->instance, NULL);
261
0
            if (!tlv) {
262
0
                ogs_error("ogs_tlv_embed()");
263
0
                return NULL;
264
0
            }
265
0
        } else {
266
0
            tlv = ogs_tlv_add(tlv, tlv_mode,
267
0
                    desc->type, 0, desc->instance, NULL);
268
0
            if (!tlv) {
269
0
                ogs_error("ogs_tlv_add()");
270
0
                return NULL;
271
0
            }
272
0
        }
273
0
        break;
274
0
    }
275
0
    default:
276
0
        ogs_error("Unknown type [%d]", desc->ctype);
277
0
        return NULL;
278
0
    }
279
280
0
    return tlv;
281
0
}
282
283
static uint32_t tlv_add_compound(ogs_tlv_t **root, ogs_tlv_t *parent_tlv,
284
        ogs_tlv_desc_t *parent_desc, void *msg, int depth, uint8_t mode)
285
0
{
286
0
    ogs_tlv_presence_t *presence_p;
287
0
    ogs_tlv_desc_t *desc = NULL, *next_desc = NULL;
288
0
    ogs_tlv_t *tlv = NULL, *emb_tlv = NULL;
289
0
    uint8_t *p = msg;
290
0
    uint32_t offset = 0, count = 0;
291
0
    int i, j, r;
292
0
    char indent[17] = "                "; /* 16 spaces */
293
294
0
    ogs_assert(root);
295
0
    ogs_assert(parent_desc);
296
0
    ogs_assert(msg);
297
298
0
    ogs_assert(depth <= 8);
299
0
    indent[depth*2] = 0;
300
301
0
    *root = NULL;
302
303
0
    for (i = 0, desc = parent_desc->child_descs[i]; desc != NULL;
304
0
            i++, desc = parent_desc->child_descs[i]) {
305
0
        next_desc = parent_desc->child_descs[i+1];
306
0
        if (next_desc != NULL && next_desc->ctype == OGS_TLV_MORE) {
307
0
            int offset2 = offset;
308
0
            for (j = 0; j < next_desc->length; j++) {
309
0
                presence_p = (ogs_tlv_presence_t *)(p + offset2);
310
311
0
                if (*presence_p == 0)
312
0
                    break;
313
314
0
                if (desc->ctype == OGS_TLV_COMPOUND) {
315
0
                    ogs_trace("BUILD %sC#%d [%s] T:%d I:%d (vsz=%d) off:%p ",
316
0
                            indent, i, desc->name, desc->type, desc->instance,
317
0
                            desc->vsize, p + offset2);
318
319
0
                    if (parent_tlv)
320
0
                        tlv = ogs_tlv_embed(parent_tlv,
321
0
                                tlv_ctype2mode(desc->ctype, mode),
322
0
                                desc->type, 0, desc->instance, NULL);
323
0
                    else
324
0
                        tlv = ogs_tlv_add(tlv,
325
0
                                tlv_ctype2mode(desc->ctype, mode),
326
0
                                desc->type, 0, desc->instance, NULL);
327
328
0
                    r = tlv_add_compound(&emb_tlv, tlv, desc,
329
0
                            p + offset2 + sizeof(ogs_tlv_presence_t),
330
0
                            depth + 1, mode);
331
0
                    if (r <= 0 || !emb_tlv) {
332
0
                        ogs_error("tlv_add_compound() failed");
333
0
                        return 0;
334
0
                    }
335
0
                    count += 1 + r;
336
0
                } else {
337
0
                    ogs_trace("BUILD %sL#%d [%s] T:%d L:%d I:%d "
338
0
                            "(cls:%d vsz:%d) off:%p ",
339
0
                            indent, i, desc->name, desc->type, desc->length,
340
0
                            desc->instance, desc->ctype, desc->vsize,
341
0
                            p + offset2);
342
343
0
                    tlv = tlv_add_leaf(parent_tlv, tlv, desc,
344
0
                            p + offset2, mode);
345
0
                    if (!tlv) {
346
0
                        ogs_error("tlv_add_leaf() failed");
347
0
                        return 0;
348
0
                    }
349
0
                    count++;
350
0
                }
351
352
0
                if (*root == NULL)
353
0
                    *root = tlv;
354
355
0
                offset2 += desc->vsize;
356
0
            }
357
0
            offset += desc->vsize * next_desc->length;
358
0
            i++;
359
0
        } else {
360
0
            presence_p = (ogs_tlv_presence_t *)(p + offset);
361
362
0
            if (*presence_p) {
363
0
                if (desc->ctype == OGS_TLV_COMPOUND) {
364
0
                    ogs_trace("BUILD %sC#%d [%s] T:%d I:%d (vsz=%d) off:%p ",
365
0
                            indent, i, desc->name, desc->type, desc->instance,
366
0
                            desc->vsize, p + offset);
367
368
0
                    if (parent_tlv)
369
0
                        tlv = ogs_tlv_embed(parent_tlv,
370
0
                                tlv_ctype2mode(desc->ctype, mode),
371
0
                                desc->type, 0, desc->instance, NULL);
372
0
                    else
373
0
                        tlv = ogs_tlv_add(tlv,
374
0
                                tlv_ctype2mode(desc->ctype, mode),
375
0
                                desc->type, 0, desc->instance, NULL);
376
377
0
                    r = tlv_add_compound(&emb_tlv, tlv, desc,
378
0
                            p + offset + sizeof(ogs_tlv_presence_t),
379
0
                            depth + 1, mode);
380
0
                    if (r <= 0 || !emb_tlv) {
381
0
                        ogs_error("tlv_add_compound() failed");
382
0
                        return 0;
383
0
                    }
384
0
                    count += 1 + r;
385
0
                } else {
386
0
                    ogs_trace("BUILD %sL#%d [%s] T:%d L:%d I:%d "
387
0
                            "(cls:%d vsz:%d) off:%p ",
388
0
                            indent, i, desc->name, desc->type, desc->length,
389
0
                            desc->instance, desc->ctype, desc->vsize,
390
0
                            p + offset);
391
392
0
                    tlv = tlv_add_leaf(parent_tlv, tlv, desc, p + offset, mode);
393
0
                    if (!tlv) {
394
0
                        ogs_error("tlv_add_leaf() failed");
395
0
                        return 0;
396
0
                    }
397
0
                    count++;
398
0
                }
399
400
0
                if (*root == NULL)
401
0
                    *root = tlv;
402
0
            }
403
0
            offset += desc->vsize;
404
0
        }
405
0
    }
406
407
0
    return count;
408
0
}
409
410
ogs_pkbuf_t *ogs_tlv_build_msg(ogs_tlv_desc_t *desc, void *msg, int mode)
411
0
{
412
0
    ogs_tlv_t *root = NULL;
413
0
    uint32_t r, length, rendlen;
414
0
    ogs_pkbuf_t *pkbuf = NULL;
415
416
0
    ogs_assert(desc);
417
0
    ogs_assert(msg);
418
419
0
    ogs_assert(desc->ctype == OGS_TLV_MESSAGE);
420
421
0
    if (desc->child_descs[0]) {
422
0
        r = tlv_add_compound(&root, NULL, desc, msg, 0, mode);
423
0
        if (r <= 0 || !root) {
424
0
            ogs_error("tlv_add_compound() failed");
425
0
            return NULL;
426
0
        }
427
428
0
        length = ogs_tlv_calc_length(root);
429
0
    } else {
430
0
        length = 0;
431
0
    }
432
0
    pkbuf = ogs_pkbuf_alloc(NULL, OGS_TLV_MAX_HEADROOM+length);
433
0
    if (!pkbuf) {
434
0
        ogs_error("ogs_pkbuf_alloc() failed");
435
0
        return NULL;
436
0
    }
437
0
    ogs_pkbuf_reserve(pkbuf, OGS_TLV_MAX_HEADROOM);
438
0
    ogs_pkbuf_put(pkbuf, length);
439
440
0
    if (desc->child_descs[0]) {
441
0
        rendlen = ogs_tlv_render(root, pkbuf->data, length);
442
0
        if (rendlen != length) {
443
0
            ogs_error("ogs_tlv_render[rendlen:%d != length:%d] failed",
444
0
                    rendlen, length);
445
0
            return NULL;
446
0
        }
447
448
0
        ogs_tlv_free_all(root);
449
0
    }
450
451
0
    return pkbuf;
452
0
}
453
454
static ogs_tlv_desc_t* tlv_find_desc_by_type_inst(uint8_t *desc_index,
455
        uint32_t *tlv_offset, ogs_tlv_desc_t *parent_desc, uint16_t match_type, uint8_t match_instance, uint8_t match_type_pos)
456
6.24k
{
457
6.24k
    ogs_tlv_desc_t *prev_desc = NULL, *desc = NULL;
458
6.24k
    int i, offset = 0;
459
6.24k
    unsigned match_i = 0;
460
461
6.24k
    ogs_assert(parent_desc);
462
463
98.8k
    for (i = 0, desc = parent_desc->child_descs[i]; desc != NULL;
464
93.9k
            i++, desc = parent_desc->child_descs[i]) {
465
93.9k
        if (desc->type == match_type && desc->instance == match_instance) {
466
1.71k
            if (match_i == match_type_pos) {
467
1.32k
                *desc_index = i;
468
1.32k
                *tlv_offset = offset;
469
1.32k
                break;
470
1.32k
            }
471
390
            match_i++;
472
390
        }
473
474
92.6k
        if (desc->ctype == OGS_TLV_MORE) {
475
968
            ogs_assert(prev_desc && prev_desc->ctype != OGS_TLV_MORE);
476
968
            offset += prev_desc->vsize * (desc->length - 1);
477
91.6k
        } else {
478
91.6k
            offset += desc->vsize;
479
91.6k
        }
480
481
92.6k
        prev_desc = desc;
482
92.6k
    }
483
484
6.24k
    return desc;
485
6.24k
}
486
487
static int tlv_parse_leaf(void *msg, ogs_tlv_desc_t *desc, ogs_tlv_t *tlv)
488
572
{
489
572
    ogs_assert(msg);
490
572
    ogs_assert(desc);
491
572
    ogs_assert(tlv);
492
493
572
    switch (desc->ctype) {
494
0
    case OGS_TV_UINT8:
495
0
    case OGS_TV_INT8:
496
42
    case OGS_TLV_UINT8:
497
42
    case OGS_TLV_INT8:
498
42
    {
499
42
        ogs_tlv_uint8_t *v = (ogs_tlv_uint8_t *)msg;
500
501
42
        if (tlv->length != 1) {
502
18
            ogs_error("Invalid TLV length %d. It should be 1", tlv->length);
503
18
            return OGS_ERROR;
504
18
        }
505
24
        v->u8 = *(uint8_t*)(tlv->value);
506
24
        break;
507
42
    }
508
0
    case OGS_TV_UINT16:
509
0
    case OGS_TV_INT16:
510
31
    case OGS_TLV_UINT16:
511
31
    case OGS_TLV_INT16:
512
31
    {
513
31
        ogs_tlv_uint16_t *v = (ogs_tlv_uint16_t *)msg;
514
515
31
        if (tlv->length < 1 || tlv->length > 2) {
516
21
            ogs_error("Invalid TLV length %d.", tlv->length);
517
21
            return OGS_ERROR;
518
21
        }
519
10
        v->u16 = ((((uint8_t*)tlv->value)[0]<< 8)&0xff00) |
520
10
               ((((uint8_t*)tlv->value)[1]    )&0x00ff);
521
10
        break;
522
31
    }
523
0
    case OGS_TV_UINT24:
524
0
    case OGS_TV_INT24:
525
0
    case OGS_TLV_UINT24:
526
0
    case OGS_TLV_INT24:
527
0
    {
528
0
        ogs_tlv_uint24_t *v = (ogs_tlv_uint24_t *)msg;
529
530
0
        if (tlv->length < 1 || tlv->length > 3) {
531
0
            ogs_error("Invalid TLV length %d.", tlv->length);
532
0
            return OGS_ERROR;
533
0
        }
534
0
        v->u24 = ((((uint8_t*)tlv->value)[0]<<16)&0x00ff0000) |
535
0
               ((((uint8_t*)tlv->value)[1]<< 8)&0x0000ff00) |
536
0
               ((((uint8_t*)tlv->value)[2]    )&0x000000ff);
537
0
        break;
538
0
    }
539
0
    case OGS_TV_UINT32:
540
0
    case OGS_TV_INT32:
541
54
    case OGS_TLV_UINT32:
542
54
    case OGS_TLV_INT32:
543
54
    {
544
54
        ogs_tlv_uint32_t *v = (ogs_tlv_uint32_t *)msg;
545
546
54
        if (tlv->length < 1 || tlv->length > 4) {
547
21
            ogs_error("Invalid TLV length %d.", tlv->length);
548
21
            return OGS_ERROR;
549
21
        }
550
33
        v->u32 = ((((uint8_t*)tlv->value)[0]<<24)&0xff000000) |
551
33
               ((((uint8_t*)tlv->value)[1]<<16)&0x00ff0000) |
552
33
               ((((uint8_t*)tlv->value)[2]<< 8)&0x0000ff00) |
553
33
               ((((uint8_t*)tlv->value)[3]    )&0x000000ff);
554
33
        break;
555
54
    }
556
0
    case OGS_TV_FIXED_STR:
557
0
    case OGS_TLV_FIXED_STR:
558
0
    {
559
0
        ogs_tlv_octet_t *v = (ogs_tlv_octet_t *)msg;
560
561
0
        if (tlv->length != desc->length)
562
0
        {
563
0
            ogs_error("Invalid TLV length %d. It should be %d",
564
0
                    tlv->length, desc->length);
565
0
            return OGS_ERROR;
566
0
        }
567
568
0
        v->data = tlv->value;
569
0
        v->len = tlv->length;
570
0
        break;
571
0
    }
572
435
    case OGS_TLV_VAR_STR:
573
435
    {
574
435
        ogs_tlv_octet_t *v = (ogs_tlv_octet_t *)msg;
575
576
435
        v->data = tlv->value;
577
435
        v->len = tlv->length;
578
435
        break;
579
0
    }
580
0
    case OGS_TV_NULL:
581
0
    case OGS_TLV_NULL:
582
0
    {
583
0
        if (tlv->length != 0) {
584
0
            ogs_error("Invalid TLV length %d. It should be 0", tlv->length);
585
0
            return OGS_ERROR;
586
0
        }
587
0
        break;
588
0
    }
589
10
    default:
590
10
        ogs_error("Unknown type[%d]", desc->ctype);
591
10
        return OGS_ERROR;
592
572
    }
593
594
502
    return OGS_OK;
595
572
}
596
597
/* rbtree structure used to keep track count of TLVs with given <type,instance>
598
 * while parsing. This is used to link it to the matching nth field in a
599
 * ogs_tlv_desc_t struct */
600
typedef struct tlv_count_node_s {
601
    ogs_rbnode_t node;
602
    uint32_t key; /* type<<8 + instance */
603
    unsigned count;
604
} tlv_count_node_t;
605
606
static tlv_count_node_t *tlv_count_node_find(ogs_rbtree_t *tree, tlv_count_node_t *count_node_arr, unsigned count_node_arr_len,
607
        unsigned *count_alloc_next, uint16_t type, uint8_t instance)
608
6.24k
{
609
6.24k
    ogs_rbnode_t **new = NULL;
610
6.24k
    ogs_rbnode_t *parent = NULL;
611
6.24k
    tlv_count_node_t *this;
612
613
6.24k
    uint64_t key = (((uint32_t)type)<<8) | instance;
614
615
6.24k
    new = &tree->root;
616
26.9k
    while (*new) {
617
22.1k
        this = ogs_rb_entry(*new, tlv_count_node_t, node);
618
22.1k
        parent = *new;
619
22.1k
        if (key < this->key) {
620
10.2k
            new = &(*new)->left;
621
11.8k
        } else if (key > this->key) {
622
10.4k
            new = &(*new)->right;
623
10.4k
        } else { /* found entry: */
624
1.42k
            return this;
625
1.42k
        }
626
22.1k
    }
627
628
    /* No entry, need to add one: */
629
4.81k
    if (*count_alloc_next == count_node_arr_len) {
630
2
        ogs_error("This TLV has to many entries, can't parse");
631
2
        return NULL;
632
2
    }
633
4.81k
    this = &count_node_arr[(*count_alloc_next)++];
634
4.81k
    this->key = key;
635
4.81k
    this->count = 0;
636
4.81k
    ogs_rbtree_link_node(&this->node, parent, new);
637
4.81k
    ogs_rbtree_insert_color(tree, &this->node);
638
4.81k
    return this;
639
4.81k
}
640
641
static int tlv_parse_compound(void *msg, ogs_tlv_desc_t *parent_desc,
642
        ogs_tlv_t *parent_tlv, int depth, int mode)
643
622
{
644
622
    int rv;
645
622
    ogs_tlv_presence_t *presence_p = (ogs_tlv_presence_t *)msg;
646
622
    ogs_tlv_desc_t *desc = NULL, *next_desc = NULL;
647
622
    ogs_tlv_t *tlv = NULL, *emb_tlv = NULL;
648
622
    uint8_t *p = msg;
649
622
    uint32_t offset = 0;
650
622
    uint8_t index = 0;
651
622
    int i = 0, j;
652
622
    OGS_RBTREE(tree);
653
622
    tlv_count_node_t count_node[OGS_TLV_MAX_CHILD_DESC];
654
622
    unsigned count_node_alloc_next = 0;
655
622
    char indent[17] = "                "; /* 16 spaces */
656
657
622
    ogs_assert(msg);
658
622
    ogs_assert(parent_desc);
659
622
    ogs_assert(parent_tlv);
660
661
622
    ogs_assert(depth <= 8);
662
622
    indent[depth*2] = 0;
663
664
622
    tlv = parent_tlv;
665
6.76k
    while (tlv) {
666
6.24k
        tlv_count_node_t *curr_count = tlv_count_node_find(&tree, &count_node[0],
667
6.24k
                OGS_ARRAY_SIZE(count_node), &count_node_alloc_next, tlv->type, tlv->instance);
668
6.24k
        if (!curr_count)
669
2
            return OGS_ERROR;
670
6.24k
        desc = tlv_find_desc_by_type_inst(&index, &offset, parent_desc, tlv->type, tlv->instance, curr_count->count);
671
6.24k
        if (desc == NULL) {
672
4.91k
            ogs_warn("Unknown TLV type [%d]", tlv->type);
673
4.91k
            tlv = tlv->next;
674
4.91k
            continue;
675
4.91k
        }
676
677
1.32k
        presence_p = (ogs_tlv_presence_t *)(p + offset);
678
679
        /* Multiple of the same type TLV may be included */
680
1.32k
        next_desc = parent_desc->child_descs[index+1];
681
1.32k
        if (next_desc != NULL && next_desc->ctype == OGS_TLV_MORE) {
682
4.91k
            for (j = 0; j < next_desc->length; j++) {
683
4.48k
                presence_p =
684
4.48k
                    (ogs_tlv_presence_t *)(p + offset + desc->vsize * j);
685
4.48k
                if (*presence_p == 0) {
686
291
                    offset += desc->vsize * j;
687
291
                    break;
688
291
                }
689
4.48k
            }
690
719
            if (j == next_desc->length) {
691
428
                ogs_fatal("Multiple of the same type TLV need more room");
692
428
                tlv = tlv->next;
693
428
                continue;
694
428
            }
695
719
        } else {
696
610
            curr_count->count++;
697
610
        }
698
699
901
        if (desc->ctype == OGS_TLV_COMPOUND) {
700
329
            emb_tlv = ogs_tlv_parse_embedded_block(tlv, mode);
701
329
            if (emb_tlv == NULL) {
702
25
                ogs_error("Error while parse TLV");
703
25
                return OGS_ERROR;
704
25
            }
705
706
304
            ogs_trace("PARSE %sC#%d [%s] T:%d I:%d (vsz=%d) off:%p ",
707
304
                    indent, i++, desc->name, desc->type, desc->instance,
708
304
                    desc->vsize, p + offset);
709
710
304
            offset += sizeof(ogs_tlv_presence_t);
711
712
304
            rv = tlv_parse_compound(
713
304
                    p + offset, desc, emb_tlv, depth + 1, mode);
714
304
            if (rv != OGS_OK) {
715
2
                ogs_error("Can't parse compound TLV");
716
2
                return OGS_ERROR;
717
2
            }
718
719
302
            *presence_p = 1;
720
572
        } else {
721
572
            ogs_trace("PARSE %sL#%d [%s] T:%d L:%d I:%d "
722
572
                    "(cls:%d vsz:%d) off:%p ",
723
572
                    indent, i++, desc->name, desc->type, desc->length,
724
572
                    desc->instance, desc->ctype, desc->vsize, p + offset);
725
726
572
            rv = tlv_parse_leaf(p + offset, desc, tlv);
727
572
            if (rv != OGS_OK) {
728
70
                ogs_error("Can't parse leaf TLV");
729
70
                return OGS_ERROR;
730
70
            }
731
732
502
            *presence_p = 1;
733
502
        }
734
735
804
        tlv = tlv->next;
736
804
    }
737
738
523
    return OGS_OK;
739
622
}
740
741
int ogs_tlv_parse_msg(void *msg, ogs_tlv_desc_t *desc, ogs_pkbuf_t *pkbuf,
742
        int mode)
743
452
{
744
452
    int rv;
745
452
    ogs_tlv_t *root;
746
747
452
    ogs_assert(msg);
748
452
    ogs_assert(desc);
749
452
    ogs_assert(pkbuf);
750
751
452
    ogs_assert(desc->ctype == OGS_TLV_MESSAGE);
752
452
    if (!desc->child_descs[0]) {
753
0
        ogs_fatal("No Child Descs in [%s]", desc->name);
754
0
        ogs_assert_if_reached();
755
0
    }
756
757
452
    root = ogs_tlv_parse_block(pkbuf->len, pkbuf->data, mode);
758
452
    if (root == NULL) {
759
134
        ogs_error("Can't parse TLV message");
760
134
        return OGS_ERROR;
761
134
    }
762
763
318
    rv = tlv_parse_compound(msg, desc, root, 0, mode);
764
765
318
    ogs_tlv_free_all(root);
766
767
318
    return rv;
768
452
}
769
770
static uint16_t parse_get_element_type(uint8_t *pos, uint8_t mode)
771
0
{
772
0
    uint16_t type;
773
774
0
    switch(mode) {
775
0
    case OGS_TLV_MODE_T1_L1:
776
0
    case OGS_TLV_MODE_T1_L2:
777
0
    case OGS_TLV_MODE_T1_L2_I1:
778
0
    case OGS_TLV_MODE_T1:
779
0
        type = *pos;
780
0
        break;
781
0
    case OGS_TLV_MODE_T2_L2:
782
0
        type = *(pos++) << 8;
783
0
        type += *(pos++);
784
0
        break;
785
0
    default:
786
0
        ogs_assert_if_reached();
787
0
        break;
788
0
    }
789
790
0
    return type;
791
0
}
792
793
/* Get TLV element taking into account msg_mode (to know TLV tag length) +
794
 * specific TLV information from "desc" (to know whether the specific IE is TLV
795
 * or TV, and its expected length in the later case). */
796
static uint8_t *tlv_get_element_desc(ogs_tlv_t *tlv, uint8_t *blk, uint8_t msg_mode, ogs_tlv_desc_t *desc)
797
0
{
798
0
    uint8_t instance;
799
0
    unsigned tlv_tag_pos;
800
0
    uint8_t desc_index = 0;
801
0
    uint32_t tlv_offset = 0;
802
0
    uint16_t tlv_tag;
803
0
    uint8_t tlv_mode;
804
0
    static ogs_tlv_desc_t* tlv_desc;
805
806
0
    tlv_tag = parse_get_element_type(blk, msg_mode);
807
0
    instance = 0;  /* TODO: support instance != 0 if ever really needed by looking it up in pos */
808
0
    tlv_tag_pos = 0; /* All tags with same instance should use the same tlv_desc, so take the first one */
809
0
    tlv_desc = tlv_find_desc_by_type_inst(&desc_index, &tlv_offset, desc, tlv_tag, instance, tlv_tag_pos);
810
0
    if (!tlv_desc) {
811
0
        ogs_error("Can't parse find TLV description for type %u", tlv_tag);
812
0
        return NULL;
813
0
    }
814
0
    tlv_mode = tlv_ctype2mode(tlv_desc->ctype, msg_mode);
815
816
0
    if (tlv_mode == OGS_TLV_MODE_T1)
817
0
        return tlv_get_element_fixed(tlv, blk, tlv_mode, tlv_desc->length);
818
0
    return tlv_get_element(tlv, blk, tlv_mode);
819
0
}
820
821
/* Similar to ogs_tlv_parse_block(), but taking into account each TLV format from "desc". */
822
static ogs_tlv_t *ogs_tlv_parse_block_desc(uint32_t length, void *data, uint8_t msg_mode, ogs_tlv_desc_t *desc)
823
0
{
824
0
    uint8_t *pos = data;
825
0
    uint8_t *blk = data;
826
827
0
    ogs_tlv_t *root = NULL;
828
0
    ogs_tlv_t *prev = NULL;
829
0
    ogs_tlv_t *curr = NULL;
830
831
0
    root = curr = ogs_tlv_get();
832
833
0
    ogs_assert(curr);
834
835
0
    pos = tlv_get_element_desc(curr, pos, msg_mode, desc);
836
837
0
    ogs_assert(pos);
838
839
0
    while(pos - blk < length) {
840
0
        prev = curr;
841
842
0
        curr = ogs_tlv_get();
843
0
        ogs_assert(curr);
844
0
        prev->next = curr;
845
846
0
        pos = tlv_get_element_desc(curr, pos, msg_mode, desc);
847
0
        ogs_assert(pos);
848
0
    }
849
850
0
    if (length != (pos - blk)) {
851
0
        ogs_error("ogs_tlv_parse_block() failed[LEN:%d,MODE:%d]",
852
0
                length, msg_mode);
853
0
        ogs_error("POS[%p] BLK[%p] POS-BLK[%d]", pos, blk, (int)(pos - blk));
854
0
        ogs_log_hexdump(OGS_LOG_FATAL, data, length);
855
856
0
        ogs_tlv_free_all(root);
857
0
        return NULL;
858
0
    }
859
860
0
    return root;
861
0
}
862
863
/* Similar to ogs_tlv_parse_msg(), but takes each TLV type from the desc
864
 * defintion. This allows parsing messages which have different types of TLVs in
865
 * it (for instance GTPv1-C). */
866
int ogs_tlv_parse_msg_desc(
867
        void *msg, ogs_tlv_desc_t *desc, ogs_pkbuf_t *pkbuf, int msg_mode)
868
0
{
869
0
    int rv;
870
0
    ogs_tlv_t *root;
871
872
0
    ogs_assert(msg);
873
0
    ogs_assert(desc);
874
0
    ogs_assert(pkbuf);
875
876
0
    ogs_assert(desc->ctype == OGS_TLV_MESSAGE);
877
0
    ogs_assert(desc->child_descs[0]);
878
879
0
    root = ogs_tlv_parse_block_desc(pkbuf->len, pkbuf->data, msg_mode, desc);
880
0
    if (root == NULL) {
881
0
        ogs_error("Can't parse TLV message");
882
0
        return OGS_ERROR;
883
0
    }
884
885
0
    rv = tlv_parse_compound(msg, desc, root, 0, msg_mode);
886
887
0
    ogs_tlv_free_all(root);
888
889
0
    return rv;
890
0
}