1 /* packet-ppi-gps.c
2  * Routines for PPI-GEOLOCATION-GPS  dissection
3  * Copyright 2010, Harris Corp, jellch@harris.com
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * Copied from packet-radiotap.c
10  *
11  * SPDX-License-Identifier: GPL-2.0-or-later
12  */
13 
14 #include "config.h"
15 
16 #include <epan/packet.h>
17 #include <epan/expert.h>
18 #include "packet-ppi-geolocation-common.h"
19 
20 enum ppi_geotagging_type {
21     PPI_GEOTAG_GPSFLAGS = 0,
22     PPI_GEOTAG_LAT = 1,
23     PPI_GEOTAG_LON = 2,
24     PPI_GEOTAG_ALT = 3,
25     PPI_GEOTAG_ALT_G = 4,
26     PPI_GEOTAG_GPSTIME = 5,
27     PPI_GEOTAG_FRACTIONALTIME = 6,
28     PPI_GEOTAG_EPH = 7,
29     PPI_GEOTAG_EPV = 8,
30     PPI_GEOTAG_EPT = 9,
31     PPI_GEOTAG_DESCRIPTIONSTR = 28,
32     PPI_GEOTAG_APPID = 29,
33     PPI_GEOTAG_APPDATA = 30,
34     PPI_GEOTAG_EXT = 31
35 };
36 #define PPI_GPS_MAXTAGLEN  144 /* increase as fields are added */
37 
38 #define PPI_GPS_MASK_GPSFLAGS       0x00000001
39 #define PPI_GPS_MASK_LAT            0x00000002
40 #define PPI_GPS_MASK_LON            0x00000004
41 #define PPI_GPS_MASK_ALT            0x00000008
42 #define PPI_GPS_MASK_ALT_G          0x00000010
43 
44 #define PPI_GPS_MASK_GPSTIME        0x00000020
45 #define PPI_GPS_MASK_FRACTIME       0x00000040
46 #define PPI_GPS_MASK_EPH            0x00000080
47 #define PPI_GPS_MASK_EPV            0x00000100
48 #define PPI_GPS_MASK_EPT            0x00000200
49 
50 #define PPI_GPS_MASK_DESCRSTR       0x10000000
51 #define PPI_GPS_MASK_APPID          0x20000000
52 #define PPI_GPS_MASK_APPDATA        0x40000000
53 #define PPI_GPS_MASK_EXT            0x80000000
54 
55 
56 void proto_register_ppi_gps(void);
57 
58 /* protocol */
59 static int proto_ppi_gps = -1;
60 
61 static int hf_ppi_gps_version = -1;
62 static int hf_ppi_gps_pad = -1;
63 static int hf_ppi_gps_length = -1;
64 static int hf_ppi_gps_present = -1;
65 static int hf_ppi_gps_gpsflags_flags = -1;
66 static int hf_ppi_gps_lon = -1;
67 static int hf_ppi_gps_lat = -1;
68 static int hf_ppi_gps_alt = -1;
69 static int hf_ppi_gps_alt_gnd = -1;
70 static int hf_ppi_gps_gpstime = -1;
71 static int hf_ppi_gps_fractime = -1;
72 static int hf_ppi_gps_eph = -1;
73 static int hf_ppi_gps_epv = -1;
74 static int hf_ppi_gps_ept = -1;
75 static int hf_ppi_gps_descstr = -1;
76 static int hf_ppi_gps_appspecific_num = -1; /* 4-byte tag no */
77 static int hf_ppi_gps_appspecific_data = -1; /* 60 byte arbitrary data */
78 /* "Present" flags, tese represent decoded-bits in the gui */
79 static int hf_ppi_gps_present_gpsflags_flags = -1;
80 static int hf_ppi_gps_present_lon = -1;
81 static int hf_ppi_gps_present_lat = -1;
82 static int hf_ppi_gps_present_alt = -1;
83 static int hf_ppi_gps_present_alt_gnd = -1;
84 static int hf_ppi_gps_present_gpstime = -1;
85 static int hf_ppi_gps_present_fractime = -1;
86 static int hf_ppi_gps_present_eph = -1;
87 static int hf_ppi_gps_present_epv = -1;
88 static int hf_ppi_gps_present_ept = -1;
89 static int hf_ppi_gps_present_descr = -1;
90 static int hf_ppi_gps_present_appspecific_num = -1;
91 static int hf_ppi_gps_present_appspecific_data = -1;
92 static int hf_ppi_gps_present_ext = -1;
93 
94 /* Devicetype flags. not to be confused with "present" flags. These are optional */
95 static int hf_ppi_gps_gpsflags_flag0_nofix = -1;
96 static int hf_ppi_gps_gpsflags_flag1_gpsfix = -1;
97 static int hf_ppi_gps_gpsflags_flag2_diffgps = -1;
98 static int hf_ppi_gps_gpsflags_flag3_PPS = -1;
99 static int hf_ppi_gps_gpsflags_flag4_RTK = -1;
100 static int hf_ppi_gps_gpsflags_flag5_floatRTK = -1;
101 static int hf_ppi_gps_gpsflags_flag6_dead_reck = -1;
102 static int hf_ppi_gps_gpsflags_flag7_manual = -1;
103 static int hf_ppi_gps_gpsflags_flag8_sim = -1;
104 
105 /* These represent arrow-dropdownthings in the gui */
106 static gint ett_ppi_gps = -1;
107 static gint ett_ppi_gps_present = -1;
108 static gint ett_ppi_gps_gpsflags_flags= -1;
109 
110 static expert_field ei_ppi_gps_present_bit = EI_INIT;
111 static expert_field ei_ppi_gps_version = EI_INIT;
112 static expert_field ei_ppi_gps_length = EI_INIT;
113 
114 static int
dissect_ppi_gps(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)115 dissect_ppi_gps(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_) {
116     /* These are locals used for processing the current tvb */
117     guint length;
118     gint  length_remaining;
119     int offset = 0;
120 
121     proto_tree *ppi_gps_tree = NULL;
122 
123     proto_item *version_item, *length_item, *pt;
124     proto_item *gps_line = NULL;
125 
126     static int * const ppi_gps_present_flags[] = {
127         &hf_ppi_gps_present_gpsflags_flags,
128         &hf_ppi_gps_present_lat,
129         &hf_ppi_gps_present_lon,
130         &hf_ppi_gps_present_alt,
131         &hf_ppi_gps_present_alt_gnd,
132         &hf_ppi_gps_present_gpstime,
133         &hf_ppi_gps_present_fractime,
134         &hf_ppi_gps_present_eph,
135         &hf_ppi_gps_present_epv,
136         &hf_ppi_gps_present_ept,
137         &hf_ppi_gps_present_descr,
138         &hf_ppi_gps_present_appspecific_num,
139         &hf_ppi_gps_present_appspecific_data,
140         &hf_ppi_gps_present_ext,
141         NULL
142     };
143 
144     static int * const ppi_antenna_gps_flags[] = {
145         &hf_ppi_gps_gpsflags_flag0_nofix,
146         &hf_ppi_gps_gpsflags_flag1_gpsfix,
147         &hf_ppi_gps_gpsflags_flag2_diffgps,
148         &hf_ppi_gps_gpsflags_flag3_PPS,
149         &hf_ppi_gps_gpsflags_flag4_RTK,
150         &hf_ppi_gps_gpsflags_flag5_floatRTK,
151         &hf_ppi_gps_gpsflags_flag6_dead_reck,
152         &hf_ppi_gps_gpsflags_flag7_manual,
153         &hf_ppi_gps_gpsflags_flag8_sim,
154         NULL
155     };
156 
157     /* bits */
158     int bit;
159     guint32 present, next_present;
160     /* values actually read out, for displaying */
161     guint32 version;
162     gdouble lat, lon, alt, alt_gnd;
163     nstime_t gps_timestamp;
164     int gps_time_size, already_processed_fractime; /* we use this internally to track if this is a 4 or 8 byte wide timestamp */
165     gdouble eph, epv, ept;
166     gchar *curr_str;
167 
168 
169     /* these are temporary intermediate values, used in the individual cases below */
170     guint32 t_lat, t_lon, t_alt, t_alt_gnd;
171     guint32 t_herr, t_verr, t_terr;
172     guint32 t_appspecific_num;
173     /* initialize the timestamp value(s) */
174     gps_timestamp.secs = gps_timestamp.nsecs = already_processed_fractime = 0;
175 
176     /* Clear out stuff in the info column */
177     col_clear(pinfo->cinfo,COL_INFO);
178 
179     /* pull out the first three fields of the BASE-GEOTAG-HEADER */
180     version = tvb_get_guint8(tvb, offset);
181     length  = tvb_get_letohs(tvb, offset+2);
182     present = tvb_get_letohl(tvb, offset+4);
183 
184     /* Setup basic column info */
185     col_add_fstr(pinfo->cinfo, COL_INFO, "PPI_GPS Capture v%u, Length %u", version, length);
186 
187     /* Create the basic dissection tree*/
188     gps_line = proto_tree_add_protocol_format(tree, proto_ppi_gps, tvb, 0, length, "GPS:");
189     ppi_gps_tree = proto_item_add_subtree(gps_line, ett_ppi_gps);
190     version_item = proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_version, tvb, offset, 1, version);
191     proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_pad, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
192     length_item = proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_length, tvb, offset + 2, 2, length);
193 
194     /* We support v1 and v2 of GPS tags (identical) */
195     if (! (version == 1 || version == 2) ) {
196         expert_add_info_format(pinfo, version_item, &ei_ppi_gps_version, "Invalid version (got %d,  expected 1 or 2)", version);
197     }
198 
199     /* initialize the length of the actual tag contents */
200     length_remaining = length;
201     /* minimum length check, should atleast be a fixed-size geotagging-base header*/
202     if (length_remaining < PPI_GEOBASE_MIN_HEADER_LEN) {
203         /*
204          * Base-geotag-header (Radiotap lookalike) is shorter than the fixed-length portion
205          * plus one "present" bitset.
206          */
207         expert_add_info_format(pinfo, length_item, &ei_ppi_gps_length, "Invalid PPI-GPS length - minimum length is 8");
208         return 2;
209     }
210 
211     /* perform tag-specific max length sanity checking */
212     if (length > PPI_GPS_MAXTAGLEN ) {
213         expert_add_info_format(pinfo, length_item, &ei_ppi_gps_length, "Invalid PPI-GPS length  (got %d, %d max\n)", length, PPI_GPS_MAXTAGLEN);
214         return 2;
215     }
216 
217     /* Subtree for the "present flags" bitfield. */
218     pt = proto_tree_add_bitmask(ppi_gps_tree, tvb, offset + 4, hf_ppi_gps_present, ett_ppi_gps_present, ppi_gps_present_flags, ENC_LITTLE_ENDIAN);
219 
220     offset += PPI_GEOBASE_MIN_HEADER_LEN;
221     length_remaining -= PPI_GEOBASE_MIN_HEADER_LEN;
222 
223     /* The fixed BASE-GEOTAG-HEADER has been handled at this point. move on to the individual fields */
224     for (; present; present = next_present) {
225         /* clear the least significant bit that is set */
226         next_present = present & (present - 1);
227         /* extract the least significant bit that is set */
228         bit = BITNO_32(present ^ next_present);
229         switch (bit) {
230         case PPI_GEOTAG_GPSFLAGS:
231             if (length_remaining < 4)
232                 break;
233             proto_tree_add_bitmask(ppi_gps_tree, tvb, offset, hf_ppi_gps_gpsflags_flags, ett_ppi_gps_gpsflags_flags, ppi_antenna_gps_flags, ENC_LITTLE_ENDIAN);
234             offset+=4;
235             length_remaining-=4;
236             break;
237         case  PPI_GEOTAG_LAT:
238             if (length_remaining < 4)
239                 break;
240             t_lat = tvb_get_letohl(tvb, offset);
241             lat =  ppi_fixed3_7_to_gdouble(t_lat);
242             if (tree)
243             {
244                 proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_lat, tvb, offset, 4, lat);
245                 proto_item_append_text(gps_line, " Lat:%f ", lat);
246             }
247             offset+=4;
248             length_remaining-=4;
249             break;
250         case  PPI_GEOTAG_LON:
251             if (length_remaining < 4)
252                 break;
253             t_lon = tvb_get_letohl(tvb, offset);
254             lon =  ppi_fixed3_7_to_gdouble(t_lon);
255             if (tree)
256             {
257                 proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_lon, tvb, offset, 4, lon);
258                 proto_item_append_text(gps_line, " Lon:%f ", lon);
259             }
260             offset+=4;
261             length_remaining-=4;
262             break;
263         case  PPI_GEOTAG_ALT:
264             if (length_remaining < 4)
265                 break;
266             t_alt = tvb_get_letohl(tvb, offset);
267             alt = ppi_fixed6_4_to_gdouble(t_alt);
268             if (tree)
269             {
270                 proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_alt, tvb, offset, 4, alt);
271                 proto_item_append_text(gps_line, " Alt:%f ", alt);
272             }
273             offset+=4;
274             length_remaining-=4;
275             break;
276         case  PPI_GEOTAG_ALT_G:
277             if (length_remaining < 4)
278                 break;
279             t_alt_gnd = tvb_get_letohl(tvb, offset);
280             alt_gnd = ppi_fixed6_4_to_gdouble(t_alt_gnd);
281             if (tree)
282             {
283                 proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_alt_gnd, tvb, offset, 4, alt_gnd);
284                 proto_item_append_text(gps_line, " Alt_g:%f ", alt_gnd);
285             }
286             offset+=4;
287             length_remaining-=4;
288             break;
289         case  PPI_GEOTAG_GPSTIME:
290             if (length_remaining < 4)
291                 break;
292             gps_timestamp.secs =    tvb_get_letohl(tvb, offset);
293             gps_timestamp.nsecs = 0;
294             gps_time_size = 4;
295             /* This is somewhat tricky, inside the GPSTIME case we test if the optional fractional time */
296             /* is present. If so, we pull it out, and combine it with GPSTime. */
297             /* If we do this, we set already_processed_fractime to avoid hitting it below */
298             if (length_remaining < 8 && (present & PPI_GPS_MASK_FRACTIME))
299                 break;
300             else if (present & PPI_GPS_MASK_FRACTIME) {
301                 gps_timestamp.nsecs =  tvb_get_letohl(tvb, offset + 4); /* manually offset seconds */
302                 already_processed_fractime = 1;
303                 gps_time_size = 8;
304             }
305             proto_tree_add_time(ppi_gps_tree, hf_ppi_gps_gpstime, tvb, offset, gps_time_size, &gps_timestamp);
306             offset += gps_time_size;
307             length_remaining -= gps_time_size;
308             break;
309         case  PPI_GEOTAG_FRACTIONALTIME:
310             if (length_remaining < 4)
311                 break;
312             if (already_processed_fractime)
313                 break;
314             proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_fractime, tvb, offset, 4, ENC_LITTLE_ENDIAN);
315             offset += 4;
316             length_remaining -= 4;
317             break;
318         case  PPI_GEOTAG_EPH:
319             if (length_remaining < 4)
320                 break;
321             t_herr = tvb_get_letohl(tvb, offset);
322             eph  =  ppi_fixed3_6_to_gdouble(t_herr);
323             proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_eph, tvb, offset, 4, eph);
324             offset+=4;
325             length_remaining-=4;
326             break;
327         case  PPI_GEOTAG_EPV:
328             if (length_remaining < 4)
329                 break;
330             t_verr = tvb_get_letohl(tvb, offset);
331             epv  =  ppi_fixed3_6_to_gdouble(t_verr);
332             proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_epv, tvb, offset, 4, epv);
333             offset+=4;
334             length_remaining-=4;
335             break;
336         case  PPI_GEOTAG_EPT:
337             if (length_remaining < 4)
338                 break;
339             t_terr = tvb_get_letohl(tvb, offset);
340             ept  =  ppi_ns_counter_to_gdouble(t_terr);
341             proto_tree_add_double(ppi_gps_tree, hf_ppi_gps_ept, tvb, offset, 4, ept);
342             offset+=4;
343             length_remaining-=4;
344             break;
345         case  PPI_GEOTAG_DESCRIPTIONSTR:
346             if (length_remaining < 32)
347                 break;
348             if (tree)
349             {
350                 /* proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_descstr, tvb, offset, 32,  ENC_ASCII|ENC_NA); */
351                 curr_str = tvb_format_stringzpad(pinfo->pool, tvb, offset, 32); /* need to append_text this */
352                 proto_tree_add_string(ppi_gps_tree, hf_ppi_gps_descstr, tvb, offset, 32, curr_str);
353                 proto_item_append_text(gps_line, " (%s)", curr_str);
354             }
355             offset+=32;
356             length_remaining-=32;
357             break;
358         case  PPI_GEOTAG_APPID:
359             if (length_remaining < 4)
360                 break;
361             t_appspecific_num  = tvb_get_letohl(tvb, offset); /* application specific parsers may switch on this later */
362             proto_tree_add_uint(ppi_gps_tree, hf_ppi_gps_appspecific_num, tvb, offset, 4, t_appspecific_num);
363             offset+=4;
364             length_remaining-=4;
365             break;
366         case  PPI_GEOTAG_APPDATA:
367             if (length_remaining < 60)
368                 break;
369             proto_tree_add_item(ppi_gps_tree, hf_ppi_gps_appspecific_data, tvb, offset, 60,  ENC_NA);
370             offset+=60;
371             length_remaining-=60;
372             break;
373 
374             /*
375              * This indicates a field whose size we do not know, so we cannot proceed.
376              */
377         default:
378             next_present = 0; /* this will terminate the loop */
379             expert_add_info_format(pinfo, pt, &ei_ppi_gps_present_bit,
380                  "Error: PPI-GEOLOCATION-GPS: unknown bit (%d) set in present field.", bit);
381             continue;
382         } /* switch (bit) */
383 
384     } /* (for present..)*/
385 
386     /* If there was any post processing of the elements, it could happen here. */
387     return tvb_captured_length(tvb);
388 }
389 
390 void
proto_register_ppi_gps(void)391 proto_register_ppi_gps(void) {
392     /* The following array initializes those header fields declared above to the values displayed */
393     static hf_register_info hf[] = {
394         { &hf_ppi_gps_version,
395           { "Header revision", "ppi_gps.version",
396             FT_UINT8, BASE_DEC, NULL, 0x0,
397             "Version of ppi_gps header format", HFILL } },
398         { &hf_ppi_gps_pad,
399           { "Header pad", "ppi_gps.pad",
400             FT_UINT8, BASE_DEC, NULL, 0x0,
401             "Padding", HFILL } },
402         { &hf_ppi_gps_length,
403           { "Header length", "ppi_gps.length",
404             FT_UINT16, BASE_DEC, NULL, 0x0,
405             "Length of header including version, pad, length and data fields", HFILL } },
406         { &hf_ppi_gps_present, /* these flag fields are composed of a uint32 on the display */
407           { "Present", "ppi_gps.present",
408             FT_UINT32, BASE_HEX, NULL, 0x0,
409             "Bitmask indicating which fields are present", HFILL } },
410 
411         /* Boolean 'present' flags */
412         { &hf_ppi_gps_present_gpsflags_flags, /* followed by a lot of booleans */
413           { "GPSFlags", "ppi_gps.present.gpsflagss",
414             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_GPSFLAGS,
415             "32-bit bitmask indicating type of GPS fix (GPS/INS/software/etc)", HFILL } },
416         { &hf_ppi_gps_present_lat,
417           { "Lat", "ppi_gps.present.lat",
418             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_LAT,
419             "Specifies if the latitude field is present", HFILL } },
420 
421         { &hf_ppi_gps_present_lon,
422           { "Lon", "ppi_gps.present.lon",
423             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_LON,
424             "Specifies if the longitude field is present", HFILL } },
425 
426         { &hf_ppi_gps_present_alt,
427           { "Alt", "ppi_gps.present.alt",
428             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_ALT,
429             "Specifies if the altitude field is present", HFILL } },
430 
431         { &hf_ppi_gps_present_alt_gnd,
432           { "Alt-gnd", "ppi_gps.present.alt_gnd",
433             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_ALT_G,
434             "Specifies if the altitude-g field is present", HFILL } },
435 
436         { &hf_ppi_gps_present_gpstime,
437           { "GPStime", "ppi_gps.present.gpstime",
438             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_GPSTIME,
439             "Specifies if the GPS time field is present", HFILL } },
440 
441 
442         { &hf_ppi_gps_present_fractime,
443           { "fractime", "ppi_gps.present.fractime",
444             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_FRACTIME,
445             "Specifies if the fractional time field is present", HFILL } },
446 
447 
448         { &hf_ppi_gps_present_eph,
449           { "error_h", "ppi_gps.present.eph",
450             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_EPH,
451             "Specifies if the horizontal error field is present (eph)", HFILL } },
452 
453         { &hf_ppi_gps_present_epv,
454           { "error_v", "ppi_gps.present.epv",
455             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_EPV,
456             "Specifies if the vertical error field present (epv)", HFILL } },
457 
458 
459         { &hf_ppi_gps_present_ept,
460           { "error_t", "ppi_gps.present.ept",
461             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_EPT,
462             "Specifies if the estimated time error field is present (ept)", HFILL } },
463 
464         { &hf_ppi_gps_present_descr,
465           { "Description", "ppi_gps.present.descr",
466             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_DESCRSTR,
467             "Specifies if the (ASCII) description is present", HFILL } },
468 
469         { &hf_ppi_gps_present_appspecific_num,
470           { "AppId", "ppi_gps.present.appid",
471             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_APPID,
472             "Specifies if the application specific field id is present", HFILL } },
473 
474         { &hf_ppi_gps_present_appspecific_data,
475           { "AppData", "ppi_gps.present.appdata",
476             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_APPDATA,
477             "Specifies if the application specific data field  is present", HFILL } },
478 
479         { &hf_ppi_gps_present_ext,
480           { "Ext", "ppi_gps.present.ext",
481             FT_BOOLEAN, 32, NULL, PPI_GPS_MASK_EXT,
482             "Specifies if there are any extensions to the header present", HFILL } },
483 
484         /* ---Now we get to the actual data fields--- */
485 
486         { &hf_ppi_gps_gpsflags_flags,
487           { "GPSFlags", "ppi_gps.gpsflags",
488             FT_UINT32, BASE_HEX, NULL, 0x0,
489             "Bitmask indicating GPS/INS/manual fix", HFILL } },
490         { &hf_ppi_gps_lat,
491           { "Latitude", "ppi_gps.lat",
492             FT_DOUBLE, BASE_NONE, NULL, 0x0,
493             "Latitude packet was received at", HFILL } },
494         { &hf_ppi_gps_lon,
495           { "Longitude", "ppi_gps.lon",
496             FT_DOUBLE, BASE_NONE, NULL, 0x0,
497             "Longitude packet was received at", HFILL } },
498         { &hf_ppi_gps_alt,
499           { "Altitude", "ppi_gps.alt",
500             FT_DOUBLE, BASE_NONE, NULL, 0x0,
501             "Altitude packet was received at", HFILL } },
502         { &hf_ppi_gps_alt_gnd,
503           { "Altitude_gnd", "ppi_gps.alt_gnd",
504             FT_DOUBLE, BASE_NONE, NULL, 0x0,
505             "Altitude packet was received at (relative to ground)", HFILL } },
506         { &hf_ppi_gps_gpstime,
507           { "GPSTimestamp", "ppi_gps.gpstime",
508             FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0x0,
509             "GPSTimestamp packet was received at", HFILL } },
510         { &hf_ppi_gps_fractime,
511           { "fractional Timestamp", "ppi_gps.fractime",
512             FT_UINT32, BASE_DEC, NULL, 0x0,
513             "Fractional of GPSTimestamp packet was received at", HFILL } },
514         { &hf_ppi_gps_eph,
515           { "Horizontal Error (m)", "ppi_gps.eph",
516             FT_DOUBLE, BASE_NONE, NULL, 0x0,
517             "Horizontal margin of error (meters)", HFILL } },
518         { &hf_ppi_gps_epv,
519           { "Vertical Error (m)", "ppi_gps.epv",
520             FT_DOUBLE, BASE_NONE, NULL, 0x0,
521             "Vertical margin of error (meters)", HFILL } },
522         { &hf_ppi_gps_ept,
523           { "Time Error (s)", "ppi_gps.ept",
524             FT_DOUBLE, BASE_NONE, NULL, 0x0,
525             "Time margin of error (secs)", HFILL } },
526         { &hf_ppi_gps_descstr,
527           { "Description", "ppi_gps.descr",
528             FT_STRING, BASE_NONE, NULL, 0x0,
529             NULL, HFILL } },
530         { &hf_ppi_gps_appspecific_num,
531           { "Application Specific id", "ppi_gps.appid",
532             FT_UINT32, BASE_HEX, NULL, 0x0,
533             NULL, HFILL } },
534         { &hf_ppi_gps_appspecific_data,
535           { "Application specific data", "ppi_gps.appdata",
536             FT_BYTES, BASE_NONE, NULL, 0x0,
537             NULL, HFILL } },
538 
539         /* --- moving on to the 'FixType' flags --- */
540 #define PPI_GPS_GPSFLAGS_FLAG0_NOFIX     0x00000001
541 #define PPI_GPS_GPSFLAGS_FLAG1_GPS       0x00000002
542 #define PPI_GPS_GPSFLAGS_FLAG2_DIFFGPS   0x00000004
543 #define PPI_GPS_GPSFLAGS_FLAG3_PPS       0x00000008
544 #define PPI_GPS_GPSFLAGS_FLAG4_RTK       0x00000010
545 #define PPI_GPS_GPSFLAGS_FLAG5_FLOATRTK  0x00000020
546 #define PPI_GPS_GPSFLAGS_FLAG6_DEAD_RECK 0x00000040
547 #define PPI_GPS_GPSFLAGS_FLAG7_MANUAL    0x00000080
548 #define PPI_GPS_GPSFLAGS_FLAG8_SIM       0x00000100
549         { &hf_ppi_gps_gpsflags_flag0_nofix, /* no fix available */
550           { "No fix available", "ppi_gps.gpsflagss.nofix",
551             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG0_NOFIX,
552             NULL, HFILL } },
553         { &hf_ppi_gps_gpsflags_flag1_gpsfix, /* GPSfix available */
554           { "GPS provided fix", "ppi_gps.gpsflagss.gps",
555             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG1_GPS,
556             NULL, HFILL } },
557         { &hf_ppi_gps_gpsflags_flag2_diffgps, /* Differential GPS fix  available */
558           { "Differential GPS provided fix", "ppi_gps.gpsflagss.diffgps",
559             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG2_DIFFGPS,
560             NULL, HFILL } },
561         { &hf_ppi_gps_gpsflags_flag3_PPS, /* PPS fix  */
562           { "PPS fix", "ppi_gps.gpsflagss.pps",
563             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG3_PPS,
564             NULL, HFILL } },
565         { &hf_ppi_gps_gpsflags_flag4_RTK, /* RTK fix*/
566           { "RTK fix", "ppi_gps.gpsflagss.rtk",
567             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG4_RTK,
568             NULL, HFILL } },
569         { &hf_ppi_gps_gpsflags_flag5_floatRTK, /*float RTK */
570           { "floatRTK fix", "ppi_gps.gpsflagss.frtk",
571             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG5_FLOATRTK,
572             NULL, HFILL } },
573         { &hf_ppi_gps_gpsflags_flag6_dead_reck, /*dead reckoning */
574           { "dead reckoning fix", "ppi_gps.gpsflagss.dead_reck",
575             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG6_DEAD_RECK,
576             NULL, HFILL } },
577         { &hf_ppi_gps_gpsflags_flag7_manual, /* manual */
578           { "manual fix", "ppi_gps.gpsflagss.manual",
579             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG7_MANUAL,
580             NULL, HFILL } },
581         { &hf_ppi_gps_gpsflags_flag8_sim, /* simulation */
582           { "simulated fix", "ppi_gps.gpsflagss.simulation",
583             FT_BOOLEAN, 32, NULL, PPI_GPS_GPSFLAGS_FLAG8_SIM,
584             NULL, HFILL } },
585 
586     };
587     static gint *ett[] = {
588         &ett_ppi_gps,
589         &ett_ppi_gps_present,
590         &ett_ppi_gps_gpsflags_flags
591     };
592 
593     static ei_register_info ei[] = {
594         { &ei_ppi_gps_present_bit, { "ppi_gps.present.unknown_bit", PI_PROTOCOL, PI_WARN, "Error: PPI-GEOLOCATION-GPS: unknown bit set in present field.", EXPFILL }},
595         { &ei_ppi_gps_version, { "ppi_gps.version.unsupported", PI_PROTOCOL, PI_WARN, "Invalid version", EXPFILL }},
596         { &ei_ppi_gps_length, { "ppi_gps.length.invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
597     };
598 
599     expert_module_t* expert_ppi_gps;
600 
601     proto_ppi_gps = proto_register_protocol("PPI Geotagging GPS tag decoder", "PPI GPS Decoder", "ppi_gps");
602     proto_register_field_array(proto_ppi_gps, hf, array_length(hf));
603     proto_register_subtree_array(ett, array_length(ett));
604     expert_ppi_gps = expert_register_protocol(proto_ppi_gps);
605     expert_register_field_array(expert_ppi_gps, ei, array_length(ei));
606     register_dissector("ppi_gps", dissect_ppi_gps, proto_ppi_gps);
607 }
608 
609 /*
610  * Editor modelines
611  *
612  * Local Variables:
613  * c-basic-offset: 4
614  * tab-width: 8
615  * indent-tabs-mode: nil
616  * End:
617  *
618  * ex: set shiftwidth=4 tabstop=8 expandtab:
619  * :indentSize=4:tabSize=8:noTabs=true:
620  */
621