Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-dis-fields.c
1 /* packet-dis-fields.c
2  * Routines and definitions for DIS field parsing.
3  * Copyright 2005, Scientific Research Corporation
4  * Initial implementation by Jeremy Ouellette <jouellet@scires.com>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  *
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.
16  *
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.
21  *
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <string.h>
32 #include <epan/packet.h>
33 #include "packet-dis-fields.h"
34 #include "packet-dis-enums.h"
35
36 guint32 pduType;
37 guint32 entityKind;
38 guint32 entityDomain;
39
40 DIS_ParserNode DIS_FIELDS_PDU_HEADER[] =
41 {
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 }
50 };
51
52 DIS_ParserNode DIS_FIELDS_ENTITY_ID[] =
53 {
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 }
58 };
59
60 DIS_ParserNode DIS_FIELDS_ENTITY_TYPE[] =
61 {
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 }
70 };
71
72 DIS_ParserNode DIS_FIELDS_EVENT_ID[] =
73 {
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 }
78 };
79
80 DIS_ParserNode DIS_FIELDS_LINEAR_VELOCITY[] =
81 {
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 }
86 };
87
88 DIS_ParserNode DIS_FIELDS_LOCATION_WORLD[] =
89 {
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 }
94 };
95
96 DIS_ParserNode DIS_FIELDS_LOCATION_ENTITY[] =
97 {
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 }
102 };
103
104 DIS_ParserNode DIS_FIELDS_ORIENTATION[] =
105 {
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 }
110 };
111
112 DIS_ParserNode DIS_FIELDS_BURST_DESCRIPTOR[] =
113 {
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 }
120 };
121
122 DIS_ParserNode DIS_FIELDS_ARTICULATION_PARAMETER[] =
123 {
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 }
130 };
131
132 DIS_ParserNode DIS_FIELDS_NONE[] =
133 {
134     { DIS_FIELDTYPE_END, NULL, 0,0,0 }
135 };
136
137 DIS_BitMask DIS_APPEARANCE_LANDPLATFORM[] =
138 {
139     { 0x00000001, 0, "Paint Scheme", {
140         { 0, "Uniform color" },
141         { 1, "Camouflage" },
142         { 0,0 }
143     } },
144     { 0x00000002, 1, "Mobility", {
145         { 0, "No mobility kill" },
146         { 1, "Mobility kill" },
147         { 0,0 }
148     } },
149     { 0x00000004, 2, "Fire Power", {
150         { 0, "No fire-power kill" },
151         { 1, "Fire-power kill" },
152         { 0,0 }
153     } },
154     { 0x00000018, 3, "Damage", {
155         { 0, "No damage" },
156         { 1, "Slight damage" },
157         { 2, "Moderate damage" },
158         { 3, "Destroyed" },
159         { 0,0 }
160     } },
161     { 0, 0, 0, {
162         { 0, 0 }
163     } }
164 };
165
166 DIS_BitMask DIS_APPEARANCE_LIFEFORM[] =
167 {
168     { 0x00000001, 0, "Paint Scheme", {
169         { 0, "Uniform color" },
170         { 1, "Camouflage" },
171         { 0,0 }
172     } },
173     { 0x00000018, 3, "Health", {
174         { 0, "No injury" },
175         { 1, "Slight injury" },
176         { 2, "Moderate injury" },
177         { 3, "Fatal injury" },
178         { 0,0 }
179     } },
180     { 0, 0, 0, {
181         { 0, 0 }
182     } }
183 };
184
185 /* Adjust an offset variable for proper alignment for a specified field length.
186  */
187 static gint alignOffset(gint offset, guint fieldLength)
188 {
189     gint remainder = offset % fieldLength;
190     if (remainder != 0)
191     {
192         offset += fieldLength - remainder;
193     }
194     return offset;
195 }
196
197 /* Parse a field consisting of a specified number of bytes.  This field parser
198  * doesn't perform any alignment.
199  */
200 gint parseField_Bytes(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
201 {
202     proto_tree_add_text(tree, tvb, offset, numBytes, "%s (%d bytes)",
203         parserNode.fieldLabel, numBytes);
204     offset += numBytes;
205     return offset;
206 }
207
208 /* Parse a bitmask field.
209  */
210 gint parseField_Bitmask(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
211 {
212     DIS_BitMask *bitMask = 0;
213     guint64 uintVal = 0;
214
215     offset = alignOffset(offset, numBytes);
216
217     switch(numBytes)
218     {
219     case 1:
220         uintVal = tvb_get_guint8(tvb, offset);
221         break;
222     case 2:
223         uintVal = tvb_get_ntohs(tvb, offset);
224         break;
225     case 4:
226         uintVal = tvb_get_ntohl(tvb, offset);
227         break;
228     case 8:
229         uintVal = tvb_get_ntoh64(tvb, offset);
230         break;
231     default:
232         /* assert */
233         break;
234     }
235
236     switch(parserNode.fieldType)
237     {
238     case DIS_FIELDTYPE_APPEARANCE:
239         if ((entityKind == DIS_ENTITYKIND_PLATFORM) &&
240             (entityDomain == DIS_DOMAIN_LAND))
241         {
242             bitMask = DIS_APPEARANCE_LANDPLATFORM;
243         }
244         else if (entityKind == DIS_ENTITYKIND_LIFE_FORM)
245         {
246             bitMask = DIS_APPEARANCE_LIFEFORM;
247         }
248         break;
249     default:
250         break;
251     }
252
253     if (bitMask != 0)
254     {
255         int maskIndex = 0;
256         while (bitMask[maskIndex].maskBits != 0)
257         {
258             int mapIndex = 0;
259             DIS_BitMaskMapping *bitMaskMap = bitMask[maskIndex].bitMappings;
260
261             while (bitMaskMap[mapIndex].label != 0)
262             {
263                 if (((bitMask[maskIndex].maskBits & uintVal) >> bitMask[maskIndex].shiftBits) ==
264                     bitMaskMap[mapIndex].value)
265                 {
266                     proto_tree_add_text(tree, tvb, offset, numBytes,
267                         "%s = %s", bitMask[maskIndex].label,
268                         bitMaskMap[mapIndex].label);
269                     break;
270                 }
271                 ++mapIndex;
272             }
273             ++maskIndex;
274         }
275     }
276     else
277     {
278         proto_tree_add_text(tree, tvb, offset, numBytes,
279             "Unknown Appearance Type (%" PRIu64 ")", uintVal);
280     }
281
282     offset += numBytes;
283
284     return offset;
285 }
286
287 /* Parse an unsigned integer field of a specified number of bytes.
288  */
289 gint parseField_UInt(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
290 {
291     guint64 uintVal = 0;
292
293     offset = alignOffset(offset, numBytes);
294
295     switch(numBytes)
296     {
297     case 1:
298         uintVal = tvb_get_guint8(tvb, offset);
299         break;
300     case 2:
301         uintVal = tvb_get_ntohs(tvb, offset);
302         break;
303     case 4:
304         uintVal = tvb_get_ntohl(tvb, offset);
305         break;
306     case 8:
307         uintVal = tvb_get_ntoh64(tvb, offset);
308         break;
309     default:
310         /* assert */
311         break;
312     }
313
314     proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" PRIu64,
315         parserNode.fieldLabel, uintVal);
316
317     if (parserNode.outputVar != 0)
318     {
319         *(parserNode.outputVar) = (guint32)uintVal;
320     }
321
322     offset += numBytes;
323
324     return offset;
325 }
326
327 /* Parse a signed integer field of a specified number of bytes.
328  */
329 gint parseField_Int(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
330 {
331     guint64 uintVal = 0;
332
333     offset = alignOffset(offset, numBytes);
334
335     switch(numBytes)
336     {
337     case 1:
338         uintVal = tvb_get_guint8(tvb, offset);
339         break;
340     case 2:
341         uintVal = tvb_get_ntohs(tvb, offset);
342         break;
343     case 4:
344         uintVal = tvb_get_ntohl(tvb, offset);
345         break;
346     case 8:
347         uintVal = tvb_get_ntoh64(tvb, offset);
348         break;
349     default:
350         /* assert */
351         break;
352     }
353
354     proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %" PRId64,
355         parserNode.fieldLabel, uintVal);
356
357     offset += numBytes;
358
359     return offset;
360 }
361
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
364  * field.
365  */
366 gint parseField_Pad(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
367 {
368     proto_tree_add_text(tree, tvb, offset, numBytes,
369         "Explicit Padding (%d bytes)", numBytes);
370
371     offset += numBytes;
372
373     return offset;
374 }
375
376 /* Parse an enumerated type field.
377  */
378 gint parseField_Enum(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode, guint numBytes)
379 {
380     const value_string *enumStrings = 0;
381     guint32 enumVal = 0;
382     const gchar *enumStr = 0;
383
384     offset = alignOffset(offset, numBytes);
385
386     switch(parserNode.fieldType)
387     {
388     case DIS_FIELDTYPE_PROTOCOL_VERSION:
389         enumStrings = DIS_PDU_ProtocolVersion_Strings;
390         break;
391     case DIS_FIELDTYPE_PROTOCOL_FAMILY:
392         enumStrings = DIS_PDU_ProtocolFamily_Strings;
393         break;
394     case DIS_FIELDTYPE_PDU_TYPE:
395         enumStrings = DIS_PDU_Type_Strings;
396         break;
397     case DIS_FIELDTYPE_ENTITY_KIND:
398         enumStrings = DIS_PDU_EntityKind_Strings;
399         break;
400     case DIS_FIELDTYPE_DOMAIN:
401         enumStrings = DIS_PDU_Domain_Strings;
402         break;
403     case DIS_FIELDTYPE_DETONATION_RESULT:
404         enumStrings = DIS_PDU_DetonationResult_Strings;
405         break;
406     case DIS_FIELDTYPE_CATEGORY:
407         if (entityKind == DIS_ENTITYKIND_PLATFORM)
408         {
409             switch(entityDomain)
410             {
411             case DIS_DOMAIN_LAND:
412                 enumStrings = DIS_PDU_Category_LandPlatform_Strings;
413                 break;
414             case DIS_DOMAIN_AIR:
415                 enumStrings = DIS_PDU_Category_AirPlatform_Strings;
416                 break;
417             case DIS_DOMAIN_SURFACE:
418                 enumStrings = DIS_PDU_Category_SurfacePlatform_Strings;
419                 break;
420             case DIS_DOMAIN_SUBSURFACE:
421                 enumStrings = DIS_PDU_Category_SubsurfacePlatform_Strings;
422                 break;
423             case DIS_DOMAIN_SPACE:
424                 enumStrings = DIS_PDU_Category_SpacePlatform_Strings;
425                 break;
426             default:
427                 enumStrings = 0;
428                 break;
429             }
430         }
431         break;
432     default:
433         enumStrings = 0;
434         break; 
435     }
436
437     switch(numBytes)
438     {
439     case 1:
440         enumVal = tvb_get_guint8(tvb, offset);
441         break;
442     case 2:
443         enumVal = tvb_get_ntohs(tvb, offset);
444         break;
445     case 4:
446         enumVal = tvb_get_ntohl(tvb, offset);
447         break;
448     default:
449         /* assert */
450         break;
451     }
452
453     if (enumStrings != 0)
454     {
455         enumStr = val_to_str(enumVal, enumStrings, "Unknown Enum Value");
456     }
457     else
458     {
459         enumStr = "Unknown Enum Type";
460     }
461
462     proto_tree_add_text(tree, tvb, offset, numBytes, "%s = %s",
463         parserNode.fieldLabel, enumStr);
464
465     if (parserNode.outputVar != 0)
466     {
467         *(parserNode.outputVar) = enumVal;
468     }
469
470     offset += numBytes;
471
472     return offset;
473 }
474
475 /* Parse a 4-byte floating-point value.
476  */
477 gint parseField_Float(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
478 {
479     gfloat floatVal;
480
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);
485
486     offset += 4;
487
488     return offset;
489 }
490
491 /* Parse an 8-byte floating-point value.
492  */
493 gint parseField_Double(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNode)
494 {
495     gdouble doubleVal;
496
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);
501
502     offset += 8;
503
504     return offset;
505 }