1 /* packet-ppi-vector.c
2  * Routines for PPI-GEOLOCATION-VECTOR  dissection
3  * Copyright 2010, Harris Corp, jellch@harris.com
4  *
5  * See
6  *
7  *    http://new.11mercenary.net/~johnycsh/ppi_geolocation_spec/
8  *
9  * for specifications.
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * Copied from packet-radiotap.c
16  *
17  * SPDX-License-Identifier: GPL-2.0-or-later
18  */
19 
20 #include "config.h"
21 
22 #include <epan/packet.h>
23 #include <epan/expert.h>
24 #include "packet-ppi-geolocation-common.h"
25 
26 enum ppi_vector_type {
27     PPI_VECTOR_VFLAGS       =  0,
28     PPI_VECTOR_VCHARS       =  1,
29     PPI_VECTOR_ROTX         =  2,
30     PPI_VECTOR_ROTY         =  3,
31     PPI_VECTOR_ROTZ         =  4,
32 
33     /* V1 */
34     PPI_VECTOR_OFF_R        =  5,
35     PPI_VECTOR_OFF_F        =  6,
36     PPI_VECTOR_OFF_U        =  7,
37     PPI_VECTOR_VEL_R        =  8,
38     PPI_VECTOR_VEL_F        =  9,
39     PPI_VECTOR_VEL_U        = 10,
40     PPI_VECTOR_VEL_T        = 11,
41     PPI_VECTOR_ACC_R        = 12,
42     PPI_VECTOR_ACC_F        = 13,
43     PPI_VECTOR_ACC_U        = 14,
44     PPI_VECTOR_ACC_T        = 15,
45 
46     /* V2 */
47     PPI_VECTOR_OFF_X        =  5,
48     PPI_VECTOR_OFF_Y        =  6,
49     PPI_VECTOR_OFF_Z        =  7,
50 
51     PPI_VECTOR_ERR_ROT      = 16,
52     PPI_VECTOR_ERR_OFF      = 17,
53 
54     /* V1 only */
55     PPI_VECTOR_ERR_VEL      = 18,
56     PPI_VECTOR_ERR_ACC      = 19,
57 
58     PPI_VECTOR_DESCSTR      = 28,
59     PPI_VECTOR_APPID        = 29,
60     PPI_VECTOR_APPDATA      = 30,
61     PPI_VECTOR_EXT          = 31
62 };
63 #define PPI_VECTOR_MAXTAGLEN 144 /* increase as fields are added */
64 
65 /*  There are currently eight vector characteristics.
66  *  These are purely descriptive (no mathematical importance)
67  */
68 #define PPI_VECTOR_VCHARS_ANTENNA                0x00000001
69 #define PPI_VECTOR_VCHARS_DIR_OF_TRAVEL          0x00000002
70 #define PPI_VECTOR_VCHARS_FRONT_OF_VEH           0x00000004
71 #define PPI_VECTOR_VCHARS_AOA                    0x00000008
72 #define PPI_VECTOR_VCHARS_TRANSMITTER_POS        0x00000010
73 
74 #define PPI_VECTOR_VCHARS_GPS_DERIVED            0x00000100
75 #define PPI_VECTOR_VCHARS_INS_DERIVED            0x00000200
76 #define PPI_VECTOR_VCHARS_COMPASS_DERIVED        0x00000400
77 #define PPI_VECTOR_VCHARS_ACCELEROMETER_DERIVED  0x00000800
78 #define PPI_VECTOR_VCHARS_HUMAN_DERIVED          0x00001000
79 
80 #define PPI_VECTOR_MASK_VFLAGS      0x00000001
81 #define PPI_VECTOR_MASK_VCHARS      0x00000002
82 #define PPI_VECTOR_MASK_ROTX        0x00000004
83 #define PPI_VECTOR_MASK_ROTY        0x00000008
84 #define PPI_VECTOR_MASK_ROTZ        0x00000010
85 
86 /* V1 */
87 #define PPI_VECTOR_MASK_OFF_R       0x00000020
88 #define PPI_VECTOR_MASK_OFF_F       0x00000040
89 #define PPI_VECTOR_MASK_OFF_U       0x00000080
90 #define PPI_VECTOR_MASK_VEL_R       0x00000100
91 #define PPI_VECTOR_MASK_VEL_F       0x00000200
92 #define PPI_VECTOR_MASK_VEL_U       0x00000400
93 #define PPI_VECTOR_MASK_VEL_T       0x00000800
94 #define PPI_VECTOR_MASK_ACC_R       0x00001000
95 #define PPI_VECTOR_MASK_ACC_F       0x00002000
96 #define PPI_VECTOR_MASK_ACC_U       0x00004000
97 #define PPI_VECTOR_MASK_ACC_T       0x00008000
98 
99 /* V2 */
100 #define PPI_VECTOR_MASK_OFF_X       0x00000020
101 #define PPI_VECTOR_MASK_OFF_Y       0x00000040
102 #define PPI_VECTOR_MASK_OFF_Z       0x00000080
103 
104 #define PPI_VECTOR_MASK_ERR_ROT     0x00010000
105 #define PPI_VECTOR_MASK_ERR_OFF     0x00020000
106 
107 /* V1 only */
108 #define PPI_VECTOR_MASK_ERR_VEL     0x00040000
109 #define PPI_VECTOR_MASK_ERR_ACC     0x00080000
110 
111 #define PPI_VECTOR_MASK_DESCSTR     0x10000000  /* 28 */
112 #define PPI_VECTOR_MASK_APPID       0x20000000  /* 29 */
113 #define PPI_VECTOR_MASK_APPDATA     0x40000000  /* 30 */
114 #define PPI_VECTOR_MASK_EXT         0x80000000  /* 31 */
115 
116 /*  There are currently only three vector flags.
117  *  These control the units/interpretation of a vector
118  */
119 #define PPI_VECTOR_VFLAGS_DEFINES_FORWARD   0x00000001
120 
121 /* V1 */
122 #define PPI_VECTOR_VFLAGS_ROTS_ABSOLUTE     0x00000002
123 #define PPI_VECTOR_VFLAGS_OFFSETS_FROM_GPS  0x00000004
124 
125 /* V2 */
126 #define PPI_VECTOR_VFLAGS_RELATIVE_TO       0x00000006 /* 2 bits */
127 
128 /* Values for the two-bit RelativeTo subfield of vflags */
129 static const value_string relativeto_string[] = {
130     { 0x00, "Forward"},
131     { 0x01, "Earth"},
132     { 0x02, "Current"},
133     { 0x03, "Reserved"},
134     { 0x00, NULL}
135 };
136 
137 void proto_register_ppi_vector(void);
138 
139 /* protocol */
140 static int proto_ppi_vector = -1;
141 
142 /* "top" level fields */
143 static int hf_ppi_vector_version = -1;
144 static int hf_ppi_vector_pad = -1;
145 static int hf_ppi_vector_length = -1;
146 static int hf_ppi_vector_present = -1;
147 static int hf_ppi_vector_vflags = -1;
148 static int hf_ppi_vector_vchars = -1;
149 static int hf_ppi_vector_rot_x = -1;
150 static int hf_ppi_vector_rot_y = -1;
151 static int hf_ppi_vector_rot_z = -1;
152 
153 /* V1 */
154 static int hf_ppi_vector_off_r = -1;
155 static int hf_ppi_vector_off_f = -1;
156 static int hf_ppi_vector_off_u = -1;
157 static int hf_ppi_vector_vel_r = -1;
158 static int hf_ppi_vector_vel_f = -1;
159 static int hf_ppi_vector_vel_u = -1;
160 static int hf_ppi_vector_vel_t = -1;
161 static int hf_ppi_vector_acc_r = -1;
162 static int hf_ppi_vector_acc_f = -1;
163 static int hf_ppi_vector_acc_u = -1;
164 static int hf_ppi_vector_acc_t = -1;
165 
166 /* V2 */
167 static int hf_ppi_vector_off_x = -1;
168 static int hf_ppi_vector_off_y = -1;
169 static int hf_ppi_vector_off_z = -1;
170 
171 static int hf_ppi_vector_err_rot= -1;
172 static int hf_ppi_vector_err_off= -1;
173 
174 /* V1 only */
175 static int hf_ppi_vector_err_vel= -1;
176 static int hf_ppi_vector_err_acc= -1;
177 
178 static int hf_ppi_vector_descstr= -1;
179 static int hf_ppi_vector_appspecific_num = -1;
180 static int hf_ppi_vector_appspecific_data = -1;
181 
182 /* "Present" flags */
183 static int hf_ppi_vector_present_vflags = -1;
184 static int hf_ppi_vector_present_vchars = -1;
185 static int hf_ppi_vector_present_val_x = -1;
186 static int hf_ppi_vector_present_val_y = -1;
187 static int hf_ppi_vector_present_val_z = -1;
188 
189 /* V1 */
190 static int hf_ppi_vector_present_off_r = -1;
191 static int hf_ppi_vector_present_off_f = -1;
192 static int hf_ppi_vector_present_off_u = -1;
193 static int hf_ppi_vector_present_vel_r = -1;
194 static int hf_ppi_vector_present_vel_f = -1;
195 static int hf_ppi_vector_present_vel_u = -1;
196 static int hf_ppi_vector_present_vel_t = -1;
197 static int hf_ppi_vector_present_acc_r = -1;
198 static int hf_ppi_vector_present_acc_f = -1;
199 static int hf_ppi_vector_present_acc_u = -1;
200 static int hf_ppi_vector_present_acc_t = -1;
201 
202 /* V2 */
203 static int hf_ppi_vector_present_off_x = -1;
204 static int hf_ppi_vector_present_off_y = -1;
205 static int hf_ppi_vector_present_off_z = -1;
206 
207 static int hf_ppi_vector_present_err_rot = -1;
208 static int hf_ppi_vector_present_err_off = -1;
209 
210 /* V1 only */
211 static int hf_ppi_vector_present_err_vel = -1;
212 static int hf_ppi_vector_present_err_acc = -1;
213 
214 static int hf_ppi_vector_present_descstr= -1;
215 static int hf_ppi_vector_presenappsecific_num = -1;
216 static int hf_ppi_vector_present_appspecific_data = -1;
217 static int hf_ppi_vector_present_ext = -1;
218 
219 /* VectorFlags bits */
220 /* There are currently only three bits and two fields defined in vector flags.
221 *  These control the units/interpretation of a vector
222 */
223 static int hf_ppi_vector_vflags_defines_forward = -1; /* bit 0 */
224 
225 /* V1 */
226 static int hf_ppi_vector_vflags_rots_absolute = -1; /* different ways to display the same bit, hi or low */
227 static int hf_ppi_vector_vflags_offsets_from_gps = -1; /* these are different ways to display the same bit, hi or low */
228 
229 /* V2 */
230 static int hf_ppi_vector_vflags_relative_to= -1; /* bits 1 and 2 */
231 
232 /*  There are currently eight vector characteristics.
233 *  These are purely descriptive (no mathematical importance)
234 */
235 static int hf_ppi_vector_vchars_antenna = -1;
236 static int hf_ppi_vector_vchars_dir_of_travel = -1;
237 static int hf_ppi_vector_vchars_front_of_veh = -1;
238 
239 /* V2 only */
240 static int hf_ppi_vector_vchars_angle_of_arrival= -1;
241 static int hf_ppi_vector_vchars_transmitter_pos= -1;
242 
243 static int hf_ppi_vector_vchars_gps_derived = -1;
244 static int hf_ppi_vector_vchars_ins_derived = -1;
245 static int hf_ppi_vector_vchars_compass_derived = -1;
246 static int hf_ppi_vector_vchars_accelerometer_derived = -1;
247 static int hf_ppi_vector_vchars_human_derived = -1;
248 static int hf_ppi_vector_unknown_data = -1;
249 
250 /*These represent arrow-dropdownthings in the gui */
251 static gint ett_ppi_vector = -1;
252 static gint ett_ppi_vector_present = -1;
253 static gint ett_ppi_vectorflags= -1;
254 static gint ett_ppi_vectorchars= -1;
255 
256 static expert_field ei_ppi_vector_present_bit = EI_INIT;
257 static expert_field ei_ppi_vector_length = EI_INIT;
258 
259 
260 /* We want to abbreviate this field into a single line. Does so without any string manipulation */
261 static void
annotate_vector_chars(guint32 chars,proto_tree * my_pt)262 annotate_vector_chars(guint32 chars, proto_tree *my_pt)
263 {
264     if (chars & PPI_VECTOR_VCHARS_ANTENNA)
265         proto_item_append_text(my_pt, " (Antenna)");
266     if (chars & PPI_VECTOR_VCHARS_DIR_OF_TRAVEL)
267         proto_item_append_text(my_pt, " (DOT)");
268     if (chars & PPI_VECTOR_VCHARS_FRONT_OF_VEH)
269         proto_item_append_text(my_pt, " (Front_of_veh)");
270     if (chars & PPI_VECTOR_VCHARS_AOA)
271         proto_item_append_text(my_pt, " (AOA)");
272     if (chars & PPI_VECTOR_VCHARS_TRANSMITTER_POS)
273         proto_item_append_text(my_pt, " (TRANSMITTER_POS)");
274 }
275 
276 static void
dissect_ppi_vector_v1(tvbuff_t * tvb,packet_info * pinfo,int offset,gint length_remaining,proto_tree * ppi_vector_tree)277 dissect_ppi_vector_v1(tvbuff_t *tvb, packet_info *pinfo, int offset, gint length_remaining, proto_tree *ppi_vector_tree)
278 {
279     proto_tree *vectorflags_tree          = NULL;
280     proto_tree *vectorchars_tree          = NULL;
281     proto_tree *my_pt, *pt;
282     proto_item *ti;
283 
284     /* bits */
285     int bit;
286     guint32 present, next_present;
287     /* values actually read out, for displaying */
288     gdouble rot_x, rot_y, rot_z;
289     gdouble off_r, off_f, off_u;
290     gdouble vel_r, vel_f, vel_u, vel_t;
291     gdouble acc_r, acc_f, acc_u, acc_t = 0;
292     gdouble err_rot, err_off, err_vel, err_acc;
293     guint32 appsecific_num; /* appdata parser should add a subtree based on this value */
294     guint32 flags=0, chars=0;
295 
296     static int * const ppi_vector_present_flags[] = {
297         &hf_ppi_vector_present_vflags,
298         &hf_ppi_vector_present_vchars,
299         &hf_ppi_vector_present_val_x,
300         &hf_ppi_vector_present_val_y,
301         &hf_ppi_vector_present_val_z,
302         &hf_ppi_vector_present_off_r,
303         &hf_ppi_vector_present_off_f,
304         &hf_ppi_vector_present_off_u,
305         &hf_ppi_vector_present_vel_r,
306         &hf_ppi_vector_present_vel_f,
307         &hf_ppi_vector_present_vel_u,
308         &hf_ppi_vector_present_vel_t,
309         &hf_ppi_vector_present_acc_r,
310         &hf_ppi_vector_present_acc_f,
311         &hf_ppi_vector_present_acc_u,
312         &hf_ppi_vector_present_acc_t,
313         &hf_ppi_vector_present_err_rot,
314         &hf_ppi_vector_present_err_off,
315         &hf_ppi_vector_present_err_vel,
316         &hf_ppi_vector_present_err_acc,
317         &hf_ppi_vector_present_descstr,
318         &hf_ppi_vector_presenappsecific_num,
319         &hf_ppi_vector_present_appspecific_data,
320         &hf_ppi_vector_present_ext,
321         NULL
322     };
323 
324     /* temporary, conversion values */
325     guint32 t_val;
326 
327     present = tvb_get_letohl(tvb, offset+4);
328     /* Subtree for the "present flags" bitfield. */
329     pt = proto_tree_add_bitmask(ppi_vector_tree, tvb, offset + 4, hf_ppi_vector_present, ett_ppi_vector_present, ppi_vector_present_flags, ENC_LITTLE_ENDIAN);
330 
331     offset += PPI_GEOBASE_MIN_HEADER_LEN;
332     length_remaining -= PPI_GEOBASE_MIN_HEADER_LEN;
333 
334 
335     /* Now all of the fixed length, fixed location stuff is over. Loop over the bits */
336     for (; present; present = next_present) {
337         /* clear the least significant bit that is set */
338         next_present = present & (present - 1);
339         /* extract the least significant bit that is set */
340         bit = BITNO_32(present ^ next_present);
341         switch (bit) {
342         case  PPI_VECTOR_VFLAGS:
343             if (length_remaining < 4)
344                 break;
345             flags =  tvb_get_letohl(tvb, offset);
346             if (ppi_vector_tree) {
347                 my_pt = proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_vflags, tvb, offset , 4, flags);
348                 vectorflags_tree= proto_item_add_subtree(my_pt, ett_ppi_vectorflags);
349 
350                 proto_tree_add_item(vectorflags_tree, hf_ppi_vector_vflags_defines_forward, tvb, offset, 4, ENC_LITTLE_ENDIAN);
351                 proto_tree_add_item(vectorflags_tree, hf_ppi_vector_vflags_rots_absolute, tvb, offset, 4, ENC_LITTLE_ENDIAN);
352                 proto_tree_add_item(vectorflags_tree, hf_ppi_vector_vflags_offsets_from_gps, tvb, offset, 4, ENC_LITTLE_ENDIAN);
353             }
354             offset+=4;
355             length_remaining-=4;
356             break;
357         case  PPI_VECTOR_VCHARS:
358             if (length_remaining < 4)
359                 break;
360             chars =  tvb_get_letohl(tvb, offset);
361             if (ppi_vector_tree) {
362                 my_pt = proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_vchars, tvb, offset , 4, chars);
363                 vectorchars_tree= proto_item_add_subtree(my_pt, ett_ppi_vectorchars);
364 
365                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_antenna, tvb, offset, 4, ENC_LITTLE_ENDIAN);
366                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_dir_of_travel, tvb, offset, 4, ENC_LITTLE_ENDIAN);
367                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_front_of_veh, tvb, offset, 4, ENC_LITTLE_ENDIAN);
368                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_gps_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
369                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_ins_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
370                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_compass_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
371                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_accelerometer_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
372                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_human_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
373             }
374             offset+=4;
375             length_remaining-=4;
376             break;
377         case  PPI_VECTOR_ROTX:
378             if (length_remaining < 4)
379                 break;
380             t_val = tvb_get_letohl(tvb, offset);
381             rot_x = ppi_fixed3_6_to_gdouble(t_val);
382             if (ppi_vector_tree) {
383                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_x, tvb, offset, 4, rot_x);
384                 if (flags &  PPI_VECTOR_VFLAGS_ROTS_ABSOLUTE)
385                     proto_item_append_text(ti, " Degrees (Absolute)");
386                 else
387                     proto_item_append_text(ti, " Degrees (Rel to forward)");
388             }
389             offset+=4;
390             length_remaining-=4;
391             break;
392         case  PPI_VECTOR_ROTY:
393             if (length_remaining < 4)
394                 break;
395             t_val = tvb_get_letohl(tvb, offset);
396             rot_y = ppi_fixed3_6_to_gdouble(t_val);
397             if (ppi_vector_tree) {
398                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_y, tvb, offset, 4, rot_y);
399                 if (flags &  PPI_VECTOR_VFLAGS_ROTS_ABSOLUTE)
400                     proto_item_append_text(ti, " Degrees (Absolute)");
401                 else
402                     proto_item_append_text(ti, " Degrees (Rel to forward)");
403             }
404             offset+=4;
405             length_remaining-=4;
406             break;
407         case  PPI_VECTOR_ROTZ:
408             if (length_remaining < 4)
409                 break;
410             t_val = tvb_get_letohl(tvb, offset);
411             rot_z = ppi_fixed3_6_to_gdouble(t_val);
412             if (ppi_vector_tree) {
413                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_z, tvb, offset, 4, rot_z);
414                 if (flags &  PPI_VECTOR_VFLAGS_ROTS_ABSOLUTE)
415                     proto_item_append_text(ti, " Degrees (Absolute) ");
416                 else
417                     proto_item_append_text(ti, " Degrees (Rel to forward)");
418             }
419             offset+=4;
420             length_remaining-=4;
421             break;
422         case  PPI_VECTOR_OFF_R:
423             if (length_remaining < 4)
424                 break;
425             t_val = tvb_get_letohl(tvb, offset);
426             off_r = ppi_fixed6_4_to_gdouble(t_val);
427             if (ppi_vector_tree) {
428                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_r, tvb, offset, 4, off_r);
429                 if (flags &  PPI_VECTOR_VFLAGS_OFFSETS_FROM_GPS)
430                     proto_item_append_text(ti, " m from Curr_GPS");
431                 else
432                     proto_item_append_text(ti, " m from Curr_Pos");
433             }
434             offset+=4;
435             length_remaining-=4;
436             break;
437         case  PPI_VECTOR_OFF_F:
438             if (length_remaining < 4)
439                 break;
440             t_val = tvb_get_letohl(tvb, offset);
441             off_f = ppi_fixed6_4_to_gdouble(t_val);
442             if (ppi_vector_tree) {
443                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_f, tvb, offset, 4, off_f);
444                 if (flags &  PPI_VECTOR_VFLAGS_OFFSETS_FROM_GPS)
445                     proto_item_append_text(ti, " m from Curr_GPS");
446                 else
447                     proto_item_append_text(ti, " m from Curr_Pos");
448             }
449             offset+=4;
450             length_remaining-=4;
451             break;
452         case  PPI_VECTOR_OFF_U:
453             if (length_remaining < 4)
454                 break;
455             t_val = tvb_get_letohl(tvb, offset);
456             off_u = ppi_fixed6_4_to_gdouble(t_val);
457             if (ppi_vector_tree) {
458                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_u, tvb, offset, 4, off_u);
459                 if (flags &  PPI_VECTOR_VFLAGS_OFFSETS_FROM_GPS)
460                     proto_item_append_text(ti, " m from Curr_GPS");
461                 else
462                     proto_item_append_text(ti, " m from Curr_Pos");
463             }
464             offset+=4;
465             length_remaining-=4;
466             break;
467         case  PPI_VECTOR_VEL_R:
468             if (length_remaining < 4)
469                 break;
470             t_val = tvb_get_letohl(tvb, offset);
471             vel_r = ppi_fixed6_4_to_gdouble(t_val);
472             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_vel_r, tvb, offset, 4, vel_r);
473             offset+=4;
474             length_remaining-=4;
475             break;
476         case  PPI_VECTOR_VEL_F:
477             if (length_remaining < 4)
478                 break;
479             t_val = tvb_get_letohl(tvb, offset);
480             vel_f = ppi_fixed6_4_to_gdouble(t_val);
481             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_vel_f, tvb, offset, 4, vel_f);
482             offset+=4;
483             length_remaining-=4;
484             break;
485         case  PPI_VECTOR_VEL_U:
486             if (length_remaining < 4)
487                 break;
488             t_val = tvb_get_letohl(tvb, offset);
489             vel_u = ppi_fixed6_4_to_gdouble(t_val);
490             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_vel_u, tvb, offset, 4, vel_u);
491             offset+=4;
492             length_remaining-=4;
493             break;
494         case  PPI_VECTOR_VEL_T:
495             if (length_remaining < 4)
496                 break;
497             t_val = tvb_get_letohl(tvb, offset);
498             vel_t = ppi_fixed6_4_to_gdouble(t_val);
499             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_vel_t, tvb, offset, 4, vel_t);
500             offset+=4;
501             length_remaining-=4;
502             break;
503         case  PPI_VECTOR_ACC_R:
504             if (length_remaining < 4)
505                 break;
506             t_val = tvb_get_letohl(tvb, offset);
507             acc_r = ppi_fixed6_4_to_gdouble(t_val);
508             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_acc_r, tvb, offset, 4, acc_r);
509             offset+=4;
510             length_remaining-=4;
511             break;
512         case  PPI_VECTOR_ACC_F:
513             if (length_remaining < 4)
514                 break;
515             t_val = tvb_get_letohl(tvb, offset);
516             acc_f = ppi_fixed6_4_to_gdouble(t_val);
517             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_acc_f, tvb, offset, 4, acc_f);
518             offset+=4;
519             length_remaining-=4;
520             break;
521         case  PPI_VECTOR_ACC_U:
522             if (length_remaining < 4)
523                 break;
524             t_val = tvb_get_letohl(tvb, offset);
525             acc_u = ppi_fixed6_4_to_gdouble(t_val);
526             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_acc_u, tvb, offset, 4, acc_u);
527             offset+=4;
528             length_remaining-=4;
529             break;
530         case  PPI_VECTOR_ACC_T:
531             if (length_remaining < 4)
532                 break;
533             t_val = tvb_get_letohl(tvb, offset);
534             acc_t = ppi_fixed6_4_to_gdouble(t_val);
535             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_acc_t, tvb, offset, 4, acc_t);
536             offset+=4;
537             length_remaining-=4;
538             break;
539         case  PPI_VECTOR_ERR_ROT:
540             if (length_remaining < 4)
541                 break;
542             t_val   = tvb_get_letohl(tvb, offset);
543             err_rot = ppi_fixed3_6_to_gdouble(t_val);
544             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_rot, tvb, offset, 4, err_rot);
545             offset+=4;
546             length_remaining-=4;
547             break;
548         case  PPI_VECTOR_ERR_OFF:
549             if (length_remaining < 4)
550                 break;
551             t_val   = tvb_get_letohl(tvb, offset);
552             err_off = ppi_fixed6_4_to_gdouble(t_val);
553             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_off, tvb, offset, 4, err_off);
554             offset+=4;
555             length_remaining-=4;
556             break;
557         case  PPI_VECTOR_ERR_VEL:
558             if (length_remaining < 4)
559                 break;
560             t_val   = tvb_get_letohl(tvb, offset);
561             err_vel = ppi_fixed6_4_to_gdouble(t_val);
562             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_vel, tvb, offset, 4, err_vel);
563             offset+=4;
564             length_remaining-=4;
565             break;
566         case  PPI_VECTOR_ERR_ACC:
567             if (length_remaining < 4)
568                 break;
569             t_val   = tvb_get_letohl(tvb, offset);
570             err_acc = ppi_fixed6_4_to_gdouble(t_val);
571             if (ppi_vector_tree) {
572                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_acc, tvb, offset, 4, err_acc);
573                 proto_item_append_text(ti, " (m/s)/s");
574             }
575             offset+=4;
576             length_remaining-=4;
577             break;
578         case  PPI_VECTOR_DESCSTR:
579             if (length_remaining < 32)
580                 break;
581             proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_descstr, tvb, offset, 32, ENC_ASCII|ENC_NA);
582             offset+=32;
583             length_remaining-=32;
584             break;
585         case  PPI_VECTOR_APPID:
586             if (length_remaining < 4)
587                 break;
588             appsecific_num  = tvb_get_letohl(tvb, offset); /* application specific parsers may switch on this later */
589             proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_appspecific_num, tvb, offset, 4, appsecific_num);
590             offset+=4;
591             length_remaining-=4;
592             break;
593         case  PPI_VECTOR_APPDATA:
594             if (length_remaining < 60)
595                 break;
596             proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_appspecific_data, tvb, offset, 60,  ENC_NA);
597             offset+=60;
598             length_remaining-=60;
599             break;
600 
601         default:
602             /*
603              * This indicates a field whose size we do not
604              * know, so we cannot proceed.
605              */
606             expert_add_info_format(pinfo, pt, &ei_ppi_vector_present_bit, "Error: PPI-VECTOR: unknown bit (%d) set in present field.", bit);
607             next_present = 0;
608             continue;
609         }
610 
611     }
612 }
613 
614 static void
dissect_ppi_vector_v2(tvbuff_t * tvb,packet_info * pinfo,int offset,gint length_remaining,proto_tree * ppi_vector_tree,proto_item * vector_line)615 dissect_ppi_vector_v2(tvbuff_t *tvb, packet_info *pinfo, int offset, gint length_remaining, proto_tree *ppi_vector_tree, proto_item *vector_line)
616 {
617     proto_tree *vectorflags_tree          = NULL;
618     proto_tree *vectorchars_tree          = NULL;
619     proto_tree *my_pt, *pt;
620     proto_item *ti;
621 
622     /* bits */
623     int bit;
624     guint32 present, next_present;
625 
626     /* values actually read out, for displaying */
627     gchar *curr_str;
628 
629     /* these are used to specially handle RelativeTo: */
630     guint32  relativeto_int;
631     const gchar *relativeto_str= "RelativeTo: Forward"; /* default if vflags is not present*/
632 
633     /* normal fields*/
634     guint32 flags=0, chars=0;
635     gdouble rot_x, rot_y, rot_z;
636     gdouble off_x, off_y, off_z;
637     gdouble err_rot, err_off;
638     guint32  appsecific_num; /* appdata parser should add a subtree based on this value */
639 
640     static int * const ppi_vector_present_flags[] = {
641         &hf_ppi_vector_present_vflags,
642         &hf_ppi_vector_present_vchars,
643         &hf_ppi_vector_present_val_x,
644         &hf_ppi_vector_present_val_y,
645         &hf_ppi_vector_present_val_z,
646         &hf_ppi_vector_present_off_x,
647         &hf_ppi_vector_present_off_y,
648         &hf_ppi_vector_present_off_z,
649         &hf_ppi_vector_present_err_rot,
650         &hf_ppi_vector_present_err_off,
651         &hf_ppi_vector_present_descstr,
652         &hf_ppi_vector_presenappsecific_num,
653         &hf_ppi_vector_present_appspecific_data,
654         &hf_ppi_vector_present_ext,
655         NULL
656     };
657 
658     /* temporary, conversion values */
659     guint32 t_val;
660 
661     present = tvb_get_letohl(tvb, offset+4);
662     /* Subtree for the "present flags" bitfield. */
663     pt = proto_tree_add_bitmask(ppi_vector_tree, tvb, offset + 4, hf_ppi_vector_present, ett_ppi_vector_present, ppi_vector_present_flags, ENC_LITTLE_ENDIAN);
664 
665     offset += PPI_GEOBASE_MIN_HEADER_LEN;
666     length_remaining -= PPI_GEOBASE_MIN_HEADER_LEN;
667 
668     /* Before we process any fields, we check what this vector is RelativeTo. */
669     /* We do this so this up front so that it displays prominently in the summary line */
670     /* Another reason to do this up here is that vflags may not be present (in which case it defaults to 0) */
671     /* It also saves us from repeating this logic in any of the individual fields */
672     if ( (present & PPI_VECTOR_MASK_VFLAGS) && length_remaining >= 4)
673     {
674          /*vflags is the first field, */
675          flags = tvb_get_letohl(tvb, offset);
676          relativeto_int = (flags & (PPI_VECTOR_VFLAGS_RELATIVE_TO)); /* mask out all other bits */
677          relativeto_int = relativeto_int >> 1; /*scoot over 1 bit to align with the type string */
678          relativeto_str = val_to_str_const (relativeto_int, relativeto_string, "Reserved"); /*re-use that type string up top */
679          /* We will append this text to the vector line once all the other fields have processed */
680 
681         /* this is important enough to put in vector line */
682          if (flags & PPI_VECTOR_VFLAGS_DEFINES_FORWARD)
683             proto_item_append_text(vector_line, " (Forward)");
684 
685         /* Intentionally don't upset offset, length_remaining. This is taken care of in the normal vflags parser below*/
686     }
687     else /* No vflags means vlfags defaults to zero. RelativeTo: Forward */
688     {
689          relativeto_str = " RelativeTo: Forward";
690     }
691    /*
692     * vchars is another field that we want to pre-process similar to vflags and for the same reasons.
693     * we perform separate length checks depending on if vector_flags is present (which would precede vector_chars)
694     */
695     if      ( ( (present & PPI_VECTOR_MASK_VFLAGS)) && (present & PPI_VECTOR_MASK_VCHARS) && length_remaining >= 8)
696             chars =  tvb_get_letohl(tvb, offset + 4);
697     else if ( (!(present & PPI_VECTOR_MASK_VFLAGS)) && (present & PPI_VECTOR_MASK_VCHARS) && length_remaining >= 4)
698             chars =  tvb_get_letohl(tvb, offset );
699 
700    if (chars)
701    {
702         /* Mark the most interesting characteristics on the vector dropdown line */
703         annotate_vector_chars(chars, vector_line);
704         /* Intentionally don't update offset, length_remaining. This is taken care of in the normal vchars parser below*/
705     }
706 
707     /* Now all of the fixed length, fixed location stuff is over. Loop over the bits */
708     for (; present; present = next_present) {
709         /* clear the least significant bit that is set */
710         next_present = present & (present - 1);
711         /* extract the least significant bit that is set */
712         bit = BITNO_32(present ^ next_present);
713         switch (bit) {
714         case  PPI_VECTOR_VFLAGS:
715             if (length_remaining < 4)
716                 break;
717             /* flags =  tvb_get_letohl(tvb, offset); */ /* Usually we read this in, but vflags is a special case handled above */
718             if (ppi_vector_tree) {
719                 my_pt = proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_vflags, tvb, offset , 4, flags);
720                 vectorflags_tree= proto_item_add_subtree(my_pt, ett_ppi_vectorflags);
721 
722                 proto_tree_add_item(vectorflags_tree, hf_ppi_vector_vflags_defines_forward, tvb, offset, 4, ENC_LITTLE_ENDIAN);
723                 proto_tree_add_item(vectorflags_tree, hf_ppi_vector_vflags_relative_to, tvb, offset, 4, ENC_LITTLE_ENDIAN);
724 
725                 if (flags & PPI_VECTOR_VFLAGS_DEFINES_FORWARD)
726                     proto_item_append_text(vectorflags_tree, " (Forward)");
727 
728                 proto_item_append_text (vectorflags_tree, " RelativeTo: %s", relativeto_str);
729             }
730             offset+=4;
731             length_remaining-=4;
732             break;
733         case  PPI_VECTOR_VCHARS:
734             if (length_remaining < 4)
735                 break;
736             /* chars =  tvb_get_letohl(tvb, offset); */ /*Usually we read this in, but vchars specially handled above */
737             if (ppi_vector_tree) {
738                 my_pt = proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_vchars, tvb, offset , 4, chars);
739                 vectorchars_tree= proto_item_add_subtree(my_pt, ett_ppi_vectorchars);
740 
741                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_antenna, tvb, offset, 4, ENC_LITTLE_ENDIAN);
742                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_dir_of_travel, tvb, offset, 4, ENC_LITTLE_ENDIAN);
743                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_front_of_veh, tvb, offset, 4, ENC_LITTLE_ENDIAN);
744                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_angle_of_arrival, tvb, offset, 4, ENC_LITTLE_ENDIAN);
745                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_transmitter_pos, tvb, offset, 4, ENC_LITTLE_ENDIAN);
746                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_gps_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
747                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_ins_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
748                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_compass_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
749                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_accelerometer_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
750                 proto_tree_add_item(vectorchars_tree, hf_ppi_vector_vchars_human_derived, tvb, offset, 4, ENC_LITTLE_ENDIAN);
751 
752                 annotate_vector_chars(chars, my_pt);
753             }
754             offset+=4;
755             length_remaining-=4;
756             break;
757         case  PPI_VECTOR_ROTX:
758             if (length_remaining < 4)
759                 break;
760             t_val = tvb_get_letohl(tvb, offset);
761             rot_x = ppi_fixed3_6_to_gdouble(t_val);
762             if (ppi_vector_tree) {
763                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_x, tvb, offset, 4, rot_x);
764                 proto_item_append_text(ti, " Degrees RelativeTo: %s", relativeto_str);
765                 proto_item_append_text(vector_line, " Pitch:%3f ", rot_x);
766             }
767             offset+=4;
768             length_remaining-=4;
769             break;
770         case  PPI_VECTOR_ROTY:
771             if (length_remaining < 4)
772                 break;
773             t_val = tvb_get_letohl(tvb, offset);
774             rot_y = ppi_fixed3_6_to_gdouble(t_val);
775             if (ppi_vector_tree) {
776                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_y, tvb, offset, 4, rot_y);
777                 proto_item_append_text(ti, " Degrees RelativeTo: %s", relativeto_str);
778                 proto_item_append_text(vector_line, " Roll:%3f ", rot_y);
779             }
780             offset+=4;
781             length_remaining-=4;
782             break;
783         case  PPI_VECTOR_ROTZ:
784             if (length_remaining < 4)
785                 break;
786             t_val = tvb_get_letohl(tvb, offset);
787             rot_z =  ppi_fixed3_6_to_gdouble(t_val);
788             if (ppi_vector_tree) {
789                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_rot_z, tvb, offset, 4, rot_z);
790                 proto_item_append_text(ti, " Degrees RelativeTo: %s", relativeto_str);
791                 proto_item_append_text(vector_line, " Heading:%3f ", rot_z);
792             }
793             offset+=4;
794             length_remaining-=4;
795             break;
796         case  PPI_VECTOR_OFF_X:
797             if (length_remaining < 4)
798                 break;
799             t_val = tvb_get_letohl(tvb, offset);
800             off_x = ppi_fixed6_4_to_gdouble(t_val);
801             if (ppi_vector_tree) {
802                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_x, tvb, offset, 4, off_x);
803                 proto_item_append_text(ti, " Meters RelativeTo: %s", relativeto_str);
804                 proto_item_append_text(vector_line, " Off-X:%3f ", off_x);
805             }
806             offset+=4;
807             length_remaining-=4;
808             break;
809         case  PPI_VECTOR_OFF_Y:
810             if (length_remaining < 4)
811                 break;
812             t_val = tvb_get_letohl(tvb, offset);
813             off_y = ppi_fixed6_4_to_gdouble(t_val);
814             if (ppi_vector_tree) {
815                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_y, tvb, offset, 4, off_y);
816                 proto_item_append_text(ti, " Meters RelativeTo: %s", relativeto_str);
817                 proto_item_append_text(vector_line, " Off-Y:%3f ", off_y);
818             }
819             offset+=4;
820             length_remaining-=4;
821             break;
822         case  PPI_VECTOR_OFF_Z:
823             if (length_remaining < 4)
824                 break;
825             t_val = tvb_get_letohl(tvb, offset);
826             off_z = ppi_fixed6_4_to_gdouble(t_val);
827             if (ppi_vector_tree) {
828                 ti = proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_off_z, tvb, offset, 4, off_z);
829                 proto_item_append_text(ti, " Meters RelativeTo: %s", relativeto_str);
830                 proto_item_append_text(vector_line, " Off-Z:%3f ", off_z);
831             }
832             offset+=4;
833             length_remaining-=4;
834             break;
835         case  PPI_VECTOR_ERR_ROT:
836             if (length_remaining < 4)
837                 break;
838             t_val   = tvb_get_letohl(tvb, offset);
839             err_rot = ppi_fixed3_6_to_gdouble(t_val);
840             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_rot, tvb, offset, 4, err_rot);
841             offset+=4;
842             length_remaining-=4;
843             break;
844         case  PPI_VECTOR_ERR_OFF:
845             if (length_remaining < 4)
846                 break;
847             t_val   = tvb_get_letohl(tvb, offset);
848             err_off = ppi_fixed6_4_to_gdouble(t_val);
849             proto_tree_add_double(ppi_vector_tree, hf_ppi_vector_err_off, tvb, offset, 4, err_off);
850             offset+=4;
851             length_remaining-=4;
852             break;
853 
854         case  PPI_VECTOR_DESCSTR:
855             if (length_remaining < 32)
856                 break;
857             if (ppi_vector_tree)
858             {
859                 /* proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_descstr, tvb, offset, 32, ENC_ASCII|ENC_NA); */
860                 curr_str = tvb_format_stringzpad(pinfo->pool, tvb, offset, 32); /* need to append_text this */
861                 proto_tree_add_string(ppi_vector_tree, hf_ppi_vector_descstr, tvb, offset, 32, curr_str);
862                 proto_item_append_text(vector_line, " (%s)", curr_str);
863             }
864             offset+=32;
865             length_remaining-=32;
866             break;
867         case  PPI_VECTOR_APPID:
868             if (length_remaining < 4)
869                 break;
870             appsecific_num  = tvb_get_letohl(tvb, offset); /* application specific parsers may switch on this later */
871             if (ppi_vector_tree) {
872                 proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_appspecific_num, tvb, offset, 4, appsecific_num);
873             }
874             offset+=4;
875             length_remaining-=4;
876             break;
877         case  PPI_VECTOR_APPDATA:
878             if (length_remaining < 60)
879                 break;
880             if (ppi_vector_tree) {
881                 proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_appspecific_data, tvb, offset, 60,  ENC_NA);
882             }
883             offset+=60;
884             length_remaining-=60;
885             break;
886 
887         default:
888             /*
889              * This indicates a field whose size we do not
890              * know, so we cannot proceed.
891              */
892             expert_add_info_format(pinfo, pt, &ei_ppi_vector_present_bit, "Error: PPI-VECTOR: unknown bit (%d) set in present field.\n", bit);
893             next_present = 0;
894             continue;
895         }
896     }
897     /* Append the RelativeTo string we computed up top */
898     proto_item_append_text (vector_line, " RelativeTo: %s", relativeto_str);
899 }
900 
901 static int
dissect_ppi_vector(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)902 dissect_ppi_vector(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
903 {
904     proto_tree *ppi_vector_tree;
905     proto_item *ti, *vector_line;
906     gint        length_remaining;
907     int         offset          = 0;
908 
909     /* values actually read out, for displaying */
910     guint32 version;
911     guint length;
912 
913     /* Clear out stuff in the info column */
914     col_clear(pinfo->cinfo,COL_INFO);
915 
916     /* pull out the first three fields of the BASE-GEOTAG-HEADER */
917     version = tvb_get_guint8(tvb, offset);
918     length  = tvb_get_letohs(tvb, offset+2);
919 
920     /* Setup basic column info */
921     col_add_fstr(pinfo->cinfo, COL_INFO, "PPI_Vector Capture v%u, Length %u",
922                      version, length);
923 
924     /* Create the basic dissection tree*/
925     vector_line = proto_tree_add_protocol_format(tree, proto_ppi_vector, tvb, 0, length, "Vector:");
926     ppi_vector_tree = proto_item_add_subtree(vector_line, ett_ppi_vector);
927     proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_version,
928                         tvb, offset, 1, version);
929     proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_pad,
930                         tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
931     ti = proto_tree_add_uint(ppi_vector_tree, hf_ppi_vector_length,
932                                 tvb, offset + 2, 2, length);
933 
934     /* initialize remaining length */
935     length_remaining = length;
936     /* minimum length check, should atleast be a fixed-size geotagging-base header*/
937     if (length_remaining < PPI_GEOBASE_MIN_HEADER_LEN) {
938         /*
939          * Base-geotag-header (Radiotap lookalike) is shorter than the fixed-length portion
940          * plus one "present" bitset.
941          */
942         expert_add_info_format(pinfo, ti, &ei_ppi_vector_length, "Invalid PPI-Vector length - minimum length is %d", PPI_GEOBASE_MIN_HEADER_LEN);
943         return 2;
944     }
945 
946     switch (version) {
947 
948     case 1:
949         dissect_ppi_vector_v1(tvb, pinfo, offset, length_remaining, ppi_vector_tree);
950         break;
951 
952     case 2:
953         /* perform max length sanity checking */
954         if (length > PPI_VECTOR_MAXTAGLEN ) {
955             expert_add_info_format(pinfo, ti, &ei_ppi_vector_length, "Invalid PPI-Vector length  (got %d, %d max\n)", length, PPI_VECTOR_MAXTAGLEN);
956             return 2;
957         }
958         dissect_ppi_vector_v2(tvb, pinfo, offset, length_remaining, ppi_vector_tree, vector_line);
959         break;
960 
961     default:
962         proto_tree_add_item(ppi_vector_tree, hf_ppi_vector_unknown_data, tvb, offset + 4, -1, ENC_NA);
963         break;
964     }
965     return tvb_captured_length(tvb);
966 }
967 
968 void
proto_register_ppi_vector(void)969 proto_register_ppi_vector(void)
970 {
971     /* The following array initializes those header fields declared above to the values displayed */
972     static hf_register_info hf[] = {
973         { &hf_ppi_vector_version,
974             { "Header revision", "ppi_vector.version",
975                 FT_UINT8, BASE_DEC, NULL, 0x0,
976                 "Version of ppi_vector header format", HFILL } },
977         { &hf_ppi_vector_pad,
978           { "Header pad", "ppi_vector.pad",
979             FT_UINT8, BASE_DEC, NULL, 0x0,
980             "Padding", HFILL } },
981         { &hf_ppi_vector_length,
982           { "Header length", "ppi_vector.length",
983             FT_UINT16, BASE_DEC, NULL, 0x0,
984             "Length of header including version, pad, length and data fields", HFILL } },
985         { &hf_ppi_vector_present,
986           { "Present", "ppi_vector.present",
987             FT_UINT32, BASE_HEX, NULL, 0x0,
988             "Bitmask indicating which fields are present", HFILL } },
989 
990         /* Boolean 'present' flags */
991         { &hf_ppi_vector_present_vflags,
992           { "Vector flags", "ppi_vector.present.flags",
993             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VFLAGS,
994             "Specifies if the Vector flags bitfield is present", HFILL } },
995 
996         { &hf_ppi_vector_present_vchars,
997           { "Vector characteristics", "ppi_vector.present.chars",
998             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VCHARS,
999             "Specifies if the Vector chars  bitfield is present", HFILL } },
1000 
1001         { &hf_ppi_vector_present_val_x,
1002           { "Pitch", "ppi_vector.present.pitch",
1003             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ROTX,
1004             "Specifies if the rotate-x field (pitch) is present", HFILL } },
1005 
1006         { &hf_ppi_vector_present_val_y,
1007           { "Roll", "ppi_vector.present.roll",
1008             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ROTY,
1009             "Specifies if the rotate-y field (roll) is present", HFILL } },
1010 
1011         { &hf_ppi_vector_present_val_z,
1012           { "Heading", "ppi_vector.present.heading",
1013             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ROTZ,
1014             "Specifies if the rotate-z field (heading) is present", HFILL } },
1015 
1016 
1017         /* V1 */
1018         { &hf_ppi_vector_present_off_r,
1019           { "Offset_R", "ppi_vector.present.off_r",
1020             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_R,
1021             "Specifies if the offset-right field  is present", HFILL } },
1022 
1023         { &hf_ppi_vector_present_off_f,
1024           { "Offset_F", "ppi_vector.present.off_f",
1025             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_F,
1026             "Specifies if the offset-forward  field  is present", HFILL } },
1027 
1028         { &hf_ppi_vector_present_off_u,
1029           { "Offset_U", "ppi_vector.present.off_u",
1030             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_U,
1031             "Specifies if the offset-up  field  is present", HFILL } },
1032 
1033         { &hf_ppi_vector_present_vel_r,
1034           { "Velocity_R", "ppi_vector.present.vel_r",
1035             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VEL_R,
1036             "Specifies if the velocity-right field  is present", HFILL } },
1037 
1038         { &hf_ppi_vector_present_vel_f,
1039           { "Velocity_F", "ppi_vector.present.vel_f",
1040             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VEL_F,
1041             "Specifies if the velocity-forward  field  is present", HFILL } },
1042 
1043         { &hf_ppi_vector_present_vel_u,
1044           { "Velocity_U", "ppi_vector.present.vel_u",
1045             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VEL_U,
1046             "Specifies if the velocity-up  field  is present", HFILL } },
1047         { &hf_ppi_vector_present_vel_t,
1048           { "Velocity_T", "ppi_vector.present.vel_t",
1049             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_VEL_T,
1050             "Specifies if the total velocity field  is present", HFILL } },
1051 
1052         { &hf_ppi_vector_present_acc_r,
1053           { "Acceleration_R", "ppi_vector.present.acc_r",
1054             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ACC_R,
1055             "Specifies if the accel-right field  is present", HFILL } },
1056 
1057         { &hf_ppi_vector_present_acc_f,
1058           { "Acceleration_F", "ppi_vector.present.acc_f",
1059             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ACC_F,
1060             "Specifies if the accel-forward  field  is present", HFILL } },
1061 
1062         { &hf_ppi_vector_present_acc_u,
1063           { "Acceleration_U", "ppi_vector.present.acc_u",
1064             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ACC_U,
1065             "Specifies if the accel-up  field  is present", HFILL } },
1066         { &hf_ppi_vector_present_acc_t,
1067           { "Acceleration_T", "ppi_vector.present.acc_t",
1068             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ACC_T,
1069             "Specifies if the total acceleration  field  is present", HFILL } },
1070 
1071         /* V2 */
1072         { &hf_ppi_vector_present_off_x,
1073           { "Offset_R", "ppi_vector.present.off_x",
1074             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_X,
1075             "Specifies if the offset-x (right/east) field  is present", HFILL } },
1076 
1077         { &hf_ppi_vector_present_off_y,
1078           { "Offset_F", "ppi_vector.present.off_y",
1079             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_Y,
1080             "Specifies if the offset-y (forward/north)  field  is present", HFILL } },
1081 
1082         { &hf_ppi_vector_present_off_z,
1083           { "Offset_U", "ppi_vector.present.off_z",
1084             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_OFF_Z,
1085             "Specifies if the offset-z (up) field  is present", HFILL } },
1086 
1087 
1088         { &hf_ppi_vector_present_err_rot,
1089           { "err_rot", "ppi_vector.present.err_rot",
1090             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ERR_ROT,
1091             "Specifies if the rotation error field is present", HFILL } },
1092 
1093         { &hf_ppi_vector_present_err_off,
1094           { "err_off", "ppi_vector.present.err_off",
1095             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ERR_OFF,
1096             "Specifies if the offset error field is present", HFILL } },
1097 
1098 
1099         /* V1 only */
1100         { &hf_ppi_vector_present_err_vel,
1101           { "err_vel", "ppi_vector.present.err_vel",
1102             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ERR_VEL,
1103             "Specifies if the velocity  error field is present", HFILL } },
1104 
1105         { &hf_ppi_vector_present_err_acc,
1106           { "err_acc", "ppi_vector.present.err_acc",
1107             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_ERR_ACC,
1108             "Specifies if the acceleration error field is present", HFILL } },
1109 
1110 
1111         { &hf_ppi_vector_present_descstr,
1112           { "descstr", "ppi_vector.present.descstr",
1113             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_DESCSTR,
1114             "Specifies if the acceleration error field is present", HFILL } },
1115 
1116         { &hf_ppi_vector_presenappsecific_num,
1117           { "appid", "ppi_vector.present.appid",
1118             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_APPID,
1119             "Specifies if the application specific field id is present", HFILL } },
1120 
1121         { &hf_ppi_vector_present_appspecific_data,
1122           { "appdata", "ppi_vector.present.appdata",
1123             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_APPDATA,
1124             "Specifies if the application specific data field  is present", HFILL } },
1125 
1126         { &hf_ppi_vector_present_ext,
1127           { "Ext", "ppi_vector.present.ext",
1128             FT_BOOLEAN, 32, NULL, PPI_VECTOR_MASK_EXT,
1129             "Specifies if there are any extensions to the header present", HFILL } },
1130 
1131         /* Now we get to the actual data fields */
1132         /* This setups the "Vector fflags" hex dropydown thing */
1133         { &hf_ppi_vector_vflags,
1134           { "Vector flags", "ppi_vector.vector_flags",
1135             FT_UINT32, BASE_HEX, NULL, 0x0,
1136             "Bitmask indicating coordinate sys, among others, etc", HFILL } },
1137         { &hf_ppi_vector_vchars,
1138           { "Vector chars", "ppi_vector.vector_chars",
1139             FT_UINT32, BASE_HEX, NULL, 0x0,
1140             "Bitmask indicating if vector tracks antenna, vehicle, motion, etc", HFILL } },
1141         { &hf_ppi_vector_rot_x,
1142           { "Pitch", "ppi_vector.pitch",
1143             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1144             "Pitch (Rotation x) packet was received at", HFILL } },
1145         { &hf_ppi_vector_rot_y,
1146           { "Roll", "ppi_vector.roll",
1147             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1148             "Roll (Rotation y) packet was received at", HFILL } },
1149         { &hf_ppi_vector_rot_z,
1150           { "Heading", "ppi_vector.heading",
1151             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1152             "Heading (Rotation z) packet was received at", HFILL } },
1153 
1154         /* V1 */
1155         { &hf_ppi_vector_off_r,
1156           { "Off-r", "ppi_vector.off_r",
1157             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1158             "Offset right", HFILL } },
1159         { &hf_ppi_vector_off_f,
1160           { "Off-f", "ppi_vector.off_f",
1161             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1162             "Offation forward", HFILL } },
1163         { &hf_ppi_vector_off_u,
1164           { "Off-u", "ppi_vector.off_u",
1165             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1166             "Offset up", HFILL } },
1167         { &hf_ppi_vector_vel_r,
1168           { "Vel-r", "ppi_vector.vel_r",
1169             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec, 0x0,
1170             "Velocity-right", HFILL } },
1171         { &hf_ppi_vector_vel_f,
1172           { "Vel-f", "ppi_vector.vel_f",
1173             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec, 0x0,
1174             "Velocity-forward", HFILL } },
1175         { &hf_ppi_vector_vel_u,
1176           { "Vel-u", "ppi_vector.vel_u",
1177             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec, 0x0,
1178             "Velocity-up", HFILL } },
1179         { &hf_ppi_vector_vel_t,
1180           { "Vel-t", "ppi_vector.vel_t",
1181             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec, 0x0,
1182             "Velocity-Total", HFILL } },
1183 
1184         { &hf_ppi_vector_acc_r,
1185           { "Accel-r", "ppi_vector.acc_r",
1186             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec_squared, 0x0,
1187             "Acceleration-right", HFILL } },
1188         { &hf_ppi_vector_acc_f,
1189           { "Accel-f", "ppi_vector.acc_f",
1190             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec_squared, 0x0,
1191             "Acceleration-forward", HFILL } },
1192         { &hf_ppi_vector_acc_u,
1193           { "Accel-u", "ppi_vector.acc_u",
1194             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec_squared, 0x0,
1195             "Acceleration-up", HFILL } },
1196         { &hf_ppi_vector_acc_t,
1197           { "Accel-t", "ppi_vector.acc_t",
1198             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec_squared, 0x0,
1199             "Acceleration-Total", HFILL } },
1200 
1201         /* V2 */
1202         { &hf_ppi_vector_off_x,
1203           { "Off-x", "ppi_vector.off_x",
1204             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1205             "Offset-x  (right/east)", HFILL } },
1206         { &hf_ppi_vector_off_y,
1207           { "Off-y", "ppi_vector.off_y",
1208             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1209             "Offset-y (forward/north)", HFILL } },
1210         { &hf_ppi_vector_off_z,
1211           { "Off-z", "ppi_vector.off_z",
1212             FT_DOUBLE, BASE_NONE, NULL, 0x0,
1213             "Offset-z (up)", HFILL } },
1214 
1215         { &hf_ppi_vector_err_rot,
1216           { "Err-Rot", "ppi_vector.err_rot",
1217             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_degree_degrees, 0x0,
1218             "Rotation margin of error", HFILL } },
1219         { &hf_ppi_vector_err_off,
1220           { "Err-Off", "ppi_vector.err_off",
1221             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_meters, 0x0,
1222             "Offset margin of  error", HFILL } },
1223 
1224         /* V1 only */
1225         { &hf_ppi_vector_err_vel,
1226           { "Err-Vel", "ppi_vector.err_vel",
1227             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec, 0x0,
1228             "Velocity margin of error", HFILL } },
1229         { &hf_ppi_vector_err_acc,
1230           { "Err-Accel", "ppi_vector.err_acc",
1231             FT_DOUBLE, BASE_NONE|BASE_UNIT_STRING, &units_meter_sec_squared, 0x0,
1232             "Acceleration margin of error", HFILL } },
1233 
1234         { &hf_ppi_vector_descstr,
1235           { "Description", "ppi_vector.descr",
1236             FT_STRING,  BASE_NONE, NULL, 0x0,
1237             NULL, HFILL } } ,
1238         { &hf_ppi_vector_appspecific_num,
1239           { "Application Specific id", "ppi_vector.appid",
1240             FT_UINT32, BASE_HEX, NULL, 0x0,
1241             "Application-specific identifier", HFILL } },
1242         { &hf_ppi_vector_appspecific_data,
1243           { "Application specific data", "ppi_vector.appdata",
1244             FT_BYTES, BASE_NONE, NULL, 0x0,
1245             "Application-specific data", HFILL } },
1246 
1247         /* Boolean vector flags */
1248         { &hf_ppi_vector_vflags_defines_forward,
1249           { "Defines forward", "ppi_vector.vflags.forward",
1250             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VFLAGS_DEFINES_FORWARD,
1251             "Current vector indicates forward frame of reference", HFILL } },
1252 
1253         /* V1 */
1254         { &hf_ppi_vector_vflags_rots_absolute,
1255           { "Absolute (E/N/U)  rotations", "ppi_vector.vflags.abs_rots",
1256             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VFLAGS_ROTS_ABSOLUTE,
1257             "Rotations are in East/North/Up coord. sys", HFILL } },
1258         { &hf_ppi_vector_vflags_offsets_from_gps,
1259           { "Offsets from prev GPS TAG", "ppi_vector.vflags.offsets_from_gps",
1260             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VFLAGS_OFFSETS_FROM_GPS,
1261             "Offsets fied rel. to Curr_Gps", HFILL } },
1262 
1263         /* V2 */
1264         { &hf_ppi_vector_vflags_relative_to,
1265           { "RelativeTo", "ppi_vector.vflags.relative_to", FT_UINT32, BASE_HEX, VALS(relativeto_string), PPI_VECTOR_VFLAGS_RELATIVE_TO,
1266             "Reference frame vectors are RelativeTo:", HFILL } },
1267 
1268         /* Boolean vector chars */
1269         { &hf_ppi_vector_vchars_antenna,
1270           { "Antenna", "ppi_vector.chars.antenna",
1271             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_ANTENNA,
1272             "Vector represents: Antenna", HFILL } },
1273 
1274         { &hf_ppi_vector_vchars_dir_of_travel,
1275           { "Dir of travel", "ppi_vector.chars.dir_of_travel",
1276             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_DIR_OF_TRAVEL,
1277             "Vector represents: Direction of travel", HFILL } },
1278 
1279         { &hf_ppi_vector_vchars_front_of_veh,
1280           { "Front of vehicle", "ppi_vector.chars.front_of_veh",
1281             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_FRONT_OF_VEH,
1282             "Vector represents: Front of vehicle", HFILL } },
1283 
1284         /* V2 only */
1285         { &hf_ppi_vector_vchars_angle_of_arrival,
1286           { "Angle of arrival", "ppi_vector.chars.angle_of_arr",
1287             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_AOA,
1288             "Vector represents: Angle of Arrival", HFILL } },
1289         { &hf_ppi_vector_vchars_transmitter_pos,
1290           { "Transmitter Position", "ppi_vector.chars.transmitter_pos",
1291             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_TRANSMITTER_POS,
1292             "Vector position represents computed transmitter location", HFILL } },
1293 
1294         { &hf_ppi_vector_vchars_gps_derived,
1295           { "GPS Derived", "ppi_vector.vflags.gps_derived",
1296             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_GPS_DERIVED,
1297             "Vector derived from: gps", HFILL } },
1298 
1299         { &hf_ppi_vector_vchars_ins_derived,
1300           { "INS Derived", "ppi_vector.vflags.ins_derived",
1301             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_INS_DERIVED,
1302             "Vector derived from: inertial nav system", HFILL } },
1303 
1304         { &hf_ppi_vector_vchars_compass_derived,
1305           { "Compass derived", "ppi_vector.vflags.compass_derived",
1306             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_COMPASS_DERIVED,
1307             "Vector derived from: compass", HFILL } },
1308 
1309         { &hf_ppi_vector_vchars_accelerometer_derived,
1310           { "Accelerometer derived", "ppi_vector.vflags.accelerometer_derived",
1311             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_ACCELEROMETER_DERIVED,
1312             "Vector derived from: accelerometer", HFILL } },
1313 
1314         { &hf_ppi_vector_vchars_human_derived,
1315           { "Human derived", "ppi_vector.vflags.human_derived",
1316             FT_BOOLEAN, 32, NULL, PPI_VECTOR_VCHARS_HUMAN_DERIVED,
1317             "Vector derived from: human", HFILL } },
1318 
1319         { &hf_ppi_vector_unknown_data,
1320           { "Data for unknown version", "ppi_vector.unknown_data",
1321             FT_BYTES, BASE_NONE, NULL, 0x0,
1322             NULL, HFILL } },
1323 
1324     };
1325     static gint *ett[] = {
1326         &ett_ppi_vector,
1327         &ett_ppi_vector_present,
1328         &ett_ppi_vectorflags,
1329         &ett_ppi_vectorchars
1330     };
1331 
1332     static ei_register_info ei[] = {
1333         { &ei_ppi_vector_present_bit, { "ppi_vector.present.unknown_bit", PI_PROTOCOL, PI_WARN, "Error: PPI-VECTOR: unknown bit set in present field.", EXPFILL }},
1334         { &ei_ppi_vector_length, { "ppi_vector.length.invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
1335     };
1336 
1337     expert_module_t* expert_ppi_vector;
1338 
1339     proto_ppi_vector = proto_register_protocol("PPI vector decoder", "PPI vector Decoder", "ppi_vector");
1340     proto_register_field_array(proto_ppi_vector, hf, array_length(hf));
1341     proto_register_subtree_array(ett, array_length(ett));
1342     expert_ppi_vector = expert_register_protocol(proto_ppi_vector);
1343     expert_register_field_array(expert_ppi_vector, ei, array_length(ei));
1344     register_dissector("ppi_vector", dissect_ppi_vector, proto_ppi_vector);
1345 
1346 }
1347 
1348 /*
1349  * Editor modelines
1350  *
1351  * Local Variables:
1352  * c-basic-offset: 4
1353  * tab-width: 8
1354  * indent-tabs-mode: nil
1355  * End:
1356  *
1357  * ex: set shiftwidth=4 tabstop=8 expandtab:
1358  * :indentSize=4:tabSize=8:noTabs=true:
1359  */
1360 
1361 
1362