Make some (preference) variables static.
[obnox/wireshark/wip.git] / epan / dissectors / packet-ziop.c
1 /* packet-ziop.c
2  * Routines for CORBA ZIOP packet disassembly
3  * Significantly based on packet-giop.c
4  * Copyright 2009 Alvaro Vega Garcia <avega at tid dot es>
5  *
6  * According with GIOP Compression RFP revised submission
7  * OMG mars/2008-12-20
8  * http://www.omg.org/docs/ptc/09-01-03.pdf
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <errno.h>
37 #include <ctype.h>
38 #include <glib.h>
39 #include <math.h>
40
41 #include "isprint.h"
42
43 #include <epan/packet.h>
44 #include <epan/conversation.h>
45
46 #include "packet-ziop.h"
47 #include "packet-giop.h"
48 #include "packet-tcp.h"
49
50 /*
51  * Set to 1 for DEBUG output - TODO make this a runtime option
52  */
53
54 #define DEBUG   0
55
56 /*
57  * ------------------------------------------------------------------------------------------+
58  *                                 Data/Variables/Structs
59  * ------------------------------------------------------------------------------------------+
60  */
61
62 static int proto_ziop = -1;
63
64 /*
65  * (sub)Tree declares
66  */
67
68 static gint hf_ziop_magic = -1;
69 static gint hf_ziop_giop_version_major = -1;
70 static gint hf_ziop_giop_version_minor = -1;
71 static gint hf_ziop_flags = -1;
72 static gint hf_ziop_message_type = -1;
73 static gint hf_ziop_message_size = -1;
74 static gint hf_ziop_compressor_id = -1;
75 static gint hf_ziop_original_length = -1;
76
77 static gint ett_ziop = -1;
78
79
80 static dissector_handle_t data_handle;
81 static dissector_handle_t ziop_tcp_handle;
82
83
84 static const value_string ziop_compressor_ids[] = {
85   { 0, "None" },
86   { 1, "GZIP"},
87   { 2, "PKZIP"},
88   { 3, "BZIP2"},
89   { 4, "ZLIB"},
90   { 5, "LZMA"},
91   { 6, "LZOP"},
92   { 7, "RZIP"},
93   { 8, "7X"},
94   { 9, "XAR"},
95   { 0, NULL}
96 };
97
98
99 static const value_string giop_message_types[] = {
100         { 0x0, "Request" },
101         { 0x1, "Reply"},
102         { 0x2, "CancelRequest"},
103         { 0x3, "LocateRequest"},
104         { 0x4, "LocateReply"},
105         { 0x5, "CloseConnection"},
106         { 0x6, "MessageError"},
107         { 0x7, "Fragment"},
108         { 0, NULL}
109 };
110
111
112 static gboolean ziop_desegment = TRUE;
113
114 static void dissect_ziop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree);
115
116 static guint
117 get_ziop_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
118 {
119   guint8 flags;
120   guint message_size;
121   gboolean stream_is_big_endian;
122
123   if ( tvb_memeql(tvb, 0, ZIOP_MAGIC, 4) != 0)
124     return 0;
125
126   flags = tvb_get_guint8(tvb, offset + 6);
127
128   stream_is_big_endian =  ((flags & 0x1) == 0);
129
130   if (stream_is_big_endian)
131     message_size = tvb_get_ntohl(tvb, offset + 8);
132   else
133     message_size = tvb_get_letohl(tvb, offset + 8);
134
135   return message_size + ZIOP_HEADER_SIZE;
136 }
137
138
139 static void
140 dissect_ziop_tcp (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
141
142   if ( tvb_memeql(tvb, 0, ZIOP_MAGIC ,4) != 0) {
143
144     if ( tvb_memeql(tvb, 0, GIOP_MAGIC ,4) == 0)
145       dissect_giop(tvb, pinfo, tree);
146
147     return;
148   }
149
150   tcp_dissect_pdus(tvb, pinfo, tree, ziop_desegment, ZIOP_HEADER_SIZE,
151                    get_ziop_pdu_len, dissect_ziop);
152 }
153
154
155 gboolean
156 dissect_ziop_heur (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
157
158   guint tot_len;
159
160   conversation_t *conversation;
161   /* check magic number and version */
162
163
164   tot_len = tvb_length(tvb);
165
166
167   if (tot_len < ZIOP_HEADER_SIZE) /* tot_len < 12 */
168     {
169       /* Not enough data captured to hold the ZIOP header; don't try
170          to interpret it as GIOP. */
171       return FALSE;
172     }
173   if ( tvb_memeql(tvb, 0, ZIOP_MAGIC, 4) != 0) {
174     return FALSE;
175   }
176
177   if ( pinfo->ptype == PT_TCP )
178     {
179       /*
180        * Make the ZIOP dissector the dissector for this conversation.
181        *
182        * If this isn't the first time this packet has been processed,
183        * we've already done this work, so we don't need to do it
184        * again.
185        */
186       if (!pinfo->fd->flags.visited)
187         {
188           conversation = find_or_create_conversation(pinfo);
189
190           /* Set dissector */
191           conversation_set_dissector(conversation, ziop_tcp_handle);
192         }
193       dissect_ziop_tcp (tvb, pinfo, tree);
194     }
195   else
196     {
197       dissect_ziop (tvb, pinfo, tree);
198     }
199   return TRUE;
200
201 }
202
203
204 /* Main entry point */
205 static void
206 dissect_ziop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree) {
207   guint offset = 0;
208   guint8 giop_version_major, giop_version_minor, message_type;
209
210   proto_tree *ziop_tree = NULL;
211   proto_item *ti;
212
213   col_set_str (pinfo->cinfo, COL_PROTOCOL, ZIOP_MAGIC);
214
215   /* Clear out stuff in the info column */
216   col_clear(pinfo->cinfo, COL_INFO);
217
218   giop_version_major = tvb_get_guint8(tvb, 4);
219   giop_version_minor = tvb_get_guint8(tvb, 5);
220   message_type = tvb_get_guint8(tvb, 7);
221
222   if ( (giop_version_major < 1) ||
223        (giop_version_minor < 2) )  /* earlier than GIOP 1.2 */
224     {
225       col_add_fstr (pinfo->cinfo, COL_INFO, "Version %u.%u",
226                     giop_version_major, giop_version_minor);
227       if (tree)
228         {
229           ti = proto_tree_add_item (tree, proto_ziop, tvb, 0, -1, FALSE);
230           ziop_tree = proto_item_add_subtree (ti, ett_ziop);
231           proto_tree_add_text (ziop_tree, tvb, 4, 2,
232                                "Version %u.%u not supported",
233                                giop_version_major,
234                                giop_version_minor);
235         }
236       call_dissector(data_handle, tvb, pinfo, tree);
237       return;
238     }
239
240   col_add_fstr (pinfo->cinfo, COL_INFO, "ZIOP %u.%u %s",
241                 giop_version_major,
242                 giop_version_minor,
243                 val_to_str(message_type, giop_message_types,
244                            "Unknown message type (0x%02x)")
245                 );
246
247   if (tree)
248     {
249       guint8 flags;
250       gboolean little_endian;
251       emem_strbuf_t *flags_strbuf = ep_strbuf_new_label("none");
252
253       ti = proto_tree_add_item (tree, proto_ziop, tvb, 0, -1, FALSE);
254       ziop_tree = proto_item_add_subtree (ti, ett_ziop);
255
256       proto_tree_add_item(ziop_tree, hf_ziop_magic, tvb, offset, 4, FALSE);
257       offset += 4;
258       proto_tree_add_item(ziop_tree, hf_ziop_giop_version_major, tvb, offset, 1, FALSE);
259       offset++;
260       proto_tree_add_item(ziop_tree, hf_ziop_giop_version_minor, tvb, offset, 1, FALSE);
261       offset++;
262
263       flags = tvb_get_guint8(tvb, offset);
264       little_endian = flags & 0x01;
265
266       if (flags & 0x01) {
267         ep_strbuf_printf(flags_strbuf, "little-endian");
268       }
269       ti = proto_tree_add_uint_format_value(ziop_tree, hf_ziop_flags, tvb, offset, 1,
270                                             flags, "0x%02x (%s)", flags, flags_strbuf->str);
271       offset++;
272
273       proto_tree_add_item(ziop_tree, hf_ziop_message_type, tvb, offset, 1, FALSE);
274       offset++;
275
276       proto_tree_add_item(ziop_tree, hf_ziop_message_size, tvb, offset, 4, little_endian);
277       offset += 4;
278       proto_tree_add_item(ziop_tree, hf_ziop_compressor_id, tvb, offset, 2, little_endian);
279       offset += 4;
280       proto_tree_add_item(ziop_tree, hf_ziop_original_length, tvb, offset, 4, little_endian);
281     }
282 }
283
284
285 void proto_register_ziop (void) {
286
287
288   /* A header field is something you can search/filter on.
289    *
290    * We create a structure to register our fields. It consists of an
291    * array of hf_register_info structures, each of which are of the format
292    * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
293    */
294   static hf_register_info hf[] = {
295     { &hf_ziop_magic,
296       { "Header magic", "ziop.magic", FT_STRING, BASE_NONE, NULL, 0x0,
297         "ZIOPHeader magic", HFILL }},
298     { &hf_ziop_giop_version_major,
299       { "Header major version", "ziop.giop_version_major", FT_UINT8, BASE_OCT, NULL, 0x0,
300         "ZIOPHeader giop_major_version", HFILL }},
301     { &hf_ziop_giop_version_minor,
302       { "Header minor version", "ziop.giop_version_minor", FT_UINT8, BASE_OCT, NULL, 0x0,
303         "ZIOPHeader giop_minor_version", HFILL }},
304     { &hf_ziop_flags,
305       { "Header flags", "ziop.flags", FT_UINT8, BASE_OCT, NULL, 0x0,
306         "ZIOPHeader flags", HFILL }},
307     { &hf_ziop_message_type,
308       { "Header type", "ziop.message_type", FT_UINT8, BASE_OCT, VALS(giop_message_types), 0x0,
309         "ZIOPHeader message_type", HFILL }},
310     { &hf_ziop_message_size,
311       { "Header size", "ziop.message_size",  FT_UINT32, BASE_DEC, NULL, 0x0,
312         "ZIOPHeader message_size", HFILL }},
313     { &hf_ziop_compressor_id,
314       { "Header compressor id", "ziop.compressor_id", FT_UINT16, BASE_DEC, VALS(ziop_compressor_ids), 0x0,
315         "ZIOPHeader compressor_id", HFILL }},
316     { &hf_ziop_original_length,
317       { "Header original length", "ziop.original_length", FT_UINT32, BASE_DEC, NULL, 0x0,
318         "ZIOP original_length", HFILL }},
319   };
320
321
322   static gint *ett[] = {
323     &ett_ziop,
324   };
325
326   proto_ziop = proto_register_protocol("Zipped Inter-ORB Protocol", "ZIOP",
327                                        "ziop");
328   proto_register_field_array (proto_ziop, hf, array_length (hf));
329   proto_register_subtree_array (ett, array_length (ett));
330
331   register_dissector("ziop", dissect_ziop, proto_ziop);
332
333 }
334
335
336 void proto_reg_handoff_ziop (void) {
337
338   ziop_tcp_handle = create_dissector_handle(dissect_ziop_tcp, proto_ziop);
339   dissector_add_handle("udp.port", ziop_tcp_handle);  /* For 'Decode As' */
340
341   heur_dissector_add("tcp", dissect_ziop_heur, proto_ziop);
342
343   data_handle = find_dissector("data");
344 }