2 * Routines for "The ICE Protocol" dissection
4 * Francesco Fondelli <fondelli dot francesco, tiscali dot it>
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.
29 1) Dissect encoded data (do sth like idl2wrs for CORBA).
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
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"
52 #define DBG(str, args...) do {\
59 fprintf(stdout, str, ## args); \
63 #define DBG1(format, arg1)
64 #define DBG2(format, arg1, arg2)
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;
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
;
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
[] = {
134 {0x1, "Batch request"},
136 {0x3, "Validate connection"},
137 {0x4, "Close connection"},
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"},
148 static const value_string icep_replystatus_vals
[] = {
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"},
160 static const value_string icep_mode_vals
[] = {
162 {0x1, "nonmutating"},
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
180 * string = 1byte (255) + 1int (255..2^32-1) + string not null terminated
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)");
199 Size
= tvb_get_guint8(tvb
, offset
);
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)");
215 /* get second field of Size */
216 Size
= tvb_get_letohl(tvb
, offset
);
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)");
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)");
244 s
= tvb_get_string(wmem_packet_scope(), tvb
, offset
, Size
);
245 proto_tree_add_string(tree
, hf_icep
, tvb
, offset
, Size
, s
);
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
);
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:
272 * sequence == Size + SizeElements
273 * sequence = 1byte (0..254) + SizeElements
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 */
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)");
298 /* get first byte of Size */
299 Size
= tvb_get_guint8(tvb
, offset
);
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)");
311 gint32 consumed_facet
= 0;
313 dissect_ice_string(pinfo
, tree
, item
, hf_icep
, tvb
, offset
, &consumed_facet
, NULL
);
315 if ( consumed_facet
== -1 ) {
320 /*offset += consumed_facet;*/
321 (*consumed
) += consumed_facet
;
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)");
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
349 * dictionary<string, string>= 1byte (255) + 1int (255..2^32-1)+SizeKeyValuePairs
353 guint32 Size
= 0; /* number of key-value in the dictionary */
355 const char *s
= NULL
;
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)");
369 /* get first byte of Size */
370 Size
= tvb_get_guint8(tvb
, offset
);
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)");
386 /* get second field of Size */
387 Size
= tvb_get_letohl(tvb
, offset
);
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)");
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
);
412 /* looping through the dictionary */
413 for ( i
= 0; i
< Size
; i
++ ) {
415 gint32 consumed_key
= 0;
416 char *str_key
= NULL
;
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 ) {
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 ) {
442 offset
+= consumed_value
;
443 (*consumed
) += consumed_value
;
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 {
463 * //(size - 6) bytes of data
469 gint tvb_data_remained
= 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)");
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)");
499 proto_tree_add_item(tree
, hf_icep_params_size
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
503 proto_tree_add_item(tree
, hf_icep_params_major
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
507 proto_tree_add_item(tree
, hf_icep_params_minor
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
512 /* skip size, major, minor */
517 if( size
== ICEP_MIN_PARAMS_SIZE
) /* no encapsulatd data present, it's normal */
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
);
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
549 * Ice::StringSeq facet;
552 * Ice::Context context;
553 * Encapsulation params;
558 char *namestr
= 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)");
572 /* got at least 15 bytes */
581 dissect_ice_string(pinfo
, icep_sub_tree
, icep_sub_item
, hf_icep_id_name
, tvb
, offset
, &consumed
, &namestr
);
583 if ( consumed
== -1 )
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 )
595 offset
+= consumed
; DBG1("consumed --> %d\n", consumed
);
596 (*total_consumed
) += consumed
;
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 )
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 )
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()",
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)");
642 proto_tree_add_item(icep_sub_tree
, hf_icep_mode
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
644 offset
++; DBG0("consumed --> 1\n");
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 )
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 )
669 /*offset += consumed;*/
670 DBG1("consumed --> %d\n", consumed
);
671 (*total_consumed
) += consumed
;
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 {
688 * Ice::StringSeq facet;
691 * Ice::Context context;
692 * Encapsulation params;
696 proto_item
*ti
= NULL
;
697 proto_tree
*icep_sub_tree
= NULL
;
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)");
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
);
723 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "(%d):", tvb_get_letohl(tvb
, offset
));
725 col_append_str(pinfo
->cinfo
, COL_INFO
, "(oneway):");
729 DBG0("consumed --> 4\n");
731 dissect_icep_request_common(tvb
, offset
, pinfo
, icep_sub_tree
, ti
, &consumed
);
733 if ( consumed
== -1 )
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 {
751 * Ice::StringSeq facet;
754 * Ice::Context context;
755 * Encapsulation params;
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;
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)");
780 num_reqs
= tvb_get_letohl(tvb
, offset
);
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
);
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)");
803 col_append_str(pinfo
->cinfo
, COL_INFO
, ":");
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
);
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 )
828 if ( icep_tree
&& ti
)
829 proto_item_set_len(ti
, 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:
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)");
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
));
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"));
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
);
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
);
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 {
930 * byte protocolMajor;
931 * byte protocolMinor;
932 * byte encodingMajor;
933 * byte encodingMinor;
935 * byte compressionStatus;
940 proto_item
*ti
, *msg_item
= NULL
;
941 proto_tree
*icep_tree
;
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),
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
);
961 /* add items to the subtree */
965 proto_tree_add_text(icep_tree
, tvb
, offset
, 4,
966 "Magic Number: 'I','c','e','P'");
969 proto_tree_add_item(icep_tree
, hf_icep_protocol_major
,
970 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
973 proto_tree_add_item(icep_tree
, hf_icep_protocol_minor
,
974 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
977 proto_tree_add_item(icep_tree
, hf_icep_encoding_major
,
978 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
981 proto_tree_add_item(icep_tree
, hf_icep_encoding_minor
,
982 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
985 msg_item
= proto_tree_add_item(icep_tree
, hf_icep_message_type
,
986 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
989 proto_tree_add_item(icep_tree
, hf_icep_compression_status
,
990 tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
993 proto_tree_add_item(icep_tree
, hf_icep_message_size
,
994 tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
997 offset
+= ICEP_HEADER_SIZE
;
1000 switch(tvb_get_guint8(tvb
, 8)) {
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
);
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
);
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
);
1018 /* messages already dissected */
1021 expert_add_info_format(pinfo
, msg_item
, &ei_icep_message_type
, "Unknown Message Type: 0x%02x", tvb_get_guint8(tvb
, 8));
1024 return tvb_length(tvb
);
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. */
1037 /* start dissecting */
1039 tcp_dissect_pdus(tvb
, pinfo
, tree
, TRUE
, ICEP_HEADER_SIZE
,
1040 get_icep_pdu_len
, dissect_icep_pdu
, data
);
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. */
1054 /* start dissecting */
1055 dissect_icep_pdu(tvb
, pinfo
, tree
, data
);
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",
1127 { &hf_icep_request_id
,
1129 "Request Identifier", "icep.request_id",
1130 FT_INT32
, BASE_DEC
, NULL
, 0x0,
1131 "The request identifier",
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
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
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
1178 "Ice::OperationMode", "icep.operation_mode",
1179 FT_INT8
, BASE_DEC
, VALS(icep_mode_vals
), 0x0,
1180 "A byte representing Ice::OperationMode", HFILL
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",
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",
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",
1221 { &hf_icep_params_encapsulated
,
1223 "Encapsulated parameters",
1224 "icep.params.encapsulated",
1225 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
1226 "Remaining encapsulated parameters",
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
,
1242 "icep.invocation_key",
1243 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
1247 { &hf_icep_invocation_value
,
1250 "icep.invocation_value",
1251 FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
1256 /* Setup protocol subtree array */
1258 static gint
*ett
[] = {
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 */
1283 proto_register_protocol("Internet Communications Engine Protocol",
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",
1301 prefs_register_uint_preference(icep_module
, "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
;