Add HP Switch Protocol SAP value
[obnox/wireshark/wip.git] / epan / dissectors / packet-icep.c
1 /* packet-icep.c
2  * Routines for "The ICE Protocol" dissection
3  * Copyright 2004 _FF_ 
4  * Francesco Fondelli <fondelli dot francesco, tiscali dot it>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <gerald@wireshark.org>
10  * Copyright 1998 Gerald Combs
11  * 
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.
16  * 
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.
21  * 
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*
28   TODO:
29   1) Dissect encoded data (do sth like idl2wrs for CORBA).
30   2) Add conversations.
31   3) Register a dissector as one that can be selected by a UDP/TCP port number.
32   4) Put in Preferences/Protocols/ICEP Option menu:
33       - ICEP_MAX_ICE_STRING_LEN
34       - ICEP_MAX_BATCH_REQUESTS
35       - ICEP_MAX_ICE_CONTEXT_PAIRS
36 */
37
38 /*
39   NOTES:
40   1) p. 586 Chapter 23.2 of "The ICE Protocol"
41      "Data is always encoded using little-endian byte order for numeric types."
42   2) Informations about Ice can be found here: http://www.zeroc.com
43 */
44
45 #ifdef HAVE_CONFIG_H
46 # include "config.h"
47 #endif
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include <glib.h>
54
55 #include <epan/packet.h>
56 #include <epan/emem.h>
57 #include "packet-tcp.h"
58
59 #if 0
60 #define DBG(str, args...)       do {\
61                                         fprintf(stdout, \
62                                         "[%s][%s][%d]: ",\
63                                         __FILE__, \
64                                         __FUNCTION__, \
65                                         __LINE__); \
66                                         fflush(stdout); \
67                                         fprintf(stdout, str, ## args); \
68                                 } while (0)
69 #else
70 #define DBG0(format)
71 #define DBG1(format, arg1)
72 #define DBG2(format, arg1, arg2)
73 #endif /* 0/1 */
74
75 /* fixed values taken from the standard */
76 static const guint8 icep_magic[] = { 'I', 'c', 'e', 'P' };
77 #define ICEP_HEADER_SIZE                        14
78 #define ICEP_MIN_REPLY_SIZE                     5
79 #define ICEP_MIN_PARAMS_SIZE                    6
80 #define ICEP_MIN_COMMON_REQ_HEADER_SIZE         13
81
82 /* values derived from common sense */
83 #define ICEP_MAX_BATCH_REQUESTS                 64
84 #define ICEP_MAX_ICE_STRING_LEN                 512
85 #define ICEP_MAX_ICE_CONTEXT_PAIRS              64
86
87
88 /* Initialize the protocol and registered fields */
89 static int proto_icep = -1;
90
91 /* Message Header */
92 static int hf_icep_protocol_major = -1;
93 static int hf_icep_protocol_minor = -1;
94 static int hf_icep_encoding_major = -1;
95 static int hf_icep_encoding_minor = -1;
96 static int hf_icep_message_type = -1;
97 static int hf_icep_compression_status = -1;
98 static int hf_icep_message_size = -1;
99
100 /* [Batch] Request Message Body */
101 static int hf_icep_request_id = -1;
102 static int hf_icep_id_name = -1;
103 static int hf_icep_id_category = -1;
104 static int hf_icep_facet = -1;
105 static int hf_icep_operation = -1;
106 static int hf_icep_mode = -1;
107 static int hf_icep_context = -1;
108 static int hf_icep_params_size = -1;
109 static int hf_icep_params_major = -1;
110 static int hf_icep_params_minor = -1;
111
112 /* Reply Message Body */
113 static int hf_icep_reply_status = -1;
114
115 /* Initialize the subtree pointers */
116 static gint ett_icep = -1;
117 static gint ett_icep_msg = -1;
118
119 static const value_string icep_msgtype_vals[] = {
120         {0x0, "Request"},
121         {0x1, "Batch request"},
122         {0x2, "Reply"},
123         {0x3, "Validate connection"},
124         {0x4, "Close connection"},
125         {0, NULL}
126 };
127
128 static const value_string icep_zipstatus_vals[] = {
129         {0x0, "Uncompressed, sender cannot accept a compressed reply"},
130         {0x1, "Uncompressed, sender can accept a compressed reply"},
131         {0x2, "Compressed, sender can accept a compressed reply"},
132         {0, NULL}
133 };
134
135 static const value_string icep_replystatus_vals[] = {
136         {0x0, "Success"},
137         {0x1, "User exception"},
138         {0x2, "Object does not exist"},
139         {0x3, "Facet does not exist"},
140         {0x4, "Operation does not exist"},
141         {0x5, "Unknown Ice local exception"},
142         {0x6, "Unknown Ice user exception"},
143         {0x7, "Unknown exception"},
144         {0, NULL}
145 };
146
147 static const value_string icep_mode_vals[] = {
148         {0x0, "normal"},
149         {0x1, "nonmutating"},
150         {0x2, "idempotent"},
151         {0, NULL}
152 };
153
154 static packet_info *mypinfo;
155
156
157
158 /* 
159  * This function dissects an "Ice string", adds hf to "tree" and returns consumed 
160  * bytes in "*consumed", if errors "*consumed" is -1.
161  *
162  * "*dest" is a null terminated version of the dissected Ice string.
163  */
164 static void dissect_ice_string(proto_tree *tree, int hf_icep, 
165                                tvbuff_t *tvb, guint32 offset, gint32 *consumed,
166                                char **dest, gboolean add_hf)
167 {
168         /* p. 586 chapter 23.2.1 and p. 588 chapter 23.2.5 
169          * string == Size + content 
170          * string = 1byte (0..254) + string not null terminated 
171          * or                                                  
172          * string = 1byte (255) + 1int (255..2^32-1) + string not null terminated 
173          */
174         
175         guint32 Size = 0;
176         char *s = NULL;
177         
178         (*consumed) = 0;
179         
180         /* check for first byte */
181         if ( !tvb_bytes_exist(tvb, offset, 1) ) {
182                 
183                 if (tree)
184                         proto_tree_add_text(tree, tvb, offset, -1, 
185                                             "1st byte of Size missing");
186                 
187                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
188                         col_append_str(mypinfo->cinfo, COL_INFO, 
189                                        " (1st byte of Size missing)");
190                 }
191                 
192                 (*consumed) = -1;
193                 return;
194         }
195         
196         /* get the Size */
197         Size = tvb_get_guint8(tvb, offset);
198         offset++;
199         (*consumed)++;
200         
201         if ( Size == 255 ) {
202                 
203                 /* check for next 4 bytes */
204                 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
205                         
206                         if (tree)
207                                 proto_tree_add_text(tree, tvb, offset, -1,
208                                                     "second field of Size missing");
209                         
210                         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
211                                 col_append_str(mypinfo->cinfo, COL_INFO, 
212                                                " (second field of Size missing)");
213                         }
214                         
215                         (*consumed) = -1;
216                         return;
217                 }
218                 
219                 /* get second field of Size */
220                 Size = tvb_get_letohl(tvb, offset);
221                 offset += 4;
222                 (*consumed) += 4;
223         }
224         
225         DBG1("string.Size --> %d\n", Size);
226         
227         /* check if the string exists */
228         if ( !tvb_bytes_exist(tvb, offset, Size) ) {
229                 
230                 if (tree)
231                         proto_tree_add_text(tree, tvb, offset, -1, 
232                                             "missing or truncated string");
233                 
234                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
235                         col_append_str(mypinfo->cinfo, COL_INFO, 
236                                        " (missing or truncated string)");
237                 }
238                 
239                 (*consumed) = -1;
240                 return;
241         }
242
243         if ( Size > ICEP_MAX_ICE_STRING_LEN ) {
244                 
245                 if (tree)
246                         proto_tree_add_text(tree, tvb, offset, -1, "string too long");
247                 
248                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
249                         col_append_str(mypinfo->cinfo, COL_INFO, 
250                                        " (string too long)");
251                 }
252                 
253                 (*consumed) = -1;
254                 return;
255         }
256         
257         
258                 
259         if ( Size != 0 ) {
260                 s = tvb_get_ephemeral_string(tvb, offset, Size);
261                 if (tree && add_hf)
262                         proto_tree_add_string(tree, hf_icep, tvb, offset, Size, s);
263         } else {
264                 s = g_strdup("(empty)");
265                 /* display the 0x00 Size byte when click on a empty ice_string */
266                 if (tree && add_hf)
267                         proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, s);
268         }
269         
270         if ( dest != NULL )
271                 *dest = s;
272         
273         offset += Size;
274         (*consumed) += Size;
275         return;
276 }
277
278 /* 
279  * This function dissects an "Ice facet", adds hf(s) to "tree" and returns consumed 
280  * bytes in "*consumed", if errors "*consumed" is -1.
281  */
282 static void dissect_ice_facet(proto_tree *tree, int hf_icep, 
283                               tvbuff_t *tvb, guint32 offset, gint32 *consumed)
284 {
285         /*  p. 588, chapter 23.2.6:
286          *  "facet" is a StringSeq, a StringSeq is a:                
287          *  sequence<string>
288          *
289          *
290          * sequence == Size + SizeElements 
291          * sequence = 1byte (0..254) + SizeElements 
292          * or                                                      
293          * sequence = 1byte (255) + 1int (255..2^32-1) + SizeElements 
294          *
295          *
296          * p.613. chapter 23.3.2
297          * "facet has either zero elements (empty) or one element"
298          *
299          *       
300          */
301         
302         guint32 Size = 0; /* number of elements in the sequence */
303         char *s = NULL;
304         
305         (*consumed) = 0;
306         
307         /* check first byte */
308         if ( !tvb_bytes_exist(tvb, offset, 1) ) {
309                 
310                 if (tree)
311                         proto_tree_add_text(tree, tvb, offset, -1, "facet field missing");
312                 
313                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
314                         col_append_str(mypinfo->cinfo, COL_INFO, 
315                                        " (facet field missing)");
316                 }
317                 
318                 (*consumed) = -1;
319                 return;
320         }
321         
322         /* get first byte of Size */
323         Size = tvb_get_guint8(tvb, offset);
324         offset++;
325         (*consumed)++;
326         
327         if ( Size == 0 ) {
328                 
329                 if (tree) {
330                         s = ep_strdup( "(empty)" );
331                         /* display the 0x00 Size byte when click on a empty ice_string */
332                         proto_tree_add_string(tree, hf_icep, tvb, offset - 1, 1, s);
333                 }
334                 return;
335         }
336         
337         if ( Size == 1 ) {
338                 
339                 gint32 consumed_facet = 0;
340                 
341                 dissect_ice_string(tree, hf_icep, tvb, offset, &consumed_facet, NULL, TRUE);
342                 
343                 if ( consumed_facet == -1 ) {
344                         (*consumed) = -1;
345                         return;
346                 }
347                 
348                 offset += consumed_facet;
349                 (*consumed) += consumed_facet;
350                 return;
351         }
352         
353         /* if here => Size > 1 => not possible */
354         
355         if (tree)
356                 /* display the XX Size byte when click here */
357                 proto_tree_add_text(tree, tvb, offset - 1, 1, 
358                                     "facet can be max one element");
359         
360         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
361                 col_append_str(mypinfo->cinfo, COL_INFO, 
362                                " (facet can be max one element)");
363         }
364         
365         (*consumed) = -1;
366         return;
367 }
368
369 /* 
370  * This function dissects an "Ice context", adds hf(s) to "tree" and returns consumed 
371  * bytes in "*consumed", if errors "*consumed" is -1.
372  */
373 static void dissect_ice_context(proto_tree *tree, tvbuff_t *tvb, guint32 offset, 
374                                 gint32 *consumed)
375 {
376         /*  p. 588, chapter 23.2.7 and p. 613, 23.3.2:
377          *  "context" is a dictionary<string, string>                
378          *
379          * dictionary<string, string> == Size + SizeKeyValuePairs 
380          * dictionary<string, string> = 1byte (0..254) + SizeKeyValuePairs
381          * or                                                      
382          * dictionary<string, string>= 1byte (255) + 1int (255..2^32-1)+SizeKeyValuePairs 
383          *       
384          */
385         
386         guint32 Size = 0; /* number of key-value in the dictionary */
387         guint32 i = 0;
388         char *s = NULL;
389         
390         (*consumed) = 0;
391         
392         /* check first byte */
393         if ( !tvb_bytes_exist(tvb, offset, 1) ) {
394                 
395                 if (tree)
396                         proto_tree_add_text(tree, tvb, offset, -1, "context missing");
397                 
398                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
399                         col_append_str(mypinfo->cinfo, COL_INFO, 
400                                        " (context missing)");
401                 }
402                 
403                 (*consumed) = -1;
404                 return;
405         }
406         
407         /* get first byte of Size */
408         Size = tvb_get_guint8(tvb, offset);
409         offset++;
410         (*consumed)++;
411         
412         if ( Size == 255 ) {
413                 
414                 /* check for next 4 bytes */
415                 if ( !tvb_bytes_exist(tvb, offset, 4) ) {
416                         
417                         if (tree)
418                                 proto_tree_add_text(tree, tvb, offset, -1,
419                                                     "second field of Size missing");
420                         
421                         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
422                                 col_append_str(mypinfo->cinfo, COL_INFO, 
423                                                " (second field of Size missing)");
424                         }
425                         
426                         (*consumed) = -1;
427                         return;
428                 }
429                 
430                 /* get second field of Size */
431                 Size = tvb_get_letohl(tvb, offset);
432                 offset += 4;
433                 (*consumed) += 4;
434         }
435         
436         DBG1("context.Size --> %d\n", Size);
437
438         if ( Size > ICEP_MAX_ICE_CONTEXT_PAIRS ) {
439                 
440                 if (tree)
441                         /* display the XX Size byte when click here */
442                         proto_tree_add_text(tree, tvb, offset - 1, 1, "too long context");
443                 
444                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
445                         col_append_str(mypinfo->cinfo, COL_INFO, 
446                                        " (too long context)");
447                 }
448                 
449                 (*consumed) = -1;
450                 return;
451         }
452         
453         if (Size == 0) {
454                 s = "(empty)";
455                 /* display the 0x00 Size byte when click on a empty context */
456                 if (tree)
457                         proto_tree_add_string(tree, hf_icep_context, tvb, offset - 1, 1, s);
458                 return;
459         }
460         
461         /* looping through the dictionary */
462         for ( i = 0; i < Size; i++ ) {
463                 /* key */
464                 gint32 consumed_key = 0;
465                 char *str_key = NULL;
466                 /* value */
467                 gint32 consumed_value = 0;
468                 char *str_value = NULL;
469                 
470
471                 DBG1("looping through context dictionary, loop #%d\n", i);
472         
473                 dissect_ice_string(tree, -1, tvb, offset, &consumed_key, 
474                                    &str_key, FALSE);
475                 
476                 if ( consumed_key == -1 ) {
477                         (*consumed) = -1;
478                         return;
479                 }
480                 
481                 offset += consumed_key;
482                 (*consumed) += consumed_key;
483                 
484                 dissect_ice_string(tree, -1, tvb, offset, &consumed_value, 
485                                    &str_value, FALSE);
486                 
487                 if ( consumed_value == -1 ) {
488                         (*consumed) = -1;
489                         return;
490                 }
491                 
492                 offset += consumed_value;
493                 (*consumed) += consumed_value;
494                 
495                 if (tree && str_value && str_key) {
496                         
497                         proto_tree_add_text(tree, tvb,
498                                             offset - (consumed_key + consumed_value) - 1, 
499                                             (consumed_key + consumed_value) + 1,
500                                             "Invocation Context: %s/%s",
501                                             str_key, str_value);
502                 }
503                 
504         }
505 }
506
507 /* 
508  * This function dissects an "Ice params", adds hf(s) to "tree" and returns consumed 
509  * bytes in "*consumed", if errors "*consumed" is -1.
510  */
511 static void dissect_ice_params(proto_tree *tree, tvbuff_t *tvb, 
512                                guint32 offset, gint32 *consumed)
513 {
514         /*  p. 612, chapter 23.3.2 and p. 587, 23.2.2:
515          *  "params" is an Encapsulation                
516          *
517          *  struct Encapsulation {
518          *      int size;
519          *      byte major;
520          *      byte minor;
521          *      //(size - 6) bytes of data
522          *  }
523          *   
524          */
525         
526         gint32 size = 0;
527         gint tvb_data_remained = 0;
528         
529         (*consumed) = 0;
530         
531         /* check first 6 bytes */
532         if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_PARAMS_SIZE) ) {
533                 
534                 if (tree)
535                         proto_tree_add_text(tree, tvb, offset, -1, "params missing");
536                 
537                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
538                         col_append_str(mypinfo->cinfo, COL_INFO, 
539                                        " (params missing)");
540                 }
541                 
542                 (*consumed) = -1;
543                 return;
544         }
545         
546         /* get the size */
547         size = tvb_get_letohl(tvb, offset);
548         
549         DBG1("params.size --> %d\n", size);
550         
551         if ( size < ICEP_MIN_PARAMS_SIZE ) {
552                 
553                 if (tree)
554                         proto_tree_add_text(tree, tvb, offset, 4, 
555                                             "params size too small");
556                 
557                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
558                         col_append_str(mypinfo->cinfo, COL_INFO, 
559                                        " (params size too small)");
560                 }
561                 
562                 (*consumed) = -1;
563                 return;
564         }
565         
566         if ( tree ) {
567         
568                 proto_tree_add_item(tree, hf_icep_params_size, tvb, offset, 4, TRUE);
569                 offset += 4;
570                 (*consumed) += 4;
571                 
572                 proto_tree_add_item(tree, hf_icep_params_major, tvb, offset, 1, TRUE);
573                 offset += 1;
574                 (*consumed)++;
575                 
576                 proto_tree_add_item(tree, hf_icep_params_minor, tvb, offset, 1, TRUE);
577                 offset += 1;
578                 (*consumed)++;
579                 
580         } else {
581                 /* skipp size, major, minor */
582                 offset += 6;
583                 (*consumed) += 6;
584         }
585         
586         if( size == ICEP_MIN_PARAMS_SIZE ) /* no encapsulatd data present, it's normal */
587                 return;
588         
589         /* check if I got all encapsulated data */
590         tvb_data_remained = tvb_reported_length_remaining(tvb, offset);
591         
592         if ( tvb_data_remained < ( size - ICEP_MIN_PARAMS_SIZE ) ) {
593                 
594                 if (tree)
595                         proto_tree_add_text(tree, tvb, offset, -1,
596                                             "missing encapsulated data (%d bytes)",
597                                             size 
598                                             - ICEP_MIN_PARAMS_SIZE 
599                                             - tvb_data_remained);
600                 
601                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
602                         col_append_fstr(mypinfo->cinfo, COL_INFO,
603                                         " (missing encapsulated data (%d bytes))",
604                                         size
605                                         - ICEP_MIN_PARAMS_SIZE 
606                                         - tvb_data_remained);
607                 }
608                 
609                 (*consumed) = -1;
610                 return;
611         }
612         
613         /* encapsulated params */
614         
615         if (tree) {
616                 proto_tree_add_text(tree, tvb, offset, (size - ICEP_MIN_PARAMS_SIZE),
617                                     "Encapsulated parameters (%d bytes)", 
618                                     (size - ICEP_MIN_PARAMS_SIZE));
619         }
620         
621         (*consumed) += (size - ICEP_MIN_PARAMS_SIZE);
622 }
623
624 static void dissect_icep_request_common(tvbuff_t *tvb, guint32 offset, 
625                                         proto_tree *icep_sub_tree, gint32 *total_consumed)
626 {
627         /*  p. 613, chapter 23.3.3 and p. 612 chapter 23.3.2:
628          *  Request and BatchRequest differ only in the first 4 bytes (requestID)
629          *  so them share this part
630          *
631          *       Ice::Identity id;
632          *       Ice::StringSeq facet;
633          *       string operation;
634          *       byte mode;
635          *       Ice::Context context;
636          *       Encapsulation params;
637          *  }
638          */
639         
640         gint32 consumed = 0;
641         char *namestr = NULL;
642         char *opstr = NULL;
643         
644         (*total_consumed) = 0;
645         
646         /* check common header (i.e. the batch request one)*/
647         if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_COMMON_REQ_HEADER_SIZE) ) {
648                 
649                 if (icep_sub_tree)
650                         proto_tree_add_text(icep_sub_tree, tvb, offset, -1, 
651                                             "too short header");
652                 
653                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
654                         col_append_str(mypinfo->cinfo, COL_INFO, 
655                                        " (too short header)");
656                 }
657                 
658                 goto error;
659         }
660         
661         /* got at least 15 bytes */
662         
663         /*  "id" is a:
664          *  struct Identity {
665          *      string name;
666          *      string category;
667          *  }
668          */
669         
670         dissect_ice_string(icep_sub_tree, hf_icep_id_name, tvb, offset, 
671                            &consumed, &namestr, TRUE);
672         
673         if ( consumed == -1 )
674                 goto error;
675         
676         offset += consumed; DBG1("consumed --> %d\n", consumed);
677         (*total_consumed) += consumed;
678         
679         
680         dissect_ice_string(icep_sub_tree, hf_icep_id_category, tvb, offset, 
681                            &consumed, NULL, TRUE);
682         
683         if ( consumed == -1 )
684                 goto error;
685         
686         offset += consumed; DBG1("consumed --> %d\n", consumed);
687         (*total_consumed) += consumed;
688         
689         
690         /*  "facet" is a:
691          *  sequence<string> StringSeq
692          *
693          */
694         
695         dissect_ice_facet(icep_sub_tree, hf_icep_facet, tvb, offset, &consumed);
696         
697         if ( consumed == -1 )
698                 goto error;
699         
700         offset += consumed; DBG1("consumed --> %d\n", consumed);
701         (*total_consumed) += consumed;
702         
703         /*  "operation" is an ice_string
704          *
705          */
706         
707         dissect_ice_string(icep_sub_tree, hf_icep_operation, tvb, offset, 
708                            &consumed, &opstr, TRUE);
709         
710         if ( consumed == -1 )
711                 goto error;
712         else {
713                 offset += consumed; DBG1("consumed --> %d\n", consumed);
714                 (*total_consumed) += consumed;
715
716                 if ( opstr && namestr ) {
717                         DBG2("operation --> %s.%s()\n", namestr, opstr);
718                         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
719                                 col_append_fstr(mypinfo->cinfo, COL_INFO, " %s.%s()", 
720                                                 namestr, opstr);
721                         }
722                         opstr = NULL;
723                         namestr = NULL;
724                 }
725         }
726         
727         /* check and get mode byte */
728         if ( !tvb_bytes_exist(tvb, offset, 1) ) {
729                 
730                 if (icep_sub_tree)
731                         proto_tree_add_text(icep_sub_tree, tvb, offset, -1, 
732                                             "mode field missing");
733                 
734                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
735                         col_append_str(mypinfo->cinfo, COL_INFO, 
736                                        " (mode field missing)");
737                 }
738                 
739                 goto error;
740         }
741         
742         if (icep_sub_tree) 
743                 proto_tree_add_item(icep_sub_tree, hf_icep_mode, tvb, offset, 1, TRUE);
744         
745         offset++; DBG0("consumed --> 1\n");
746         (*total_consumed)++;
747         
748         
749         /*  "context" is a dictionary<string, string>
750          *
751          */
752         
753         dissect_ice_context(icep_sub_tree, tvb, offset, &consumed);
754         
755         if ( consumed == -1 )
756                 goto error;
757         
758         offset += consumed; DBG1("consumed --> %d\n", consumed);
759         (*total_consumed) += consumed;
760         
761         /*  "params" is a Encapsulation
762          *  
763          */
764         
765         dissect_ice_params(icep_sub_tree, tvb, offset, &consumed);
766         
767         if ( consumed == -1 )
768                 goto error;
769         
770         offset += consumed; DBG1("consumed --> %d\n", consumed);
771         (*total_consumed) += consumed;
772                 
773         return;
774         
775 error:
776         (*total_consumed) = -1;
777 }
778
779
780 static void dissect_icep_request(tvbuff_t *tvb, guint32 offset, proto_tree *icep_tree)
781 {
782         /*  p. 612, chapter 23.3.2:
783          *
784          *  struct RequestData {
785          *       int requestID;
786          *       Ice::Identity id;
787          *       Ice::StringSeq facet;
788          *       string operation;
789          *       byte mode;
790          *       Ice::Context context;
791          *       Encapsulation params;
792          *  }
793          */
794         
795         proto_item *ti = NULL;
796         proto_tree *icep_sub_tree = NULL;
797         gint32 consumed = 0;
798         guint32 reqid = 0;
799         
800         DBG0("dissect request\n");
801         
802         /* check for req id */
803         if ( !tvb_bytes_exist(tvb, offset, 4) ) {
804                 
805                 if (icep_tree)
806                         proto_tree_add_text(icep_tree, tvb, offset, -1, 
807                                             "too short header");
808                 
809                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
810                         col_append_str(mypinfo->cinfo, COL_INFO, 
811                                        " (too short header)");
812                 }
813                 
814                 return;
815         }
816         
817         /* got at least 4 bytes */
818         
819         /* create display subtree for this message type */
820         
821         reqid = tvb_get_letohl(tvb, offset);
822         
823         if (icep_tree) {
824                 
825                 ti = proto_tree_add_text(icep_tree, tvb, offset, -1, 
826                                          "Request Message Body");
827                 
828                 icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
829                 
830                 proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, 
831                                     TRUE);
832                 
833         }
834         
835         if ( reqid != 0 ) {
836                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
837                         col_append_fstr(mypinfo->cinfo, COL_INFO, "(%d):",
838                                         tvb_get_letohl(tvb, offset));
839                 }
840         } else
841                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
842                         col_append_str(mypinfo->cinfo, COL_INFO, "(oneway):");
843                 }
844         
845         
846         offset += 4;
847         DBG0("consumed --> 4\n");
848         
849         dissect_icep_request_common(tvb, offset, icep_sub_tree, &consumed);
850         
851         if ( consumed == -1 )
852                 return;
853         
854         offset += consumed;
855         DBG1("consumed --> %d\n", consumed);
856 }
857
858
859
860 static void dissect_icep_batch_request(tvbuff_t *tvb, guint32 offset, 
861                                        proto_tree *icep_tree)
862 {
863         /*  p. 613, chapter 23.3.3
864          *  A batch request msg is a "sequence" of batch request
865          *  Sequence is Size + elements
866          *
867          *  struct BatchRequestData {
868          *       Ice::Identity id;
869          *       Ice::StringSeq facet;
870          *       string operation;
871          *       byte mode;
872          *       Ice::Context context;
873          *       Encapsulation params;
874          *  }
875          *
876          * NOTE!!!:
877          * The only real implementation of the Ice protocol puts a 32bit count in front
878          * of a Batch Request, *not* an Ice::Sequence (as the standard says). Basically the
879          * same people wrote both code and standard so I'll follow the code.
880          */
881         
882         proto_item *ti = NULL;
883         proto_tree *icep_sub_tree = NULL;
884         guint32 num_reqs = 0;
885         guint32 i = 0;
886         gint32 consumed = 0;
887                 
888         DBG0("dissect batch request\n");
889         
890         /* check for first 4 byte */
891         if ( !tvb_bytes_exist(tvb, offset, 4) ) {
892                 
893                 if (icep_tree)
894                         proto_tree_add_text(icep_tree, tvb, offset, -1, 
895                                             "counter of batch requests missing");
896                 
897                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
898                         col_append_str(mypinfo->cinfo, COL_INFO, 
899                                        " (counter of batch requests missing)");
900                 }
901                 
902                 return;
903         }
904         
905         num_reqs = tvb_get_letohl(tvb, offset);
906         offset += 4;
907         
908         DBG1("batch_requests.count --> %d\n", num_reqs);
909         
910         if ( num_reqs > ICEP_MAX_BATCH_REQUESTS ) {
911                 
912                 if (icep_tree)
913                         proto_tree_add_text(icep_tree, tvb, offset, -1,
914                                             "too many batch requests (%d)", num_reqs);
915                 
916                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
917                         col_append_fstr(mypinfo->cinfo, COL_INFO, 
918                                         " (too many batch requests, %d)", 
919                                         num_reqs);
920                 }
921                 
922                 return;
923         }
924
925         if ( num_reqs == 0 ) {
926                 
927                 if (icep_tree)
928                         proto_tree_add_text(icep_tree, tvb, offset, -1,
929                                             "empty batch requests sequence");
930                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
931                         col_append_fstr(mypinfo->cinfo, COL_INFO, 
932                                         " (empty batch requests sequence)");
933                 }
934                 
935                 return;
936         }
937         
938         
939         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
940                 col_append_fstr(mypinfo->cinfo, COL_INFO, 
941                                 ":");
942         }
943         
944         /*
945          * process requests 
946          */
947         
948         for ( i = 0; i < num_reqs; i++ ) {
949                                 
950                 DBG1("looping through sequence of batch requests, loop #%d\n", i);
951                 
952                 /* create display subtree for this message type */
953                 
954                 if (icep_tree) {
955                         
956                         ti = proto_tree_add_text(icep_tree, tvb, offset, -1,
957                                                  "Batch Request Message Body: #%d", i);
958                         
959                         icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
960                 
961                 }
962                         
963                 if ( check_col(mypinfo->cinfo, COL_INFO) && (i != 0) ) {
964                         col_append_fstr(mypinfo->cinfo, COL_INFO,
965                                         ",");
966                 }
967                 
968                 dissect_icep_request_common(tvb, offset, icep_sub_tree, &consumed);
969                 
970                 if ( consumed == -1 )
971                         return;
972                 
973                 if ( icep_tree && ti )
974                         proto_item_set_len(ti, consumed);
975                 
976                 offset += consumed;
977                 DBG1("consumed --> %d\n", consumed);
978         }
979 }
980
981 static void dissect_icep_reply(tvbuff_t *tvb, guint32 offset, proto_tree *icep_tree)
982 {
983         /*  p. 614, chapter 23.3.4:
984          *
985          *  struct ReplyData {
986          *       int requestId;
987          *       byte replyStatus;
988          *       [... messageSize - 19 bytes ...  ]
989          *  }
990          */
991         
992         gint32 messageSize = 0;
993         guint32 tvb_data_remained = 0;
994         guint32 reported_reply_data = 0;
995         proto_item *ti = NULL;
996         proto_tree *icep_sub_tree = NULL;
997         
998         DBG0("dissect reply\n");
999         
1000         /* get at least a full reply message header */
1001         
1002         if ( !tvb_bytes_exist(tvb, offset, ICEP_MIN_REPLY_SIZE) ) {
1003                 
1004                 if (icep_tree)
1005                         proto_tree_add_text(icep_tree, tvb, offset, -1, 
1006                                             "too short header");
1007                 
1008                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
1009                         col_append_str(mypinfo->cinfo, COL_INFO, 
1010                                        " (too short header)");
1011                 }
1012                 
1013                 return;
1014         }
1015         
1016         /* got 5 bytes, then data */
1017         
1018         /* create display subtree for this message type */
1019         
1020         if (icep_tree) {
1021                 
1022                 ti = proto_tree_add_text(icep_tree, tvb, offset, -1, 
1023                                          "Reply Message Body");
1024                 
1025                 icep_sub_tree = proto_item_add_subtree(ti, ett_icep_msg);
1026                 
1027                 proto_tree_add_item(icep_sub_tree, hf_icep_request_id, tvb, offset, 4, 
1028                                     TRUE);
1029         }
1030         
1031         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
1032                 col_append_fstr(mypinfo->cinfo, COL_INFO, "(%d):",
1033                                 tvb_get_letohl(tvb, offset));
1034         }
1035         
1036         offset += 4;
1037         
1038         if (icep_tree)
1039                 proto_tree_add_item(icep_sub_tree, hf_icep_reply_status, tvb, offset, 1, 
1040                                     TRUE);
1041         
1042         if ( check_col(mypinfo->cinfo, COL_INFO) ) {
1043                 col_append_fstr(mypinfo->cinfo, COL_INFO, " %s",
1044                                 val_to_str(tvb_get_guint8(tvb, offset),
1045                                            icep_replystatus_vals,
1046                                            "unknown reply status"));
1047         }
1048         
1049         offset++;
1050                 
1051         DBG1("consumed --> %d\n", 5);
1052         
1053         /* check if I got all reply data */
1054         tvb_data_remained = tvb_length_remaining(tvb, offset);
1055         messageSize = tvb_get_letohl(tvb, 10);
1056         reported_reply_data = messageSize - (ICEP_HEADER_SIZE + ICEP_MIN_REPLY_SIZE);
1057         
1058         /* no */
1059         if ( tvb_data_remained < reported_reply_data ) {
1060                 
1061                 if (icep_sub_tree) 
1062                         proto_tree_add_text(icep_sub_tree, tvb, offset, -1,
1063                                             "Reply Data (missing %d bytes out of %d)",
1064                                             reported_reply_data - tvb_data_remained,
1065                                             reported_reply_data);
1066                 
1067                 if ( check_col(mypinfo->cinfo, COL_INFO) ) {
1068                         col_append_fstr(mypinfo->cinfo, COL_INFO,
1069                                         " (missing reply data, %d bytes)",
1070                                         reported_reply_data - tvb_data_remained);
1071                 }
1072                 
1073                 offset += tvb_data_remained;
1074                 DBG1("consumed --> %d\n", tvb_data_remained);
1075                 return;
1076         }
1077         
1078         /* yes (reported_reply_data can be 0) */
1079         
1080         if (icep_sub_tree) {
1081                 
1082                 if ( reported_reply_data !=0 )
1083                         proto_tree_add_text(icep_sub_tree, tvb, offset, 
1084                                             reported_reply_data,
1085                                             "Reply data (%d bytes)",
1086                                             reported_reply_data);
1087                 else
1088                         proto_tree_add_text(icep_sub_tree, tvb, offset, 
1089                                             reported_reply_data,
1090                                             "Reply data (empty)");
1091         }
1092         
1093         offset += reported_reply_data;
1094         DBG1("consumed --> %d\n", reported_reply_data);
1095 }
1096
1097 static guint get_icep_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
1098 {
1099         return tvb_get_letohl(tvb, offset + 10);
1100 }
1101
1102 static void dissect_icep_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1103 {
1104         /*  p. 611, chapter 23.3.1:
1105          *
1106          *  struct HeaderData {
1107          *       int magic;
1108          *       byte protocolMajor;
1109          *       byte protocolMinor;
1110          *       byte encodingMajor;
1111          *       byte encodingMinor;
1112          *       byte messageType;
1113          *       byte compressionStatus;
1114          *       int messageSize;
1115          *  }
1116          */
1117         
1118         proto_item *ti = NULL;
1119         proto_tree *icep_tree = NULL;
1120         guint32 offset = 0;
1121
1122         /* Make entries in Protocol column and Info column on summary display */
1123         
1124         if ( check_col(pinfo->cinfo, COL_PROTOCOL) ) 
1125                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ICEP");
1126         
1127         if ( check_col(pinfo->cinfo, COL_INFO) ) {
1128                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s", 
1129                              val_to_str(tvb_get_guint8(tvb, 8),
1130                                         icep_msgtype_vals,
1131                                         "Unknown Message Type: 0x%02x"));
1132         }
1133         
1134         mypinfo = pinfo;
1135         
1136         if (tree) {
1137                 
1138                 DBG0("got an icep msg, start analisys\n");
1139                 
1140                 /* create display subtree for the protocol */
1141                 
1142                 ti = proto_tree_add_item(tree, proto_icep, tvb, 0, -1, FALSE);
1143                 
1144                 icep_tree = proto_item_add_subtree(ti, ett_icep);
1145                 
1146                 /* add items to the subtree */
1147                 
1148                 /* message header */
1149                 
1150                 proto_tree_add_text(icep_tree, tvb, offset, 4,
1151                                     "Magic Number: 'I','c','e','P'");
1152                 offset += 4;
1153                 
1154                 proto_tree_add_item(icep_tree, hf_icep_protocol_major, 
1155                                     tvb, offset, 1, TRUE);
1156                 offset++;
1157                 
1158                 proto_tree_add_item(icep_tree, hf_icep_protocol_minor, 
1159                                     tvb, offset, 1, TRUE);
1160                 offset++;
1161                 
1162                 proto_tree_add_item(icep_tree, hf_icep_encoding_major, 
1163                                     tvb, offset, 1, TRUE);
1164                 offset++;
1165
1166                 proto_tree_add_item(icep_tree, hf_icep_encoding_minor, 
1167                                     tvb, offset, 1, TRUE);
1168                 offset++;
1169
1170                 proto_tree_add_item(icep_tree, hf_icep_message_type, 
1171                                     tvb, offset, 1, TRUE);
1172                 offset++;
1173
1174                 proto_tree_add_item(icep_tree, hf_icep_compression_status, 
1175                                     tvb, offset, 1, TRUE);
1176                 offset++;
1177
1178                 proto_tree_add_item(icep_tree, hf_icep_message_size, 
1179                                     tvb, offset, 4, TRUE);
1180                 offset += 4;
1181         } else {
1182                 offset += ICEP_HEADER_SIZE;
1183         }
1184         
1185         switch(tvb_get_guint8(tvb, 8)) {
1186         case 0x0:
1187                 DBG1("request message body: parsing %d bytes\n",
1188                     tvb_length_remaining(tvb, offset));
1189                 dissect_icep_request(tvb, offset, icep_tree);
1190                 break;
1191         case 0x1:
1192                 DBG1("batch request message body: parsing %d bytes\n",
1193                     tvb_length_remaining(tvb, offset));
1194                 dissect_icep_batch_request(tvb, offset, icep_tree);
1195                 break;
1196         case 0x2:
1197                 DBG1("reply message body: parsing %d bytes\n",
1198                     tvb_length_remaining(tvb, offset));
1199                 dissect_icep_reply(tvb, offset, icep_tree);
1200                 break;
1201         case 0x3:
1202         case 0x4:
1203                 /* messages already dissected */
1204                 break;
1205         default:
1206                 if (tree)
1207                         proto_tree_add_text(tree, tvb, 8, 1, /* display msg type byte */
1208                                             "Unknown Message Type: 0x%02x", 
1209                                             tvb_get_guint8(tvb, 8));
1210                 break;
1211         }
1212 }       
1213
1214 /* entry point */
1215 static gboolean dissect_icep(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1216 {
1217         DBG0("triggered\n");
1218         
1219         /* get at least a full message header (taken from packet-yhoo.c) */
1220         
1221         /* check for magic string (taken from packet-giop.c) */
1222         
1223         if ( tvb_memeql(tvb, 0, icep_magic, 4) == -1 ) {
1224                 /* Not a ICEP packet. */
1225                 return FALSE;
1226         }
1227                 
1228         /* start dissecting */
1229         
1230         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, ICEP_HEADER_SIZE,
1231             get_icep_pdu_len, dissect_icep_pdu);
1232
1233         return TRUE;
1234 }
1235
1236
1237 /* Register the protocol with Wireshark */
1238
1239 void proto_register_icep(void)
1240 {                 
1241         
1242         /* Setup list of header fields */
1243         
1244         static hf_register_info hf[] = {
1245                 
1246                 { &hf_icep_protocol_major,
1247                   { 
1248                           "Protocol Major", "icep.protocol_major", 
1249                           FT_INT8, BASE_DEC, NULL, 0x0, 
1250                           "The protocol major version number", HFILL
1251                   }
1252                 },
1253                 
1254                 { &hf_icep_protocol_minor,
1255                   { 
1256                           "Protocol Minor", "icep.protocol_minor", 
1257                           FT_INT8, BASE_DEC, NULL, 0x0, 
1258                           "The protocol minor version number", HFILL
1259                   }
1260                 },
1261
1262                 { &hf_icep_encoding_major,
1263                   { 
1264                           "Encoding Major", "icep.encoding_major", 
1265                           FT_INT8, BASE_DEC, NULL, 0x0, 
1266                           "The encoding major version number", HFILL
1267                   }
1268                 },
1269
1270                 { &hf_icep_encoding_minor,
1271                   { 
1272                           "Encoding Minor", "icep.encoding_minor", 
1273                           FT_INT8, BASE_DEC, NULL, 0x0, 
1274                           "The encoding minor version number", HFILL
1275                   }
1276                 },
1277                 
1278                 { &hf_icep_message_type,
1279                   { 
1280                           "Message Type", "icep.message_type", 
1281                           FT_INT8, BASE_DEC, VALS(icep_msgtype_vals), 0x0, 
1282                           "The message type", HFILL
1283                   }
1284                 },
1285
1286                 { &hf_icep_compression_status,
1287                   { 
1288                           "Compression Status", "icep.compression_status", 
1289                           FT_INT8, BASE_DEC, VALS(icep_zipstatus_vals), 0x0, 
1290                           "The compression status of the message", HFILL
1291                   }
1292                 },
1293                 
1294                 { &hf_icep_message_size,
1295                   { 
1296                           "Message Size", "icep.message_status", 
1297                           FT_INT32, BASE_DEC, NULL, 0x0, 
1298                           "The size of the message in bytes, including the header", 
1299                           HFILL
1300                   }
1301                 },
1302                 
1303                 { &hf_icep_request_id,
1304                   { 
1305                           "Request Identifier", "icep.request_id", 
1306                           FT_INT32, BASE_DEC, NULL, 0x0, 
1307                           "The request identifier", 
1308                           HFILL
1309                   }
1310                 },
1311                 
1312                 { &hf_icep_reply_status,
1313                   { 
1314                           "Reply Status", "icep.protocol_major", 
1315                           FT_INT8, BASE_DEC, VALS(icep_replystatus_vals), 0x0, 
1316                           "The reply status", HFILL
1317                   }
1318                 },
1319
1320                 { &hf_icep_id_name,
1321                   { 
1322                           "Object Identity Name", "icep.id.name", 
1323                           FT_STRINGZ, BASE_NONE, NULL, 0x0, 
1324                           "The object identity name", HFILL
1325                   }
1326                 },
1327
1328                 { &hf_icep_id_category,
1329                   { 
1330                           "Object Identity Content", "icep.id.content", 
1331                           FT_STRINGZ, BASE_NONE, NULL, 0x0,
1332                           "The object identity content", HFILL
1333                   }
1334                 },
1335
1336                 { &hf_icep_facet,
1337                   { 
1338                           "Facet Name", "icep.facet", 
1339                           FT_STRINGZ, BASE_NONE, NULL, 0x0, 
1340                           "The facet name", HFILL
1341                   }
1342                 },
1343
1344                 { &hf_icep_operation,
1345                   { 
1346                           "Operation Name", "icep.operation", 
1347                           FT_STRINGZ, BASE_NONE, NULL, 0x0, 
1348                           "The operation name", HFILL
1349                   }
1350                 },
1351
1352                 { &hf_icep_mode,
1353                   { 
1354                           "Ice::OperationMode", "icep.operation_mode", 
1355                           FT_INT8, BASE_DEC, VALS(icep_mode_vals), 0x0, 
1356                           "A byte representing Ice::OperationMode", HFILL
1357                   }
1358                 },
1359
1360                 { &hf_icep_context,
1361                   { 
1362                           "Invocation Context", "icep.context", 
1363                           FT_STRINGZ, BASE_NONE, NULL, 0x0, 
1364                           "The invocation context", HFILL
1365                   }
1366                 },
1367                 
1368                 { &hf_icep_params_size,
1369                   { 
1370                           "Input Parameters Size", "icep.params.size", 
1371                           FT_INT32, BASE_DEC, NULL, 0x0, 
1372                           "The encapsulated input parameters size", 
1373                           HFILL
1374                   }
1375                 },
1376                 
1377                 { &hf_icep_params_major,
1378                   { 
1379                           "Input Parameters Encoding Major", 
1380                           "icep.params.major", 
1381                           FT_INT8, BASE_DEC, NULL, 0x0, 
1382                           "The major encoding version of encapsulated parameters", 
1383                           HFILL
1384                   }
1385                 },
1386                 
1387                 { &hf_icep_params_minor,
1388                   { 
1389                           "Input Parameters Encoding Minor", 
1390                           "icep.params.minor", 
1391                           FT_INT8, BASE_DEC, NULL, 0x0, 
1392                           "The minor encoding version of encapsulated parameters", 
1393                           HFILL
1394                   }
1395                 },
1396                 
1397         };
1398         
1399         /* Setup protocol subtree array */
1400         
1401         static gint *ett[] = {
1402                 &ett_icep,
1403                 &ett_icep_msg,
1404         };
1405         
1406         /* Register the protocol name and description */
1407         
1408         proto_icep = 
1409                 proto_register_protocol("Internet Communications Engine Protocol",
1410                                         "ICEP", "icep");
1411         
1412         /* Required function calls to register the header fields and subtrees used */
1413         
1414         proto_register_field_array(proto_icep, hf, array_length(hf));
1415         proto_register_subtree_array(ett, array_length(ett));
1416 }
1417
1418
1419 void proto_reg_handoff_icep(void)
1420 {
1421         /* Register as a heuristic TCP/UDP dissector */
1422         
1423         heur_dissector_add("tcp", dissect_icep, proto_icep);
1424         heur_dissector_add("udp", dissect_icep, proto_icep);
1425 }