Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-dis.c
1 /* packet-dis.c
2  * Routines for Distributed Interactive Simulation packet
3  * disassembly (IEEE-1278).
4  * Copyright 2005, Scientific Research Corporation
5  * Initial implementation by Jeremy Ouellette <jouellet@scires.com>
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 /* TODO / NOTES:
29  * Field handling isn't ideal; this dissector should probably register
30  * each individual field via the proto_register_field_array mechanism.
31  * This would lead to better PDML output (instead of requiring the end user
32  * to manually parse out the key/value pairs) and better searchability in
33  * interactive mode.
34  *
35  * Lots more PDUs to implement.  Only the basic engagement events are currently
36  * handled (Fire, Detonation, Entity State).  Most of the basic field types are
37  * complete, however, so declaring new PDUs should be fairly simple.
38  *
39  * Lots more enumerations to implement.
40  */
41
42 #ifdef HAVE_CONFIG_H
43 # include "config.h"
44 #endif
45
46 #include <stdio.h>
47 #include <epan/packet.h>
48 #include <epan/value_string.h>
49 #include <epan/prefs.h>
50 #include "packet-dis-enums.h"
51 #include "packet-dis-pdus.h"
52 #include "packet-dis-fields.h"
53
54 #define DEFAULT_DIS_UDP_PORT 3000
55
56 static gint proto_dis = -1;
57 static gint ett_dis = -1;
58 static gint ett_dis_header = -1;
59 static gint ett_dis_payload = -1;
60
61 static dissector_handle_t dis_dissector_handle;
62 static guint dis_udp_port = DEFAULT_DIS_UDP_PORT;
63
64 static const char* dis_proto_name = "Distributed Interactive Simulation";
65 static const char* dis_proto_name_short = "DIS";
66
67 /* Main dissector routine to be invoked for a DIS PDU.
68  */
69 static gint dissect_dis(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
70 {
71     proto_item *dis_tree = 0;
72     proto_item *dis_node = 0;
73     proto_item *dis_header_tree = 0;
74     proto_item *dis_header_node = 0;
75     proto_item *dis_payload_tree = 0;
76     proto_item *dis_payload_node = 0;
77     gint offset = 0;
78     const gchar *pduString = 0;
79     DIS_ParserNode *pduParser = 0;
80
81     /* DIS packets must be at least 12 bytes long.  DIS uses port 3000, by
82      * default, but the Cisco Redundant Link Management protocol can also use
83      * that port; RLM packets are 8 bytes long, so we use this to distinguish
84      * between them.
85      */
86     if (tvb_reported_length(tvb) < 12)
87     {
88         return 0;
89     }
90
91     /* Reset the global PDU type variable -- this will be parsed as part of
92      * the DIS header.
93      */
94     pduType = DIS_PDUTYPE_OTHER;
95     numArticulations = 0;
96
97     if (check_col(pinfo->cinfo, COL_PROTOCOL))
98     {
99         col_set_str(pinfo->cinfo, COL_PROTOCOL, dis_proto_name_short);
100     }
101
102     /* Add the top-level DIS node under which the rest of the fields will be
103      * displayed.
104      */
105     dis_node = proto_tree_add_protocol_format(tree, proto_dis, tvb, offset,
106         -1, "Distributed Interactive Simulation");
107     dis_tree = proto_item_add_subtree(dis_node, ett_dis);
108
109     /* Add a node to contain the DIS header fields.
110      */
111     dis_header_node = proto_tree_add_text(dis_tree, tvb, offset, -1, "Header");
112     dis_header_tree = proto_item_add_subtree(dis_header_node, ett_dis_header);
113     offset = parseFields(tvb, dis_header_tree, offset, DIS_FIELDS_PDU_HEADER);
114     proto_item_set_end(dis_header_node, tvb, offset);
115
116     /* Locate the appropriate PDU parser, if type is known.
117      */
118     switch (pduType)
119     {
120     case DIS_PDUTYPE_ENTITY_STATE:
121         pduParser = DIS_PARSER_ENTITY_STATE_PDU;
122         break;
123     case DIS_PDUTYPE_FIRE:
124         pduParser = DIS_PARSER_FIRE_PDU;
125         break;
126     case DIS_PDUTYPE_DETONATION:
127         pduParser = DIS_PARSER_DETONATION_PDU;
128         break;
129     default:
130         pduParser = 0;
131         break;
132     }
133
134     /* Locate the string name for the PDU type enumeration, or default to
135      * "Unknown".
136      */
137     pduString = val_to_str(pduType, DIS_PDU_Type_Strings, "Unknown"); 
138
139     /* Add a node to contain the DIS PDU fields.
140      */
141     dis_payload_node = proto_tree_add_text(dis_tree, tvb, offset, -1,
142         "%s PDU", pduString);
143
144     /* If a parser was located, invoke it on the data packet.
145      */
146     if (pduParser != 0)
147     {
148         dis_payload_tree = proto_item_add_subtree(dis_payload_node,
149             ett_dis_payload);
150         offset = parseFields(tvb, dis_payload_tree, offset, pduParser);
151         proto_item_set_end(dis_payload_node, tvb, offset);
152     }
153     return tvb_length(tvb);
154 }
155
156 /* Register handoff routine for DIS dissector.  This will be invoked initially
157  * and when the preferences are changed, to handle changing the UDP port for
158  * which this dissector is registered.
159  */
160 void proto_reg_handoff_dis(void)
161 {
162     static gboolean dis_prefs_initialized = FALSE;
163
164     if (!dis_prefs_initialized)
165     {
166         dis_dissector_handle = new_create_dissector_handle(dissect_dis, proto_dis);
167     }
168     else
169     {
170         dissector_delete("udp.port", dis_udp_port, dis_dissector_handle);
171     }
172
173     dissector_add("udp.port", dis_udp_port, dis_dissector_handle);
174 }
175
176 /* Registration routine for the DIS protocol.
177  */
178 void proto_register_dis(void)
179 {
180     /* Only these 3 ett variables will be present for every DIS PDU --
181      * the rest are dynamic based on PDU type.
182      */
183     static gint *ett[] =
184     {
185         &ett_dis,
186         &ett_dis_header,
187         &ett_dis_payload
188     };
189
190     module_t *dis_module;
191
192     proto_dis = proto_register_protocol(dis_proto_name, dis_proto_name_short,
193         "dis");
194     proto_register_subtree_array(ett, array_length(ett));
195
196     dis_module = prefs_register_protocol(proto_dis, proto_reg_handoff_dis);
197
198     /* Create an unsigned integer preference to allow the user to specify the
199      * UDP port on which to capture DIS packets.
200      */
201     prefs_register_uint_preference(dis_module, "udp.port",
202         "DIS UDP Port",
203         "Set the UDP port for DIS messages",
204         10, &dis_udp_port);
205
206     /* Perform the one-time initialization of the DIS parsers.
207      */
208     initializeParsers();
209 }