Coverage Report

Created: 2026-07-12 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-asterix.c
Line
Count
Source
1
/* packet-asterix.c
2
 * Routines for ASTERIX decoding
3
 *
4
 * By BoĊĦtjan Polanc <bostjan.polanc@gmail.com>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*
14
 * ASTERIX (All-purpose structured EUROCONTROL surveillances
15
 * information exchange) is a protocol/data format related to air traffic control.
16
 *
17
 * Specifications can be downloaded from:
18
 *  - https://www.eurocontrol.int/asterix (original specifications - in PDF)
19
 *  - https://zoranbosnjak.github.io/asterix-specs/ (structured version)
20
 */
21
22
#include <config.h>
23
24
#include "exceptions.h"
25
#include "packet-asterix.h"
26
#include "packet-asterix-generated.h"
27
#include "packet-tcp.h"
28
29
15.4k
#define HEADER_LENGTH 3
30
30
#define ASTERIX_PORT 8600
31
9.96k
#define MAX_INTERPRETATIONS 100
32
#define MAX_INTERPRETATION_DEPTH 30
33
23.7M
#define MAX_FSPEC_BIT_LENGTH 1024
34
676k
#define OCTAL_BIT_LENGTH 3
35
327k
#define ICAO_BIT_LENGTH 6
36
37
static int proto_asterix;
38
39
static char fspec_bit_string[MAX_FSPEC_BIT_LENGTH];
40
41
static dissector_handle_t asterix_handle;
42
static dissector_handle_t asterix_tcp_handle;
43
44
static int ett_asterix;
45
static int ett_asterix_record;
46
static int ett_asterix_possible_interpretation;
47
static int ett_asterix_possible_interpretations;
48
static int ett_asterix_spare_error;
49
50
/* With invalid data (e.g. fuzz tests), to great of interpretation depth can cause "freezes",
51
   where search for interpretations can last a long time. By default depth is set to 15,
52
   which should never be a problem for random data. Users can select a higher depth.
53
*/
54
static int selected_interpretations_depth = depth_15;
55
56
static unsigned int solution_count;
57
static int solutions[MAX_INTERPRETATIONS][MAX_INTERPRETATION_DEPTH + 1];
58
59
static unsigned asterix_get_unsigned_value(tvbuff_t *tvb, unsigned offset, unsigned bytes)
60
3.23M
{
61
3.23M
    switch (bytes)
62
3.23M
    {
63
1.90M
        case 1:
64
1.90M
            return tvb_get_uint8(tvb, offset);
65
982k
        case 2:
66
982k
            return tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
67
267k
        case 3:
68
267k
            return tvb_get_uint24(tvb, offset, ENC_BIG_ENDIAN);
69
81.1k
        case 4:
70
81.1k
            return tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN);
71
0
        default:
72
0
            return -1;
73
3.23M
    }
74
3.23M
}
75
76
static int asterix_get_signed_value(tvbuff_t *tvb, unsigned offset, unsigned bytes)
77
46.7k
{
78
46.7k
    switch (bytes)
79
46.7k
    {
80
33.1k
        case 1:
81
33.1k
            return tvb_get_int8(tvb, offset);
82
13.6k
        case 2:
83
13.6k
            return tvb_get_int16(tvb, offset, ENC_BIG_ENDIAN);
84
0
        case 3:
85
0
            return tvb_get_int24(tvb, offset, ENC_BIG_ENDIAN);
86
0
        case 4:
87
0
            return tvb_get_int32(tvb, offset, ENC_BIG_ENDIAN);
88
0
        default:
89
0
            return -1;
90
46.7k
    }
91
46.7k
}
92
93
// get signed integer from specified number of bits
94
static int get_signed_int(unsigned value, unsigned bits)
95
308k
{
96
308k
    int ret = 0;
97
308k
    int sign = 1;
98
308k
    if ((value >> (bits - 1) & 1))
99
101k
    {
100
101k
        sign = -1;
101
101k
        value = ~value;
102
101k
        value++;
103
101k
    }
104
105
308k
    unsigned int mask = 1;
106
5.28M
    for (unsigned int i = 0; i < (bits - 1); i++)
107
4.97M
    {
108
4.97M
        if ((value >> i) & 1)
109
1.67M
        {
110
1.67M
            ret |= mask;
111
1.67M
        }
112
4.97M
        mask *= 2;
113
4.97M
    }
114
308k
    return ret * sign;
115
308k
}
116
117
// test extended FX bit
118
static bool asterix_extended_end (tvbuff_t *tvb, unsigned offset)
119
399k
{
120
399k
  uint8_t val = tvb_get_uint8(tvb, offset);
121
399k
  if ((val & 0x01) == 0)
122
177k
  {
123
177k
    return true;
124
177k
  }
125
221k
  else
126
221k
  {
127
221k
    return false;
128
221k
  }
129
399k
}
130
131
// test FSPEC bit
132
static bool asterix_field_exists (tvbuff_t *tvb, unsigned offset, unsigned bit_index)
133
20.5M
{
134
20.5M
    unsigned int byte_index = bit_index / 8;
135
20.5M
    uint8_t value = tvb_get_uint8 (tvb, offset + byte_index);
136
20.5M
    bit_index = bit_index % 8;
137
20.5M
    return 0x80 == ( (value << bit_index) & 0x80);
138
20.5M
}
139
140
// prints null terminated octal string
141
static void print_octal_string (tvbuff_t *tvb, unsigned offset, unsigned bit_offset, unsigned bit_size, unsigned byte_size, proto_tree *tree, int expand_var)
142
67.7k
{
143
67.7k
    if ((bit_size % OCTAL_BIT_LENGTH) != 0)
144
0
    {
145
0
        return;
146
0
    }
147
67.7k
    unsigned count = bit_size / OCTAL_BIT_LENGTH;
148
67.7k
    char buff[1024];
149
67.7k
    if (count > (sizeof(buff) - 1))
150
0
    {
151
0
        return;
152
0
    }
153
338k
    for (unsigned i = 0; i < count; i++)
154
270k
    {
155
270k
        uint8_t value = tvb_get_bits8(tvb, offset * 8 + bit_offset, OCTAL_BIT_LENGTH);
156
270k
        bit_offset += OCTAL_BIT_LENGTH;
157
158
270k
        buff[i] = value + 0x30;
159
270k
    }
160
67.7k
    buff[count] = 0;
161
162
67.7k
    proto_tree_add_string(tree, expand_var, tvb, offset, byte_size, buff);
163
67.7k
}
164
165
static char decode_icao_char(uint8_t x)
166
137k
{
167
137k
    if (x >= 0x01 && x <= 0x1A)
168
46.5k
    {
169
46.5k
        return 'A' + (x - 1);
170
46.5k
    }
171
91.2k
    else if (x == 0x20)
172
3.59k
    {
173
3.59k
        return ' ';
174
3.59k
    }
175
87.6k
    else if (x >= 0x30 && x <= 0x39)
176
14.3k
    {
177
14.3k
        return '0' + (x - 0x30);
178
14.3k
    }
179
73.2k
    return '?';
180
137k
}
181
182
// prints null terminated ICAO string
183
static void print_icao_string (tvbuff_t *tvb, unsigned offset, unsigned bit_offset, unsigned bit_size, unsigned byte_size, proto_tree *tree, int expand_var)
184
21.2k
{
185
21.2k
    if ((bit_size % ICAO_BIT_LENGTH) != 0)
186
0
    {
187
0
        return;
188
0
    }
189
21.2k
    unsigned count = bit_size / ICAO_BIT_LENGTH;
190
21.2k
    char buff[1024];
191
21.2k
    if (count > (sizeof(buff) - 1))
192
0
    {
193
0
        return;
194
0
    }
195
163k
    for (unsigned i = 0; i < count; i++)
196
142k
    {
197
142k
        uint8_t value = tvb_get_bits8(tvb, offset * 8 + bit_offset, ICAO_BIT_LENGTH);
198
142k
        bit_offset += ICAO_BIT_LENGTH;
199
200
142k
        buff[i] = decode_icao_char(value);
201
142k
    }
202
21.2k
    buff[count] = 0;
203
204
21.2k
    proto_tree_add_string(tree, expand_var, tvb, offset, byte_size, buff);
205
21.2k
}
206
207
static void check_spare_bits (tvbuff_t *tvb, unsigned bit_offset, unsigned bit_size, proto_item *item)
208
334k
{
209
334k
    if (bit_size > (64 - bit_offset))
210
1.33k
    {
211
1.33k
        return;
212
1.33k
    }
213
332k
    uint64_t bits = tvb_get_bits64(tvb, bit_offset, bit_size, ENC_BIG_ENDIAN);
214
332k
    if (bits != 0)
215
176k
    {
216
176k
        expert_add_info(NULL, item, &hf_asterix_spare_error);
217
176k
    }
218
332k
}
219
220
static unsigned asterix_fspec_len (tvbuff_t *tvb, unsigned offset)
221
965k
{
222
965k
    unsigned int i;
223
965k
    unsigned int max_length = tvb_reported_length (tvb) - offset;
224
1.49M
    for (i = 0; (tvb_get_uint8 (tvb, offset + i) & 1) && i < max_length; i++);
225
965k
    return i + 1;
226
965k
}
227
228
static bool asterix_fspec_check (unsigned fspec_len, unsigned list_length, proto_item *ti)
229
81.1k
{
230
81.1k
    unsigned fspec_expected_len = list_length / 7;
231
81.1k
    if ((list_length % 7) != 0) {
232
37.2k
        fspec_expected_len++;
233
37.2k
    }
234
81.1k
    if (fspec_len > fspec_expected_len) {
235
19.5k
        expert_add_info(NULL, ti, &hf_asterix_fspec_error);
236
19.5k
        return false;
237
19.5k
    }
238
61.6k
    return true;
239
81.1k
}
240
241
static unsigned asterix_dissect_fspec (tvbuff_t *tvb, unsigned offset, proto_tree *tree)
242
883k
{
243
883k
    unsigned fspec_len = asterix_fspec_len (tvb, offset);
244
245
883k
    if (fspec_len > 4) {
246
20.1k
        proto_tree_add_item (tree, hf_asterix_fspec, tvb, offset, fspec_len, ENC_NA);
247
863k
    } else {
248
863k
        unsigned value = asterix_get_unsigned_value(tvb, offset, fspec_len);
249
863k
        unsigned fspec_bit_length = fspec_len * 9 + 1;
250
863k
        memset(fspec_bit_string, 0, fspec_bit_length);
251
863k
        unsigned str_index = 0;
252
10.1M
        for (unsigned int i = 0; i < fspec_len * 8; i++) {
253
9.33M
            fspec_bit_string[str_index] = (value & (1U << ((fspec_len * 8 - 1) - i))) ? '1' : '0';
254
9.33M
            if (i > 0 && ((i + 1) % 8) == 0) {
255
1.16M
                str_index++;
256
1.16M
                fspec_bit_string[str_index] = ' ';
257
1.16M
            }
258
9.33M
            str_index++;
259
9.33M
        }
260
863k
        proto_tree_add_string_format_value (tree, hf_asterix_fspec_bitstring, tvb, offset, fspec_len, NULL, "%s", fspec_bit_string);
261
863k
    }
262
883k
    return fspec_len;
263
883k
}
264
265
static unsigned asterix_parse_re_field (tvbuff_t *tvb, unsigned offset, proto_tree *tree, unsigned fspec_len, unsigned cat)
266
531
{
267
531
    int start_offset = offset;
268
531
    offset+=fspec_len;
269
270
531
    unsigned int ed = -1;
271
16.4k
    for (size_t i = 0; i < array_length(asterix_properties); i++)
272
15.9k
    {
273
15.9k
        const dialog_cat_struct *prop_cat = &asterix_properties[i];
274
15.9k
        if (prop_cat->cat == cat && !prop_cat->cat_basic)
275
531
        {
276
531
            ed = *prop_cat->edition_default_value;
277
531
        }
278
15.9k
    }
279
280
531
    table_params table_p = {0};
281
531
    get_expansion_table(cat, ed, &table_p);
282
283
4.48k
    for (unsigned i = 0; i < table_p.table_size; i++) {
284
3.95k
        if (asterix_field_exists(tvb, start_offset, i)) {
285
1.98k
            const int *expand = table_p.table_pointer_expand[i];
286
1.98k
            int expand_value = -1;
287
1.98k
            if (expand != NULL)
288
1.98k
            {
289
1.98k
                expand_value = *expand;
290
1.98k
            }
291
1.98k
            offset += table_p.table_pointer[i](tvb, offset, tree, expand_value);
292
1.98k
        }
293
3.95k
    }
294
531
    return offset - start_offset;
295
531
}
296
297
static bool check_fspec_validity (tvbuff_t *tvb, unsigned offset, table_params *table)
298
967k
{
299
967k
    unsigned i = 0;
300
967k
    unsigned fs_index = 0;
301
11.8M
    while (fs_index < MAX_FSPEC_BIT_LENGTH && i < table->table_size) {
302
11.7M
        if (((fs_index + 1) % 8) == 0) {
303
1.43M
            if (!asterix_field_exists(tvb, offset, fs_index)) {
304
                // FSPEC end, all fields may not have been present, but that's ok
305
772k
                return true;
306
772k
            }
307
662k
            fs_index++;
308
662k
        }
309
11.0M
        if (asterix_field_exists(tvb, offset, fs_index)) {
310
3.62M
            if (table->table_pointer[i] == NULL) {
311
                // bit should not be set, FSPEC invalid
312
119k
                return false;
313
119k
            }
314
3.62M
        }
315
10.8M
        i++;
316
10.8M
        fs_index++;
317
10.8M
    }
318
75.2k
    if (fs_index >= MAX_FSPEC_BIT_LENGTH) {
319
0
        return false;
320
0
    }
321
75.2k
    unsigned fs_end_index = ((fs_index / 8) + 1) * 8 - 1;
322
75.2k
    if (asterix_field_exists(tvb, offset, fs_end_index)) {
323
        // FSPEC should not go beyond current byte
324
31.7k
        return false;
325
31.7k
    }
326
43.4k
    return true;
327
75.2k
}
328
329
static int probe_possible_record (tvbuff_t *tvb, unsigned offset, unsigned int cat, unsigned int ed, unsigned int record)
330
690k
{
331
    // use NULL pointer for proto_tree pointer, so that wireshark ignores all tree add calls
332
690k
    proto_tree *asterix_packet_tree = NULL;
333
334
690k
    int start_offset = offset;
335
336
690k
    table_params table_p;
337
690k
    get_category_uap_table(cat, ed, record, &table_p);
338
339
690k
    if (table_p.table_pointer == NULL) {
340
        //unknown category, abort
341
0
        return -1;
342
0
    }
343
690k
    if (!check_fspec_validity (tvb, start_offset, &table_p)) {
344
150k
        return -1;
345
150k
    }
346
347
539k
    offset += asterix_dissect_fspec (tvb, offset, asterix_packet_tree);
348
539k
    unsigned i = 0;
349
539k
    unsigned fs_index = 0;
350
4.95M
    while (i < table_p.table_size) {
351
4.79M
        if (((fs_index + 1) % 8) == 0) {
352
527k
            if (!asterix_field_exists(tvb, start_offset, fs_index)) {
353
346k
                break;
354
346k
            }
355
180k
            fs_index++;
356
180k
        }
357
4.45M
        if (asterix_field_exists(tvb, start_offset, fs_index)) {
358
1.21M
            const int *expand = table_p.table_pointer_expand[i];
359
1.21M
            int expand_value = -1;
360
1.21M
            if (expand != NULL)
361
1.21M
            {
362
1.21M
                expand_value = *expand;
363
1.21M
            }
364
1.21M
            int fun_len = table_p.table_pointer[i](tvb, offset, asterix_packet_tree, expand_value);
365
1.21M
            if (fun_len == -1) {
366
42.3k
                return -1;
367
42.3k
            }
368
1.17M
            offset += fun_len;
369
1.17M
        }
370
4.41M
        i++;
371
4.41M
        fs_index++;
372
4.41M
    }
373
497k
    return offset;
374
539k
}
375
376
/* possible return values:
377
    0 success
378
    -1 to many interpretations
379
    -2 recursive depth limit breached
380
*/
381
// NOLINTNEXTLINE(misc-no-recursion)
382
static int probe_possible_records (tvbuff_t *tvb, packet_info *pinfo, int offset, int datablock_end, unsigned int cat, unsigned int ed, uap_table_indexes *indexes, unsigned int *stack, unsigned int depth)
383
346k
{
384
1.03M
    for (volatile unsigned int i = indexes->start_index; i <= indexes->end_index; i++)
385
690k
    {
386
690k
        volatile int new_offset = (int)offset;
387
690k
        stack[depth] = i;
388
690k
        TRY
389
690k
        {
390
690k
            new_offset = probe_possible_record (tvb, new_offset, cat, ed, i);
391
690k
        }
392
690k
        CATCH_NONFATAL_ERRORS
393
141k
        {
394
141k
            new_offset = -1;
395
141k
        }
396
690k
        ENDTRY;
397
690k
        if (new_offset != -1) {
398
355k
            if (new_offset == datablock_end)
399
9.96k
            {
400
109k
                for (unsigned int j = 0; j <= depth; j++)
401
99.1k
                {
402
99.1k
                    solutions[solution_count][j] = stack[j];
403
99.1k
                }
404
9.96k
                solution_count++;
405
9.96k
                if (solution_count >= MAX_INTERPRETATIONS)
406
62
                {
407
62
                    return -1;
408
62
                }
409
9.96k
            }
410
345k
            else if (new_offset < datablock_end)
411
345k
            {
412
345k
                if ((depth + 1) >= (unsigned)selected_interpretations_depth)
413
75
                {
414
75
                    return -2;
415
75
                }
416
345k
                int result = probe_possible_records (tvb, pinfo, new_offset, datablock_end, cat, ed, indexes, stack, depth + 1);
417
345k
                if (result != 0)
418
1.68k
                {
419
1.68k
                    return result;
420
1.68k
                }
421
345k
            }
422
355k
        }
423
690k
    }
424
344k
    return 0;
425
346k
}
426
427
/* possible return values:
428
    -1 for error
429
    new offset value, larger by at least one byte (fspec)
430
*/
431
static int dissect_asterix_record (tvbuff_t *tvb, packet_info *pinfo, unsigned offset, unsigned datablock_end, proto_tree *tree, unsigned int cat, unsigned int ed, unsigned int uap)
432
277k
{
433
277k
    proto_item *ti;
434
277k
    proto_tree *asterix_packet_tree;
435
436
277k
    ti = proto_tree_add_item (tree, hf_asterix_record, tvb, offset, 0, ENC_NA);
437
277k
    asterix_packet_tree = proto_item_add_subtree (ti, ett_asterix);
438
439
277k
    table_params table_p;
440
277k
    get_category_uap_table(cat, ed, uap, &table_p);
441
442
277k
    if (table_p.table_pointer == NULL || table_p.table_pointer_expand == NULL) {
443
        // skip unknown category
444
358
        expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "Unknown category");
445
358
        return -1;
446
358
    }
447
277k
    if (!check_fspec_validity (tvb, offset, &table_p)) {
448
        // something wrong with FSPEC field
449
892
        expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "FSPEC field invalid");
450
892
        return -1;
451
892
    }
452
276k
    int start_offset = offset;
453
454
276k
    offset += asterix_dissect_fspec (tvb, offset, asterix_packet_tree);
455
276k
    unsigned i = 0;
456
276k
    unsigned fs_index = 0;
457
2.66M
    while (i < table_p.table_size) {
458
2.65M
        if (((fs_index + 1) % 8) == 0 && fs_index > 0) {
459
332k
            if (!asterix_field_exists(tvb, start_offset, fs_index)) {
460
263k
                break;
461
263k
            }
462
68.1k
            fs_index++;
463
68.1k
        }
464
2.39M
        if (asterix_field_exists(tvb, start_offset, fs_index)) {
465
457k
            const int *expand = table_p.table_pointer_expand[i];
466
457k
            int expand_value = -1;
467
457k
            if (expand != NULL)
468
457k
            {
469
457k
                expand_value = *expand;
470
457k
            }
471
457k
            if (table_p.table_pointer[i] != NULL) {
472
457k
                int fun_len = table_p.table_pointer[i](tvb, offset, asterix_packet_tree, expand_value);
473
457k
                if (fun_len == -1) {
474
1.04k
                    return -1;
475
1.04k
                }
476
456k
                offset += fun_len;
477
456k
            } else {
478
0
                return -1;
479
0
            }
480
457k
        }
481
2.39M
        i++;
482
2.39M
        fs_index++;
483
2.39M
    }
484
275k
    unsigned int item_length = offset - start_offset;
485
275k
    proto_item_set_len(ti, item_length);
486
275k
    proto_item_append_text(ti, ", length %u", item_length);
487
275k
    proto_item_append_text(ti, ", %s", table_p.uap_name);
488
489
275k
    if (offset > datablock_end) {
490
        //record outside datablock
491
23
        expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "Record out of bounds");
492
23
    }
493
275k
    return offset;
494
276k
}
495
496
static void dissect_asterix_records (tvbuff_t *tvb, packet_info *pinfo, int offset, unsigned datablock_length, proto_tree *tree, unsigned int cat)
497
7.73k
{
498
7.73k
    int datablock_end = offset + datablock_length;
499
500
    // get edition from settings
501
7.73k
    unsigned int ed = -1;
502
106k
    for (size_t i = 0; i < array_length(asterix_properties); i++)
503
105k
    {
504
105k
        const dialog_cat_struct *prop_cat = &asterix_properties[i];
505
105k
        if (prop_cat->cat == cat && prop_cat->cat_basic)
506
7.37k
        {
507
7.37k
            ed = *prop_cat->edition_default_value;
508
7.37k
            break;
509
7.37k
        }
510
105k
    }
511
    // get uap selection
512
7.73k
    int uap = -1;
513
38.6k
    for (size_t i = 0; i < array_length(interpretation_properties); i++)
514
30.9k
    {
515
30.9k
        if (interpretation_properties[i].cat == cat && interpretation_properties[i].ed == ed)
516
1.07k
        {
517
1.07k
            uap = *interpretation_properties[i].int_default_value;
518
1.07k
        }
519
30.9k
    }
520
521
7.73k
    memset(solutions, -1, sizeof(solutions));
522
7.73k
    solution_count = 0;
523
7.73k
    unsigned int stack[MAX_INTERPRETATION_DEPTH];
524
525
7.73k
    uap_table_indexes indexes;
526
7.73k
    get_uap_tables(cat, ed, &indexes);
527
528
7.73k
    if (uap >= 0)
529
0
    {
530
        // specific uap selected in settings, disable probing
531
0
        indexes.start_index = uap;
532
0
        indexes.end_index = uap;
533
0
    }
534
535
    // if category unknown both start_index and end_index are 0
536
7.73k
    if ((indexes.end_index - indexes.start_index) > 0)
537
1.07k
    {
538
1.07k
        int result = probe_possible_records (tvb, pinfo, offset, datablock_end, cat, ed, &indexes, stack, 0);
539
540
1.07k
        unsigned int backup_offset = offset;
541
542
1.07k
        proto_item *possibilities_ti = proto_tree_add_item (tree, hf_asterix_possible_interpretations, tvb, offset, 0, ENC_NA);
543
1.07k
        proto_tree *possibilities_tree = proto_item_add_subtree (possibilities_ti, ett_asterix_possible_interpretations);
544
1.07k
        proto_item_append_text (possibilities_tree, " %u", solution_count);
545
546
1.07k
        if (result < 0) {
547
137
            if (result == -1) {
548
62
                expert_add_info_format(pinfo, possibilities_ti, &ei_asterix_overflow, "Interpretations number of solutions exceeded");
549
75
            } else {
550
75
                expert_add_info_format(pinfo, possibilities_ti, &ei_asterix_overflow, "Interpretations depth exceeded");
551
75
            }
552
137
        }
553
554
1.07k
        if (solution_count == 0) {
555
656
            expert_add_info_format(pinfo, possibilities_ti, &ei_asterix_overflow, "No possible solution found");
556
656
        } else {
557
10.3k
            for (unsigned int i = 0; i < solution_count; i++) {
558
9.96k
                offset = backup_offset;
559
9.96k
                proto_item *possible_ti = proto_tree_add_item (possibilities_tree, hf_asterix_possible_interpretation, tvb, offset, 0, ENC_NA);
560
9.96k
                proto_item_append_text (possible_ti, " (%u/%u)", i + 1, solution_count);
561
9.96k
                proto_tree *possible_tree = proto_item_add_subtree (possible_ti, ett_asterix_possible_interpretation);
562
563
109k
                for (unsigned int j = 0; solutions[i][j] != -1; j++) {
564
99.1k
                    int new_offset = dissect_asterix_record (tvb, pinfo, offset, datablock_end, possible_tree, cat, ed, solutions[i][j]);
565
                    // there should not be any error, as this solution already tried, but check anyway
566
99.1k
                    if (new_offset <= offset) {
567
0
                        return;
568
0
                    }
569
99.1k
                    offset = new_offset;
570
99.1k
                }
571
9.96k
            }
572
423
        }
573
1.07k
    }
574
6.65k
    else {
575
182k
        while (offset < datablock_end) {
576
178k
            int new_offset = dissect_asterix_record (tvb, pinfo, offset, datablock_end, tree, cat, ed, indexes.start_index);
577
178k
            if (new_offset <= offset) {
578
2.29k
                return;
579
2.29k
            }
580
176k
            offset = new_offset;
581
176k
        }
582
6.65k
    }
583
7.73k
}
584
585
static bool check_datagram_datablocks (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
586
7.77k
{
587
7.77k
    int i = 0;
588
7.77k
    int n = tvb_reported_length (tvb);
589
590
15.5k
    while (i < n) {
591
7.78k
        int remaining = n - i;
592
7.78k
        proto_item *item;
593
594
7.78k
        if (remaining < 4) {
595
42
            item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, remaining, ENC_NA);
596
42
            expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Data length less than 4B");
597
42
            return false;
598
42
        }
599
600
7.74k
        uint16_t len = tvb_get_uint16 (tvb, i+1, ENC_BIG_ENDIAN);
601
7.74k
        if (len < 4) {
602
1
            item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA);
603
1
            expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Datablock length less than 4B");
604
1
            return false;
605
1
        }
606
607
7.74k
        if (remaining < len) {
608
3
            item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA);
609
3
            expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Not enough data for datablock");
610
3
            return false;
611
3
        }
612
        // move to next datablock
613
7.74k
        i += len;
614
7.74k
    }
615
7.73k
    if (i == n) {
616
7.73k
        return true;
617
7.73k
    }
618
0
    else {
619
0
        proto_item *item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, n, ENC_NA);
620
0
        expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Datablocks datagram misalignment");
621
0
        return false;
622
0
    }
623
7.73k
}
624
625
static void dissect_asterix_data_blocks (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
626
7.77k
{
627
7.77k
    int i = 0;
628
7.77k
    int n = tvb_reported_length (tvb);
629
630
    // Datablock parsing is strict. This means that all datablocks must be aligned with UDP datagram data. If not, no datablock is parsed.
631
    // In future versions strictness level may be added as a configuration option.
632
7.77k
    if (check_datagram_datablocks (tvb, pinfo, tree))
633
7.73k
    {
634
15.4k
        while (i < n) {
635
7.73k
            uint8_t cat = tvb_get_uint8 (tvb, i);
636
7.73k
            uint16_t len = tvb_get_uint16 (tvb, i+1, ENC_BIG_ENDIAN);
637
638
7.73k
            proto_item *datablock = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA);
639
7.73k
            proto_tree *datablock_tree = proto_item_add_subtree (datablock, ett_asterix_record);
640
641
7.73k
            proto_item_append_text (datablock_tree, ", Category %03d", cat);
642
7.73k
            proto_tree_add_item (datablock_tree, hf_asterix_category, tvb, i, 1, ENC_BIG_ENDIAN);
643
7.73k
            proto_tree_add_item (datablock_tree, hf_asterix_length, tvb, i + 1, 2, ENC_BIG_ENDIAN);
644
645
7.73k
            dissect_asterix_records (tvb, pinfo, i + HEADER_LENGTH, len - HEADER_LENGTH, datablock_tree, cat);
646
647
            // move to next datablock
648
7.73k
            i += len;
649
7.73k
        }
650
7.73k
    }
651
7.77k
}
652
653
static int dissect_asterix (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
654
7.77k
{
655
7.77k
    col_set_str (pinfo->cinfo, COL_PROTOCOL, "ASTERIX");
656
7.77k
    col_clear (pinfo->cinfo, COL_INFO);
657
658
7.77k
    if (hf_asterix_category <= 0) {
659
2
        proto_registrar_get_byname("asterix.category");
660
2
    }
661
662
7.77k
    if (tree) { /* we are being asked for details */
663
7.77k
        dissect_asterix_data_blocks (tvb, pinfo, tree);
664
7.77k
    }
665
666
7.77k
    return tvb_captured_length(tvb);
667
7.77k
}
668
669
static unsigned get_asterix_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
670
6.27k
{
671
6.27k
    uint16_t plen;
672
6.27k
    plen = tvb_get_uint16 (tvb, offset + 1, ENC_BIG_ENDIAN);
673
6.27k
    return plen;
674
6.27k
}
675
676
static int dissect_asterix_tcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
677
5.64k
{
678
    /* We do delayed field registration if needed in dissect_asterix. */
679
5.64k
    tcp_dissect_pdus(tvb, pinfo, tree, true, 3, get_asterix_pdu_len, dissect_asterix, data);
680
5.64k
    return tvb_reported_length (tvb);
681
5.64k
}
682
683
static void register_asterix_fields(const char* unused _U_)
684
2
{
685
2
    proto_register_field_array (proto_asterix, hf, array_length (hf));
686
687
2
    static int *ett[] = {
688
2
        &ett_asterix,
689
2
        &ett_asterix_record,
690
2
        &ett_asterix_subtree,
691
2
        &ett_asterix_possible_interpretation,
692
2
        &ett_asterix_possible_interpretations,
693
2
        &ett_asterix_spare_error
694
2
    };
695
696
2
    proto_register_subtree_array (ett, array_length (ett));
697
2
}
698
699
void proto_register_asterix (void)
700
15
{
701
15
    module_t* asterix_module;
702
15
    expert_module_t* expert_asterix;
703
704
15
    static ei_register_info ei[] = {
705
15
        { &ei_asterix_overflow, { "asterix.overflow", PI_PROTOCOL, PI_ERROR, "Asterix overflow", EXPFILL }},
706
15
        { &hf_asterix_spare_error, { "asterix.spare_error", PI_PROTOCOL, PI_WARN, "Spare bit error", EXPFILL }},
707
15
        { &hf_asterix_fx_error, { "asterix.fx_error", PI_PROTOCOL, PI_ERROR, "FX end bit error", EXPFILL }},
708
15
        { &hf_asterix_fspec_error, { "asterix.fspec_error", PI_PROTOCOL, PI_ERROR, "FSPEC error", EXPFILL }}
709
15
    };
710
711
15
    proto_asterix = proto_register_protocol ("ASTERIX packet", "ASTERIX", "asterix");
712
713
    /* Delay registration of ASTERIX fields */
714
15
    proto_register_prefix("asterix", register_asterix_fields);
715
716
15
    asterix_module = prefs_register_protocol(proto_asterix, NULL);
717
15
    asterix_handle = register_dissector ("asterix", dissect_asterix, proto_asterix);
718
15
    asterix_tcp_handle = register_dissector ("asterix-tcp", dissect_asterix_tcp, proto_asterix);
719
720
15
    expert_asterix = expert_register_protocol(proto_asterix);
721
15
    expert_register_field_array(expert_asterix, ei, array_length(ei));
722
723
465
    for (size_t i = 0; i < array_length(asterix_properties); i++)
724
450
    {
725
450
        const dialog_cat_struct *cat = &asterix_properties[i];
726
450
        prefs_register_enum_preference(asterix_module, cat->edition_name, cat->edition_desc, NULL, cat->edition_default_value, cat->edition_enums, FALSE);
727
728
2.25k
        for (size_t j = 0; j < array_length(interpretation_properties); j++)
729
1.80k
        {
730
1.80k
            if (interpretation_properties[j].cat == cat->cat)
731
60
            {
732
60
                const dialog_int_struct *int_prop = &interpretation_properties[j];
733
60
                prefs_register_enum_preference(asterix_module, int_prop->edition_name, int_prop->edition_desc, NULL, int_prop->int_default_value, int_prop->int_enums, FALSE);
734
60
            }
735
1.80k
        }
736
450
    }
737
738
15
    prefs_register_enum_preference(asterix_module, "interpretations_depth", "Interpretations depth",
739
15
                                   "Interpretations depth for categories with multiple possible UAPs",
740
15
                                   &selected_interpretations_depth, interpretations_level_enum_vals, false);
741
15
}
742
743
void proto_reg_handoff_asterix (void)
744
15
{
745
15
    dissector_add_uint_with_preference("udp.port", ASTERIX_PORT, asterix_handle);
746
15
    dissector_add_uint_with_preference("tcp.port", ASTERIX_PORT, asterix_tcp_handle);
747
15
}