HACK: pinfo->private_data points to smb_info again
[wireshark-wip.git] / epan / dissectors / packet-icep.c
blob7c2dd8f85d791c223cc63184e1d28d51c28842b7
1 /* packet-icep.c
2 * Routines for "The ICE Protocol" dissection
3 * Copyright 2004 _FF_
4 * Francesco Fondelli <fondelli dot francesco, tiscali dot it>
6 * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 TODO:
29 1) Dissect encoded data (do sth like idl2wrs for CORBA).
30 2) Add conversations.
35 NOTES:
36 1) p. 586 Chapter 23.2 of "The ICE Protocol"
37 "Data is always encoded using little-endian byte order for numeric types."
38 2) Informations about Ice can be found here: http://www.zeroc.com
41 #include "config.h"
43 #include <glib.h>
45 #include <epan/packet.h>
46 #include <epan/expert.h>
47 #include <epan/prefs.h>
48 #include <epan/wmem/wmem.h>
49 #include "packet-tcp.h"
51 #if 0
52 #define DBG(str, args...) do {\
53 fprintf(stdout, \
54 "[%s][%s][%d]: ",\
55 __FILE__, \
56 __FUNCTION__, \
57 __LINE__); \
58 fflush(stdout); \
59 fprintf(stdout, str, ## args); \
60 } while (0)
61 #else
62 #define DBG0(format)
63 #define DBG1(format, arg1)
64 #define DBG2(format, arg1, arg2)
65 #endif /* 0/1 */
67 /* fixed values taken from the standard */
68 static const guint8 icep_magic[] = { 'I', 'c', 'e', 'P' };
69 #define ICEP_HEADER_SIZE 14
70 #define ICEP_MIN_REPLY_SIZE 5
71 #define ICEP_MIN_PARAMS_SIZE 6
72 #define ICEP_MIN_COMMON_REQ_HEADER_SIZE 13
74 /* Initialize the protocol and registered fields */
75 static int proto_icep = -1;
77 /* Message Header */
78 static int hf_icep_protocol_major = -1;
79 static int hf_icep_protocol_minor = -1;
80 static int hf_icep_encoding_major = -1;
81 static int hf_icep_encoding_minor = -1;
82 static int hf_icep_message_type = -1;
83 static int hf_icep_compression_status = -1;
84 static int hf_icep_message_size = -1;
86 /* [Batch] Request Message Body */
87 static int hf_icep_request_id = -1;
88 static int hf_icep_id_name = -1;
89 static int hf_icep_id_category = -1;
90 static int hf_icep_facet = -1;
91 static int hf_icep_operation = -1;
92 static int hf_icep_mode = -1;
93 static int hf_icep_context = -1;
94 static int hf_icep_params_size = -1;
95 static int hf_icep_params_major = -1;
96 static int hf_icep_params_minor = -1;
97 static int hf_icep_params_encapsulated = -1;
98 static int hf_icep_reply_data = -1;
99 static int hf_icep_invocation_key = -1;
100 static int hf_icep_invocation_value = -1;
102 /* Reply Message Body */
103 static int hf_icep_reply_status = -1;
105 /* Initialize the subtree pointers */
106 static gint ett_icep = -1;
107 static gint ett_icep_msg = -1;
109 static expert_field ei_icep_params_size = EI_INIT;
110 static expert_field ei_icep_context_missing = EI_INIT;
111 static expert_field ei_icep_reply_data = EI_INIT;
112 static expert_field ei_icep_length = EI_INIT;
113 static expert_field ei_icep_facet_max_one_element = EI_INIT;
114 static expert_field ei_icep_string_too_long = EI_INIT;
115 static expert_field ei_icep_string_malformed = EI_INIT;
116 static expert_field ei_icep_message_type = EI_INIT;
117 static expert_field ei_icep_mode_missing = EI_INIT;
118 static expert_field ei_icep_params_encapsulated = EI_INIT;
119 static expert_field ei_icep_params_missing = EI_INIT;
120 static expert_field ei_icep_batch_requests = EI_INIT;
121 static expert_field ei_icep_facet_missing = EI_INIT;
122 static expert_field ei_icep_context_too_long = EI_INIT;
124 /* Preferences */
125 static guint icep_max_batch_requests = 64;
126 static guint icep_max_ice_string_len = 512;
127 static guint icep_max_ice_context_pairs = 64;
128 static guint icep_tcp_port = 0;
129 static guint icep_udp_port = 0;
132 static const value_string icep_msgtype_vals[] = {
133 {0x0, "Request"},
134 {0x1, "Batch request"},
135 {0x2, "Reply"},
136 {0x3, "Validate connection"},
137 {0x4, "Close connection"},
138 {0, NULL}
141 static const value_string icep_zipstatus_vals[] = {
142 {0x0, "Uncompressed, sender cannot accept a compressed reply"},
143 {0x1, "Uncompressed, sender can accept a compressed reply"},
144 {0x2, "Compressed, sender can accept a compressed reply"},
145 {0, NULL}
148 static const value_string icep_replystatus_vals[] = {
149 {0x0, "Success"},
150 {0x1, "User exception"},
151 {0x2, "Object does not exist"},
152 {0x3, "Facet does not exist"},
153 {0x4, "Operation does not exist"},
154 {0x5, "Unknown Ice local exception"},
155 {0x6, "Unknown Ice user exception"},
156 {0x7, "Unknown exception"},
157 {0, NULL}
160 static const value_string icep_mode_vals[] = {
161 {0x0, "normal"},
162 {0x1, "nonmutating"},
163 {0x2, "idempotent"},
164 {0, NULL}
168 * This function dissects an "Ice string", adds hf to "tree" and returns consumed
169 * bytes in "*consumed", if errors "*consumed" is -1.
171 * "*dest" is a null terminated version of the dissected Ice string.
173 static void dissect_ice_string(packet_info *pinfo, proto_tree *tree, proto_item *item, int hf_icep,
174 tvbuff_t *tvb, guint32 offset, gint32 *consumed, char **dest)
176 /* p. 586 chapter 23.2.1 and p. 588 chapter 23.2.5
177 * string == Size + content
178 * string = 1byte (0..254) + string not null terminated
179 * or
180 * string = 1byte (255) + 1int (255..2^32-1) + string not null terminated
183 guint32 Size = 0;
184 char *s = NULL;
186 (*consumed) = 0;
188 /* check for first byte */
189 if ( !tvb_bytes_exist(tvb, offset, 1) ) {
191 expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "1st byte of Size missing");
192 col_append_str(pinfo->cinfo, COL_INFO, " (1st byte of Size missing)");
194 (*consumed) = -1;
195 return;
198 /* get the Size */
199 Size = tvb_get_guint8(tvb, offset);
200 offset++;
201 (*consumed)++;
203 if ( Size == 255 ) {
205 /* check for next 4 bytes */
206 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
208 expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "second field of Size missing");
209 col_append_str(pinfo->cinfo, COL_INFO, " (second field of Size missing)");
211 (*consumed) = -1;
212 return;
215 /* get second field of Size */
216 Size = tvb_get_letohl(tvb, offset);
217 offset += 4;
218 (*consumed) += 4;
221 DBG1("string.Size --> %d\n", Size);
223 /* check if the string exists */
224 if ( !tvb_bytes_exist(tvb, offset, Size) ) {
226 expert_add_info_format(pinfo, item, &ei_icep_string_malformed, "missing or truncated string");
227 col_append_str(pinfo->cinfo, COL_INFO, " (missing or truncated string)");
229 (*consumed) = -1;
230 return;
233 if ( Size > icep_max_ice_string_len ) {
235 expert_add_info(pinfo, item, &ei_icep_string_too_long);
236 col_append_str(pinfo->cinfo, COL_INFO, " (string too long)");
238 (*consumed) = -1;
239 return;
243 if ( Size != 0 ) {
244 s = tvb_get_string(wmem_packet_scope(), tvb, offset, Size);
245 proto_tree_add_string(tree, hf_icep, tvb, offset, Size, s);
246 } else {
247 s = wmem_strdup(wmem_packet_scope(), "(empty)");
248 /* display the 0x00 Size byte when click on a empty ice_string */
249 proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, s);
252 if ( dest != NULL )
253 *dest = s;
255 /*offset += Size;*/
256 (*consumed) += Size;
257 return;
261 * This function dissects an "Ice facet", adds hf(s) to "tree" and returns consumed
262 * bytes in "*consumed", if errors "*consumed" is -1.
264 static void dissect_ice_facet(packet_info *pinfo, proto_tree *tree, proto_item *item, int hf_icep,
265 tvbuff_t *tvb, guint32 offset, gint32 *consumed)
267 /* p. 588, chapter 23.2.6:
268 * "facet" is a StringSeq, a StringSeq is a:
269 * sequence<string>
272 * sequence == Size + SizeElements
273 * sequence = 1byte (0..254) + SizeElements
274 * or
275 * sequence = 1byte (255) + 1int (255..2^32-1) + SizeElements
278 * p.613. chapter 23.3.2
279 * "facet has either zero elements (empty) or one element"
284 guint32 Size = 0; /* number of elements in the sequence */
286 (*consumed) = 0;
288 /* check first byte */
289 if ( !tvb_bytes_exist(tvb, offset, 1) ) {
291 expert_add_info(pinfo, item, &ei_icep_facet_missing);
292 col_append_str(pinfo->cinfo, COL_INFO, " (facet field missing)");
294 (*consumed) = -1;
295 return;
298 /* get first byte of Size */
299 Size = tvb_get_guint8(tvb, offset);
300 offset++;
301 (*consumed)++;
303 if ( Size == 0 ) {
304 /* display the 0x00 Size byte when click on a empty ice_string */
305 proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, "(empty)");
306 return;
309 if ( Size == 1 ) {
311 gint32 consumed_facet = 0;
313 dissect_ice_string(pinfo, tree, item, hf_icep, tvb, offset, &consumed_facet, NULL);
315 if ( consumed_facet == -1 ) {
316 (*consumed) = -1;
317 return;
320 /*offset += consumed_facet;*/
321 (*consumed) += consumed_facet;
322 return;
325 /* if here => Size > 1 => not possible */
327 /* display the XX Size byte when click here */
328 expert_add_info(pinfo, item, &ei_icep_facet_max_one_element);
330 col_append_str(pinfo->cinfo, COL_INFO, " (facet can be max one element)");
332 (*consumed) = -1;
333 return;
337 * This function dissects an "Ice context", adds hf(s) to "tree" and returns consumed
338 * bytes in "*consumed", if errors "*consumed" is -1.
340 static void dissect_ice_context(packet_info *pinfo, proto_tree *tree, proto_item *item,
341 tvbuff_t *tvb, guint32 offset, gint32 *consumed)
343 /* p. 588, chapter 23.2.7 and p. 613, 23.3.2:
344 * "context" is a dictionary<string, string>
346 * dictionary<string, string> == Size + SizeKeyValuePairs
347 * dictionary<string, string> = 1byte (0..254) + SizeKeyValuePairs
348 * or
349 * dictionary<string, string>= 1byte (255) + 1int (255..2^32-1)+SizeKeyValuePairs
353 guint32 Size = 0; /* number of key-value in the dictionary */
354 guint32 i = 0;
355 const char *s = NULL;
357 (*consumed) = 0;
359 /* check first byte */
360 if ( !tvb_bytes_exist(tvb, offset, 1) ) {
362 expert_add_info_format(pinfo, item, &ei_icep_context_missing, "context missing");
363 col_append_str(pinfo->cinfo, COL_INFO, " (context missing)");
365 (*consumed) = -1;
366 return;
369 /* get first byte of Size */
370 Size = tvb_get_guint8(tvb, offset);
371 offset++;
372 (*consumed)++;
374 if ( Size == 255 ) {
376 /* check for next 4 bytes */
377 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
379 expert_add_info_format(pinfo, item, &ei_icep_context_missing, "second field of Size missing");
380 col_append_str(pinfo->cinfo, COL_INFO, " (second field of Size missing)");
382 (*consumed) = -1;
383 return;
386 /* get second field of Size */
387 Size = tvb_get_letohl(tvb, offset);
388 offset += 4;
389 (*consumed) += 4;
392 DBG1("context.Size --> %d\n", Size);
394 if ( Size > icep_max_ice_context_pairs ) {
396 /* display the XX Size byte when click here */
397 expert_add_info(pinfo, item, &ei_icep_context_too_long);
399 col_append_str(pinfo->cinfo, COL_INFO, " (too long context)");
401 (*consumed) = -1;
402 return;
405 if (Size == 0) {
406 s = "(empty)";
407 /* display the 0x00 Size byte when click on a empty context */
408 proto_tree_add_string(tree, hf_icep_context, tvb, offset - 1, 1, s);
409 return;
412 /* looping through the dictionary */
413 for ( i = 0; i < Size; i++ ) {
414 /* key */
415 gint32 consumed_key = 0;
416 char *str_key = NULL;
417 /* value */
418 gint32 consumed_value = 0;
419 char *str_value = NULL;
420 proto_item *ti = NULL;
422 DBG1("looping through context dictionary, loop #%d\n", i);
423 ti = proto_tree_add_text(tree, tvb, offset, -1, "Invocation Context");
425 dissect_ice_string(pinfo, tree, ti, hf_icep_invocation_key, tvb, offset, &consumed_key, &str_key);
427 if ( consumed_key == -1 ) {
428 (*consumed) = -1;
429 return;
432 offset += consumed_key;
433 (*consumed) += consumed_key;
435 dissect_ice_string(pinfo, tree, ti, hf_icep_invocation_value, tvb, offset, &consumed_value, &str_value);
437 if ( consumed_value == -1 ) {
438 (*consumed) = -1;
439 return;
442 offset += consumed_value;
443 (*consumed) += consumed_value;
444 if (ti)
445 proto_item_set_len(ti, (consumed_key + consumed_value) + 1);
450 * This function dissects an "Ice params", adds hf(s) to "tree" and returns consumed
451 * bytes in "*consumed", if errors "*consumed" is -1.
453 static void dissect_ice_params(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
454 guint32 offset, gint32 *consumed)
456 /* p. 612, chapter 23.3.2 and p. 587, 23.2.2:
457 * "params" is an Encapsulation
459 * struct Encapsulation {
460 * int size;
461 * byte major;
462 * byte minor;
463 * //(size - 6) bytes of data
468 gint32 size = 0;
469 gint tvb_data_remained = 0;
471 (*consumed) = 0;
473 /* check first 6 bytes */
474 if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_PARAMS_SIZE) ) {
476 expert_add_info(pinfo, item, &ei_icep_params_missing);
477 col_append_str(pinfo->cinfo, COL_INFO, " (params missing)");
479 (*consumed) = -1;
480 return;
483 /* get the size */
484 size = tvb_get_letohl(tvb, offset);
486 DBG1("params.size --> %d\n", size);
488 if ( size < ICEP_MIN_PARAMS_SIZE ) {
490 expert_add_info(pinfo, item, &ei_icep_params_size);
491 col_append_str(pinfo->cinfo, COL_INFO, " (params size too small)");
493 (*consumed) = -1;
494 return;
497 if ( tree ) {
499 proto_tree_add_item(tree, hf_icep_params_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
500 offset += 4;
501 (*consumed) += 4;
503 proto_tree_add_item(tree, hf_icep_params_major, tvb, offset, 1, ENC_LITTLE_ENDIAN);
504 offset += 1;
505 (*consumed)++;
507 proto_tree_add_item(tree, hf_icep_params_minor, tvb, offset, 1, ENC_LITTLE_ENDIAN);
508 offset += 1;
509 (*consumed)++;
511 } else {
512 /* skip size, major, minor */
513 offset += 6;
514 (*consumed) += 6;
517 if( size == ICEP_MIN_PARAMS_SIZE ) /* no encapsulatd data present, it's normal */
518 return;
520 /* check if I got all encapsulated data */
521 tvb_data_remained = tvb_reported_length_remaining(tvb, offset);
523 if ( tvb_data_remained < ( size - ICEP_MIN_PARAMS_SIZE ) ) {
525 expert_add_info_format(pinfo, item, &ei_icep_params_encapsulated, "missing encapsulated data (%d bytes)", size - ICEP_MIN_PARAMS_SIZE - tvb_data_remained);
527 col_append_fstr(pinfo->cinfo, COL_INFO,
528 " (missing encapsulated data (%d bytes))",
529 size - ICEP_MIN_PARAMS_SIZE - tvb_data_remained);
531 (*consumed) = -1;
532 return;
535 /* encapsulated params */
536 proto_tree_add_item(tree, hf_icep_params_encapsulated, tvb, offset, (size - ICEP_MIN_PARAMS_SIZE), ENC_LITTLE_ENDIAN);
538 (*consumed) += (size - ICEP_MIN_PARAMS_SIZE);
541 static void dissect_icep_request_common(tvbuff_t *tvb, guint32 offset,
542 packet_info *pinfo, proto_tree *icep_sub_tree, proto_item* icep_sub_item, gint32 *total_consumed)
544 /* p. 613, chapter 23.3.3 and p. 612 chapter 23.3.2:
545 * Request and BatchRequest differ only in the first 4 bytes (requestID)
546 * so them share this part
548 * Ice::Identity id;
549 * Ice::StringSeq facet;
550 * string operation;
551 * byte mode;
552 * Ice::Context context;
553 * Encapsulation params;
557 gint32 consumed = 0;
558 char *namestr = NULL;
559 char *opstr = NULL;
561 (*total_consumed) = 0;
563 /* check common header (i.e. the batch request one)*/
564 if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_COMMON_REQ_HEADER_SIZE) ) {
566 expert_add_info_format(pinfo, icep_sub_item, &ei_icep_length, "too short header");
567 col_append_str(pinfo->cinfo, COL_INFO, " (too short header)");
569 goto error;
572 /* got at least 15 bytes */
574 /* "id" is a:
575 * struct Identity {
576 * string name;
577 * string category;
581 dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_id_name, tvb, offset, &consumed, &namestr);
583 if ( consumed == -1 )
584 goto error;
586 offset += consumed; DBG1("consumed --> %d\n", consumed);
587 (*total_consumed) += consumed;
590 dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_id_category, tvb, offset, &consumed, NULL);
592 if ( consumed == -1 )
593 goto error;
595 offset += consumed; DBG1("consumed --> %d\n", consumed);
596 (*total_consumed) += consumed;
599 /* "facet" is a:
600 * sequence<string> StringSeq
604 dissect_ice_facet(pinfo, icep_sub_tree, icep_sub_item, hf_icep_facet, tvb, offset, &consumed);
606 if ( consumed == -1 )
607 goto error;
609 offset += consumed; DBG1("consumed --> %d\n", consumed);
610 (*total_consumed) += consumed;
612 /* "operation" is an ice_string
616 dissect_ice_string(pinfo, icep_sub_tree, icep_sub_item, hf_icep_operation, tvb, offset, &consumed, &opstr);
618 if ( consumed == -1 )
619 goto error;
620 else {
621 offset += consumed; DBG1("consumed --> %d\n", consumed);
622 (*total_consumed) += consumed;
624 if ( opstr && namestr ) {
625 DBG2("operation --> %s.%s()\n", namestr, opstr);
626 col_append_fstr(pinfo->cinfo, COL_INFO, " %s.%s()",
627 namestr, opstr);
628 opstr = NULL;
629 namestr = NULL;
633 /* check and get mode byte */
634 if ( !tvb_bytes_exist(tvb, offset, 1) ) {
636 expert_add_info(pinfo, icep_sub_item, &ei_icep_mode_missing);
638 col_append_str(pinfo->cinfo, COL_INFO, " (mode field missing)");
639 goto error;
642 proto_tree_add_item(icep_sub_tree, hf_icep_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN);
644 offset++; DBG0("consumed --> 1\n");
645 (*total_consumed)++;
648 /* "context" is a dictionary<string, string>
652 dissect_ice_context(pinfo, icep_sub_tree, icep_sub_item, tvb, offset, &consumed);
654 if ( consumed == -1 )
655 goto error;
657 offset += consumed; DBG1("consumed --> %d\n", consumed);
658 (*total_consumed) += consumed;
660 /* "params" is a Encapsulation
664 dissect_ice_params(pinfo, icep_sub_tree, icep_sub_item, tvb, offset, &consumed);
666 if ( consumed == -1 )
667 goto error;
669 /*offset += consumed;*/
670 DBG1("consumed --> %d\n", consumed);
671 (*total_consumed) += consumed;
673 return;
675 error:
676 (*total_consumed) = -1;
680 static void dissect_icep_request(tvbuff_t *tvb, guint32 offset,
681 packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item)
683 /* p. 612, chapter 23.3.2:
685 * struct RequestData {
686 * int requestID;
687 * Ice::Identity id;
688 * Ice::StringSeq facet;
689 * string operation;
690 * byte mode;
691 * Ice::Context context;
692 * Encapsulation params;
696 proto_item *ti = NULL;
697 proto_tree *icep_sub_tree = NULL;
698 gint32 consumed = 0;
699 guint32 reqid = 0;
701 DBG0("dissect request\n");
703 /* check for req id */
704 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
706 expert_add_info_format(pinfo, icep_item, &ei_icep_length, "too short header");
707 col_append_str(pinfo->cinfo, COL_INFO, " (too short header)");
708 return;
711 /* got at least 4 bytes */
713 /* create display subtree for this message type */
715 reqid = tvb_get_letohl(tvb, offset);
717 ti = proto_tree_add_text(icep_tree, tvb, offset, -1, "Request Message Body");
718 icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
720 proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
722 if ( reqid != 0 ) {
723 col_append_fstr(pinfo->cinfo, COL_INFO, "(%d):", tvb_get_letohl(tvb, offset));
724 } else
725 col_append_str(pinfo->cinfo, COL_INFO, "(oneway):");
728 offset += 4;
729 DBG0("consumed --> 4\n");
731 dissect_icep_request_common(tvb, offset, pinfo, icep_sub_tree, ti, &consumed);
733 if ( consumed == -1 )
734 return;
736 /*offset += consumed;*/
737 DBG1("consumed --> %d\n", consumed);
742 static void dissect_icep_batch_request(tvbuff_t *tvb, guint32 offset,
743 packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item)
745 /* p. 613, chapter 23.3.3
746 * A batch request msg is a "sequence" of batch request
747 * Sequence is Size + elements
749 * struct BatchRequestData {
750 * Ice::Identity id;
751 * Ice::StringSeq facet;
752 * string operation;
753 * byte mode;
754 * Ice::Context context;
755 * Encapsulation params;
758 * NOTE!!!:
759 * The only real implementation of the Ice protocol puts a 32bit count in front
760 * of a Batch Request, *not* an Ice::Sequence (as the standard says). Basically the
761 * same people wrote both code and standard so I'll follow the code.
764 proto_item *ti = NULL;
765 proto_tree *icep_sub_tree = NULL;
766 guint32 num_reqs = 0;
767 guint32 i = 0;
768 gint32 consumed = 0;
770 DBG0("dissect batch request\n");
772 /* check for first 4 byte */
773 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
775 expert_add_info_format(pinfo, icep_item, &ei_icep_length, "counter of batch requests missing");
776 col_append_str(pinfo->cinfo, COL_INFO, " (counter of batch requests missing)");
777 return;
780 num_reqs = tvb_get_letohl(tvb, offset);
781 offset += 4;
783 DBG1("batch_requests.count --> %d\n", num_reqs);
785 if ( num_reqs > icep_max_batch_requests ) {
787 expert_add_info_format(pinfo, icep_item, &ei_icep_batch_requests, "too many batch requests (%d)", num_reqs);
789 col_append_fstr(pinfo->cinfo, COL_INFO, " (too many batch requests, %d)", num_reqs);
790 return;
793 if ( num_reqs == 0 ) {
795 proto_tree_add_text(icep_tree, tvb, offset, -1,
796 "empty batch requests sequence");
797 col_append_str(pinfo->cinfo, COL_INFO, " (empty batch requests sequence)");
799 return;
803 col_append_str(pinfo->cinfo, COL_INFO, ":");
806 * process requests
809 for ( i = 0; i < num_reqs; i++ ) {
811 DBG1("looping through sequence of batch requests, loop #%d\n", i);
813 /* create display subtree for this message type */
815 ti = proto_tree_add_text(icep_tree, tvb, offset, -1,
816 "Batch Request Message Body: #%d", i);
817 icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
819 if (i != 0) {
820 col_append_str(pinfo->cinfo, COL_INFO, ",");
823 dissect_icep_request_common(tvb, offset, pinfo, icep_sub_tree, ti, &consumed);
825 if ( consumed == -1 )
826 return;
828 if ( icep_tree && ti )
829 proto_item_set_len(ti, consumed);
831 offset += consumed;
832 DBG1("consumed --> %d\n", consumed);
836 static void dissect_icep_reply(tvbuff_t *tvb, guint32 offset,
837 packet_info *pinfo, proto_tree *icep_tree, proto_item* icep_item)
839 /* p. 614, chapter 23.3.4:
841 * struct ReplyData {
842 * int requestId;
843 * byte replyStatus;
844 * [... messageSize - 19 bytes ... ]
848 gint32 messageSize = 0;
849 guint32 tvb_data_remained = 0;
850 guint32 reported_reply_data = 0;
851 proto_item *ti = NULL;
852 proto_tree *icep_sub_tree = NULL;
854 DBG0("dissect reply\n");
856 /* get at least a full reply message header */
858 if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_REPLY_SIZE) ) {
860 expert_add_info_format(pinfo, icep_item, &ei_icep_length, "too short header");
862 col_append_str(pinfo->cinfo, COL_INFO, " (too short header)");
863 return;
866 /* got 5 bytes, then data */
868 /* create display subtree for this message type */
870 ti = proto_tree_add_text(icep_tree, tvb, offset, -1,
871 "Reply Message Body");
873 icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
875 proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, ENC_LITTLE_ENDIAN);
877 col_append_fstr(pinfo->cinfo, COL_INFO, "(%d):", tvb_get_letohl(tvb, offset));
879 offset += 4;
881 proto_tree_add_item(icep_sub_tree, hf_icep_reply_status, tvb, offset, 1, ENC_LITTLE_ENDIAN);
883 col_append_fstr(pinfo->cinfo, COL_INFO, " %s",
884 val_to_str_const(tvb_get_guint8(tvb, offset),
885 icep_replystatus_vals,
886 "unknown reply status"));
888 offset++;
890 DBG1("consumed --> %d\n", 5);
892 /* check if I got all reply data */
893 tvb_data_remained = tvb_length_remaining(tvb, offset);
894 messageSize = tvb_get_letohl(tvb, 10);
895 reported_reply_data = messageSize - (ICEP_HEADER_SIZE + ICEP_MIN_REPLY_SIZE);
897 /* no */
898 if ( tvb_data_remained < reported_reply_data ) {
900 expert_add_info_format(pinfo, ti, &ei_icep_reply_data, "Reply Data (missing %d bytes out of %d)", reported_reply_data - tvb_data_remained, reported_reply_data);
902 col_append_fstr(pinfo->cinfo, COL_INFO,
903 " (missing reply data, %d bytes)",
904 reported_reply_data - tvb_data_remained);
906 /*offset += tvb_data_remained;*/
907 DBG1("consumed --> %d\n", tvb_data_remained);
908 return;
911 /* yes (reported_reply_data can be 0) */
913 proto_tree_add_item(icep_sub_tree, hf_icep_reply_data, tvb, offset, reported_reply_data, ENC_NA);
915 /*offset += reported_reply_data;*/
916 DBG1("consumed --> %d\n", reported_reply_data);
919 static guint get_icep_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
921 return tvb_get_letohl(tvb, offset + 10);
924 static int dissect_icep_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
926 /* p. 611, chapter 23.3.1:
928 * struct HeaderData {
929 * int magic;
930 * byte protocolMajor;
931 * byte protocolMinor;
932 * byte encodingMajor;
933 * byte encodingMinor;
934 * byte messageType;
935 * byte compressionStatus;
936 * int messageSize;
940 proto_item *ti, *msg_item = NULL;
941 proto_tree *icep_tree;
942 guint32 offset = 0;
944 /* Make entries in Protocol column and Info column on summary display */
946 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICEP");
948 col_add_str(pinfo->cinfo, COL_INFO,
949 val_to_str(tvb_get_guint8(tvb, 8),
950 icep_msgtype_vals,
951 "Unknown Message Type: 0x%02x"));
953 DBG0("got an icep msg, start analysis\n");
955 /* create display subtree for the protocol */
957 ti = proto_tree_add_item(tree, proto_icep, tvb, 0, -1, ENC_NA);
958 icep_tree = proto_item_add_subtree(ti, ett_icep);
960 if (icep_tree) {
961 /* add items to the subtree */
963 /* message header */
965 proto_tree_add_text(icep_tree, tvb, offset, 4,
966 "Magic Number: 'I','c','e','P'");
967 offset += 4;
969 proto_tree_add_item(icep_tree, hf_icep_protocol_major,
970 tvb, offset, 1, ENC_LITTLE_ENDIAN);
971 offset++;
973 proto_tree_add_item(icep_tree, hf_icep_protocol_minor,
974 tvb, offset, 1, ENC_LITTLE_ENDIAN);
975 offset++;
977 proto_tree_add_item(icep_tree, hf_icep_encoding_major,
978 tvb, offset, 1, ENC_LITTLE_ENDIAN);
979 offset++;
981 proto_tree_add_item(icep_tree, hf_icep_encoding_minor,
982 tvb, offset, 1, ENC_LITTLE_ENDIAN);
983 offset++;
985 msg_item = proto_tree_add_item(icep_tree, hf_icep_message_type,
986 tvb, offset, 1, ENC_LITTLE_ENDIAN);
987 offset++;
989 proto_tree_add_item(icep_tree, hf_icep_compression_status,
990 tvb, offset, 1, ENC_LITTLE_ENDIAN);
991 offset++;
993 proto_tree_add_item(icep_tree, hf_icep_message_size,
994 tvb, offset, 4, ENC_LITTLE_ENDIAN);
995 offset += 4;
996 } else {
997 offset += ICEP_HEADER_SIZE;
1000 switch(tvb_get_guint8(tvb, 8)) {
1001 case 0x0:
1002 DBG1("request message body: parsing %d bytes\n",
1003 tvb_length_remaining(tvb, offset));
1004 dissect_icep_request(tvb, offset, pinfo, icep_tree, ti);
1005 break;
1006 case 0x1:
1007 DBG1("batch request message body: parsing %d bytes\n",
1008 tvb_length_remaining(tvb, offset));
1009 dissect_icep_batch_request(tvb, offset, pinfo, icep_tree, ti);
1010 break;
1011 case 0x2:
1012 DBG1("reply message body: parsing %d bytes\n",
1013 tvb_length_remaining(tvb, offset));
1014 dissect_icep_reply(tvb, offset, pinfo, icep_tree, ti);
1015 break;
1016 case 0x3:
1017 case 0x4:
1018 /* messages already dissected */
1019 break;
1020 default:
1021 expert_add_info_format(pinfo, msg_item, &ei_icep_message_type, "Unknown Message Type: 0x%02x", tvb_get_guint8(tvb, 8));
1022 break;
1024 return tvb_length(tvb);
1027 /* entry point */
1028 static gboolean dissect_icep_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1030 DBG0("triggered\n");
1032 if ( tvb_memeql(tvb, 0, icep_magic, 4) == -1 ) {
1033 /* Not a ICEP packet. */
1034 return FALSE;
1037 /* start dissecting */
1039 tcp_dissect_pdus(tvb, pinfo, tree, TRUE, ICEP_HEADER_SIZE,
1040 get_icep_pdu_len, dissect_icep_pdu, data);
1042 return TRUE;
1045 static gboolean dissect_icep_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
1047 DBG0("triggered\n");
1049 if ( tvb_memeql(tvb, 0, icep_magic, 4) == -1 ) {
1050 /* Not a ICEP packet. */
1051 return FALSE;
1054 /* start dissecting */
1055 dissect_icep_pdu(tvb, pinfo, tree, data);
1056 return TRUE;
1059 /* Register the protocol with Wireshark */
1061 void proto_register_icep(void)
1063 module_t *icep_module;
1064 expert_module_t* expert_icep;
1066 /* Setup list of header fields */
1068 static hf_register_info hf[] = {
1070 { &hf_icep_protocol_major,
1072 "Protocol Major", "icep.protocol_major",
1073 FT_INT8, BASE_DEC, NULL, 0x0,
1074 "The protocol major version number", HFILL
1078 { &hf_icep_protocol_minor,
1080 "Protocol Minor", "icep.protocol_minor",
1081 FT_INT8, BASE_DEC, NULL, 0x0,
1082 "The protocol minor version number", HFILL
1086 { &hf_icep_encoding_major,
1088 "Encoding Major", "icep.encoding_major",
1089 FT_INT8, BASE_DEC, NULL, 0x0,
1090 "The encoding major version number", HFILL
1094 { &hf_icep_encoding_minor,
1096 "Encoding Minor", "icep.encoding_minor",
1097 FT_INT8, BASE_DEC, NULL, 0x0,
1098 "The encoding minor version number", HFILL
1102 { &hf_icep_message_type,
1104 "Message Type", "icep.message_type",
1105 FT_INT8, BASE_DEC, VALS(icep_msgtype_vals), 0x0,
1106 "The message type", HFILL
1110 { &hf_icep_compression_status,
1112 "Compression Status", "icep.compression_status",
1113 FT_INT8, BASE_DEC, VALS(icep_zipstatus_vals), 0x0,
1114 "The compression status of the message", HFILL
1118 { &hf_icep_message_size,
1120 "Message Size", "icep.message_status",
1121 FT_INT32, BASE_DEC, NULL, 0x0,
1122 "The size of the message in bytes, including the header",
1123 HFILL
1127 { &hf_icep_request_id,
1129 "Request Identifier", "icep.request_id",
1130 FT_INT32, BASE_DEC, NULL, 0x0,
1131 "The request identifier",
1132 HFILL
1136 { &hf_icep_reply_status,
1138 "Reply Status", "icep.protocol_major",
1139 FT_INT8, BASE_DEC, VALS(icep_replystatus_vals), 0x0,
1140 "The reply status", HFILL
1144 { &hf_icep_id_name,
1146 "Object Identity Name", "icep.id.name",
1147 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1148 "The object identity name", HFILL
1152 { &hf_icep_id_category,
1154 "Object Identity Content", "icep.id.content",
1155 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1156 "The object identity content", HFILL
1160 { &hf_icep_facet,
1162 "Facet Name", "icep.facet",
1163 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1164 "The facet name", HFILL
1168 { &hf_icep_operation,
1170 "Operation Name", "icep.operation",
1171 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1172 "The operation name", HFILL
1176 { &hf_icep_mode,
1178 "Ice::OperationMode", "icep.operation_mode",
1179 FT_INT8, BASE_DEC, VALS(icep_mode_vals), 0x0,
1180 "A byte representing Ice::OperationMode", HFILL
1184 { &hf_icep_context,
1186 "Invocation Context", "icep.context",
1187 FT_STRINGZ, BASE_NONE, NULL, 0x0,
1188 "The invocation context", HFILL
1192 { &hf_icep_params_size,
1194 "Input Parameters Size", "icep.params.size",
1195 FT_INT32, BASE_DEC, NULL, 0x0,
1196 "The encapsulated input parameters size",
1197 HFILL
1201 { &hf_icep_params_major,
1203 "Input Parameters Encoding Major",
1204 "icep.params.major",
1205 FT_INT8, BASE_DEC, NULL, 0x0,
1206 "The major encoding version of encapsulated parameters",
1207 HFILL
1211 { &hf_icep_params_minor,
1213 "Input Parameters Encoding Minor",
1214 "icep.params.minor",
1215 FT_INT8, BASE_DEC, NULL, 0x0,
1216 "The minor encoding version of encapsulated parameters",
1217 HFILL
1221 { &hf_icep_params_encapsulated,
1223 "Encapsulated parameters",
1224 "icep.params.encapsulated",
1225 FT_BYTES, BASE_NONE, NULL, 0x0,
1226 "Remaining encapsulated parameters",
1227 HFILL
1231 { &hf_icep_reply_data,
1233 "Reported reply data",
1234 "icep.params.reply_data",
1235 FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL
1239 { &hf_icep_invocation_key,
1241 "Key",
1242 "icep.invocation_key",
1243 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL
1247 { &hf_icep_invocation_value,
1249 "Value",
1250 "icep.invocation_value",
1251 FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL
1256 /* Setup protocol subtree array */
1258 static gint *ett[] = {
1259 &ett_icep,
1260 &ett_icep_msg,
1263 static ei_register_info ei[] = {
1264 { &ei_icep_string_malformed, { "icep.string.malformed", PI_MALFORMED, PI_ERROR, "String malformed", EXPFILL }},
1265 { &ei_icep_string_too_long, { "icep.string.too_long", PI_PROTOCOL, PI_WARN, "string too long", EXPFILL }},
1266 { &ei_icep_facet_missing, { "icep.facet.missing", PI_MALFORMED, PI_ERROR, "facet field missing", EXPFILL }},
1267 { &ei_icep_facet_max_one_element, { "icep.facet.max_one_element", PI_PROTOCOL, PI_WARN, "facet can be max one element", EXPFILL }},
1268 { &ei_icep_context_missing, { "icep.context.missing", PI_MALFORMED, PI_ERROR, "context missing", EXPFILL }},
1269 { &ei_icep_context_too_long, { "icep.context.too_long", PI_PROTOCOL, PI_WARN, "too long context", EXPFILL }},
1270 { &ei_icep_params_missing, { "icep.params.missing", PI_MALFORMED, PI_ERROR, "params missing", EXPFILL }},
1271 { &ei_icep_params_size, { "icep.params.size.invalid", PI_PROTOCOL, PI_WARN, "params size too small", EXPFILL }},
1272 { &ei_icep_params_encapsulated, { "icep.params.encapsulated.missing", PI_PROTOCOL, PI_WARN, "missing encapsulated data (%d bytes)", EXPFILL }},
1273 { &ei_icep_length, { "icep.length_invalid", PI_MALFORMED, PI_ERROR, "Invalid length", EXPFILL }},
1274 { &ei_icep_mode_missing, { "icep.mode.missing", PI_MALFORMED, PI_ERROR, "mode field missing", EXPFILL }},
1275 { &ei_icep_batch_requests, { "icep.batch_requests.invalid", PI_PROTOCOL, PI_WARN, "too many batch requests", EXPFILL }},
1276 { &ei_icep_reply_data, { "icep.params.reply_data.missing", PI_MALFORMED, PI_ERROR, "Reply Data missing", EXPFILL }},
1277 { &ei_icep_message_type, { "icep.message_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Message Type", EXPFILL }},
1280 /* Register the protocol name and description */
1282 proto_icep =
1283 proto_register_protocol("Internet Communications Engine Protocol",
1284 "ICEP", "icep");
1286 /* Required function calls to register the header fields and subtrees used */
1288 proto_register_field_array(proto_icep, hf, array_length(hf));
1289 proto_register_subtree_array(ett, array_length(ett));
1290 expert_icep = expert_register_protocol(proto_icep);
1291 expert_register_field_array(expert_icep, ei, array_length(ei));
1293 icep_module = prefs_register_protocol(proto_icep, NULL);
1295 prefs_register_uint_preference(icep_module, "tcp.port",
1296 "ICEP TCP Port",
1297 "ICEP TCP port",
1299 &icep_tcp_port);
1301 prefs_register_uint_preference(icep_module, "udp.port",
1302 "ICEP UDP Port",
1303 "ICEP UDP port",
1305 &icep_udp_port);
1307 prefs_register_uint_preference(icep_module, "max_batch_requests",
1308 "Maximum batch requests",
1309 "Maximum number of batch requests allowed",
1310 10, &icep_max_batch_requests);
1312 prefs_register_uint_preference(icep_module, "max_ice_string_len",
1313 "Maximum string length",
1314 "Maximum length allowed of an ICEP string",
1315 10, &icep_max_ice_string_len);
1317 prefs_register_uint_preference(icep_module, "max_ice_context_pairs",
1318 "Maximum context pairs",
1319 "Maximum number of context pairs allowed",
1320 10, &icep_max_ice_context_pairs);
1324 void proto_reg_handoff_icep(void)
1326 static gboolean icep_prefs_initialized = FALSE;
1327 static dissector_handle_t icep_tcp_handle, icep_udp_handle;
1328 static guint old_icep_tcp_port = 0;
1329 static guint old_icep_udp_port = 0;
1331 /* Register as a heuristic TCP/UDP dissector */
1332 if (icep_prefs_initialized == FALSE) {
1333 icep_tcp_handle = new_create_dissector_handle(dissect_icep_tcp, proto_icep);
1334 icep_udp_handle = new_create_dissector_handle(dissect_icep_udp, proto_icep);
1336 heur_dissector_add("tcp", dissect_icep_tcp, proto_icep);
1337 heur_dissector_add("udp", dissect_icep_udp, proto_icep);
1339 icep_prefs_initialized = TRUE;
1342 /* Register TCP port for dissection */
1343 if(old_icep_tcp_port != 0 && old_icep_tcp_port != icep_tcp_port){
1344 dissector_delete_uint("tcp.port", old_icep_tcp_port, icep_tcp_handle);
1347 if(icep_tcp_port != 0 && old_icep_tcp_port != icep_tcp_port) {
1348 dissector_add_uint("tcp.port", icep_tcp_port, icep_tcp_handle);
1351 old_icep_tcp_port = icep_tcp_port;
1353 /* Register UDP port for dissection */
1354 if(old_icep_udp_port != 0 && old_icep_udp_port != icep_udp_port){
1355 dissector_delete_uint("udp.port", old_icep_udp_port, icep_udp_handle);
1358 if(icep_udp_port != 0 && old_icep_udp_port != icep_udp_port) {
1359 dissector_add_uint("udp.port", icep_udp_port, icep_udp_handle);
1362 old_icep_udp_port = icep_udp_port;