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

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-12-100316-3623-1 -x c /builds/wireshark/wireshark/epan/dissectors/packet-asterix.c
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
37static int proto_asterix;
38
39static char fspec_bit_string[MAX_FSPEC_BIT_LENGTH1024];
40
41static dissector_handle_t asterix_handle;
42static dissector_handle_t asterix_tcp_handle;
43
44static int ett_asterix;
45static int ett_asterix_record;
46static int ett_asterix_possible_interpretation;
47static int ett_asterix_possible_interpretations;
48static int ett_asterix_spare_error;
49
50
51static 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
68static 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
86static 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
110static 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
124static 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
133static 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
158static 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
176static 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
201static 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
214static 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
222static 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
235static 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
259static 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
294unsigned int solution_count;
295int solutions[MAX_INTERPRETATIONS200][MAX_INTERPRETATION_LENGTH200];
296
297static 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
326static 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)
375static 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*/
419static 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
484static 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
548static 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
588static 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
616static 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
632static 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
639static 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
646static 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
662void 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
689void 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}