TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags
[wireshark-sm.git] / tools / asterix / packet-asterix-template.c
blobd584f1cf16a3eb25057e3d86d7850ca2efe6bcfc
1 /*
3 Notice:
6 This file is auto generated, do not edit!
7 See tools/asterix/README.md for details.
10 Data source:
11 ---{gitrev}---
16 /* packet-asterix.c
17 * Routines for ASTERIX decoding
18 * By Marko Hrastovec <marko.hrastovec@sloveniacontrol.si>
20 * Wireshark - Network traffic analyzer
21 * By Gerald Combs <gerald@wireshark.org>
22 * Copyright 1998 Gerald Combs
24 * SPDX-License-Identifier: GPL-2.0-or-later
28 * ASTERIX (All-purpose structured EUROCONTROL surveillances
29 * information exchange) is a protocol related to air traffic control.
31 * The specifications can be downloaded from
32 * http://www.eurocontrol.int/services/asterix
35 #include <config.h>
37 #include <wsutil/bits_ctz.h>
39 #include <epan/packet.h>
40 #include <epan/prefs.h>
41 #include <epan/proto_data.h>
43 void proto_register_asterix(void);
44 void proto_reg_handoff_asterix(void);
46 #define PROTO_TAG_ASTERIX "ASTERIX"
47 #define ASTERIX_PORT 8600
49 #define MAX_DISSECT_STR 1024
50 #define MAX_BUFFER 256
52 static int proto_asterix;
54 static int hf_asterix_category;
55 static int hf_asterix_length;
56 static int hf_asterix_message;
57 static int hf_asterix_fspec;
58 static int hf_re_field_len;
59 static int hf_spare;
60 static int hf_counter;
61 static int hf_XXX_FX;
63 static int ett_asterix;
64 static int ett_asterix_category;
65 static int ett_asterix_length;
66 static int ett_asterix_message;
67 static int ett_asterix_subtree;
69 static dissector_handle_t asterix_handle;
70 /* The following defines tell us how to decode the length of
71 * fields and how to construct their display structure */
72 #define FIXED 1
73 #define REPETITIVE 2
74 #define FX 3
75 /*#define FX_1 4*/
76 /*#define RE 5*/
77 #define COMPOUND 6
78 /*#define SP 7*/
79 /*#define FX_UAP 8*/
80 #define EXP 9 /* Explicit (RE or SP) */
82 /* The following defines tell us how to
83 * decode and display individual fields. */
84 #define FIELD_PART_INT 0
85 #define FIELD_PART_UINT 1
86 #define FIELD_PART_FLOAT 2
87 #define FIELD_PART_UFLOAT 3
88 #define FIELD_PART_SQUAWK 4
89 #define FIELD_PART_CALLSIGN 5
90 #define FIELD_PART_ASCII 6
91 #define FIELD_PART_FX 7
92 #define FIELD_PART_HEX 8
93 #define FIELD_PART_IAS_IM 9
94 #define FIELD_PART_IAS_ASPD 10
96 typedef struct FieldPart_s FieldPart;
97 struct FieldPart_s {
98 uint16_t bit_length; /* length of field in bits */
99 double scaling_factor; /* scaling factor of the field (for instance: 1/128) */
100 uint8_t type; /* Pre-defined type for proper presentation */
101 int *hf; /* Pointer to hf representing this kind of data */
102 const char *format_string; /* format string for showing float values */
105 typedef struct AsterixField_s AsterixField;
106 struct AsterixField_s {
107 uint8_t type; /* type of field */
108 unsigned length; /* fixed length */
109 unsigned repetition_counter_size; /* size of repetition counter, length of one item is in length */
110 unsigned header_length; /* the size is in first header_length bytes of the field */
111 int *hf; /* pointer to Wireshark hf_register_info */
112 const FieldPart * const *part; /* Look declaration and description of FieldPart above. */
113 const AsterixField * const field[]; /* subfields */
116 static void dissect_asterix_packet (tvbuff_t *, packet_info *pinfo, proto_tree *);
117 static void dissect_asterix_data_block (tvbuff_t *tvb, packet_info *pinfo, unsigned, proto_tree *, uint8_t, int);
118 static int dissect_asterix_fields (tvbuff_t *, packet_info *pinfo, unsigned, proto_tree *, uint8_t, const AsterixField * const []);
120 static void asterix_build_subtree (tvbuff_t *, packet_info *pinfo, unsigned, proto_tree *, const AsterixField *);
121 static void twos_complement (int64_t *, int);
122 static uint8_t asterix_bit (uint8_t, uint8_t);
123 static unsigned asterix_fspec_len (tvbuff_t *, unsigned);
124 static uint8_t asterix_field_exists (tvbuff_t *, unsigned, int);
125 static uint8_t asterix_get_active_uap (tvbuff_t *, unsigned, uint8_t);
126 static int asterix_field_length (tvbuff_t *, unsigned, const AsterixField * const);
127 static int asterix_field_offset (tvbuff_t *, unsigned, const AsterixField * const [], int);
128 static int asterix_message_length (tvbuff_t *, unsigned, uint8_t, uint8_t);
130 static const char AISCode[] = { ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
131 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', ' ', ' ', ' ', ' ',
132 ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
133 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', ' ', ' ', ' ', ' ', ' ' };
135 static const value_string valstr_XXX_FX[] = {
136 { 0, "End of data item" },
137 { 1, "Extension into next extent" },
138 { 0, NULL }
140 static const FieldPart IXXX_FX = { 1, 1.0, FIELD_PART_FX, &hf_XXX_FX, NULL };
141 static const FieldPart IXXX_1bit_spare = { 1, 1.0, FIELD_PART_UINT, NULL, NULL };
142 static const FieldPart IXXX_2bit_spare = { 2, 1.0, FIELD_PART_UINT, NULL, NULL };
143 static const FieldPart IXXX_3bit_spare = { 3, 1.0, FIELD_PART_UINT, NULL, NULL };
144 static const FieldPart IXXX_4bit_spare = { 4, 1.0, FIELD_PART_UINT, NULL, NULL };
145 static const FieldPart IXXX_5bit_spare = { 5, 1.0, FIELD_PART_UINT, NULL, NULL };
146 static const FieldPart IXXX_6bit_spare = { 6, 1.0, FIELD_PART_UINT, NULL, NULL };
147 static const FieldPart IXXX_7bit_spare = { 7, 1.0, FIELD_PART_UINT, NULL, NULL };
149 /* Spare Item */
150 static const AsterixField IX_SPARE = { FIXED, 0, 0, 0, &hf_spare, NULL, { NULL } };
152 /* insert1 */
153 ---{insert1}---
154 /* insert1 */
156 /* settings which category version to use for each ASTERIX category */
157 static int global_categories_version[] = {
158 0, /* 000 */
159 0, /* 001 */
160 0, /* 002 */
161 0, /* 003 */
162 0, /* 004 */
163 0, /* 005 */
164 0, /* 006 */
165 0, /* 007 */
166 0, /* 008 */
167 0, /* 009 */
168 0, /* 010 */
169 0, /* 011 */
170 0, /* 012 */
171 0, /* 013 */
172 0, /* 014 */
173 0, /* 015 */
174 0, /* 016 */
175 0, /* 017 */
176 0, /* 018 */
177 0, /* 019 */
178 0, /* 020 */
179 0, /* 021 */
180 0, /* 022 */
181 0, /* 023 */
182 0, /* 024 */
183 0, /* 025 */
184 0, /* 026 */
185 0, /* 027 */
186 0, /* 028 */
187 0, /* 029 */
188 0, /* 030 */
189 0, /* 031 */
190 0, /* 032 */
191 0, /* 033 */
192 0, /* 034 */
193 0, /* 035 */
194 0, /* 036 */
195 0, /* 037 */
196 0, /* 038 */
197 0, /* 039 */
198 0, /* 040 */
199 0, /* 041 */
200 0, /* 042 */
201 0, /* 043 */
202 0, /* 044 */
203 0, /* 045 */
204 0, /* 046 */
205 0, /* 047 */
206 0, /* 048 */
207 0, /* 049 */
208 0, /* 050 */
209 0, /* 051 */
210 0, /* 052 */
211 0, /* 053 */
212 0, /* 054 */
213 0, /* 055 */
214 0, /* 056 */
215 0, /* 057 */
216 0, /* 058 */
217 0, /* 059 */
218 0, /* 060 */
219 0, /* 061 */
220 0, /* 062 */
221 0, /* 063 */
222 0, /* 064 */
223 0, /* 065 */
224 0, /* 066 */
225 0, /* 067 */
226 0, /* 068 */
227 0, /* 069 */
228 0, /* 070 */
229 0, /* 071 */
230 0, /* 072 */
231 0, /* 073 */
232 0, /* 074 */
233 0, /* 075 */
234 0, /* 076 */
235 0, /* 077 */
236 0, /* 078 */
237 0, /* 079 */
238 0, /* 080 */
239 0, /* 081 */
240 0, /* 082 */
241 0, /* 083 */
242 0, /* 084 */
243 0, /* 085 */
244 0, /* 086 */
245 0, /* 087 */
246 0, /* 088 */
247 0, /* 089 */
248 0, /* 090 */
249 0, /* 091 */
250 0, /* 092 */
251 0, /* 093 */
252 0, /* 094 */
253 0, /* 095 */
254 0, /* 096 */
255 0, /* 097 */
256 0, /* 098 */
257 0, /* 099 */
258 0, /* 100 */
259 0, /* 101 */
260 0, /* 102 */
261 0, /* 103 */
262 0, /* 104 */
263 0, /* 105 */
264 0, /* 106 */
265 0, /* 107 */
266 0, /* 108 */
267 0, /* 109 */
268 0, /* 110 */
269 0, /* 111 */
270 0, /* 112 */
271 0, /* 113 */
272 0, /* 114 */
273 0, /* 115 */
274 0, /* 116 */
275 0, /* 117 */
276 0, /* 118 */
277 0, /* 119 */
278 0, /* 120 */
279 0, /* 121 */
280 0, /* 122 */
281 0, /* 123 */
282 0, /* 124 */
283 0, /* 125 */
284 0, /* 126 */
285 0, /* 127 */
286 0, /* 128 */
287 0, /* 129 */
288 0, /* 130 */
289 0, /* 131 */
290 0, /* 132 */
291 0, /* 133 */
292 0, /* 134 */
293 0, /* 135 */
294 0, /* 136 */
295 0, /* 137 */
296 0, /* 138 */
297 0, /* 139 */
298 0, /* 140 */
299 0, /* 141 */
300 0, /* 142 */
301 0, /* 143 */
302 0, /* 144 */
303 0, /* 145 */
304 0, /* 146 */
305 0, /* 147 */
306 0, /* 148 */
307 0, /* 149 */
308 0, /* 150 */
309 0, /* 151 */
310 0, /* 152 */
311 0, /* 153 */
312 0, /* 154 */
313 0, /* 155 */
314 0, /* 156 */
315 0, /* 157 */
316 0, /* 158 */
317 0, /* 159 */
318 0, /* 160 */
319 0, /* 161 */
320 0, /* 162 */
321 0, /* 163 */
322 0, /* 164 */
323 0, /* 165 */
324 0, /* 166 */
325 0, /* 167 */
326 0, /* 168 */
327 0, /* 169 */
328 0, /* 170 */
329 0, /* 171 */
330 0, /* 172 */
331 0, /* 173 */
332 0, /* 174 */
333 0, /* 175 */
334 0, /* 176 */
335 0, /* 177 */
336 0, /* 178 */
337 0, /* 179 */
338 0, /* 180 */
339 0, /* 181 */
340 0, /* 182 */
341 0, /* 183 */
342 0, /* 184 */
343 0, /* 185 */
344 0, /* 186 */
345 0, /* 187 */
346 0, /* 188 */
347 0, /* 189 */
348 0, /* 190 */
349 0, /* 191 */
350 0, /* 192 */
351 0, /* 193 */
352 0, /* 194 */
353 0, /* 195 */
354 0, /* 196 */
355 0, /* 197 */
356 0, /* 198 */
357 0, /* 199 */
358 0, /* 200 */
359 0, /* 201 */
360 0, /* 202 */
361 0, /* 203 */
362 0, /* 204 */
363 0, /* 205 */
364 0, /* 206 */
365 0, /* 207 */
366 0, /* 208 */
367 0, /* 209 */
368 0, /* 210 */
369 0, /* 211 */
370 0, /* 212 */
371 0, /* 213 */
372 0, /* 214 */
373 0, /* 215 */
374 0, /* 216 */
375 0, /* 217 */
376 0, /* 218 */
377 0, /* 219 */
378 0, /* 220 */
379 0, /* 221 */
380 0, /* 222 */
381 0, /* 223 */
382 0, /* 224 */
383 0, /* 225 */
384 0, /* 226 */
385 0, /* 227 */
386 0, /* 228 */
387 0, /* 229 */
388 0, /* 230 */
389 0, /* 231 */
390 0, /* 232 */
391 0, /* 233 */
392 0, /* 234 */
393 0, /* 235 */
394 0, /* 236 */
395 0, /* 237 */
396 0, /* 238 */
397 0, /* 239 */
398 0, /* 240 */
399 0, /* 241 */
400 0, /* 242 */
401 0, /* 243 */
402 0, /* 244 */
403 0, /* 245 */
404 0, /* 246 */
405 0, /* 247 */
406 0, /* 248 */
407 0, /* 249 */
408 0, /* 250 */
409 0, /* 251 */
410 0, /* 252 */
411 0, /* 253 */
412 0, /* 254 */
413 0 /* 255 */
416 static int dissect_asterix (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
418 col_set_str (pinfo->cinfo, COL_PROTOCOL, "ASTERIX");
419 col_clear (pinfo->cinfo, COL_INFO);
421 if (tree) { /* we are being asked for details */
422 dissect_asterix_packet (tvb, pinfo, tree);
425 return tvb_captured_length(tvb);
428 static void dissect_asterix_packet (tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
430 unsigned i;
431 uint8_t category;
432 uint16_t length;
433 proto_item *asterix_packet_item;
434 proto_tree *asterix_packet_tree;
436 for (i = 0; i < tvb_reported_length (tvb); i += length + 3) {
437 /* all ASTERIX messages have the same structure:
439 * header:
441 * 1 byte category even though a category is referenced as I019,
442 * this is just stored as decimal 19 (i.e. 0x13)
443 * 2 bytes length the total length of this ASTERIX message, the
444 * length includes the size of the header.
446 * Note that the there was a structural change at
447 * one point that changes whether multiple
448 * records can occur after the header or not
449 * (each category specifies this explicitly. All
450 * of the currently supported categories can have
451 * multiple records so this implementation just
452 * assumes that is always the case)
454 * record (multiple records can exists):
456 * n bytes FSPEC the field specifier is a bit mask where the
457 * lowest bit of each byte is called the FX bit.
458 * When the FX bit is set this indicates that
459 * the FSPEC extends into the next byte.
460 * Any other bit indicates the presence of the
461 * field that owns that bit (as per the User
462 * Application Profile (UAP)).
463 * X bytes Field Y X is as per the specification for field Y.
464 * etc.
466 * The User Application Profile (UAP) is simply a mapping from the
467 * FSPEC to fields. Each category has its own UAP.
469 category = tvb_get_uint8 (tvb, i);
470 length = (tvb_get_uint8 (tvb, i + 1) << 8) + tvb_get_uint8 (tvb, i + 2) - 3; /* -3 for category and length */
472 asterix_packet_item = proto_tree_add_item (tree, proto_asterix, tvb, i, length + 3, ENC_NA);
473 proto_item_append_text (asterix_packet_item, ", Category %03d", category);
474 asterix_packet_tree = proto_item_add_subtree (asterix_packet_item, ett_asterix);
475 proto_tree_add_item (asterix_packet_tree, hf_asterix_category, tvb, i, 1, ENC_BIG_ENDIAN);
476 proto_tree_add_item (asterix_packet_tree, hf_asterix_length, tvb, i + 1, 2, ENC_BIG_ENDIAN);
478 dissect_asterix_data_block (tvb, pinfo, i + 3, asterix_packet_tree, category, length);
482 static void dissect_asterix_data_block (tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, uint8_t category, int length)
484 uint8_t active_uap;
485 int fspec_len, inner_offset, size, counter;
486 proto_item *asterix_message_item = NULL;
487 proto_tree *asterix_message_tree = NULL;
489 for (counter = 1, inner_offset = 0; inner_offset < length; counter++) {
491 /* This loop handles parsing of each ASTERIX record */
493 active_uap = asterix_get_active_uap (tvb, offset + inner_offset, category);
494 size = asterix_message_length (tvb, offset + inner_offset, category, active_uap);
495 if (size > 0) {
496 asterix_message_item = proto_tree_add_item (tree, hf_asterix_message, tvb, offset + inner_offset, size, ENC_NA);
497 proto_item_append_text (asterix_message_item, ", #%02d, length: %d", counter, size);
498 asterix_message_tree = proto_item_add_subtree (asterix_message_item, ett_asterix_message);
499 fspec_len = asterix_fspec_len (tvb, offset + inner_offset);
500 /*show_fspec (tvb, asterix_message_tree, offset + inner_offset, fspec_len);*/
501 proto_tree_add_item (asterix_message_tree, hf_asterix_fspec, tvb, offset + inner_offset, fspec_len, ENC_NA);
503 size = dissect_asterix_fields (tvb, pinfo, offset + inner_offset, asterix_message_tree, category, categories[category][global_categories_version[category]][active_uap]);
505 inner_offset += size + fspec_len;
507 else {
508 inner_offset = length;
513 // We're transported over UDP and our offset always advances.
514 // NOLINTNEXTLINE(misc-no-recursion)
515 static int dissect_asterix_fields (tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *tree, uint8_t category, const AsterixField * const current_uap [])
517 unsigned i, j, size, start, len, inner_offset, fspec_len;
518 uint64_t counter;
519 proto_item *asterix_field_item = NULL;
520 proto_tree *asterix_field_tree = NULL;
521 proto_item *asterix_field_item2 = NULL;
522 proto_tree *asterix_field_tree2 = NULL;
524 if (current_uap == NULL)
525 return 0;
527 for (i = 0, size = 0; current_uap[i] != NULL; i++) {
528 start = asterix_field_offset (tvb, offset, current_uap, i);
529 if (start > 0) {
530 len = asterix_field_length (tvb, offset + start, current_uap[i]);
531 size += len;
532 switch(current_uap[i]->type) {
533 case COMPOUND:
534 asterix_field_item = proto_tree_add_item (tree, *current_uap[i]->hf, tvb, offset + start, len, ENC_NA);
535 asterix_field_tree = proto_item_add_subtree (asterix_field_item, ett_asterix_subtree);
536 fspec_len = asterix_fspec_len (tvb, offset + start);
537 proto_tree_add_item (asterix_field_tree, hf_asterix_fspec, tvb, offset + start, fspec_len, ENC_NA);
538 dissect_asterix_fields (tvb, pinfo, offset + start, asterix_field_tree, category, current_uap[i]->field);
539 break;
540 case REPETITIVE:
541 asterix_field_item = proto_tree_add_item (tree, *current_uap[i]->hf, tvb, offset + start, len, ENC_NA);
542 asterix_field_tree = proto_item_add_subtree (asterix_field_item, ett_asterix_subtree);
543 for (j = 0, counter = 0; j < current_uap[i]->repetition_counter_size; j++) {
544 counter = (counter << 8) + tvb_get_uint8 (tvb, offset + start + j);
546 proto_tree_add_item (asterix_field_tree, hf_counter, tvb, offset + start, current_uap[i]->repetition_counter_size, ENC_BIG_ENDIAN);
547 for (j = 0, inner_offset = 0; j < counter; j++, inner_offset += current_uap[i]->length) {
548 asterix_field_item2 = proto_tree_add_item (asterix_field_tree, *current_uap[i]->hf, tvb, offset + start + current_uap[i]->repetition_counter_size + inner_offset, current_uap[i]->length, ENC_NA);
549 asterix_field_tree2 = proto_item_add_subtree (asterix_field_item2, ett_asterix_subtree);
550 asterix_build_subtree (tvb, pinfo, offset + start + current_uap[i]->repetition_counter_size + inner_offset, asterix_field_tree2, current_uap[i]);
552 break;
553 /* currently not generated from asterix-spec*/
554 /*case EXP:
555 asterix_field_item = proto_tree_add_item (tree, *current_uap[i]->hf, tvb, offset + start, len, ENC_NA);
556 asterix_field_tree = proto_item_add_subtree (asterix_field_item, ett_asterix_subtree);
557 proto_tree_add_item (asterix_field_tree, hf_re_field_len, tvb, offset + start, 1, ENC_BIG_ENDIAN);
558 start++;
559 fspec_len = asterix_fspec_len (tvb, offset + start);
560 proto_tree_add_item (asterix_field_tree, hf_asterix_fspec, tvb, offset + start, fspec_len, ENC_NA);
561 dissect_asterix_fields (tvb, pinfo, offset + start, asterix_field_tree, category, current_uap[i]->field);
562 break;*/
563 default: /* FIXED, FX, FX_1, FX_UAP */
564 asterix_field_item = proto_tree_add_item (tree, *current_uap[i]->hf, tvb, offset + start, len, ENC_NA);
565 asterix_field_tree = proto_item_add_subtree (asterix_field_item, ett_asterix_subtree);
566 asterix_build_subtree (tvb, pinfo, offset + start, asterix_field_tree, current_uap[i]);
567 break;
571 return size;
574 static void asterix_build_subtree (tvbuff_t *tvb, packet_info *pinfo, unsigned offset, proto_tree *parent, const AsterixField *field)
576 header_field_info* hfi;
577 int bytes_in_type, byte_offset_of_mask;
578 int i, inner_offset, offset_in_tvb, length_in_tvb;
579 uint8_t go_on;
580 int64_t value;
581 char *str_buffer = NULL;
582 double scaling_factor = 1.0;
583 uint8_t *air_speed_im_bit;
584 if (field->part != NULL) {
585 for (i = 0, inner_offset = 0, go_on = 1; go_on && field->part[i] != NULL; i++) {
586 value = tvb_get_bits64 (tvb, offset * 8 + inner_offset, field->part[i]->bit_length, ENC_BIG_ENDIAN);
587 if (field->part[i]->hf != NULL) {
588 offset_in_tvb = offset + inner_offset / 8;
589 length_in_tvb = (inner_offset % 8 + field->part[i]->bit_length + 7) / 8;
590 switch (field->part[i]->type) {
591 case FIELD_PART_FX:
592 if (!value) go_on = 0;
593 /* Fall through */
594 case FIELD_PART_INT:
595 case FIELD_PART_UINT:
596 case FIELD_PART_HEX:
597 case FIELD_PART_ASCII:
598 case FIELD_PART_SQUAWK:
599 hfi = proto_registrar_get_nth (*field->part[i]->hf);
600 if (hfi->bitmask)
602 // for a small bit field to decode correctly with
603 // a mask that belongs to a large(r) one we need to
604 // re-adjust offset_in_tvb and length_in_tvb to
605 // correctly align with the given hf mask.
607 // E.g. the following would not decode correctly:
608 // { &hf_020_050_V, ... FT_UINT16, ... 0x8000, ...
609 // instead one would have to use
610 // { &hf_020_050_V, ... FT_UINT8, ... 0x80, ...
612 bytes_in_type = ftype_wire_size(hfi->type);
613 if (bytes_in_type > 1)
615 byte_offset_of_mask = bytes_in_type - (ws_ilog2 (hfi->bitmask) + 8)/8;
616 if (byte_offset_of_mask >= 0)
618 offset_in_tvb -= byte_offset_of_mask;
619 length_in_tvb = bytes_in_type;
623 proto_tree_add_item (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, ENC_BIG_ENDIAN);
624 break;
625 case FIELD_PART_FLOAT:
626 twos_complement (&value, field->part[i]->bit_length);
627 /* Fall through */
628 case FIELD_PART_UFLOAT:
629 scaling_factor = field->part[i]->scaling_factor;
630 if (field->part[i]->format_string != NULL)
631 proto_tree_add_double_format_value (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, value * scaling_factor, field->part[i]->format_string, value * scaling_factor);
632 else
633 proto_tree_add_double (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, value * scaling_factor);
634 break;
635 case FIELD_PART_CALLSIGN:
636 str_buffer = wmem_strdup_printf(
637 pinfo->pool,
638 "%c%c%c%c%c%c%c%c",
639 AISCode[(value >> 42) & 63],
640 AISCode[(value >> 36) & 63],
641 AISCode[(value >> 30) & 63],
642 AISCode[(value >> 24) & 63],
643 AISCode[(value >> 18) & 63],
644 AISCode[(value >> 12) & 63],
645 AISCode[(value >> 6) & 63],
646 AISCode[value & 63]);
647 proto_tree_add_string (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, str_buffer);
648 break;
649 case FIELD_PART_IAS_IM:
650 /* special processing for I021/150 and I062/380#4 because Air Speed depends on IM subfield */
651 air_speed_im_bit = wmem_new (pinfo->pool, uint8_t);
652 *air_speed_im_bit = (tvb_get_uint8 (tvb, offset_in_tvb) & 0x80) >> 7;
653 /* Save IM info for the packet. key = 21150. */
654 p_add_proto_data (pinfo->pool, pinfo, proto_asterix, 21150, air_speed_im_bit);
655 proto_tree_add_item (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, ENC_BIG_ENDIAN);
656 break;
657 case FIELD_PART_IAS_ASPD:
658 /* special processing for I021/150 and I062/380#4 because Air Speed depends on IM subfield */
659 air_speed_im_bit = (uint8_t *)p_get_proto_data (pinfo->pool, pinfo, proto_asterix, 21150);
660 if (!air_speed_im_bit || *air_speed_im_bit == 0)
661 scaling_factor = 1.0/16384.0;
662 else
663 scaling_factor = 0.001;
664 proto_tree_add_double (parent, *field->part[i]->hf, tvb, offset_in_tvb, length_in_tvb, value * scaling_factor);
665 break;
668 inner_offset += field->part[i]->bit_length;
670 } /* if not null */
673 static uint8_t asterix_bit (uint8_t b, uint8_t bitNo)
675 return bitNo < 8 && (b & (0x80 >> bitNo)) > 0;
678 /* Function makes int64_t two's complement.
679 * Only the bit_len bit are set in int64_t. All more significant
680 * bits need to be set to have proper two's complement.
681 * If the number is negative, all other bits must be set to 1.
682 * If the number is positive, all other bits must remain 0. */
683 static void twos_complement (int64_t *v, int bit_len)
685 if (*v & (UINT64_C(1) << (bit_len - 1))) {
686 *v |= (UINT64_C(0xffffffffffffffff) << bit_len);
690 static unsigned asterix_fspec_len (tvbuff_t *tvb, unsigned offset)
692 unsigned i;
693 unsigned max_length = tvb_reported_length (tvb) - offset;
694 for (i = 0; (tvb_get_uint8 (tvb, offset + i) & 1) && i < max_length; i++);
695 return i + 1;
698 static uint8_t asterix_field_exists (tvbuff_t *tvb, unsigned offset, int bitIndex)
700 uint8_t bitNo, i;
701 bitNo = bitIndex + bitIndex / 7;
702 for (i = 0; i < bitNo / 8; i++) {
703 if (!(tvb_get_uint8 (tvb, offset + i) & 1)) return 0;
705 return asterix_bit (tvb_get_uint8 (tvb, offset + i), bitNo % 8);
708 // We're transported over UDP and our offset always advances.
709 // NOLINTNEXTLINE(misc-no-recursion)
710 static int asterix_field_length (tvbuff_t *tvb, unsigned offset, const AsterixField * const field)
712 unsigned bit_size;
713 unsigned size;
714 uint64_t count;
715 uint8_t i;
716 bool should_break;
718 size = 0;
719 switch(field->type) {
720 case FIXED:
721 size = field->length;
722 break;
723 case REPETITIVE:
724 for (i = 0, count = 0; i < field->repetition_counter_size && i < sizeof (count); i++)
725 count = (count << 8) + tvb_get_uint8 (tvb, offset + i);
726 size = (unsigned)(field->repetition_counter_size + count * field->length);
727 break;
728 case FX:
729 for (i = 0, bit_size = 0; field->part[i] != NULL; i++) {
730 // We don't need to shift value as FX bits are always at the end
731 should_break = field->part[i]->type == FIELD_PART_FX && !(tvb_get_uint8 (tvb, offset + bit_size / 8) & 1);
732 bit_size += field->part[i]->bit_length;
733 if (should_break) break;
735 size = bit_size / 8;
736 break;
737 case EXP:
738 for (i = 0, size = 0; i < field->header_length; i++) {
739 size = (size << 8) + tvb_get_uint8 (tvb, offset + i);
741 break;
742 case COMPOUND:
743 /* FSPEC */
744 for (size = 0; tvb_get_uint8 (tvb, offset + size) & 1; size++);
745 size++;
747 for (i = 0; field->field[i] != NULL; i++) {
748 if (asterix_field_exists (tvb, offset, i))
749 size += asterix_field_length (tvb, offset + size, field->field[i]);
751 break;
753 return size;
756 /* This works for category 001. For other it may require changes. */
757 static uint8_t asterix_get_active_uap (tvbuff_t *tvb, unsigned offset, uint8_t category)
759 int i, inner_offset;
760 AsterixField const * const *current_uap;
762 if ((category == 1) && (categories[category] != NULL)) { /* if category is supported */
763 if (categories[category][global_categories_version[category]][1] != NULL) { /* if exists another uap */
764 current_uap = categories[category][global_categories_version[category]][0];
765 if (current_uap != NULL) {
766 inner_offset = asterix_fspec_len (tvb, offset);
767 for (i = 0; current_uap[i] != NULL; i++) {
768 if (asterix_field_exists (tvb, offset, i)) {
769 if (i == 1) { /* uap selector (I001/020) is always at index '1' */
770 return tvb_get_uint8 (tvb, offset + inner_offset) >> 7;
772 inner_offset += asterix_field_length (tvb, offset + inner_offset, current_uap[i]);
778 return 0;
781 static int asterix_field_offset (tvbuff_t *tvb, unsigned offset, const AsterixField * const current_uap[], int field_index)
783 int i, inner_offset;
784 inner_offset = 0;
785 if (asterix_field_exists (tvb, offset, field_index)) {
786 inner_offset = asterix_fspec_len (tvb, offset);
787 for (i = 0; i < field_index; i++) {
788 if (asterix_field_exists (tvb, offset, i))
789 inner_offset += asterix_field_length (tvb, offset + inner_offset, current_uap[i]);
792 return inner_offset;
795 static int asterix_message_length (tvbuff_t *tvb, unsigned offset, uint8_t category, uint8_t active_uap)
797 int i, size;
798 AsterixField const * const *current_uap;
800 if (categories[category] != NULL) { /* if category is supported */
801 current_uap = categories[category][global_categories_version[category]][active_uap];
802 if (current_uap != NULL) {
803 size = asterix_fspec_len (tvb, offset);
804 for (i = 0; current_uap[i] != NULL; i++) {
805 if (asterix_field_exists (tvb, offset, i)) {
806 size += asterix_field_length (tvb, offset + size, current_uap[i]);
809 return size;
812 return 0;
815 void proto_register_asterix (void)
817 static hf_register_info hf[] = {
818 { &hf_asterix_category, { "Category", "asterix.category", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
819 { &hf_asterix_length, { "Length", "asterix.length", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } },
820 { &hf_asterix_message, { "Asterix message", "asterix.message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
821 { &hf_asterix_fspec, { "FSPEC", "asterix.fspec", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
822 { &hf_re_field_len, { "RE LEN", "asterix.re_field_len", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } },
823 { &hf_spare, { "Spare", "asterix.spare", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL } },
824 { &hf_counter, { "Counter", "asterix.counter", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
825 { &hf_XXX_FX, { "FX", "asterix.FX", FT_UINT8, BASE_DEC, VALS (valstr_XXX_FX), 0x01, "Extension into next extent", HFILL } },
826 /* insert2 */
827 ---{insert2}---
828 /* insert2 */
831 /* Setup protocol subtree array */
832 static int *ett[] = {
833 &ett_asterix,
834 &ett_asterix_category,
835 &ett_asterix_length,
836 &ett_asterix_message,
837 &ett_asterix_subtree
840 module_t *asterix_prefs_module;
842 proto_asterix = proto_register_protocol (
843 "ASTERIX packet", /* name */
844 "ASTERIX", /* short name */
845 "asterix" /* abbrev */
848 proto_register_field_array (proto_asterix, hf, array_length (hf));
849 proto_register_subtree_array (ett, array_length (ett));
851 asterix_handle = register_dissector ("asterix", dissect_asterix, proto_asterix);
853 asterix_prefs_module = prefs_register_protocol (proto_asterix, NULL);
855 /* insert3 */
856 ---{insert3}---
857 /* insert3 */
860 void proto_reg_handoff_asterix (void)
862 dissector_add_uint_with_preference("udp.port", ASTERIX_PORT, asterix_handle);
866 * Editor modelines - https://www.wireshark.org/tools/modelines.html
868 * Local variables:
869 * c-basic-offset: 4
870 * tab-width: 8
871 * indent-tabs-mode: nil
872 * End:
874 * vi: set shiftwidth=4 tabstop=8 expandtab:
875 * :indentSize=4:tabSize=8:noTabs=true: