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"
39 guint32 variableDatumLength;
41 DIS_ParserNode DIS_FIELDS_PDU_HEADER[] =
43 { DIS_FIELDTYPE_PROTOCOL_VERSION, "Protocol Version",0,0,0 },
44 { DIS_FIELDTYPE_UINT8, "Exercise ID",0,0,0 },
45 { DIS_FIELDTYPE_PDU_TYPE, "PDU Type",0,0,&pduType },
46 { DIS_FIELDTYPE_PROTOCOL_FAMILY, "Protocol Family",0,0,0 },
47 { DIS_FIELDTYPE_TIMESTAMP, "Timestamp",0,0,0 },
48 { DIS_FIELDTYPE_UINT16, "Length",0,0,0 },
49 { DIS_FIELDTYPE_PAD16, "Padding",0,0,0 },
50 { DIS_FIELDTYPE_END, NULL,0,0,0 }
53 DIS_ParserNode DIS_FIELDS_ENTITY_ID[] =
55 { DIS_FIELDTYPE_UINT16, "Site",0,0,0 },
56 { DIS_FIELDTYPE_UINT16, "Application",0,0,0 },
57 { DIS_FIELDTYPE_UINT16, "Entity",0,0,0 },
58 { DIS_FIELDTYPE_END, NULL,0,0,0 }
61 DIS_ParserNode DIS_FIELDS_ENTITY_TYPE[] =
63 { DIS_FIELDTYPE_ENTITY_KIND, "Entity Kind",0,0,&entityKind },
64 { DIS_FIELDTYPE_DOMAIN, "Domain",0,0,&entityDomain },
65 { DIS_FIELDTYPE_COUNTRY, "Country",0,0,0 },
66 { DIS_FIELDTYPE_CATEGORY, "Category",0,0,0 },
67 { DIS_FIELDTYPE_SUBCATEGORY, "Subcategory",0,0,0 },
68 { DIS_FIELDTYPE_SPECIFIC, "Specific",0,0,0 },
69 { DIS_FIELDTYPE_EXTRA, "Extra",0,0,0 },
70 { DIS_FIELDTYPE_END, NULL,0,0,0 }
73 DIS_ParserNode DIS_FIELDS_EVENT_ID[] =
75 { DIS_FIELDTYPE_UINT16, "Site",0,0,0 },
76 { DIS_FIELDTYPE_UINT16, "Application",0,0,0 },
77 { DIS_FIELDTYPE_UINT16, "Event Number",0,0,0 },
78 { DIS_FIELDTYPE_END, NULL,0,0,0 }
81 DIS_ParserNode DIS_FIELDS_LINEAR_VELOCITY[] =
83 { DIS_FIELDTYPE_FLOAT32, "X",0,0,0 },
84 { DIS_FIELDTYPE_FLOAT32, "Y",0,0,0 },
85 { DIS_FIELDTYPE_FLOAT32, "Z",0,0,0 },
86 { DIS_FIELDTYPE_END, NULL,0,0,0 }
89 DIS_ParserNode DIS_FIELDS_LOCATION_WORLD[] =
91 { DIS_FIELDTYPE_FLOAT64, "X",0,0,0 },
92 { DIS_FIELDTYPE_FLOAT64, "Y",0,0,0 },
93 { DIS_FIELDTYPE_FLOAT64, "Z",0,0,0 },
94 { DIS_FIELDTYPE_END, NULL,0,0,0 }
97 DIS_ParserNode DIS_FIELDS_LOCATION_ENTITY[] =
99 { DIS_FIELDTYPE_FLOAT32, "X",0,0,0 },
100 { DIS_FIELDTYPE_FLOAT32, "Y",0,0,0 },
101 { DIS_FIELDTYPE_FLOAT32, "Z",0,0,0 },
102 { DIS_FIELDTYPE_END, NULL,0,0,0 }
105 DIS_ParserNode DIS_FIELDS_ORIENTATION[] =
107 { DIS_FIELDTYPE_FLOAT32, "Psi",0,0,0 },
108 { DIS_FIELDTYPE_FLOAT32, "Theta",0,0,0 },
109 { DIS_FIELDTYPE_FLOAT32, "Phi",0,0,0 },
110 { DIS_FIELDTYPE_END, NULL,0,0,0 }
113 DIS_ParserNode DIS_FIELDS_BURST_DESCRIPTOR[] =
115 { DIS_FIELDTYPE_ENTITY_TYPE, "Munition",0,0,0 },
116 { DIS_FIELDTYPE_WARHEAD, "Warhead",0,0,0 },
117 { DIS_FIELDTYPE_FUSE, "Fuse",0,0,0 },
118 { DIS_FIELDTYPE_UINT16, "Quantity",0,0,0 },
119 { DIS_FIELDTYPE_UINT16, "Rate",0,0,0 },
120 { DIS_FIELDTYPE_END, NULL,0,0,0 }
123 DIS_ParserNode DIS_FIELDS_ARTICULATION_PARAMETER[] =
125 { DIS_FIELDTYPE_ARTIC_PARAM_TYPE_DESIGNATOR, "Parameter Type Designator",0,0,0 },
126 { DIS_FIELDTYPE_UINT8, "Change",0,0,0 },
127 { DIS_FIELDTYPE_UINT16, "Part Attached To ID",0,0,0 },
128 { DIS_FIELDTYPE_ARTIC_PARAM_TYPE, "Parameter Type",0,0,0 },
129 { DIS_FIELDTYPE_UINT64, "Parameter Value",0,0,0 },
130 { DIS_FIELDTYPE_END, NULL,0,0,0 }
133 DIS_ParserNode DIS_FIELDS_NONE[] =
135 { DIS_FIELDTYPE_END, NULL, 0,0,0 }
138 DIS_ParserNode DIS_FIELDS_FIXED_DATUM[] =
140 { DIS_FIELDTYPE_DATUM_ID, "Datum ID",0,0,0 },
141 { DIS_FIELDTYPE_FIXED_DATUM_VALUE, "Datum value",0,0,0 },
142 { DIS_FIELDTYPE_END, NULL,0,0,0 }
145 DIS_ParserNode DIS_FIELDS_VARIABLE_DATUM[] =
147 { DIS_FIELDTYPE_DATUM_ID, "Datum ID",0,0,0 },
148 { DIS_FIELDTYPE_DATUM_LENGTH, "Datum length",0,0,&variableDatumLength },
149 { DIS_FIELDTYPE_VARIABLE_DATUM_VALUE, "Datum value",0,0,0 },
150 { DIS_FIELDTYPE_END, NULL,0,0,0 }
153 DIS_BitMask DIS_APPEARANCE_LANDPLATFORM[] =
155 { 0x00000001, 0, "Paint Scheme", {
156 { 0, "Uniform color" },
160 { 0x00000002, 1, "Mobility", {
161 { 0, "No mobility kill" },
162 { 1, "Mobility kill" },
165 { 0x00000004, 2, "Fire Power", {
166 { 0, "No fire-power kill" },
167 { 1, "Fire-power kill" },
170 { 0x00000018, 3, "Damage", {
172 { 1, "Slight damage" },
173 { 2, "Moderate damage" },
182 DIS_BitMask DIS_APPEARANCE_LIFEFORM[] =
184 { 0x00000001, 0, "Paint Scheme", {
185 { 0, "Uniform color" },
189 { 0x00000018, 3, "Health", {
191 { 1, "Slight injury" },
192 { 2, "Moderate injury" },
193 { 3, "Fatal injury" },
201 /* Adjust an offset variable for proper alignment for a specified field length.
203 static gint alignOffset(gint offset, guint fieldLength)
205 gint remainder = offset % fieldLength;
208 offset += fieldLength - remainder;
213 /* Parse a field consisting of a specified number of bytes. This field parser
214 * doesn't perform any alignment.
216 gint parseField_Bytes(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
218 proto_tree_add_text(tree, tvb, offset, numBytes, "%s (%d bytes)",
219 parserNode.fieldLabel, numBytes);
224 /* Parse a bitmask field.
226 gint parseField_Bitmask(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
228 DIS_BitMask *bitMask = 0;
231 offset = alignOffset(offset, numBytes);
236 uintVal = tvb_get_guint8(tvb, offset);
239 uintVal = tvb_get_ntohs(tvb, offset);
242 uintVal = tvb_get_ntohl(tvb, offset);
245 uintVal = tvb_get_ntoh64(tvb, offset);
252 switch(parserNode.fieldType)
254 case DIS_FIELDTYPE_APPEARANCE:
255 if ((entityKind == DIS_ENTITYKIND_PLATFORM) &&
256 (entityDomain == DIS_DOMAIN_LAND))
258 bitMask = DIS_APPEARANCE_LANDPLATFORM;
260 else if (entityKind == DIS_ENTITYKIND_LIFE_FORM)
262 bitMask = DIS_APPEARANCE_LIFEFORM;
272 while (bitMask[maskIndex].maskBits != 0)
275 DIS_BitMaskMapping *bitMaskMap = bitMask[maskIndex].bitMappings;
277 while (bitMaskMap[mapIndex].label != 0)
279 if (((bitMask[maskIndex].maskBits & uintVal) >> bitMask[maskIndex].shiftBits) ==
280 bitMaskMap[mapIndex].value)
282 proto_tree_add_text(tree, tvb, offset, numBytes,
283 "%s = %s", bitMask[maskIndex].label,
284 bitMaskMap[mapIndex].label);
294 proto_tree_add_text(tree, tvb, offset, numBytes,
295 "Unknown Appearance Type (%" G_GINT64_MODIFIER "u)", uintVal);
303 /* Parse an unsigned integer field of a specified number of bytes.
305 gint parseField_UInt(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
309 offset = alignOffset(offset, numBytes);
314 uintVal = tvb_get_guint8(tvb, offset);
317 uintVal = tvb_get_ntohs(tvb, offset);
320 uintVal = tvb_get_ntohl(tvb, offset);
323 uintVal = tvb_get_ntoh64(tvb, offset);
330 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" G_GINT64_MODIFIER "u",
331 parserNode.fieldLabel, uintVal);
333 if (parserNode.outputVar != 0)
335 *(parserNode.outputVar) = (guint32)uintVal;
343 /* Parse a signed integer field of a specified number of bytes.
345 gint parseField_Int(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
349 offset = alignOffset(offset, numBytes);
354 uintVal = tvb_get_guint8(tvb, offset);
357 uintVal = tvb_get_ntohs(tvb, offset);
360 uintVal = tvb_get_ntohl(tvb, offset);
363 uintVal = tvb_get_ntoh64(tvb, offset);
370 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" G_GINT64_MODIFIER "d",
371 parserNode.fieldLabel, uintVal);
378 /* Parse a field that explicitly specified a number of pad bytes (vs implicit
379 * padding, which occurs whenever padding is inserted to properly align the
382 gint parseField_Pad(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode _U_, guint numBytes)
384 proto_tree_add_text(tree, tvb, offset, numBytes,
385 "Explicit Padding (%d bytes)", numBytes);
392 /* Parse an enumerated type field.
394 gint parseField_Enum(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
396 const value_string *enumStrings = 0;
398 const gchar *enumStr = 0;
400 offset = alignOffset(offset, numBytes);
402 switch(parserNode.fieldType)
404 case DIS_FIELDTYPE_PROTOCOL_VERSION:
405 enumStrings = DIS_PDU_ProtocolVersion_Strings;
407 case DIS_FIELDTYPE_PROTOCOL_FAMILY:
408 enumStrings = DIS_PDU_ProtocolFamily_Strings;
410 case DIS_FIELDTYPE_PDU_TYPE:
411 enumStrings = DIS_PDU_Type_Strings;
413 case DIS_FIELDTYPE_ENTITY_KIND:
414 enumStrings = DIS_PDU_EntityKind_Strings;
416 case DIS_FIELDTYPE_DOMAIN:
417 enumStrings = DIS_PDU_Domain_Strings;
419 case DIS_FIELDTYPE_DETONATION_RESULT:
420 enumStrings = DIS_PDU_DetonationResult_Strings;
422 case DIS_FIELDTYPE_CATEGORY:
423 if (entityKind == DIS_ENTITYKIND_PLATFORM)
427 case DIS_DOMAIN_LAND:
428 enumStrings = DIS_PDU_Category_LandPlatform_Strings;
431 enumStrings = DIS_PDU_Category_AirPlatform_Strings;
433 case DIS_DOMAIN_SURFACE:
434 enumStrings = DIS_PDU_Category_SurfacePlatform_Strings;
436 case DIS_DOMAIN_SUBSURFACE:
437 enumStrings = DIS_PDU_Category_SubsurfacePlatform_Strings;
439 case DIS_DOMAIN_SPACE:
440 enumStrings = DIS_PDU_Category_SpacePlatform_Strings;
456 enumVal = tvb_get_guint8(tvb, offset);
459 enumVal = tvb_get_ntohs(tvb, offset);
462 enumVal = tvb_get_ntohl(tvb, offset);
469 if (enumStrings != 0)
471 enumStr = val_to_str(enumVal, enumStrings, "Unknown Enum Value");
475 enumStr = "Unknown Enum Type";
478 proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %s",
479 parserNode.fieldLabel, enumStr);
481 if (parserNode.outputVar != 0)
483 *(parserNode.outputVar) = enumVal;
491 /* Parse a 4-byte floating-point value.
493 gint parseField_Float(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
497 offset = alignOffset(offset, 4);
498 floatVal = tvb_get_ntohieee_float(tvb, offset);
499 proto_tree_add_text(tree, tvb, offset, 4, "%s = %f",
500 parserNode.fieldLabel, floatVal);
507 /* Parse an 8-byte floating-point value.
509 gint parseField_Double(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
513 offset = alignOffset(offset, 8);
514 doubleVal = tvb_get_ntohieee_double(tvb, offset);
515 proto_tree_add_text(tree, tvb, offset, 8, "%s = %lf",
516 parserNode.fieldLabel, doubleVal);
523 /* Parse the Timestamp */
524 gint parseField_Timestamp(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
527 static double MSEC_PER_SECOND = 1000.0;
528 static double MSEC_PER_MINUTE = 60.0 * 1000.0 ;
529 static double MSEC_PER_HOUR = 60.0 * 60.0 * 1000.0;
530 static double FSV = 0x7fffffff;
532 guint isAbsolute = 0;
539 offset = alignOffset(offset, 4);
541 /* convert to host value */
542 uintVal = tvb_get_ntohl(tvb, offset);
543 /* determine absolute vis sim time */
547 /* convert TS to MS */
548 ms = (uintVal >> 1) * MSEC_PER_HOUR / FSV;
551 /* calc minutes and reduce ms */
552 minutes = (guint) (ms / MSEC_PER_MINUTE);
553 ms -= (minutes * MSEC_PER_MINUTE);
555 /* calc seconds and reduce ms */
556 seconds = (guint) (ms / MSEC_PER_SECOND);
557 ms -= (seconds * MSEC_PER_SECOND);
559 /* truncate milliseconds */
560 milliseconds = (guint) ms;
562 /* push out the values */
565 proto_tree_add_text(tree, tvb, offset, 4, "%s = %02d:%02d %03d absolute (UTM)",
566 parserNode.fieldLabel, minutes, seconds, milliseconds);
570 proto_tree_add_text(tree, tvb, offset, 4, "%s = %02d:%02d %03d relative",
571 parserNode.fieldLabel, minutes, seconds, milliseconds);