GIOP 1.2 support and other GIOP enhancements, from Craig Rodrigues.
[obnox/wireshark/wip.git] / packet-giop.c
1 /* packet-giop.c
2  * Routines for CORBA GIOP/IIOP packet disassembly
3  *
4  * Laurent Deniel <deniel@worldnet.fr>
5  * Craig Rodrigues <rodrigc@mediaone.net>
6  *
7  * $Id: packet-giop.c,v 1.19 2000/11/07 07:46:20 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@zing.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * 
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  * 
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
27  *
28  *
29  */
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #ifdef HAVE_SYS_TYPES_H
36 # include <sys/types.h>
37 #endif
38
39 #include <string.h>
40 #include <ctype.h>
41 #include <glib.h>
42 #include "packet.h"
43
44 static int proto_giop = -1;
45 static int hf_giop_message_type = -1;
46 static int hf_giop_message_size = -1;
47
48 static gint ett_giop = -1;
49 static gint ett_giop_reply = -1;
50 static gint ett_giop_request = -1;
51 static gint ett_giop_cancel_request = -1;
52 static gint ett_giop_locate_request = -1;
53 static gint ett_giop_locate_reply = -1;
54 static gint ett_giop_fragment = -1;
55
56 static const value_string sync_scope[] = {
57         { 0x0, "SYNC_NONE" },
58         { 0x1, "SYNC_WITH_TRANSPORT"},
59         { 0x2, "SYNC_WITH_SERVER"},
60         { 0x3, "SYNC_WITH_TARGET"},
61         { 0, NULL}
62 };
63
64 static const value_string giop_message_types[] = {
65         { 0x0, "Request" },
66         { 0x1, "Reply"},
67         { 0x2, "CancelRequest"},
68         { 0x3, "LocateRequest"},
69         { 0x4, "LocateReply"},
70         { 0x5, "CloseConnection"},
71         { 0x6, "MessageError"},
72         { 0x7, "Fragment"},
73         { 0, NULL}
74 };
75
76 static const value_string giop_locate_status_types[] = {
77         { 0x0, "Unknown Object" },
78         { 0x1, "Object Here"},
79         { 0x2, "Object Forward"},
80         { 0x3, "Object Forward Perm"},
81         { 0x4, "Loc System Exception"},
82         { 0x5, "Loc Needs Addressing Mode"},
83         { 0, NULL }     
84 };
85
86
87 /*
88  * GIOP / IIOP types definition - OMG CORBA 2.x / GIOP 1.[012]
89  * See CORBA 2.4 specification: http://cgi.omg.org/cgi-bin/doc?formal/00-10-1
90  *
91  * Notes on mapping:
92  *
93  * <sequence> : unsigned int (# elts) + elements
94  * <string>   : unsigned int (string length) + length characters (with '\0')
95  * <enum>     : unsigned int (from 0 to n)
96  */
97
98 #define GIOP_MAGIC       "GIOP"
99 static const guint GIOP_MAJOR =  1;
100 static const guint GIOP_MINOR =  2;
101
102 static const guint GIOP_HEADER_SIZE = 12;
103
104 static const int KeyAddr       = 0;
105 static const int ProfileAddr   = 1;
106 static const int ReferenceAddr = 2;
107
108 typedef struct OctetSequence
109 {
110   guint32 sequence_length;
111   guint8 sequence_data[1];      /* of length bytes */
112 }
113 OctetSequence;
114
115 typedef OctetSequence Principal;
116 typedef OctetSequence String;
117
118 /* 
119  * Some structures that contain sequences can not be directly used 
120  * (alignment problem on 64 bit architectures)
121  */
122
123 typedef struct ServiceContext
124 {
125   guint32 context_id;
126   OctetSequence context_data;
127 }
128 ServiceContext;
129
130 typedef struct ServiceContextList
131 {
132   guint32 nr_context;
133   ServiceContext service_context[1];    /* nr_context elements */
134 }
135 ServiceContextList;
136
137 typedef enum MsgType
138 {
139   Request,
140   Reply,
141   CancelRequest,
142   LocateRequest,
143   LocateReply,
144   CloseConnection,
145   MessageError,
146   Fragment                      /* GIOP 1.1 only */
147 }
148 MsgType;
149
150 typedef struct Version
151 {
152   guint8 major;
153   guint8 minor;
154 }
155 Version;
156
157 typedef struct MessageHeader
158 {
159   guint8 magic[4];
160   Version GIOP_version;
161   guint8 flags;                 /* byte_order in 1.0 */
162   guint8 message_type;
163   guint32 message_size;
164 }
165 MessageHeader;
166
167 typedef struct RequestHeader_1_0
168 {
169   /* ServiceContextList service_context; */
170   guint32 request_id;
171   guint8 response_expected;
172   OctetSequence object_key;
173   /* String     operation;              */
174   /* Principal  requesting_principal;   */
175 }
176 RequestHeader_1_0;
177
178 typedef struct RequestHeader_1_1
179 {
180   /* ServiceContextList service_context; */
181   guint32 request_id;
182   guint8 response_expected;
183   guint8 reserved[3];
184   OctetSequence object_key;
185   /* String     operation;              */
186   /* Principal  requesting_principal;   */
187 }
188 RequestHeader_1_1;
189
190 typedef enum ReplyStatusType
191 {
192   NO_EXCEPTION,
193   USER_EXCEPTION,
194   SYSTEM_EXCEPTION,
195   LOCATION_FORWARD,
196   LOCATION_FORWARD_PERM,        /* new for GIOP 1.2 */
197   NEEDS_ADDRESSING_MODE         /* new for GIOP 1.2 */
198 }
199 ReplyStatusType;
200
201 const static value_string reply_status_types[] = { 
202    { NO_EXCEPTION, "No Exception" } ,
203    { USER_EXCEPTION, "User Exception" } ,
204    { SYSTEM_EXCEPTION, "System Exception" } ,
205    { LOCATION_FORWARD, "Location Forward" } ,
206    { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
207    { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode"} ,
208    { 0, NULL }
209 };
210
211 typedef struct ReplyHeader
212 {
213   /* ServiceContext service_context;    */
214   guint32 request_id;
215   guint32 reply_status;
216 }
217 ReplyHeader;
218
219 typedef struct SystemExceptionReplyBody
220 {
221   String exception_id;
222   u_int minor_code_value;
223   u_int completion_status;
224 }
225 SystemExceptionReplyBody;
226
227 typedef struct CancelRequestHeader
228 {
229   guint32 request_id;
230 }
231 CancelRequestHeader;
232
233 typedef struct LocateRequestHeader
234 {
235   guint32 request_id;
236   OctetSequence object_key;
237 }
238 LocateRequestHeader;
239
240 typedef enum LocateStatusType
241 {
242   UNKNOWN_OBJECT,
243   OBJECT_HERE,
244   OBJECT_FORWARD,
245   OBJECT_FORWARD_PERM,      // new value for GIOP 1.2
246   LOC_SYSTEM_EXCEPTION,     // new value for GIOP 1.2
247   LOC_NEEDS_ADDRESSING_MODE // new value for GIOP 1.2
248 }
249 LocateStatusType;
250
251 typedef struct LocateReplyHeader
252 {
253   guint32 request_id;
254   guint32 locate_status;
255 }
256 LocateReplyHeader;
257
258 /* Take in a string and replace non-printable characters with periods */
259 static void
260 printable_string (gchar *in, guint32 len)
261 {
262   int i = 0;
263
264   for(i=0; i < len; i++)
265   {
266          if( !isprint( in[i] ) ) 
267                  in[i] = '.';
268   }
269 }
270
271 /* Determine the byte order from the GIOP MessageHeader */
272 static gboolean 
273 is_big_endian (MessageHeader * header)
274 {
275   gboolean big_endian = FALSE;
276
277   switch (header->GIOP_version.minor)
278     {
279     case 2:
280     case 1:
281       if (header->flags & 0x01)
282         big_endian = FALSE;
283       else
284         big_endian = TRUE;
285       break;
286     case 0:
287       if (header->flags)
288         big_endian = FALSE;
289       else
290         big_endian = TRUE;
291       break;
292     default:
293       break;
294     }
295   return big_endian;
296 }
297
298 /* Copy a 4 octet sequence from the tvbuff 
299  * which represents an unsigned long value, and convert
300  * it to an unsigned long vaule, taking into account byte order.
301  * offset is first incremented so that it falls on a proper alignment
302  * boundary for unsigned long values.
303  * offset is then incremented by 4, to indicate the 4 octets which
304  * have been processed.
305  */
306 static guint32
307 get_CDR_ulong(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian)
308 {
309   guint32 val;
310
311   /* unsigned long values must be aligned on a 4 byte boundary */
312   while( ( (*offset + GIOP_HEADER_SIZE) % 4) != 0)
313           ++(*offset);
314
315   val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
316                                  tvb_get_letohl (tvb, *offset);
317
318   *offset += 4; 
319   return val; 
320 }
321
322 /* Copy a 2 octet sequence from the tvbuff 
323  * which represents an unsigned short value, and convert
324  * it to an unsigned short value, taking into account byte order.
325  * offset is first incremented so that it falls on a proper alignment
326  * boundary for unsigned short values.
327  * offset is then incremented by 2, to indicate the 2 octets which
328  * have been processed.
329  */
330 static guint16
331 get_CDR_ushort(tvbuff_t *tvb, int *offset, gboolean stream_is_big_endian)
332 {
333   guint16 val;
334
335   /* unsigned long values must be aligned on a 4 byte boundary */
336   while( ( (*offset + GIOP_HEADER_SIZE) % 2) != 0)
337           ++(*offset);
338
339   val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
340                                  tvb_get_letohs (tvb, *offset);
341
342   *offset += 2; 
343   return val; 
344 }
345
346 /* Copy a sequence of octets from the tvbuff.
347  * Caller of this function must remember to free the 
348  * array pointed to by seq.
349  * This function also increments offset by len. 
350  */
351 static void
352 get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len)
353 {
354      *seq = g_new0(gchar, len + 1);
355      tvb_memcpy( tvb, *seq, *offset, len);
356      *offset += len;
357 }
358
359 /**
360  *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
361  *  // GIOP 1.2
362  *  typedef short AddressingDisposition;
363  *  const short KeyAddr = 0;
364  *  const short ProfileAddr = 1;
365  *  const short ReferenceAddr = 2;
366  *  struct IORAddressingInfo {
367  *    unsigned long selected_profile_index;
368  *    IOP::IOR ior;
369  *  };
370  *
371  *  union TargetAddress switch (AddressingDisposition) {
372  *      case KeyAddr: sequence <octet> object_key;
373  *      case ProfileAddr: IOP::TaggedProfile profile;
374  *      case ReferenceAddr: IORAddressingInfo ior;
375  *  };
376  */
377 static void
378 dissect_target_address(tvbuff_t * tvb, int *offset, proto_tree * sub_tree, 
379                        MessageHeader * header, gboolean stream_is_big_endian)
380 {
381    guint16 discriminant;
382    gchar *object_key = NULL;
383    guint32 len = 0;
384
385    discriminant = get_CDR_ushort(tvb, offset, stream_is_big_endian);
386    if(sub_tree)
387    {
388      proto_tree_add_text (sub_tree, tvb, *offset -2, 2,
389                  "TargetAddress Discriminant: %d", discriminant);
390    }
391   
392    switch (discriminant)
393    {
394            case 0:  // KeyAddr
395                    len = get_CDR_ulong(tvb, offset, stream_is_big_endian);
396                    get_CDR_octet_seq(tvb, &object_key, offset, len);
397                    printable_string( object_key, len );
398
399                    if(sub_tree)
400                    {
401                       proto_tree_add_text (sub_tree, tvb, *offset -len -4, 4,
402                                            "KeyAddr (object key length): %d", len);
403                       proto_tree_add_text (sub_tree, tvb, *offset -len, len,
404                                            "KeyAddr (object key): %s", object_key);
405                    }
406                    break;
407            case 1:
408                    if(sub_tree)
409                    {
410                       proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
411                                            "ProfileAddr (not implemented) %s", object_key);
412                    }
413                    break;
414            case 2:
415                    if(sub_tree)
416                    {
417                       proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
418                                            "ReferenceAddr (not implemented) %s", object_key);
419                    }
420                    break;
421            default:
422                    break;
423    }
424    g_free( object_key );
425 }
426
427 /* The format of the Reply Header for GIOP 1.0 and 1.1
428  * is documented in Section 15.4.3.1 * of the CORBA 2.4 standard.
429
430     struct ReplyHeader_1_0 {
431           IOP::ServiceContextList service_context;
432           unsigned long request_id;
433           ReplyStatusType_1_0 reply_status;
434     };
435  */
436 static void
437 dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
438                     proto_tree * clnp_tree, MessageHeader * header,
439                     gboolean stream_is_big_endian)
440 {
441   guint32 offset = 0;
442   guint32 nr_seq = 0;
443   guint32 context_id;
444   guint32 sequence_length;
445   guint32 request_id;
446   guint8 reply_status;
447   gboolean big_endian;
448   proto_tree *reply_tree = NULL;
449   proto_item *tf;
450
451   int i;
452
453   big_endian = is_big_endian (header);
454
455   /* From Section 15.3.2.5 of the CORBA 2.4 standard, a sequence
456    * is an unsigned long value (4 octets) indicating the number of 
457    * items in the sequence, followed by the items in the sequence 
458    */
459
460   /* The format of the IOP::ServiceContextList struct is defined in
461    * section 13.7 of the CORBA 2.4 standard  as:
462    module IOP { // IDL
463    typedef unsigned long ServiceId;
464
465    struct ServiceContext {
466    ServiceId context_id;
467    sequence <octet> context_data;
468    };
469    typedef sequence <ServiceContext>ServiceContextList;
470    };
471    */
472   if (tree)
473     {
474       tf = proto_tree_add_text (tree, tvb, offset,
475                                 tvb_length (tvb),
476                                 "General Inter-ORB Protocol Reply");
477       if (reply_tree == NULL)
478         {
479           reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
480
481         }
482     }
483
484   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
485
486   for (i = 1; i <= nr_seq; i++)
487     {
488
489       if (big_endian)
490         {
491           context_id = tvb_get_ntohl (tvb, offset);
492           sequence_length = tvb_get_ntohl (tvb, offset + 4);
493         }
494       else
495         {
496           context_id = tvb_get_letohl (tvb, offset);
497           sequence_length = tvb_get_letohl (tvb, offset + 4);
498         }
499
500       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
501
502       if (tree)
503         {
504           proto_tree_add_text (reply_tree, tvb, offset -4, 4,
505                                "Context id: %d", context_id);
506         }
507
508       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
509       if(tree)
510       {      
511           proto_tree_add_text (reply_tree, tvb, offset -4,
512                                4, "Sequence length: %d", sequence_length);
513       }
514
515       if(tree)
516       {
517           if (sequence_length > 0)
518             {
519               proto_tree_add_text (reply_tree, tvb, offset,
520                                    sequence_length,
521                                    "Sequence data: <not shown>");
522             }
523         }
524
525       offset += sequence_length;        
526
527     }                           /* for */
528
529   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
530
531   if (tree)
532     {
533       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
534                            "Request id: %d", request_id);
535     }
536
537   reply_status = tvb_get_guint8 (tvb, offset);
538   if (tree)
539     {
540       proto_tree_add_text (reply_tree, tvb, offset, 1,
541                            "Reply status: %s",
542                            match_strval(reply_status, reply_status_types));
543
544     }
545   offset += 1;
546
547 }
548
549 /** The format of the GIOP 1.2 Reply header is very similar to the 1.0
550  *  and 1.1 header, only the fields have been rearranged.  From Section
551  *  15.4.3.1 of the CORBA 2.4 specification:
552  *
553  *   struct ReplyHeader_1_2 {
554           unsigned long request_id;
555           ReplyStatusType_1_2 reply_status;
556           IOP:ServiceContextList service_context; // 1.2 change
557      };
558  */
559 static void
560 dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
561                         proto_tree * tree, proto_tree * clnp_tree,
562                         MessageHeader * header,
563                         gboolean stream_is_big_endian)
564 {
565   u_int offset = 0;
566   guint32 nr_seq = 0;
567   guint32 context_id;
568   guint32 sequence_length;
569   guint32 request_id;
570   guint8 reply_status;
571   proto_tree *reply_tree = NULL;
572   proto_item *tf;
573   int i;
574
575   if (tree)
576     {
577       tf = proto_tree_add_text (tree, tvb, offset,
578                                 tvb_length (tvb),
579                                 "General Inter-ORB Protocol Reply");
580       if (reply_tree == NULL)
581         {
582           reply_tree = proto_item_add_subtree (tf, ett_giop_reply);
583
584         }
585     }
586
587   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
588   if (tree)
589     {
590       proto_tree_add_text (reply_tree, tvb, offset-4, 4,
591                            "Request id: %d", request_id);
592     }
593
594   reply_status = tvb_get_guint8 (tvb, offset);
595   offset += 1;
596   if (tree)
597     {
598       proto_tree_add_text (reply_tree, tvb, offset-1, 1,
599                            "Reply status: %s",
600                            match_strval(reply_status, reply_status_types));
601
602     }
603
604   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
605
606   for (i = 1; i <= nr_seq; i++)
607     {
608
609       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
610       if (tree)
611         {
612           proto_tree_add_text (reply_tree, tvb, offset -4, 4,
613                                "Context id: %d", context_id);
614         }
615
616       sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
617       if (tree)
618       {
619           proto_tree_add_text (reply_tree, tvb, offset- 4,
620                                4, "Sequence length: %d", sequence_length);
621       }
622
623       offset += sequence_length;
624       if (tree)
625       {
626           if (sequence_length > 0)
627             {
628               proto_tree_add_text (reply_tree, tvb, offset - sequence_length,
629                                    sequence_length,
630                                    "Sequence data: <not shown>");
631             }
632       }
633
634     }                           /* for */
635 }
636
637 static void
638 dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
639                         proto_tree * tree, proto_tree * clnp_tree,
640                         MessageHeader * header, gboolean stream_is_big_endian)
641 {
642   u_int offset = 0;
643   guint32 request_id;
644   proto_tree *cancel_request_tree = NULL;
645   proto_item *tf;
646
647   if (tree)
648     {
649       tf = proto_tree_add_text (tree, tvb, offset,
650                                 tvb_length (tvb),
651                                 "General Inter-ORB Protocol CancelRequest");
652       if (cancel_request_tree == NULL)
653         {
654           cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);
655
656         }
657     }
658
659   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
660   if (tree)
661     {
662       proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
663                            "Request id: %d", request_id);
664     }
665
666
667 }
668
669 /**  The formats for GIOP 1.0 and 1.1 Request messages are defined
670  *   in section 15.4.2.1 of the CORBA 2.4 specification.
671  *
672  *   struct RequestHeader{
673  *          IOP::ServiceContextList   service_context;
674  *          unsigned long             request_id;
675  *          boolean                   response_expected;
676  *          octet                     reserved[3];  // Only in GIOP 1.1
677  *          sequence<octet>           object_key;
678  *          string                    operation;
679  *          CORBA::OctetSeq           requesting_principal;
680  *   }
681  */
682 static void
683 dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
684                         proto_tree * tree, proto_tree * clnp_tree,
685                         MessageHeader * header, gboolean stream_is_big_endian)
686 {
687   guint32 offset = 0;
688   guint32 nr_seq = 0;
689   guint32 context_id;
690   guint32 sequence_length;
691   guint32 request_id;
692   guint32 len = 0;
693   gchar *object_key = NULL;
694   gchar *operation = NULL;
695   gchar *requesting_principal = NULL;
696   guint8 response_expected;
697   gchar *reserved = NULL;
698   proto_tree *request_tree = NULL;
699   proto_item *tf;
700   int i;
701
702
703   if (tree)
704     {
705       tf = proto_tree_add_text (tree, tvb, offset,
706                                 tvb_length (tvb),
707                                 "General Inter-ORB Protocol Request");
708       if (request_tree == NULL)
709         {
710           request_tree = proto_item_add_subtree (tf, ett_giop_request);
711
712         }
713     }
714
715   nr_seq = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
716
717   for (i = 1; i <= nr_seq; i++)
718     {
719
720       context_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
721       if (tree)
722         {
723           proto_tree_add_text (request_tree, tvb, offset-4, 4,
724                                "Context id: %d", context_id);
725         }
726
727        sequence_length = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
728        if(tree)
729         {
730            proto_tree_add_text (request_tree, tvb, offset-4, 4, 
731                                 "Sequence length: %d", sequence_length);
732         }
733
734         offset +=  sequence_length;
735         if (sequence_length > 0)
736         {
737               proto_tree_add_text (request_tree, tvb, offset - sequence_length,
738                                    sequence_length,
739                                    "Sequence data: <not shown>");
740         }
741         
742
743     } /* for */
744
745   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
746   if (tree)
747     {
748       proto_tree_add_text (request_tree, tvb, offset-4, 4,
749                            "Request id: %d", request_id);
750     }
751
752   response_expected = tvb_get_guint8( tvb, offset );
753   offset += 1;
754   if (tree)
755     {
756       proto_tree_add_text (request_tree, tvb, offset-1, 1,
757                            "Response expected: %d", response_expected);
758     }
759
760   if( header->GIOP_version.minor > 0)
761   {
762      get_CDR_octet_seq( tvb, &reserved, &offset, 3);
763      if (tree)
764        {
765          proto_tree_add_text (request_tree, tvb, offset-3, 3,
766                            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
767        }
768   }
769
770   /* Length of object_key sequence */
771   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
772
773   if(tree)
774   {
775          proto_tree_add_text (request_tree, tvb, offset-4, 4,
776          /**/                 "Object Key length: %d", len);
777   } 
778
779   if( len > 0)
780   {
781        get_CDR_octet_seq(tvb, &object_key, &offset, len);
782        printable_string( object_key, len );
783
784        if(tree)
785        {
786          proto_tree_add_text (request_tree, tvb, offset - len, len,
787          /**/                 "Object Key: %s", object_key);
788
789        }
790   } 
791
792   /* length of operation string */ 
793   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
794   if(tree)
795   {
796          proto_tree_add_text (request_tree, tvb, offset -4, 4,
797          /**/                 "Operation length: %d", len);
798   } 
799
800   if( len > 0)
801   {
802        get_CDR_octet_seq(tvb, &operation, &offset, len);
803        if(tree)
804        {
805          proto_tree_add_text (request_tree, tvb, offset - len, len,
806          /**/                 "Operation: %s", operation);
807
808        }
809   }
810
811   /* length of requesting_principal string */ 
812   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
813   if(tree)
814   {
815          proto_tree_add_text (request_tree, tvb, offset-4, 4,
816          /**/                 "Requesting Principal Length: %d", len);
817   } 
818
819   if( len > 0)
820   {
821        get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
822        if(tree)
823        {
824          proto_tree_add_text (request_tree, tvb, offset - len, len, 
825          /**/                 "Requesting Principal: %s", requesting_principal);
826
827        }
828   }
829
830   g_free( object_key );
831   g_free( operation );
832   g_free( requesting_principal );
833 }
834
835 /**  The format of a GIOP 1.2 RequestHeader message is 
836  *   (CORBA 2.4, sec. 15.4.2):
837  *
838  *   struct RequestHeader_1_2 {
839  *       unsigned long request_id;
840  *       octet response_flags;
841  *       octet reserved[3];
842  *       TargetAddress target;
843  *       string operation;
844  *       IOP::ServiceContextList service_context;
845  *       // requesting_principal not in GIOP 1.2
846  *   };
847  */
848 static void
849 dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
850                         proto_tree * tree, proto_tree * clnp_tree,
851                         MessageHeader * header, gboolean stream_is_big_endian)
852 {
853   guint32 offset = 0;
854   guint32 request_id;
855   guint32 len = 0;
856   guint8 response_flags;
857   gchar *reserved = NULL;
858   gchar *operation = NULL;
859   proto_tree *request_tree = NULL;
860   proto_item *tf;
861
862   if (tree)
863     {
864       tf = proto_tree_add_text (tree, tvb, offset,
865                                 tvb_length (tvb),
866                                 "General Inter-ORB Protocol Request");
867       if (request_tree == NULL)
868         {
869           request_tree = proto_item_add_subtree (tf, ett_giop_reply);
870
871         }
872     }
873
874   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
875   if (request_tree)
876     {
877       proto_tree_add_text (request_tree, tvb, offset-4, 4,
878                            "Request id: %d", request_id);
879     }
880
881   response_flags = tvb_get_guint8( tvb, offset );
882   offset += 1;
883   if (request_tree)
884     {
885       proto_tree_add_text (request_tree, tvb, offset-1, 1,
886                            "Response flags: %s (%d)",
887                                 match_strval(response_flags, sync_scope),  
888                                 response_flags);
889     }
890
891   get_CDR_octet_seq( tvb, &reserved, &offset, 3);
892   if (request_tree)
893    {
894      proto_tree_add_text (request_tree, tvb, offset-3, 3,
895            "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
896    }
897
898   dissect_target_address(tvb, &offset, request_tree, header, stream_is_big_endian);
899
900   /* length of operation string */ 
901   len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
902   if(tree)
903   {
904          proto_tree_add_text (request_tree, tvb, offset -4, 4,
905          /**/                 "Operation length: %d", len);
906   } 
907
908   if( len > 0)
909   {
910        get_CDR_octet_seq(tvb, &operation, &offset, len);
911        if(request_tree)
912        {
913          proto_tree_add_text (request_tree, tvb, offset - len, len,
914          /**/                 "Operation: %s", operation);
915
916        }
917
918   }
919   g_free(reserved);
920 }
921
922 static void
923 dissect_giop_locate_request( tvbuff_t * tvb, proto_tree * tree, 
924                         MessageHeader * header, gboolean stream_is_big_endian)
925 {
926   guint32 offset = 0;
927   guint32 request_id;
928   guint32 len = 0;
929   gchar *object_key = NULL;
930   proto_tree *locate_request_tree = NULL;
931   proto_item *tf;
932
933   if (tree)
934     {
935       tf = proto_tree_add_text (tree, tvb, offset,
936                                 tvb_length (tvb),
937                                 "General Inter-ORB Locate Request");
938       if (locate_request_tree == NULL)
939         {
940           locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);
941
942         }
943     }
944
945   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
946   if (locate_request_tree)
947     {
948       proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
949                            "Request id: %d", request_id);
950     }
951
952   if(header->GIOP_version.minor < 2)
953   {
954         len = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
955         get_CDR_octet_seq(tvb, &object_key, &offset, len);
956
957         if(locate_request_tree)
958         {
959
960            proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
961                            "Object Key: %s", object_key);
962
963
964         }
965
966   }
967   else     // GIOP 1.2 and higher
968   {
969       dissect_target_address(tvb, &offset, locate_request_tree, header,
970                              stream_is_big_endian);
971
972   }
973   g_free( object_key );  
974 }
975
976 static void
977 dissect_giop_locate_reply( tvbuff_t * tvb, proto_tree * tree, 
978                         MessageHeader * header, gboolean stream_is_big_endian)
979 {
980   guint32 offset = 0;
981   guint32 request_id;
982   guint32 locate_status;
983   proto_tree *locate_reply_tree = NULL;
984   proto_item *tf;
985
986   if (tree)
987     {
988       tf = proto_tree_add_text (tree, tvb, offset,
989                                 tvb_length (tvb),
990                                 "General Inter-ORB Locate Reply");
991       if (locate_reply_tree == NULL)
992         {
993           locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);
994
995         }
996     }
997
998   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
999   if (locate_reply_tree)
1000     {
1001       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
1002                            "Request id: %d", request_id);
1003     }
1004
1005   locate_status = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1006   if (locate_reply_tree)
1007     {
1008       proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
1009                            "Locate status: %s", 
1010                            match_strval(locate_status, giop_locate_status_types)
1011                            );
1012                                    
1013     }
1014
1015 }
1016
1017 static void
1018 dissect_giop_fragment( tvbuff_t * tvb, proto_tree * tree, 
1019                         MessageHeader * header, gboolean stream_is_big_endian)
1020 {
1021   guint32 offset = 0;
1022   guint32 request_id;
1023   proto_tree *fragment_tree = NULL;
1024   proto_item *tf;
1025
1026   if (tree)
1027     {
1028       tf = proto_tree_add_text (tree, tvb, offset,
1029                                 tvb_length (tvb),
1030                                 "General Inter-ORB Fragment");
1031       if (fragment_tree == NULL)
1032         {
1033           fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);
1034
1035         }
1036     }
1037
1038   request_id = get_CDR_ulong(tvb, &offset, stream_is_big_endian);
1039   if (fragment_tree )
1040     {
1041       proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
1042                            "Request id: %d", request_id);
1043     }
1044
1045                                    
1046 }
1047
1048
1049 /* main entry point */
1050 static gboolean
1051 dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
1052 {
1053   u_int offset = 0;
1054   MessageHeader header;
1055   tvbuff_t *giop_header_tvb;
1056   tvbuff_t *payload_tvb;
1057
1058   proto_tree *clnp_tree = NULL;
1059   proto_item *ti;
1060   u_int message_size;
1061   u_int minor_version;
1062   gboolean stream_is_big_endian;
1063
1064   if( !proto_is_protocol_enabled( proto_giop ))
1065           return FALSE; /* GIOP has been disabled */
1066
1067   pinfo->current_proto = "GIOP";
1068
1069   /* check magic number and version */
1070
1071
1072   if (check_col (pinfo->fd, COL_PROTOCOL))
1073     {
1074       col_add_str (pinfo->fd, COL_PROTOCOL, "GIOP");
1075     }
1076
1077
1078   /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */
1079
1080   giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
1081   payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);
1082
1083   /*  memcpy(&header, &pd[offset], sizeof(header)); */
1084   tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, sizeof (header));
1085
1086   if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
1087     {
1088       /* Not a GIOP message. */
1089       return FALSE;
1090     }
1091
1092   if (header.GIOP_version.major != GIOP_MAJOR ||
1093       ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
1094     {
1095       /* Bad version number; should we note that and dissect the rest
1096          as data, or should we return FALSE on the theory that it
1097          might have been some other packet that happened to begin with
1098          "GIOP"? */
1099       if (check_col (pinfo->fd, COL_INFO))
1100         {
1101           col_add_fstr (pinfo->fd, COL_INFO, "Version %d.%d",
1102                         header.GIOP_version.major, header.GIOP_version.minor);
1103         }
1104       if (tree)
1105         {
1106           ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
1107                                     tvb_length (tvb), FALSE);
1108           clnp_tree = proto_item_add_subtree (ti, ett_giop);
1109           proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
1110                                tvb_length (giop_header_tvb),
1111                                "Version %d.%d not supported",
1112                                header.GIOP_version.major,
1113                                header.GIOP_version.minor);
1114         }
1115       dissect_data (payload_tvb, pinfo, tree);
1116       return FALSE;
1117     }
1118
1119   stream_is_big_endian = is_big_endian (&header);
1120
1121   if (stream_is_big_endian)
1122     message_size = pntohl (&header.message_size);
1123   else
1124     message_size = pletohl (&header.message_size);
1125
1126   if (tree)
1127     {
1128       ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
1129       clnp_tree = proto_item_add_subtree (ti, ett_giop);
1130       proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
1131                            "Magic number: %s", GIOP_MAGIC);
1132       proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
1133                            "Version: %d.%d",
1134                            header.GIOP_version.major,
1135                            header.GIOP_version.minor);
1136       switch (minor_version)
1137         {
1138         case 2:
1139         case 1:
1140           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
1141                                "Flags: 0x%02x (%s %s)",
1142                                header.flags,
1143                                (stream_is_big_endian) ? "big-endian" : "little-endian",
1144                                (header.flags & 0x02) ? " fragment" : "");
1145           break;
1146         case 0:
1147           proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
1148                                "Byte ordering: %s-endian",
1149                                (stream_is_big_endian) ? "big" : "little");
1150           break;
1151         default:
1152           break;
1153         }                       /* minor_version */
1154
1155       proto_tree_add_uint_format (clnp_tree,
1156                                   hf_giop_message_type,
1157                                   giop_header_tvb, 7, 1,
1158                                   header.message_type,
1159                                   "Message type: %s", match_strval(header.message_type, giop_message_types));
1160
1161       proto_tree_add_uint (clnp_tree,
1162                            hf_giop_message_size,
1163                            giop_header_tvb, 8, 4, message_size);
1164
1165     }                           /* tree */
1166
1167   if (check_col (pinfo->fd, COL_INFO)) 
1168   { 
1169       col_add_fstr (pinfo->fd, COL_INFO, "GIOP %d.%d %s",
1170                     header.GIOP_version.major, header.GIOP_version.minor,
1171                     match_strval(header.message_type, giop_message_types));
1172   }
1173
1174   switch (header.message_type)
1175     {
1176
1177     case Request:
1178       if(header.GIOP_version.minor < 2)
1179       {
1180            dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree,
1181                                      &header, stream_is_big_endian);
1182       }
1183       else
1184       {    
1185            dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree,
1186                                      &header, stream_is_big_endian);
1187       }
1188       
1189       break;
1190
1191
1192     case Reply:
1193       if(header.GIOP_version.minor < 2)
1194         {
1195            dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header,
1196                                stream_is_big_endian);
1197         }
1198       else
1199         {
1200            dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree,
1201                                    &header, stream_is_big_endian);
1202         }
1203       break;
1204     case CancelRequest:
1205         dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree,
1206                                     &header, stream_is_big_endian);
1207         break;
1208     case LocateRequest:
1209         dissect_giop_locate_request(payload_tvb, tree, &header,
1210                                     stream_is_big_endian);
1211         break;
1212     case LocateReply:
1213         dissect_giop_locate_reply(payload_tvb, tree, &header,
1214                                   stream_is_big_endian);
1215         break;
1216     case Fragment:
1217         dissect_giop_fragment(payload_tvb, tree, &header,
1218                               stream_is_big_endian);
1219         break;  
1220     default:
1221       break;
1222
1223     }                           /* switch message_type */
1224     return TRUE;
1225 }
1226
1227 void
1228 proto_register_giop (void)
1229 {
1230   static hf_register_info hf[] = {
1231     {
1232      &hf_giop_message_type,
1233      {
1234       "Message type", "giop.type",
1235       FT_UINT8, BASE_DEC, NULL, 0x0, ""}
1236      }
1237     ,
1238     {
1239      &hf_giop_message_size,
1240      {
1241       "Message size", "giop.len",
1242       FT_UINT32, BASE_DEC, NULL, 0x0, ""}
1243      }
1244     ,
1245   };
1246   static gint *ett[] = {
1247     &ett_giop,
1248     &ett_giop_reply,
1249     &ett_giop_request,
1250     &ett_giop_cancel_request,
1251     &ett_giop_locate_request,
1252     &ett_giop_locate_reply,
1253     &ett_giop_fragment
1254   };
1255   proto_giop = proto_register_protocol ("General Inter-ORB Protocol", "giop");
1256   proto_register_field_array (proto_giop, hf, array_length (hf));
1257   proto_register_subtree_array (ett, array_length (ett));
1258 }
1259
1260 void
1261 proto_reg_handoff_giop (void)
1262 {
1263   heur_dissector_add ("tcp", dissect_giop);
1264 }