feab79e328
svn path=/trunk/; revision=18196
404 lines
15 KiB
C
404 lines
15 KiB
C
/* packet-dis-pdus.c
|
|
* Routines and definitions for DIS PDU parsing.
|
|
* Copyright 2005, Scientific Research Corporation
|
|
* Initial implementation by Jeremy Ouellette <jouellet@scires.com>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <string.h>
|
|
#include "packet-dis-pdus.h"
|
|
#include "packet-dis-fields.h"
|
|
|
|
guint32 numArticulations;
|
|
gint ettArticulations[DIS_PDU_MAX_ARTICULATIONS];
|
|
|
|
DIS_ParserNode DIS_PARSER_ENTITY_STATE_PDU[] =
|
|
{
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Entity ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_FORCE_ID, "Force ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_UINT8, "Number of Articulation Parameters",0,0,&numArticulations },
|
|
{ DIS_FIELDTYPE_ENTITY_TYPE, "Entity Type",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_TYPE, "Alternative Entity Type",0,0,0 },
|
|
{ DIS_FIELDTYPE_LINEAR_VELOCITY, "Entity Linear Velocity",0,0,0 },
|
|
{ DIS_FIELDTYPE_LOCATION_WORLD, "Entity Location",0,0,0 },
|
|
{ DIS_FIELDTYPE_ORIENTATION, "Entity Orientation",0,0,0 },
|
|
{ DIS_FIELDTYPE_APPEARANCE, "Entity Appearance",0,0,0 },
|
|
{ DIS_FIELDTYPE_DEAD_RECKONING_PARAMS, "Dead Reckoning Parameters",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_MARKING, "Entity Marking",0,0,0 },
|
|
{ DIS_FIELDTYPE_CAPABILITIES, "Capabilities",0,0,0 },
|
|
{ DIS_FIELDTYPE_ARTICULATION_PARAMETERS, "Articulation Parameters",0,0,0 },
|
|
{ DIS_FIELDTYPE_END, NULL,0,0,0 }
|
|
};
|
|
|
|
DIS_ParserNode DIS_PARSER_FIRE_PDU[] =
|
|
{
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Firing Entity ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Target Entity ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Munition ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_EVENT_ID, "Event ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_UINT32, "Fire Mission Index",0,0,0 },
|
|
{ DIS_FIELDTYPE_LOCATION_WORLD, "Location in World Coordinates",0,0,0 },
|
|
{ DIS_FIELDTYPE_BURST_DESCRIPTOR, "Burst Descriptor",0,0,0 },
|
|
{ DIS_FIELDTYPE_LINEAR_VELOCITY, "Velocity",0,0,0 },
|
|
{ DIS_FIELDTYPE_FLOAT32, "Range",0,0,0 },
|
|
{ DIS_FIELDTYPE_END, NULL,0,0,0 }
|
|
};
|
|
|
|
DIS_ParserNode DIS_PARSER_DETONATION_PDU[] =
|
|
{
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Firing Entity ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Target Entity ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_ENTITY_ID, "Munition ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_EVENT_ID, "Event ID",0,0,0 },
|
|
{ DIS_FIELDTYPE_LINEAR_VELOCITY, "Velocity",0,0,0 },
|
|
{ DIS_FIELDTYPE_LOCATION_WORLD, "Location in World Coordinates",0,0,0 },
|
|
{ DIS_FIELDTYPE_BURST_DESCRIPTOR, "Burst Descriptor",0,0,0 },
|
|
{ DIS_FIELDTYPE_LOCATION_ENTITY, "Location in Entity Coordinates",0,0,0 },
|
|
{ DIS_FIELDTYPE_DETONATION_RESULT, "Detonation Result",0,0,0 },
|
|
{ DIS_FIELDTYPE_UINT8, "Number of Articulation Parameters",0,0,0 },
|
|
{ DIS_FIELDTYPE_PAD16, "Padding",0,0,0 },
|
|
{ DIS_FIELDTYPE_ARTICULATION_PARAMETERS, "Articulation Parameters",0,0,0 },
|
|
{ DIS_FIELDTYPE_END, NULL,0,0,0 }
|
|
};
|
|
|
|
/* Initialize the parsers for each PDU type and the standard DIS header.
|
|
*/
|
|
void initializeParsers(void)
|
|
{
|
|
initializeParser(DIS_PARSER_ENTITY_STATE_PDU);
|
|
initializeParser(DIS_PARSER_FIRE_PDU);
|
|
initializeParser(DIS_PARSER_DETONATION_PDU);
|
|
initializeParser(DIS_FIELDS_PDU_HEADER);
|
|
}
|
|
|
|
/* Create a specific subtree for a PDU or a composite PDU field.
|
|
*/
|
|
DIS_ParserNode *createSubtree(DIS_ParserNode parserNodes[], gint *ettVar)
|
|
{
|
|
guint fieldIndex = 0;
|
|
guint fieldCount;
|
|
gint *ett[1];
|
|
DIS_ParserNode *newSubtree;
|
|
|
|
while (parserNodes[fieldIndex].fieldType != DIS_FIELDTYPE_END)
|
|
{
|
|
++fieldIndex;
|
|
}
|
|
|
|
fieldCount = fieldIndex + 1;
|
|
|
|
newSubtree = (DIS_ParserNode*)g_malloc(sizeof(DIS_ParserNode) * fieldCount);
|
|
|
|
memcpy(newSubtree, parserNodes, sizeof(DIS_ParserNode) * fieldCount);
|
|
|
|
initializeParser(newSubtree);
|
|
|
|
ett[0] = ettVar;
|
|
proto_register_subtree_array(ett, array_length(ett));
|
|
|
|
return newSubtree;
|
|
}
|
|
|
|
/* Initialize an array of parser nodes.
|
|
*/
|
|
void initializeParser(DIS_ParserNode parserNodes[])
|
|
{
|
|
guint parserIndex = 0;
|
|
|
|
/* Create the parser subtrees for each of the composite field types.
|
|
*/
|
|
while (parserNodes[parserIndex].fieldType != DIS_FIELDTYPE_END)
|
|
{
|
|
switch (parserNodes[parserIndex].fieldType)
|
|
{
|
|
case DIS_FIELDTYPE_APPEARANCE:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_NONE,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_ARTICULATION_PARAMETERS:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_ARTICULATION_PARAMETER,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_BURST_DESCRIPTOR:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_BURST_DESCRIPTOR,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_ENTITY_ID:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_ENTITY_ID,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_ENTITY_TYPE:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_ENTITY_TYPE,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_EVENT_ID:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_EVENT_ID,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_LINEAR_VELOCITY:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_LINEAR_VELOCITY,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_LOCATION_WORLD:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_LOCATION_WORLD,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_LOCATION_ENTITY:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_LOCATION_ENTITY,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
case DIS_FIELDTYPE_ORIENTATION:
|
|
parserNodes[parserIndex].children = createSubtree(
|
|
DIS_FIELDS_ORIENTATION,
|
|
&parserNodes[parserIndex].ettVar);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
++parserIndex;
|
|
}
|
|
}
|
|
|
|
/* Parse packet data based on a specified array of DIS_ParserNodes.
|
|
*/
|
|
gint parseFields(tvbuff_t *tvb, proto_tree *tree, gint offset, DIS_ParserNode parserNodes[])
|
|
{
|
|
guint fieldIndex = 0;
|
|
|
|
while (parserNodes[fieldIndex].fieldType != DIS_FIELDTYPE_END)
|
|
{
|
|
proto_item *newField = 0;
|
|
switch(parserNodes[fieldIndex].fieldType)
|
|
{
|
|
case DIS_FIELDTYPE_INT8:
|
|
offset = parseField_Int(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_INT16:
|
|
offset = parseField_Int(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_INT32:
|
|
offset = parseField_Int(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_INT64:
|
|
offset = parseField_Int(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 8);
|
|
break;
|
|
case DIS_FIELDTYPE_UINT8:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_UINT16:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_UINT32:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_UINT64:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 8);
|
|
break;
|
|
case DIS_FIELDTYPE_FLOAT32:
|
|
offset = parseField_Float(tvb, tree, offset,
|
|
parserNodes[fieldIndex]);
|
|
break;
|
|
case DIS_FIELDTYPE_FLOAT64:
|
|
offset = parseField_Double(tvb, tree, offset,
|
|
parserNodes[fieldIndex]);
|
|
break;
|
|
case DIS_FIELDTYPE_PAD8:
|
|
offset = parseField_Pad(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_PAD16:
|
|
offset = parseField_Pad(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_PAD32:
|
|
offset = parseField_Pad(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_APPEARANCE:
|
|
{
|
|
proto_item *newSubtree;
|
|
newField = proto_tree_add_text(tree, tvb, offset, 4,
|
|
parserNodes[fieldIndex].fieldLabel);
|
|
newSubtree = proto_item_add_subtree(newField,
|
|
parserNodes[fieldIndex].ettVar);
|
|
offset = parseField_Bitmask(tvb, newSubtree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
}
|
|
break;
|
|
case DIS_FIELDTYPE_ARTIC_PARAM_TYPE_DESIGNATOR:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_ARTIC_PARAM_TYPE:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_CAPABILITIES:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_CATEGORY:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_COUNTRY:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_DEAD_RECKONING_PARAMS:
|
|
/* This is really a struct... needs a field parser.
|
|
* For now, just skip the 12 bytes.
|
|
*/
|
|
offset = parseField_Bytes(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 40);
|
|
break;
|
|
case DIS_FIELDTYPE_DETONATION_RESULT:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_DOMAIN:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_ENTITY_KIND:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_ENTITY_MARKING:
|
|
/* This is really a struct... needs a field parser.
|
|
* For now, just skip the 12 bytes.
|
|
*/
|
|
offset = parseField_Bytes(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 12);
|
|
break;
|
|
case DIS_FIELDTYPE_EXTRA:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_FORCE_ID:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_FUSE:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_PDU_TYPE:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_PROTOCOL_FAMILY:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_PROTOCOL_VERSION:
|
|
offset = parseField_Enum(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_SPECIFIC:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_SUBCATEGORY:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 1);
|
|
break;
|
|
case DIS_FIELDTYPE_TIMESTAMP:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 4);
|
|
break;
|
|
case DIS_FIELDTYPE_WARHEAD:
|
|
offset = parseField_UInt(tvb, tree, offset,
|
|
parserNodes[fieldIndex], 2);
|
|
break;
|
|
case DIS_FIELDTYPE_BURST_DESCRIPTOR:
|
|
case DIS_FIELDTYPE_ENTITY_ID:
|
|
case DIS_FIELDTYPE_EVENT_ID:
|
|
case DIS_FIELDTYPE_LINEAR_VELOCITY:
|
|
case DIS_FIELDTYPE_LOCATION_WORLD:
|
|
case DIS_FIELDTYPE_LOCATION_ENTITY:
|
|
case DIS_FIELDTYPE_ENTITY_TYPE:
|
|
case DIS_FIELDTYPE_ORIENTATION:
|
|
newField = proto_tree_add_text(tree, tvb, offset, -1,
|
|
parserNodes[fieldIndex].fieldLabel);
|
|
if (parserNodes[fieldIndex].children != 0)
|
|
{
|
|
proto_item *newSubtree = proto_item_add_subtree(newField,
|
|
parserNodes[fieldIndex].ettVar);
|
|
offset = parseFields(tvb, newSubtree, offset,
|
|
parserNodes[fieldIndex].children);
|
|
}
|
|
proto_item_set_end(newField, tvb, offset);
|
|
break;
|
|
case DIS_FIELDTYPE_ARTICULATION_PARAMETERS:
|
|
{
|
|
guint i;
|
|
|
|
if (numArticulations > DIS_PDU_MAX_ARTICULATIONS)
|
|
{
|
|
numArticulations = DIS_PDU_MAX_ARTICULATIONS;
|
|
}
|
|
|
|
for (i = 0; i < numArticulations; ++i)
|
|
{
|
|
proto_item *newSubtree;
|
|
newField = proto_tree_add_text(tree, tvb, offset, -1,
|
|
parserNodes[fieldIndex].fieldLabel);
|
|
newSubtree = proto_item_add_subtree(newField,
|
|
ettArticulations[i]);
|
|
offset = parseFields(tvb, newSubtree, offset,
|
|
parserNodes[fieldIndex].children);
|
|
proto_item_set_end(newField, tvb, offset);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
++fieldIndex;
|
|
}
|
|
|
|
return offset;
|
|
}
|