2 * Routines and definitions for DIS field parsing.
3 * Copyright 2005, Scientific Research Corporation
4 * Initial implementation by Jeremy Ouellette <jouellet@scires.com>
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include <epan/packet.h>
33 #include "packet-dis-fields.h"
34 #include "packet-dis-enums.h"
40 DIS_ParserNode DIS_FIELDS_PDU_HEADER[] =
42 { DIS_FIELDTYPE_PROTOCOL_VERSION, "Protocol Version",0,0,0 },
43 { DIS_FIELDTYPE_UINT8, "Exercise ID",0,0,0 },
44 { DIS_FIELDTYPE_PDU_TYPE, "PDU Type",0,0,&pduType },
45 { DIS_FIELDTYPE_PROTOCOL_FAMILY, "Protocol Family",0,0,0 },
46 { DIS_FIELDTYPE_TIMESTAMP, "Timestamp",0,0,0 },
47 { DIS_FIELDTYPE_UINT16, "Length",0,0,0 },
48 { DIS_FIELDTYPE_PAD16, "Padding",0,0,0 },
49 { DIS_FIELDTYPE_END, NULL,0,0,0 }
52 DIS_ParserNode DIS_FIELDS_ENTITY_ID[] =
54 { DIS_FIELDTYPE_UINT16, "Site",0,0,0 },
55 { DIS_FIELDTYPE_UINT16, "Application",0,0,0 },
56 { DIS_FIELDTYPE_UINT16, "Entity",0,0,0 },
57 { DIS_FIELDTYPE_END, NULL,0,0,0 }
60 DIS_ParserNode DIS_FIELDS_ENTITY_TYPE[] =
62 { DIS_FIELDTYPE_ENTITY_KIND, "Entity Kind",0,0,&entityKind },
63 { DIS_FIELDTYPE_DOMAIN, "Domain",0,0,&entityDomain },
64 { DIS_FIELDTYPE_COUNTRY, "Country",0,0,0 },
65 { DIS_FIELDTYPE_CATEGORY, "Category",0,0,0 },
66 { DIS_FIELDTYPE_SUBCATEGORY, "Subcategory",0,0,0 },
67 { DIS_FIELDTYPE_SPECIFIC, "Specific",0,0,0 },
68 { DIS_FIELDTYPE_EXTRA, "Extra",0,0,0 },
69 { DIS_FIELDTYPE_END, NULL,0,0,0 }
72 DIS_ParserNode DIS_FIELDS_EVENT_ID[] =
74 { DIS_FIELDTYPE_UINT16, "Site",0,0,0 },
75 { DIS_FIELDTYPE_UINT16, "Application",0,0,0 },
76 { DIS_FIELDTYPE_UINT16, "Event Number",0,0,0 },
77 { DIS_FIELDTYPE_END, NULL,0,0,0 }
80 DIS_ParserNode DIS_FIELDS_LINEAR_VELOCITY[] =
82 { DIS_FIELDTYPE_FLOAT32, "X",0,0,0 },
83 { DIS_FIELDTYPE_FLOAT32, "Y",0,0,0 },
84 { DIS_FIELDTYPE_FLOAT32, "Z",0,0,0 },
85 { DIS_FIELDTYPE_END, NULL,0,0,0 }
88 DIS_ParserNode DIS_FIELDS_LOCATION_WORLD[] =
90 { DIS_FIELDTYPE_FLOAT64, "X",0,0,0 },
91 { DIS_FIELDTYPE_FLOAT64, "Y",0,0,0 },
92 { DIS_FIELDTYPE_FLOAT64, "Z",0,0,0 },
93 { DIS_FIELDTYPE_END, NULL,0,0,0 }
96 DIS_ParserNode DIS_FIELDS_LOCATION_ENTITY[] =
98 { DIS_FIELDTYPE_FLOAT32, "X",0,0,0 },
99 { DIS_FIELDTYPE_FLOAT32, "Y",0,0,0 },
100 { DIS_FIELDTYPE_FLOAT32, "Z",0,0,0 },
101 { DIS_FIELDTYPE_END, NULL,0,0,0 }
104 DIS_ParserNode DIS_FIELDS_ORIENTATION[] =
106 { DIS_FIELDTYPE_FLOAT32, "Psi",0,0,0 },
107 { DIS_FIELDTYPE_FLOAT32, "Theta",0,0,0 },
108 { DIS_FIELDTYPE_FLOAT32, "Phi",0,0,0 },
109 { DIS_FIELDTYPE_END, NULL,0,0,0 }
112 DIS_ParserNode DIS_FIELDS_BURST_DESCRIPTOR[] =
114 { DIS_FIELDTYPE_ENTITY_TYPE, "Munition",0,0,0 },
115 { DIS_FIELDTYPE_WARHEAD, "Warhead",0,0,0 },
116 { DIS_FIELDTYPE_FUSE, "Fuse",0,0,0 },
117 { DIS_FIELDTYPE_UINT16, "Quantity",0,0,0 },
118 { DIS_FIELDTYPE_UINT16, "Rate",0,0,0 },
119 { DIS_FIELDTYPE_END, NULL,0,0,0 }
122 DIS_ParserNode DIS_FIELDS_ARTICULATION_PARAMETER[] =
124 { DIS_FIELDTYPE_ARTIC_PARAM_TYPE_DESIGNATOR, "Parameter Type Designator",0,0,0 },
125 { DIS_FIELDTYPE_UINT8, "Change",0,0,0 },
126 { DIS_FIELDTYPE_UINT16, "Part Attached To ID",0,0,0 },
127 { DIS_FIELDTYPE_ARTIC_PARAM_TYPE, "Parameter Type",0,0,0 },
128 { DIS_FIELDTYPE_UINT64, "Parameter Value",0,0,0 },
129 { DIS_FIELDTYPE_END, NULL,0,0,0 }
132 DIS_ParserNode DIS_FIELDS_NONE[] =
134 { DIS_FIELDTYPE_END, NULL, 0,0,0 }
137 DIS_BitMask DIS_APPEARANCE_LANDPLATFORM[] =
139 { 0x00000001, 0, "Paint Scheme", {
140 { 0, "Uniform color" },
144 { 0x00000002, 1, "Mobility", {
145 { 0, "No mobility kill" },
146 { 1, "Mobility kill" },
149 { 0x00000004, 2, "Fire Power", {
150 { 0, "No fire-power kill" },
151 { 1, "Fire-power kill" },
154 { 0x00000018, 3, "Damage", {
156 { 1, "Slight damage" },
157 { 2, "Moderate damage" },
166 DIS_BitMask DIS_APPEARANCE_LIFEFORM[] =
168 { 0x00000001, 0, "Paint Scheme", {
169 { 0, "Uniform color" },
173 { 0x00000018, 3, "Health", {
175 { 1, "Slight injury" },
176 { 2, "Moderate injury" },
177 { 3, "Fatal injury" },
185 /* Adjust an offset variable for proper alignment for a specified field length.
187 static gint alignOffset(gint offset, guint fieldLength)
189 gint remainder = offset % fieldLength;
192 offset += fieldLength - remainder;
197 /* Parse a field consisting of a specified number of bytes. This field parser
198 * doesn't perform any alignment.
200 gint parseField_Bytes(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
202 proto_tree_add_text(tree, tvb, offset, numBytes, "%s (%d bytes)",
203 parserNode.fieldLabel, numBytes);
208 /* Parse a bitmask field.
210 gint parseField_Bitmask(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
212 DIS_BitMask *bitMask = 0;
215 offset = alignOffset(offset, numBytes);
220 uintVal = tvb_get_guint8(tvb, offset);
223 uintVal = tvb_get_ntohs(tvb, offset);
226 uintVal = tvb_get_ntohl(tvb, offset);
229 uintVal = tvb_get_ntoh64(tvb, offset);
236 switch(parserNode.fieldType)
238 case DIS_FIELDTYPE_APPEARANCE:
239 if ((entityKind == DIS_ENTITYKIND_PLATFORM) &&
240 (entityDomain == DIS_DOMAIN_LAND))
242 bitMask = DIS_APPEARANCE_LANDPLATFORM;
244 else if (entityKind == DIS_ENTITYKIND_LIFE_FORM)
246 bitMask = DIS_APPEARANCE_LIFEFORM;
256 while (bitMask[maskIndex].maskBits != 0)
259 DIS_BitMaskMapping *bitMaskMap = bitMask[maskIndex].bitMappings;
261 while (bitMaskMap[mapIndex].label != 0)
263 if (((bitMask[maskIndex].maskBits & uintVal) >> bitMask[maskIndex].shiftBits) ==
264 bitMaskMap[mapIndex].value)
266 proto_tree_add_text(tree, tvb, offset, numBytes,
267 "%s = %s", bitMask[maskIndex].label,
268 bitMaskMap[mapIndex].label);
278 proto_tree_add_text(tree, tvb, offset, numBytes,
279 "Unknown Appearance Type (%" G_GINT64_MODIFIER "u)", uintVal);
287 /* Parse an unsigned integer field of a specified number of bytes.
289 gint parseField_UInt(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
293 offset = alignOffset(offset, numBytes);
298 uintVal = tvb_get_guint8(tvb, offset);
301 uintVal = tvb_get_ntohs(tvb, offset);
304 uintVal = tvb_get_ntohl(tvb, offset);
307 uintVal = tvb_get_ntoh64(tvb, offset);
314 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" G_GINT64_MODIFIER "u",
315 parserNode.fieldLabel, uintVal);
317 if (parserNode.outputVar != 0)
319 *(parserNode.outputVar) = (guint32)uintVal;
327 /* Parse a signed integer field of a specified number of bytes.
329 gint parseField_Int(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
333 offset = alignOffset(offset, numBytes);
338 uintVal = tvb_get_guint8(tvb, offset);
341 uintVal = tvb_get_ntohs(tvb, offset);
344 uintVal = tvb_get_ntohl(tvb, offset);
347 uintVal = tvb_get_ntoh64(tvb, offset);
354 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" G_GINT64_MODIFIER "d",
355 parserNode.fieldLabel, uintVal);
362 /* Parse a field that explicitly specified a number of pad bytes (vs implicit
363 * padding, which occurs whenever padding is inserted to properly align the
366 gint parseField_Pad(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode _U_, guint numBytes)
368 proto_tree_add_text(tree, tvb, offset, numBytes,
369 "Explicit Padding (%d bytes)", numBytes);
376 /* Parse an enumerated type field.
378 gint parseField_Enum(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
380 const value_string *enumStrings = 0;
382 const gchar *enumStr = 0;
384 offset = alignOffset(offset, numBytes);
386 switch(parserNode.fieldType)
388 case DIS_FIELDTYPE_PROTOCOL_VERSION:
389 enumStrings = DIS_PDU_ProtocolVersion_Strings;
391 case DIS_FIELDTYPE_PROTOCOL_FAMILY:
392 enumStrings = DIS_PDU_ProtocolFamily_Strings;
394 case DIS_FIELDTYPE_PDU_TYPE:
395 enumStrings = DIS_PDU_Type_Strings;
397 case DIS_FIELDTYPE_ENTITY_KIND:
398 enumStrings = DIS_PDU_EntityKind_Strings;
400 case DIS_FIELDTYPE_DOMAIN:
401 enumStrings = DIS_PDU_Domain_Strings;
403 case DIS_FIELDTYPE_DETONATION_RESULT:
404 enumStrings = DIS_PDU_DetonationResult_Strings;
406 case DIS_FIELDTYPE_CATEGORY:
407 if (entityKind == DIS_ENTITYKIND_PLATFORM)
411 case DIS_DOMAIN_LAND:
412 enumStrings = DIS_PDU_Category_LandPlatform_Strings;
415 enumStrings = DIS_PDU_Category_AirPlatform_Strings;
417 case DIS_DOMAIN_SURFACE:
418 enumStrings = DIS_PDU_Category_SurfacePlatform_Strings;
420 case DIS_DOMAIN_SUBSURFACE:
421 enumStrings = DIS_PDU_Category_SubsurfacePlatform_Strings;
423 case DIS_DOMAIN_SPACE:
424 enumStrings = DIS_PDU_Category_SpacePlatform_Strings;
440 enumVal = tvb_get_guint8(tvb, offset);
443 enumVal = tvb_get_ntohs(tvb, offset);
446 enumVal = tvb_get_ntohl(tvb, offset);
453 if (enumStrings != 0)
455 enumStr = val_to_str(enumVal, enumStrings, "Unknown Enum Value");
459 enumStr = "Unknown Enum Type";
462 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %s",
463 parserNode.fieldLabel, enumStr);
465 if (parserNode.outputVar != 0)
467 *(parserNode.outputVar) = enumVal;
475 /* Parse a 4-byte floating-point value.
477 gint parseField_Float(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
481 offset = alignOffset(offset, 4);
482 floatVal = tvb_get_ntohieee_float(tvb, offset);
483 proto_tree_add_text(tree, tvb, offset, 4, "%s = %f",
484 parserNode.fieldLabel, floatVal);
491 /* Parse an 8-byte floating-point value.
493 gint parseField_Double(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
497 offset = alignOffset(offset, 8);
498 doubleVal = tvb_get_ntohieee_double(tvb, offset);
499 proto_tree_add_text(tree, tvb, offset, 8, "%s = %lf",
500 parserNode.fieldLabel, doubleVal);
507 /* Parse the Timestamp */
508 gint parseField_Timestamp(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
511 static double MSEC_PER_SECOND = 1000.0;
512 static double MSEC_PER_MINUTE = 60.0 * 1000.0 ;
513 static double MSEC_PER_HOUR = 60.0 * 60.0 * 1000.0;
514 static double FSV = 0x7fffffff;
516 guint isAbsolute = 0;
523 offset = alignOffset(offset, 4);
525 /* convert to host value */
526 uintVal = tvb_get_ntohl(tvb, offset);
527 /* determine absolute vis sim time */
531 /* convert TS to MS */
532 ms = (uintVal >> 1) * MSEC_PER_HOUR / FSV;
535 /* calc minutes and reduce ms */
536 minutes = (guint) (ms / MSEC_PER_MINUTE);
537 ms -= (minutes * MSEC_PER_MINUTE);
539 /* calc seconds and reduce ms */
540 seconds = (guint) (ms / MSEC_PER_SECOND);
541 ms -= (seconds * MSEC_PER_SECOND);
543 /* truncate milliseconds */
544 milliseconds = (guint) ms;
546 /* push out the values */
549 proto_tree_add_text(tree, tvb, offset, 4, "%s = %02d:%02d %03d absolute (UTM)",
550 parserNode.fieldLabel, minutes, seconds, milliseconds);
554 proto_tree_add_text(tree, tvb, offset, 4, "%s = %02d:%02d %03d relative",
555 parserNode.fieldLabel, minutes, seconds, milliseconds);