### Bug Summary

File: | epan/dissectors/packet-asterix.c
Warning: | line 147, column 17 Value stored to 'value' during its initialization is never read

### Annotated Source Code

Press '?' to see keyboard shortcuts

Show analyzer invocation
clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name packet-asterix.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -ffloat16-excess-precision=fast -fbfloat16-excess-precision=fast -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/builds/wireshark/wireshark/build -fcoverage-compilation-dir=/builds/wireshark/wireshark/build -resource-dir /usr/lib/llvm-21/lib/clang/21 -isystem /usr/include/glib-2.0 -isystem /usr/lib/x86_64-linux-gnu/glib-2.0/include -isystem /builds/wireshark/wireshark/epan/dissectors -isystem /builds/wireshark/wireshark/build/epan/dissectors -isystem /usr/include/mit-krb5 -isystem /usr/include/libxml2 -isystem /builds/wireshark/wireshark/epan -D G_DISABLE_DEPRECATED -D G_DISABLE_SINGLE_INCLUDES -D WS_BUILD_DLL -D WS_DEBUG -D WS_DEBUG_UTF_8 -I /builds/wireshark/wireshark/build -I /builds/wireshark/wireshark -I /builds/wireshark/wireshark/include -D _GLIBCXX_ASSERTIONS -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/builds/wireshark/wireshark/= -fmacro-prefix-map=/builds/wireshark/wireshark/build/= -fmacro-prefix-map=../= -Wno-format-truncation -Wno-format-nonliteral -Wno-pointer-sign -std=gnu11 -ferror-limit 19 -fvisibility=hidden -fwrapv -fwrapv-pointer -fstrict-flex-arrays=3 -stack-protector 2 -fstack-clash-protection -fcf-protection=full -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fexceptions -fcolor-diagnostics -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /builds/wireshark/wireshark/sbout/2025-10-13-100350-3623-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-asterix.c

Keyboard shortcuts:

- Use 'j/k' keys for keyboard navigation
- Use 'Shift+S' to show/hide relevant lines
- Use '?' to toggle this window

Close
Show only relevant lines Show control flow arrows

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 | #define HEADER_LENGTH3 3
30 | #define ASTERIX_PORT8600 8600
31 | #define MAX_INTERPRETATIONS200 200
32 | #define MAX_INTERPRETATION_LENGTH200 200
33 | #define MAX_FSPEC_BIT_LENGTH1024 1024
34 | #define OCTAL_BIT_LENGTH3 3
35 | #define ICAO_BIT_LENGTH6 6
36 |
37 | static int proto_asterix;
38 |
39 | static char fspec_bit_string[MAX_FSPEC_BIT_LENGTH1024];
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 |
51 | static unsigned asterix_get_unsigned_value(tvbuff_t *tvb, unsigned offset, unsigned bytes)
52 | {
53 | switch (bytes)
54 | {
55 | case 1:
56 | return tvb_get_uint8(tvb, offset);
57 | case 2:
58 | return tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
59 | case 3:
60 | return tvb_get_uint24(tvb, offset, ENC_BIG_ENDIAN0x00000000);
61 | case 4:
62 | return tvb_get_uint32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
63 | default:
64 | return -1;
65 | }
66 | }
67 |
68 | static int asterix_get_signed_value(tvbuff_t *tvb, unsigned offset, unsigned bytes)
69 | {
70 | switch (bytes)
71 | {
72 | case 1:
73 | return tvb_get_int8(tvb, offset);
74 | case 2:
75 | return tvb_get_int16(tvb, offset, ENC_BIG_ENDIAN0x00000000);
76 | case 3:
77 | return tvb_get_int24(tvb, offset, ENC_BIG_ENDIAN0x00000000);
78 | case 4:
79 | return tvb_get_int32(tvb, offset, ENC_BIG_ENDIAN0x00000000);
80 | default:
81 | return -1;
82 | }
83 | }
84 |
85 | // get signed integer from specified number of bits
86 | static int get_signed_int(unsigned value, unsigned bits)
87 | {
88 | int ret = 0;
89 | int sign = 1;
90 | if ((value >> (bits - 1) & 1))
91 | {
92 | sign = -1;
93 | value = ~value;
94 | value++;
95 | }
96 |
97 | unsigned int mask = 1;
98 | for (unsigned int i = 0; i < (bits - 1); i++)
99 | {
100 | if ((value >> i) & 1)
101 | {
102 | ret |= mask;
103 | }
104 | mask *= 2;
105 | }
106 | return ret * sign;
107 | }
108 |
109 | // test extended FX bit
110 | static bool_Bool asterix_extended_end (tvbuff_t *tvb, unsigned offset)
111 | {
112 | uint8_t val = tvb_get_uint8(tvb, offset);
113 | if ((val & 0x01) == 0)
114 | {
115 | return true1;
116 | }
117 | else
118 | {
119 | return false0;
120 | }
121 | }
122 |
123 | // test specifix FSPEC bit
124 | static bool_Bool asterix_field_exists (tvbuff_t *tvb, unsigned offset, unsigned bit_index)
125 | {
126 | unsigned int byte_index = bit_index / 8;
127 | uint8_t value = tvb_get_uint8 (tvb, offset + byte_index);
128 | bit_index = bit_index % 8;
129 | return 0x80 == ( (value << bit_index) & 0x80);
130 | }
131 |
132 | // prints null terminated octal string
133 | 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)
134 | {
135 | if ((bit_size % OCTAL_BIT_LENGTH3) != 0)
136 | {
137 | return;
138 | }
139 | unsigned count = bit_size / OCTAL_BIT_LENGTH3;
140 | char buff[1024];
141 | if (count > (1023))
142 | {
143 | return;
144 | }
145 | for (unsigned i = 0; i < count; i++)
146 | {
147 | uint8_t value = tvb_get_uint8(tvb, offset);
| Value stored to 'value' during its initialization is never read
148 | value = tvb_get_bits8(tvb, offset * 8 + bit_offset, OCTAL_BIT_LENGTH3);
149 | bit_offset += OCTAL_BIT_LENGTH3;
150 |
151 | buff[i] = value + 0x30;
152 | }
153 | buff[count] = 0;
154 |
155 | proto_tree_add_string(tree, expand_var, tvb, offset, byte_size, buff);
156 | }
157 |
158 | static char decode_icao_char(uint8_t x)
159 | {
160 | if (x >= 0x01 && x <= 0x1A)
161 | {
162 | return 'A' + (x - 1);
163 | }
164 | else if (x == 0x20)
165 | {
166 | return ' ';
167 | }
168 | else if (x >= 0x30 && x <= 0x39)
169 | {
170 | return '0' + (x - 0x30);
171 | }
172 | return '?';
173 | }
174 |
175 | // prints null terminated ICAO string
176 | 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)
177 | {
178 | if ((bit_size % ICAO_BIT_LENGTH6) != 0)
179 | {
180 | return;
181 | }
182 | unsigned count = bit_size / ICAO_BIT_LENGTH6;
183 | char buff[1024];
184 | if (count > (1023))
185 | {
186 | return;
187 | }
188 | for (unsigned i = 0; i < count; i++)
189 | {
190 | uint8_t value = tvb_get_uint8(tvb, offset);
191 | value = tvb_get_bits8(tvb, offset * 8 + bit_offset, ICAO_BIT_LENGTH6);
192 | bit_offset += ICAO_BIT_LENGTH6;
193 |
194 | buff[i] = decode_icao_char(value);
195 | }
196 | buff[count] = 0;
197 |
198 | proto_tree_add_string(tree, expand_var, tvb, offset, byte_size, buff);
199 | }
200 |
201 | static void check_spare_bits (tvbuff_t *tvb, unsigned bit_offset, unsigned bit_size, proto_item *item)
202 | {
203 | if (bit_size > (64 - bit_offset))
204 | {
205 | return;
206 | }
207 | uint64_t bits = tvb_get_bits64(tvb, bit_offset, bit_size, ENC_BIG_ENDIAN0x00000000);
208 | if (bits != 0)
209 | {
210 | expert_add_info_format(NULL((void*)0), item, &hf_asterix_spare_error, "Spare bit error");
211 | }
212 | }
213 |
214 | static unsigned asterix_fspec_len (tvbuff_t *tvb, unsigned offset)
215 | {
216 | unsigned int i;
217 | unsigned int max_length = tvb_reported_length (tvb) - offset;
218 | for (i = 0; (tvb_get_uint8 (tvb, offset + i) & 1) && i < max_length; i++);
219 | return i + 1;
220 | }
221 |
222 | static bool_Bool asterix_fspec_check (unsigned fspec_len, unsigned list_length, proto_item *ti)
223 | {
224 | unsigned fspec_expected_len = list_length / 7;
225 | if ((list_length % 7) != 0) {
226 | fspec_expected_len++;
227 | }
228 | if (fspec_len > fspec_expected_len) {
229 | expert_add_info_format(NULL((void*)0), ti, &hf_asterix_fspec_error, "FSPEC error");
230 | return false0;
231 | }
232 | return true1;
233 | }
234 |
235 | static unsigned asterix_dissect_fspec (tvbuff_t *tvb, unsigned offset, proto_tree *tree)
236 | {
237 | unsigned fspec_len = asterix_fspec_len (tvb, offset);
238 |
239 | if (fspec_len > 4) {
240 | proto_tree_add_item (tree, hf_asterix_fspec, tvb, offset, fspec_len, ENC_NA0x00000000);
241 | } else {
242 | unsigned value = asterix_get_unsigned_value(tvb, offset, fspec_len);
243 | unsigned fspec_bit_length = fspec_len * 9 + 1;
244 | memset(fspec_bit_string, 0, fspec_bit_length);
245 | unsigned str_index = 0;
246 | for (unsigned int i = 0; i < fspec_len * 8; i++) {
247 | fspec_bit_string[str_index] = (value & (1 << ((fspec_len * 8 - 1) - i))) ? '1' : '0';
248 | if (i > 0 && ((i + 1) % 8) == 0) {
249 | str_index++;
250 | fspec_bit_string[str_index] = ' ';
251 | }
252 | str_index++;
253 | }
254 | proto_tree_add_string_format_value (tree, hf_asterix_fspec_bitstring, tvb, offset, fspec_len, NULL((void*)0), "%s", fspec_bit_string);
255 | }
256 | return fspec_len;
257 | }
258 |
259 | static unsigned asterix_parse_re_field (tvbuff_t *tvb, unsigned offset, proto_tree *tree, unsigned fspec_len, unsigned cat)
260 | {
261 | unsigned i = 0;
262 | int start_offset = offset;
263 | offset+=fspec_len;
264 |
265 | unsigned int ed = -1;
266 | for (i = 0; i < sizeof(asterix_properties) / sizeof(asterix_properties[0]); i++)
267 | {
268 | dialog_cat_struct prop_cat = asterix_properties[i];
269 | if (prop_cat.cat == cat && !prop_cat.cat_basic)
270 | {
271 | ed = *prop_cat.cat_default_value;
272 | }
273 | }
274 |
275 | table_params table_p = {0};
276 | get_expansion_table(cat, ed, &table_p);
277 |
278 | i = 0;
279 | while (i < table_p.table_size) {
280 | if (asterix_field_exists(tvb, start_offset, i)) {
281 | int *expand = table_p.table_pointer_expand[i];
282 | int expand_value = -1;
283 | if (expand != NULL((void*)0))
284 | {
285 | expand_value = *expand;
286 | }
287 | offset += table_p.table_pointer[i](tvb, offset, tree, expand_value);
288 | }
289 | i++;
290 | }
291 | return offset - start_offset;
292 | }
293 |
294 | unsigned int solution_count;
295 | int solutions[MAX_INTERPRETATIONS200][MAX_INTERPRETATION_LENGTH200];
296 |
297 | static bool_Bool check_fspec_validity (tvbuff_t *tvb, unsigned offset, table_params *table)
298 | {
299 | unsigned i = 0;
300 | unsigned fs_index = 0;
301 | while (i < MAX_FSPEC_BIT_LENGTH1024) {
302 | if (((fs_index + 1) % 8) == 0) {
303 | if (!asterix_field_exists(tvb, offset, fs_index)) {
304 | break;
305 | }
306 | if (i > table->table_size) {
307 | // FSPEC value longer than defined
308 | return false0;
309 | }
310 | fs_index++;
311 | }
312 | if (asterix_field_exists(tvb, offset, fs_index)) {
313 | if (table->table_pointer[i] == NULL((void*)0))
314 | {
315 | // bit should not be set, FSPEC invalid
316 | return false0;
317 | }
318 | }
319 | i++;
320 | fs_index++;
321 | }
322 |
323 | return true1;
324 | }
325 |
326 | static int probe_possible_record (tvbuff_t *tvb, unsigned offset, unsigned int cat, unsigned int ed, unsigned int record)
327 | {
328 | // use NULL pointer for proto_tree pointer, so that wireshark ignores all tree add calls
329 | proto_tree *asterix_packet_tree = NULL((void*)0);
330 |
331 | int start_offset = offset;
332 |
333 | table_params table_p;
334 | get_category_uap_table(cat, ed, record, &table_p);
335 |
336 | if (table_p.table_pointer == NULL((void*)0)) {
337 | //unknown category, abort
338 | return -1;
339 | }
340 | if (!check_fspec_validity (tvb, start_offset, &table_p)) {
341 | return -1;
342 | }
343 |
344 | offset += asterix_dissect_fspec (tvb, offset, asterix_packet_tree);
345 | unsigned i = 0;
346 | unsigned fs_index = 0;
347 | while (i <= table_p.table_size) {
348 | if (((fs_index + 1) % 8) == 0) {
349 | if (!asterix_field_exists(tvb, start_offset, fs_index)) {
350 | break;
351 | }
352 | fs_index++;
353 | }
354 | if (asterix_field_exists(tvb, start_offset, fs_index)) {
355 | int *expand = table_p.table_pointer_expand[i];
356 | int expand_value = -1;
357 | if (expand != NULL((void*)0))
358 | {
359 | expand_value = *expand;
360 | }
361 | int fun_len = table_p.table_pointer[i](tvb, offset, asterix_packet_tree, expand_value);
362 | if (fun_len == -1) {
363 | return -1;
364 | }
365 | offset += fun_len;
366 | }
367 | i++;
368 | fs_index++;
369 | }
370 |
371 | return offset;
372 | }
373 |
374 | // NOLINTNEXTLINE(misc-no-recursion)
375 | static void 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)
376 | {
377 | for (volatile unsigned int i = indexes->start_index; i <= indexes->end_index; i++)
378 | {
379 | volatile int new_offset = (int)offset;
380 | stack[depth] = i;
381 | TRY{ except_t *volatile exc; volatile int except_state = 0; static const except_id_t catch_spec[] = { { 1, 0 } }; { struct except_stacknode except_sn; struct except_catch except_ch; except_setup_try(& except_sn, &except_ch, catch_spec, 1); if (_setjmp (except_ch .except_jmp)) *(&exc) = &except_ch.except_obj; else * (&exc) = 0; if(except_state & 1) except_state |= 2; except_state &= ~1; if (except_state == 0 && exc == 0)
382 | {
383 | new_offset = probe_possible_record (tvb, new_offset, cat, ed, i);
384 | }
385 | CATCH_NONFATAL_ERRORSif (except_state == 0 && exc != 0 && (exc-> except_id.except_code == (3) || exc->except_id.except_code == (2) || exc->except_id.except_code == (7) || exc->except_id .except_code == (9)) && (except_state|=1))
386 | {
387 | new_offset = -1;
388 | }
389 | ENDTRYif(!(except_state&1) && exc != 0) except_rethrow( exc); except_free(except_ch.except_obj.except_dyndata); except_pop (); };};
390 | if (new_offset != -1) {
391 | if (new_offset == datablock_end)
392 | {
393 | for (unsigned int j = 0; j <= depth; j++)
394 | {
395 | solutions[solution_count][j] = stack[j];
396 | }
397 | solution_count++;
398 | if (solution_count >= MAX_INTERPRETATIONS200)
399 | {
400 | THROW(BoundsError)except_throw(1, (1), ((void*)0));
401 | }
402 | }
403 | else if (new_offset < datablock_end)
404 | {
405 | if ((depth + 1) >= MAX_INTERPRETATION_LENGTH200)
406 | {
407 | THROW(BoundsError)except_throw(1, (1), ((void*)0));
408 | }
409 | probe_possible_records (tvb, pinfo, new_offset, datablock_end, cat, ed, indexes, stack, depth + 1);
410 | }
411 | }
412 | }
413 | }
414 |
415 | /* possible return values:
416 | -1 for error
417 | new offset value, larger by at least one byte (fspec)
418 | */
419 | 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)
420 | {
421 | proto_item *ti;
422 | proto_tree *asterix_packet_tree;
423 |
424 | ti = proto_tree_add_item (tree, hf_asterix_record, tvb, offset, 0, ENC_NA0x00000000);
425 | asterix_packet_tree = proto_item_add_subtree (ti, ett_asterix);
426 |
427 | table_params table_p;
428 | get_category_uap_table(cat, ed, uap, &table_p);
429 |
430 | if (table_p.table_pointer == NULL((void*)0) || table_p.table_pointer_expand == NULL((void*)0)) {
431 | // skip unknown category
432 | expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "Unknown category");
433 | return -1;
434 | }
435 | if (!check_fspec_validity (tvb, offset, &table_p)) {
436 | // something wrong with FSPEC field
437 | expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "FSPEC field invalid");
438 | return -1;
439 | }
440 | int start_offset = offset;
441 |
442 | offset += asterix_dissect_fspec (tvb, offset, asterix_packet_tree);;
443 | unsigned i = 0;
444 | unsigned fs_index = 0;
445 | while (i <= table_p.table_size) {
446 | if (((fs_index + 1) % 8) == 0 && fs_index > 0) {
447 | if (!asterix_field_exists(tvb, start_offset, fs_index)) {
448 | break;
449 | }
450 | fs_index++;
451 | }
452 | if (asterix_field_exists(tvb, start_offset, fs_index)) {
453 | int *expand = table_p.table_pointer_expand[i];
454 | int expand_value = -1;
455 | if (expand != NULL((void*)0))
456 | {
457 | expand_value = *expand;
458 | }
459 | if (table_p.table_pointer[i] != NULL((void*)0)) {
460 | int fun_len = table_p.table_pointer[i](tvb, offset, asterix_packet_tree, expand_value);
461 | if (fun_len == -1) {
462 | return -1;
463 | }
464 | offset += fun_len;
465 | } else {
466 | return -1;
467 | }
468 | }
469 | i++;
470 | fs_index++;
471 | }
472 | unsigned int item_length = offset - start_offset;
473 | proto_item_set_len(ti, item_length);
474 | proto_item_append_text(ti, ", length %u", item_length);
475 | proto_item_append_text(ti, ", %s", table_p.uap_name);
476 |
477 | if (offset > datablock_end) {
478 | //record outside datablock
479 | expert_add_info_format(pinfo, ti, &ei_asterix_overflow, "Record out of bounds");
480 | }
481 | return offset;
482 | }
483 |
484 | static void dissect_asterix_records (tvbuff_t *tvb, packet_info *pinfo, int offset, unsigned datablock_length, proto_tree *tree, unsigned int cat)
485 | {
486 | int datablock_end = offset + datablock_length;
487 |
488 | // get edition from settings
489 | unsigned int ed = -1;
490 | for (unsigned i = 0; i < sizeof(asterix_properties) / sizeof(asterix_properties[0]); i++)
491 | {
492 | dialog_cat_struct prop_cat = asterix_properties[i];
493 | if (prop_cat.cat == cat && prop_cat.cat_basic)
494 | {
495 | ed = *prop_cat.cat_default_value;
496 | break;
497 | }
498 | }
499 |
500 | memset(solutions, -1, sizeof(solutions));
501 | solution_count = 0;
502 | unsigned int stack[MAX_INTERPRETATION_LENGTH200];
503 |
504 | uap_table_indexes indexes;
505 | get_uap_tables(cat, ed, &indexes);
506 |
507 | // if category unknown both start_index and end_index are 0
508 | if ((indexes.end_index - indexes.start_index) > 0)
509 | {
510 | probe_possible_records (tvb, pinfo, offset, datablock_end, cat, ed, &indexes, stack, 0);
511 | unsigned int backup_offset = offset;
512 |
513 | proto_item *possibilities_ti = proto_tree_add_item (tree, hf_asterix_possible_interpretations, tvb, offset, 0, ENC_NA0x00000000);
514 | proto_tree *possibilities_tree = proto_item_add_subtree (possibilities_ti, ett_asterix_possible_interpretations);
515 | proto_item_append_text (possibilities_tree, " %u", solution_count);
516 |
517 | if (solution_count == 0) {
518 | expert_add_info_format(pinfo, possibilities_ti, &ei_asterix_overflow, "No possible solution found");
519 | } else {
520 | for (unsigned int i = 0; i < solution_count; i++) {
521 | offset = backup_offset;
522 | proto_item *possible_ti = proto_tree_add_item (possibilities_tree, hf_asterix_possible_interpretation, tvb, offset, 0, ENC_NA0x00000000);
523 | proto_item_append_text (possible_ti, " (%u/%u)", i + 1, solution_count);
524 | proto_tree *possible_tree = proto_item_add_subtree (possible_ti, ett_asterix_possible_interpretation);
525 |
526 | for (unsigned int j = 0; solutions[i][j] != -1; j++) {
527 | int new_offset = dissect_asterix_record (tvb, pinfo, offset, datablock_end, possible_tree, cat, ed, solutions[i][j]);
528 | // there should not be any error, as this solution already tried, but check anyway
529 | if (new_offset <= offset) {
530 | return;
531 | }
532 | offset = new_offset;
533 | }
534 | }
535 | }
536 | }
537 | else {
538 | while (offset < datablock_end) {
539 | int new_offset = dissect_asterix_record (tvb, pinfo, offset, datablock_end, tree, cat, ed, indexes.start_index);
540 | if (new_offset <= offset) {
541 | return;
542 | }
543 | offset = new_offset;
544 | }
545 | }
546 | }
547 |
548 | static bool_Bool check_datagram_datablocks (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
549 | {
550 | int i = 0;
551 | int n = tvb_reported_length (tvb);
552 |
553 | while (i < n) {
554 | int remaining = n - i;
555 | proto_item *item;
556 |
557 | if (remaining < 4) {
558 | item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, remaining, ENC_NA0x00000000);
559 | expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Data length less than 4B");
560 | return false0;
561 | }
562 |
563 | uint16_t len = tvb_get_uint16 (tvb, i+1, ENC_BIG_ENDIAN0x00000000);
564 | if (len < 4) {
565 | item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA0x00000000);
566 | expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Datablock length less than 4B");
567 | return false0;
568 | }
569 |
570 | if (remaining < len) {
571 | item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA0x00000000);
572 | expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Not enough data for datablock");
573 | return false0;
574 | }
575 | // move to next datablock
576 | i += len;
577 | }
578 | if (i == n) {
579 | return true1;
580 | }
581 | else {
582 | proto_item *item = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, n, ENC_NA0x00000000);
583 | expert_add_info_format(pinfo, item, &ei_asterix_overflow, "Datablocks datagram misalignment");
584 | return false0;
585 | }
586 | }
587 |
588 | static void dissect_asterix_data_blocks (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
589 | {
590 | int i = 0;
591 | int n = tvb_reported_length (tvb);
592 |
593 | // Datablock parsing is strict. This means that all datablocks must be alligned with UDP datagram data. If not, no datablock is parsed.
594 | // In future versions strictness level may be added as a configuration option.
595 | if (check_datagram_datablocks (tvb, pinfo, tree))
596 | {
597 | while (i < n) {
598 | uint8_t cat = tvb_get_uint8 (tvb, i);
599 | uint16_t len = tvb_get_uint16 (tvb, i+1, ENC_BIG_ENDIAN0x00000000);
600 |
601 | proto_item *datablock = proto_tree_add_item (tree, hf_asterix_datablock, tvb, i, len, ENC_NA0x00000000);
602 | proto_tree *datablock_tree = proto_item_add_subtree (datablock, ett_asterix_record);
603 |
604 | proto_item_append_text (datablock_tree, ", Category %03d", cat);
605 | proto_tree_add_item (datablock_tree, hf_asterix_category, tvb, i, 1, ENC_BIG_ENDIAN0x00000000);
606 | proto_tree_add_item (datablock_tree, hf_asterix_length, tvb, i + 1, 2, ENC_BIG_ENDIAN0x00000000);
607 |
608 | dissect_asterix_records (tvb, pinfo, i + HEADER_LENGTH3, len - HEADER_LENGTH3, datablock_tree, cat);
609 |
610 | // move to next datablock
611 | i += len;
612 | }
613 | }
614 | }
615 |
616 | static int dissect_asterix (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U___attribute__((unused)))
617 | {
618 | col_set_str (pinfo->cinfo, COL_PROTOCOL, "ASTERIX");
619 | col_clear (pinfo->cinfo, COL_INFO);
620 |
621 | if (hf_asterix_category <= 0) {
622 | proto_registrar_get_byname("asterix.category");
623 | }
624 |
625 | if (tree) { /* we are being asked for details */
626 | dissect_asterix_data_blocks (tvb, pinfo, tree);
627 | }
628 |
629 | return tvb_captured_length(tvb);
630 | }
631 |
632 | static unsigned get_asterix_pdu_len(packet_info *pinfo _U___attribute__((unused)), tvbuff_t *tvb, int offset, void *data _U___attribute__((unused)))
633 | {
634 | uint16_t plen;
635 | plen = tvb_get_uint16 (tvb, offset + 1, ENC_BIG_ENDIAN0x00000000);
636 | return plen;
637 | }
638 |
639 | static int dissect_asterix_tcp (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
640 | {
641 | /* We do delayed field registration if needed in dissect_asterix. */
642 | tcp_dissect_pdus(tvb, pinfo, tree, true1, 3, get_asterix_pdu_len, dissect_asterix, data);
643 | return tvb_reported_length (tvb);
644 | }
645 |
646 | static void register_asterix_fields(const char* unused _U___attribute__((unused)))
647 | {
648 | proto_register_field_array (proto_asterix, hf, array_length (hf)(sizeof (hf) / sizeof (hf)[0]));
649 |
650 | static int *ett[] = {
651 | &ett_asterix,
652 | &ett_asterix_record,
653 | &ett_asterix_subtree,
654 | &ett_asterix_possible_interpretation,
655 | &ett_asterix_possible_interpretations,
656 | &ett_asterix_spare_error
657 | };
658 |
659 | proto_register_subtree_array (ett, array_length (ett)(sizeof (ett) / sizeof (ett)[0]));
660 | }
661 |
662 | void proto_register_asterix (void)
663 | {
664 | static ei_register_info ei[] = {
665 | { &ei_asterix_overflow, { "asterix.overflow", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "Asterix overflow", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }},
666 | { &hf_asterix_spare_error, { "asterix.spare_error", PI_PROTOCOL0x09000000, PI_WARN0x00600000, "Spare bit error", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }},
667 | { &hf_asterix_fspec_error, { "asterix.fspec_error", PI_PROTOCOL0x09000000, PI_ERROR0x00800000, "FSPEC error", EXPFILL0, ((void*)0), 0, {0, {((void*)0), ((void*)0), FT_NONE, BASE_NONE , ((void*)0), 0, ((void*)0), -1, 0, HF_REF_TYPE_NONE, -1, ((void *)0)}} }}
668 | };
669 |
670 | proto_asterix = proto_register_protocol ("ASTERIX packet", "ASTERIX", "asterix");
671 |
672 | /* Delay registration of ASTERIX fields */
673 | proto_register_prefix("asterix", register_asterix_fields);
674 |
675 | asterix_module = prefs_register_protocol(proto_asterix, NULL((void*)0));
676 | asterix_handle = register_dissector ("asterix", dissect_asterix, proto_asterix);
677 | asterix_tcp_handle = register_dissector ("asterix-tcp", dissect_asterix_tcp, proto_asterix);
678 |
679 | expert_asterix = expert_register_protocol(proto_asterix);
680 | expert_register_field_array(expert_asterix, ei, array_length(ei)(sizeof (ei) / sizeof (ei)[0]));
681 |
682 | for (unsigned i = 0; i < sizeof(asterix_properties) / sizeof(asterix_properties[0]); i++)
683 | {
684 | dialog_cat_struct cat = asterix_properties[i];
685 | prefs_register_enum_preference(asterix_module, cat.cat_name, cat.cat_name, NULL((void*)0), cat.cat_default_value, cat.cat_enums, FALSE(0));
686 | }
687 | }
688 |
689 | void proto_reg_handoff_asterix (void)
690 | {
691 | dissector_add_uint_with_preference("udp.port", ASTERIX_PORT8600, asterix_handle);
692 | dissector_add_uint_with_preference("tcp.port", ASTERIX_PORT8600, asterix_tcp_handle);
693 | }