Ethereal-dev: [Ethereal-dev] Enhancements to packet-giop.c

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Craig Rodrigues <rodrigc@xxxxxxxxxxxx>
Date: Mon, 6 Nov 2000 20:23:41 -0500
Hi,

I have made a lot of enhancements to packet-giop.c.
I have:
(1) Added support for dissecting GIOP 1.2
(2) converted everything to use tvbuff structures (wow those things
    are so cool!)
(3) use value_strings in a bunch of places  (value_strings are cool too!)
(4) added helper routines for getting unsigned long, unsigned short
    and octet sequences, keeping in mind the data alignment rules
    that CDR imposes
(5) Cleaned the code up a bit by putting different GIOP message header
    dissecting routines in different functions.

I dissect most of the GIOP message headers, but not the message contents.
There is a lot here that is very useful, though.
I hope this code makes it into Ethereal......
-- 
Craig Rodrigues        
http://www.gis.net/~craigr    
rodrigc@xxxxxxxxxxxx          
/* packet-giop.c
 * Routines for CORBA GIOP/IIOP packet disassembly
 *
 * Laurent Deniel <deniel@xxxxxxxxxxx>
 * Craig Rodrigues <rodrigc@xxxxxxxxxxxx>
 *
 * $Id: packet-giop.c,v 1.18 2000/09/01 16:02:36 gram Exp $
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs <gerald@xxxxxxxx>
 * Copyright 1998 Gerald Combs
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif

#include <string.h>
#include <ctype.h>
#include <glib.h>
#include "packet.h"

static int proto_giop = -1;
static int hf_giop_message_type = -1;
static int hf_giop_message_size = -1;

static gint ett_giop = -1;
static gint ett_giop_reply = -1;
static gint ett_giop_request = -1;
static gint ett_giop_cancel_request = -1;
static gint ett_giop_locate_request = -1;
static gint ett_giop_locate_reply = -1;
static gint ett_giop_fragment = -1;

static gboolean stream_is_big_endian = FALSE;

static const value_string sync_scope[] = {
	{ 0x0, "SYNC_NONE" },
	{ 0x1, "SYNC_WITH_TRANSPORT"},
	{ 0x2, "SYNC_WITH_SERVER"},
	{ 0x3, "SYNC_WITH_TARGET"},
	{ 0, NULL}
};

static const value_string giop_message_types[] = {
	{ 0x0, "Request" },
	{ 0x1, "Reply"},
	{ 0x2, "CancelRequest"},
	{ 0x3, "LocateRequest"},
	{ 0x4, "LocateReply"},
	{ 0x5, "CloseConnection"},
	{ 0x6, "MessageError"},
	{ 0x7, "Fragment"},
	{ 0, NULL}
};

static const value_string giop_locate_status_types[] = {
	{ 0x0, "Unknown Object" },
        { 0x1, "Object Here"},
	{ 0x2, "Object Forward"},
        { 0x3, "Object Forward Perm"},
        { 0x4, "Loc System Exception"},
        { 0x5, "Loc Needs Addressing Mode"},
        { 0, NULL }	
};


/*
 * GIOP / IIOP types definition - OMG CORBA 2.x / GIOP 1.[012]
 * See CORBA 2.4 specification: http://cgi.omg.org/cgi-bin/doc?formal/00-10-1
 *
 * Notes on mapping:
 *
 * <sequence> : unsigned int (# elts) + elements
 * <string>   : unsigned int (string length) + length characters (with '\0')
 * <enum>     : unsigned int (from 0 to n)
 */

#define GIOP_MAGIC 	 "GIOP"
const guint GIOP_MAJOR =  1;
const guint GIOP_MINOR =  2;

const guint GIOP_HEADER_SIZE = 12;

const int KeyAddr       = 0;
const int ProfileAddr   = 1;
const int ReferenceAddr = 2;

typedef struct OctetSequence
{
  guint32 sequence_length;
  guint8 sequence_data[1];	/* of length bytes */
}
OctetSequence;

typedef OctetSequence Principal;
typedef OctetSequence String;

/* 
 * Some structures that contain sequences can not be directly used 
 * (alignment problem on 64 bit architectures)
 */

typedef struct ServiceContext
{
  guint32 context_id;
  OctetSequence context_data;
}
ServiceContext;

typedef struct ServiceContextList
{
  guint32 nr_context;
  ServiceContext service_context[1];	/* nr_context elements */
}
ServiceContextList;

typedef enum MsgType
{
  Request,
  Reply,
  CancelRequest,
  LocateRequest,
  LocateReply,
  CloseConnection,
  MessageError,
  Fragment			/* GIOP 1.1 only */
}
MsgType;

typedef struct Version
{
  guint8 major;
  guint8 minor;
}
Version;

typedef struct MessageHeader
{
  guint8 magic[4];
  Version GIOP_version;
  guint8 flags;			/* byte_order in 1.0 */
  guint8 message_type;
  guint32 message_size;
}
MessageHeader;

typedef struct RequestHeader_1_0
{
  /* ServiceContextList service_context; */
  guint32 request_id;
  guint8 response_expected;
  OctetSequence object_key;
  /* String     operation;              */
  /* Principal  requesting_principal;   */
}
RequestHeader_1_0;

typedef struct RequestHeader_1_1
{
  /* ServiceContextList service_context; */
  guint32 request_id;
  guint8 response_expected;
  guint8 reserved[3];
  OctetSequence object_key;
  /* String     operation;              */
  /* Principal  requesting_principal;   */
}
RequestHeader_1_1;

typedef enum ReplyStatusType
{
  NO_EXCEPTION,
  USER_EXCEPTION,
  SYSTEM_EXCEPTION,
  LOCATION_FORWARD,
  LOCATION_FORWARD_PERM,	/* new for GIOP 1.2 */
  NEEDS_ADDRESSING_MODE		/* new for GIOP 1.2 */
}
ReplyStatusType;

const static value_string reply_status_types[] = { 
   { NO_EXCEPTION, "No Exception" } ,
   { USER_EXCEPTION, "User Exception" } ,
   { SYSTEM_EXCEPTION, "System Exception" } ,
   { LOCATION_FORWARD, "Location Forward" } ,
   { LOCATION_FORWARD_PERM, "Location Forward Perm" } ,
   { NEEDS_ADDRESSING_MODE, "Needs Addressing Mode"} ,
   { 0, NULL }
};

typedef struct ReplyHeader
{
  /* ServiceContext service_context;    */
  guint32 request_id;
  guint32 reply_status;
}
ReplyHeader;

typedef struct SystemExceptionReplyBody
{
  String exception_id;
  u_int minor_code_value;
  u_int completion_status;
}
SystemExceptionReplyBody;

typedef struct CancelRequestHeader
{
  guint32 request_id;
}
CancelRequestHeader;

typedef struct LocateRequestHeader
{
  guint32 request_id;
  OctetSequence object_key;
}
LocateRequestHeader;

typedef enum LocateStatusType
{
  UNKNOWN_OBJECT,
  OBJECT_HERE,
  OBJECT_FORWARD,
  OBJECT_FORWARD_PERM,      // new value for GIOP 1.2
  LOC_SYSTEM_EXCEPTION,     // new value for GIOP 1.2
  LOC_NEEDS_ADDRESSING_MODE // new value for GIOP 1.2
}
LocateStatusType;

typedef struct LocateReplyHeader
{
  guint32 request_id;
  guint32 locate_status;
}
LocateReplyHeader;

/* Take in a string and replace non-printable characters with periods */
void
printable_string (gchar *in, guint32 len)
{
  int i = 0;

  for(i=0; i < len; i++)
  {
	 if( !isprint( in[i] ) ) 
		 in[i] = '.';
  }
}

/* Determine the byte order from the GIOP MessageHeader */
gboolean 
is_big_endian (MessageHeader * header)
{
  gboolean big_endian = FALSE;

  switch (header->GIOP_version.minor)
    {
    case 2:
    case 1:
      if (header->flags & 0x01)
	big_endian = FALSE;
      else
	big_endian = TRUE;
      break;
    case 0:
      if (header->flags)
	big_endian = FALSE;
      else
	big_endian = TRUE;
      break;
    default:
      break;
    }
  return big_endian;
}

/* Copy a 4 octet sequence from the tvbuff 
 * which represents an unsigned long value, and convert
 * it to an unsigned long vaule, taking into account byte order.
 * offset is first incremented so that it falls on a proper alignment
 * boundary for unsigned long values.
 * offset is then incremented by 4, to indicate the 4 octets which
 * have been processed.
 */
guint32
get_CDR_ulong(tvbuff_t *tvb, int *offset)
{
  guint32 val;

  /* unsigned long values must be aligned on a 4 byte boundary */
  while( ( (*offset + GIOP_HEADER_SIZE) % 4) != 0)
	  ++(*offset);

  val = (stream_is_big_endian) ? tvb_get_ntohl (tvb, *offset) :
                                 tvb_get_letohl (tvb, *offset);

  *offset += 4; 
  return val; 
}

/* Copy a 2 octet sequence from the tvbuff 
 * which represents an unsigned short value, and convert
 * it to an unsigned short value, taking into account byte order.
 * offset is first incremented so that it falls on a proper alignment
 * boundary for unsigned short values.
 * offset is then incremented by 2, to indicate the 2 octets which
 * have been processed.
 */
guint16
get_CDR_ushort(tvbuff_t *tvb, int *offset)
{
  guint16 val;

  /* unsigned long values must be aligned on a 4 byte boundary */
  while( ( (*offset + GIOP_HEADER_SIZE) % 2) != 0)
	  ++(*offset);

  val = (stream_is_big_endian) ? tvb_get_ntohs (tvb, *offset) :
                                 tvb_get_letohs (tvb, *offset);

  *offset += 2; 
  return val; 
}

/* Copy a sequence of octets from the tvbuff.
 * Caller of this function must remember to free the 
 * array pointed to by seq.
 * This function also increments offset by len. 
 */
void
get_CDR_octet_seq(tvbuff_t *tvb, gchar **seq, int *offset, int len)
{
     *seq = g_new0(gchar, len + 1);
     tvb_memcpy( tvb, *seq, *offset, len);
     *offset += len;
}

/**
 *  Dissects a TargetAddress which is defined in (CORBA 2.4, section 15.4.2)
 *  // GIOP 1.2
 *  typedef short AddressingDisposition;
 *  const short KeyAddr = 0;
 *  const short ProfileAddr = 1;
 *  const short ReferenceAddr = 2;
 *  struct IORAddressingInfo {
 *    unsigned long selected_profile_index;
 *    IOP::IOR ior;
 *  };
 *
 *  union TargetAddress switch (AddressingDisposition) {
 *      case KeyAddr: sequence <octet> object_key;
 *      case ProfileAddr: IOP::TaggedProfile profile;
 *      case ReferenceAddr: IORAddressingInfo ior;
 *  };
 */
void
dissect_target_address(tvbuff_t * tvb, int *offset, proto_tree * sub_tree, 
		       MessageHeader * header)
{
   guint16 discriminant;
   gchar *object_key = NULL;
   guint32 len = 0;

   discriminant = get_CDR_ushort(tvb, offset);
   if(sub_tree)
   {
     proto_tree_add_text (sub_tree, tvb, *offset -2, 2,
                 "TargetAddress Discriminant: %d", discriminant);
   }
  
   switch (discriminant)
   {
	   case 0:  // KeyAddr
		   len = get_CDR_ulong(tvb, offset);
		   get_CDR_octet_seq(tvb, &object_key, offset, len);
                   printable_string( object_key, len );

		   if(sub_tree)
		   {
                      proto_tree_add_text (sub_tree, tvb, *offset -len -4, 4,
			                   "KeyAddr (object key length): %d", len);
                      proto_tree_add_text (sub_tree, tvb, *offset -len, len,
			                   "KeyAddr (object key): %s", object_key);
		   }
		   break;
	   case 1:
		   if(sub_tree)
		   {
                      proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
			                   "ProfileAddr (not implemented) %s", object_key);
		   }
		   break;
           case 2:
		   if(sub_tree)
		   {
                      proto_tree_add_text (sub_tree, tvb, *offset, tvb_length(tvb) - *offset,
			                   "ReferenceAddr (not implemented) %s", object_key);
		   }
		   break;
	   default:
		   break;
   }
   g_free( object_key );
}

/* The format of the Reply Header for GIOP 1.0 and 1.1
 * is documented in Section 15.4.3.1 * of the CORBA 2.4 standard.

    struct ReplyHeader_1_0 {
          IOP::ServiceContextList service_context;
          unsigned long request_id;
          ReplyStatusType_1_0 reply_status;
    };
 */
void
dissect_giop_reply (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree,
		    proto_tree * clnp_tree, MessageHeader * header)
{
  guint32 offset = 0;
  guint32 nr_seq = 0;
  guint32 context_id;
  guint32 sequence_length;
  guint32 request_id;
  guint8 reply_status;
  gboolean big_endian;
  proto_tree *reply_tree = NULL;
  proto_item *tf;

  int i;

  big_endian = is_big_endian (header);

  /* From Section 15.3.2.5 of the CORBA 2.4 standard, a sequence
   * is an unsigned long value (4 octets) indicating the number of 
   * items in the sequence, followed by the items in the sequence 
   */

  /* The format of the IOP::ServiceContextList struct is defined in
   * section 13.7 of the CORBA 2.4 standard  as:
   module IOP { // IDL
   typedef unsigned long ServiceId;

   struct ServiceContext {
   ServiceId context_id;
   sequence <octet> context_data;
   };
   typedef sequence <ServiceContext>ServiceContextList;
   };
   */
  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Protocol Reply");
      if (reply_tree == NULL)
	{
	  reply_tree = proto_item_add_subtree (tf, ett_giop_reply);

	}
    }

  nr_seq = get_CDR_ulong(tvb, &offset);

  for (i = 1; i <= nr_seq; i++)
    {

      if (big_endian)
	{
	  context_id = tvb_get_ntohl (tvb, offset);
	  sequence_length = tvb_get_ntohl (tvb, offset + 4);
	}
      else
	{
	  context_id = tvb_get_letohl (tvb, offset);
	  sequence_length = tvb_get_letohl (tvb, offset + 4);
	}

      context_id = get_CDR_ulong(tvb, &offset);

      if (tree)
	{
	  proto_tree_add_text (reply_tree, tvb, offset -4, 4,
			       "Context id: %d", context_id);
	}

      sequence_length = get_CDR_ulong(tvb, &offset);
      if(tree)
      {	     
	  proto_tree_add_text (reply_tree, tvb, offset -4,
			       4, "Sequence length: %d", sequence_length);
      }

      if(tree)
      {
	  if (sequence_length > 0)
	    {
	      proto_tree_add_text (reply_tree, tvb, offset,
				   sequence_length,
				   "Sequence data: <not shown>");
	    }
	}

      offset += sequence_length;	

    }				/* for */

  request_id = get_CDR_ulong(tvb, &offset);

  if (tree)
    {
      proto_tree_add_text (reply_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  reply_status = tvb_get_guint8 (tvb, offset);
  if (tree)
    {
      proto_tree_add_text (reply_tree, tvb, offset, 1,
			   "Reply status: %s",
			   match_strval(reply_status, reply_status_types));

    }
  offset += 1;

}

/** The format of the GIOP 1.2 Reply header is very similar to the 1.0
 *  and 1.1 header, only the fields have been rearranged.  From Section
 *  15.4.3.1 of the CORBA 2.4 specification:
 *
 *   struct ReplyHeader_1_2 {
          unsigned long request_id;
          ReplyStatusType_1_2 reply_status;
          IOP:ServiceContextList service_context; // 1.2 change
     };
 */
void
dissect_giop_reply_1_2 (tvbuff_t * tvb, packet_info * pinfo,
			proto_tree * tree, proto_tree * clnp_tree,
			MessageHeader * header)
{
  u_int offset = 0;
  guint32 nr_seq = 0;
  guint32 context_id;
  guint32 sequence_length;
  guint32 request_id;
  guint8 reply_status;
  proto_tree *reply_tree = NULL;
  proto_item *tf;
  int i;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Protocol Reply");
      if (reply_tree == NULL)
	{
	  reply_tree = proto_item_add_subtree (tf, ett_giop_reply);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (tree)
    {
      proto_tree_add_text (reply_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  reply_status = tvb_get_guint8 (tvb, offset);
  offset += 1;
  if (tree)
    {
      proto_tree_add_text (reply_tree, tvb, offset-1, 1,
			   "Reply status: %s",
			   match_strval(reply_status, reply_status_types));

    }

  nr_seq = get_CDR_ulong(tvb, &offset);

  for (i = 1; i <= nr_seq; i++)
    {

      context_id = get_CDR_ulong(tvb, &offset);
      if (tree)
	{
	  proto_tree_add_text (reply_tree, tvb, offset -4, 4,
			       "Context id: %d", context_id);
	}

      sequence_length = get_CDR_ulong(tvb, &offset);
      if (tree)
      {
	  proto_tree_add_text (reply_tree, tvb, offset- 4,
			       4, "Sequence length: %d", sequence_length);
      }

      offset += sequence_length;
      if (tree)
      {
	  if (sequence_length > 0)
	    {
	      proto_tree_add_text (reply_tree, tvb, offset - sequence_length,
				   sequence_length,
				   "Sequence data: <not shown>");
	    }
      }

    }				/* for */
}

void
dissect_giop_cancel_request (tvbuff_t * tvb, packet_info * pinfo,
			proto_tree * tree, proto_tree * clnp_tree,
			MessageHeader * header)
{
  u_int offset = 0;
  guint32 request_id;
  proto_tree *cancel_request_tree = NULL;
  proto_item *tf;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Protocol CancelRequest");
      if (cancel_request_tree == NULL)
	{
	  cancel_request_tree = proto_item_add_subtree (tf, ett_giop_cancel_request);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (tree)
    {
      proto_tree_add_text (cancel_request_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }


}

/**  The formats for GIOP 1.0 and 1.1 Request messages are defined
 *   in section 15.4.2.1 of the CORBA 2.4 specification.
 *
 *   struct RequestHeader{
 *          IOP::ServiceContextList   service_context;
 *          unsigned long             request_id;
 *          boolean                   response_expected;
 *          octet                     reserved[3];  // Only in GIOP 1.1
 *          sequence<octet>           object_key;
 *          string                    operation;
 *          CORBA::OctetSeq           requesting_principal;
 *   }
 */
void
dissect_giop_request_1_1 (tvbuff_t * tvb, packet_info * pinfo,
			proto_tree * tree, proto_tree * clnp_tree,
			MessageHeader * header)
{
  guint32 offset = 0;
  guint32 nr_seq = 0;
  guint32 context_id;
  guint32 sequence_length;
  guint32 request_id;
  guint32 len = 0;
  gchar *object_key = NULL;
  gchar *operation = NULL;
  gchar *requesting_principal = NULL;
  guint8 response_expected;
  gchar *reserved = NULL;
  proto_tree *request_tree = NULL;
  proto_item *tf;
  int i;


  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Protocol Request");
      if (request_tree == NULL)
	{
	  request_tree = proto_item_add_subtree (tf, ett_giop_request);

	}
    }

  nr_seq = get_CDR_ulong(tvb, &offset);

  for (i = 1; i <= nr_seq; i++)
    {

      context_id = get_CDR_ulong(tvb, &offset);
      if (tree)
	{
	  proto_tree_add_text (request_tree, tvb, offset-4, 4,
			       "Context id: %d", context_id);
	}

       sequence_length = get_CDR_ulong(tvb, &offset);
       if(tree)
	{
	   proto_tree_add_text (request_tree, tvb, offset-4, 4, 
			        "Sequence length: %d", sequence_length);
	}

        offset +=  sequence_length;
        if (sequence_length > 0)
        {
	      proto_tree_add_text (request_tree, tvb, offset - sequence_length,
				   sequence_length,
				   "Sequence data: <not shown>");
        }
	

    } /* for */

  request_id = get_CDR_ulong(tvb, &offset);
  if (tree)
    {
      proto_tree_add_text (request_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  response_expected = tvb_get_guint8( tvb, offset );
  offset += 1;
  if (tree)
    {
      proto_tree_add_text (request_tree, tvb, offset-1, 1,
			   "Response expected: %d", response_expected);
    }

  if( header->GIOP_version.minor > 0)
  {
     get_CDR_octet_seq( tvb, &reserved, &offset, 3);
     if (tree)
       {
         proto_tree_add_text (request_tree, tvb, offset-3, 3,
	   		   "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
       }
  }

  /* Length of object_key sequence */
  len = get_CDR_ulong(tvb, &offset);

  if(tree)
  {
         proto_tree_add_text (request_tree, tvb, offset-4, 4,
         /**/                 "Object Key length: %d", len);
  } 

  if( len > 0)
  {
       get_CDR_octet_seq(tvb, &object_key, &offset, len);
       printable_string( object_key, len );

       if(tree)
       {
         proto_tree_add_text (request_tree, tvb, offset - len, len,
         /**/                 "Object Key: %s", object_key);

       }
  } 

  /* length of operation string */ 
  len = get_CDR_ulong(tvb, &offset);
  if(tree)
  {
         proto_tree_add_text (request_tree, tvb, offset -4, 4,
         /**/                 "Operation length: %d", len);
  } 

  if( len > 0)
  {
       get_CDR_octet_seq(tvb, &operation, &offset, len);
       if(tree)
       {
         proto_tree_add_text (request_tree, tvb, offset - len, len,
         /**/                 "Operation: %s", operation);

       }
  }

  /* length of requesting_principal string */ 
  len = get_CDR_ulong(tvb, &offset);
  if(tree)
  {
         proto_tree_add_text (request_tree, tvb, offset-4, 4,
         /**/                 "Requesting Principal Length: %d", len);
  } 

  if( len > 0)
  {
       get_CDR_octet_seq(tvb, &requesting_principal, &offset, len);
       if(tree)
       {
         proto_tree_add_text (request_tree, tvb, offset - len, len, 
         /**/                 "Requesting Principal: %s", requesting_principal);

       }
  }

  g_free( object_key );
  g_free( operation );
  g_free( requesting_principal );
}

/**  The format of a GIOP 1.2 RequestHeader message is 
 *   (CORBA 2.4, sec. 15.4.2):
 *
 *   struct RequestHeader_1_2 {
 *       unsigned long request_id;
 *       octet response_flags;
 *       octet reserved[3];
 *       TargetAddress target;
 *       string operation;
 *       IOP::ServiceContextList service_context;
 *       // requesting_principal not in GIOP 1.2
 *   };
 */
void
dissect_giop_request_1_2 (tvbuff_t * tvb, packet_info * pinfo,
			proto_tree * tree, proto_tree * clnp_tree,
			MessageHeader * header)
{
  guint32 offset = 0;
  guint32 request_id;
  guint32 len = 0;
  guint8 response_flags;
  gchar *reserved = NULL;
  gchar *operation = NULL;
  proto_tree *request_tree = NULL;
  proto_item *tf;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Protocol Request");
      if (request_tree == NULL)
	{
	  request_tree = proto_item_add_subtree (tf, ett_giop_reply);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (request_tree)
    {
      proto_tree_add_text (request_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  response_flags = tvb_get_guint8( tvb, offset );
  offset += 1;
  if (request_tree)
    {
      proto_tree_add_text (request_tree, tvb, offset-1, 1,
			   "Response flags: %s (%d)",
			        match_strval(response_flags, sync_scope),  
			        response_flags);
    }

  get_CDR_octet_seq( tvb, &reserved, &offset, 3);
  if (request_tree)
   {
     proto_tree_add_text (request_tree, tvb, offset-3, 3,
 	   "Reserved: %x %x %x", reserved[0], reserved[1], reserved[2]);
   }

  dissect_target_address(tvb, &offset, request_tree, header);

  /* length of operation string */ 
  len = get_CDR_ulong(tvb, &offset);
  if(tree)
  {
         proto_tree_add_text (request_tree, tvb, offset -4, 4,
         /**/                 "Operation length: %d", len);
  } 

  if( len > 0)
  {
       get_CDR_octet_seq(tvb, &operation, &offset, len);
       if(request_tree)
       {
         proto_tree_add_text (request_tree, tvb, offset - len, len,
         /**/                 "Operation: %s", operation);

       }

  }
  g_free(reserved);
}

void
dissect_giop_locate_request( tvbuff_t * tvb, proto_tree * tree, 
			MessageHeader * header)
{
  guint32 offset = 0;
  guint32 request_id;
  guint32 len = 0;
  gchar *object_key = NULL;
  proto_tree *locate_request_tree = NULL;
  proto_item *tf;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Locate Request");
      if (locate_request_tree == NULL)
	{
	  locate_request_tree = proto_item_add_subtree (tf, ett_giop_locate_request);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (locate_request_tree)
    {
      proto_tree_add_text (locate_request_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  if(header->GIOP_version.minor < 2)
  {
        len = get_CDR_ulong(tvb, &offset);
        get_CDR_octet_seq(tvb, &object_key, &offset, len);

	if(locate_request_tree)
	{

           proto_tree_add_text (locate_request_tree, tvb, offset-len, len,
			   "Object Key: %s", object_key);


	}

  }
  else     // GIOP 1.2 and higher
  {
      dissect_target_address(tvb, &offset, locate_request_tree, header); 

  }
  g_free( object_key );  
}

void
dissect_giop_locate_reply( tvbuff_t * tvb, proto_tree * tree, 
			MessageHeader * header)
{
  guint32 offset = 0;
  guint32 request_id;
  guint32 locate_status;
  proto_tree *locate_reply_tree = NULL;
  proto_item *tf;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Locate Reply");
      if (locate_reply_tree == NULL)
	{
	  locate_reply_tree = proto_item_add_subtree (tf, ett_giop_locate_reply);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (locate_reply_tree)
    {
      proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

  locate_status = get_CDR_ulong(tvb, &offset);
  if (locate_reply_tree)
    {
      proto_tree_add_text (locate_reply_tree, tvb, offset-4, 4,
			   "Locate status: %s", 
			   match_strval(locate_status, giop_locate_status_types)
			   );
				   
    }

}

void
dissect_giop_fragment( tvbuff_t * tvb, proto_tree * tree, 
			MessageHeader * header)
{
  guint32 offset = 0;
  guint32 request_id;
  proto_tree *fragment_tree = NULL;
  proto_item *tf;

  if (tree)
    {
      tf = proto_tree_add_text (tree, tvb, offset,
				tvb_length (tvb),
				"General Inter-ORB Fragment");
      if (fragment_tree == NULL)
	{
	  fragment_tree = proto_item_add_subtree (tf, ett_giop_fragment);

	}
    }

  request_id = get_CDR_ulong(tvb, &offset);
  if (fragment_tree )
    {
      proto_tree_add_text (fragment_tree, tvb, offset-4, 4,
			   "Request id: %d", request_id);
    }

				   
}


/* main entry point */
gboolean
dissect_giop (tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
{
  u_int offset = 0;
  MessageHeader header;
  tvbuff_t *giop_header_tvb;
  tvbuff_t *payload_tvb;

  proto_tree *clnp_tree = NULL;
  proto_item *ti;
  u_int message_size;
  u_int minor_version;

  /* CHECK_DISPLAY_AS_DATA (proto_giop, tvb, pinfo, tree); */
  if( !proto_is_protocol_enabled( proto_giop )){
	  dissect_data(tvb, pinfo, tree);
	  return FALSE;
  }

  pinfo->current_proto = "GIOP";

  /* check magic number and version */


  if (check_col (pinfo->fd, COL_PROTOCOL))
    {
      col_add_str (pinfo->fd, COL_PROTOCOL, "GIOP");
    }


  /*define END_OF_GIOP_MESSAGE (offset - first_offset - GIOP_HEADER_SIZE) */

  giop_header_tvb = tvb_new_subset (tvb, 0, GIOP_HEADER_SIZE, -1);
  payload_tvb = tvb_new_subset (tvb, GIOP_HEADER_SIZE, -1, -1);

  /*  memcpy(&header, &pd[offset], sizeof(header)); */
  tvb_memcpy (giop_header_tvb, (guint8 *)&header, 0, sizeof (header));

  if (memcmp (header.magic, GIOP_MAGIC, sizeof (header.magic)) != 0)
    {
      /* Not a GIOP message. */
      return FALSE;
    }

  if (header.GIOP_version.major != GIOP_MAJOR ||
      ((minor_version = header.GIOP_version.minor) > GIOP_MINOR))
    {
      /* Bad version number; should we note that and dissect the rest
         as data, or should we return FALSE on the theory that it
         might have been some other packet that happened to begin with
         "GIOP"? */
      if (check_col (pinfo->fd, COL_INFO))
	{
	  col_add_fstr (pinfo->fd, COL_INFO, "Version %d.%d",
			header.GIOP_version.major, header.GIOP_version.minor);
	}
      if (tree)
	{
	  ti = proto_tree_add_item (tree, proto_giop, tvb, 0,
				    tvb_length (tvb), FALSE);
	  clnp_tree = proto_item_add_subtree (ti, ett_giop);
	  proto_tree_add_text (clnp_tree, giop_header_tvb, 0,
			       tvb_length (giop_header_tvb),
			       "Version %d.%d not supported",
			       header.GIOP_version.major,
			       header.GIOP_version.minor);
	}
      dissect_data (payload_tvb, pinfo, tree);
      return FALSE;
    }

  stream_is_big_endian = is_big_endian (&header);


  if (stream_is_big_endian)
    message_size = pntohl (&header.message_size);
  else
    message_size = pletohl (&header.message_size);

  if (tree)
    {
      ti = proto_tree_add_item (tree, proto_giop, tvb, 0, 12, FALSE);
      clnp_tree = proto_item_add_subtree (ti, ett_giop);
      proto_tree_add_text (clnp_tree, giop_header_tvb, offset, 4,
			   "Magic number: %s", GIOP_MAGIC);
      proto_tree_add_text (clnp_tree, giop_header_tvb, 4, 2,
			   "Version: %d.%d",
			   header.GIOP_version.major,
			   header.GIOP_version.minor);
      switch (minor_version)
	{
	case 2:
	case 1:
	  proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
			       "Flags: 0x%02x (%s %s)",
			       header.flags,
			       (stream_is_big_endian) ? "big-endian" : "little-endian",
			       (header.flags & 0x02) ? " fragment" : "");
	  break;
	case 0:
	  proto_tree_add_text (clnp_tree, giop_header_tvb, 6, 1,
			       "Byte ordering: %s-endian",
			       (stream_is_big_endian) ? "big" : "little");
	  break;
	default:
	  break;
	}			/* minor_version */

      proto_tree_add_uint_format (clnp_tree,
				  hf_giop_message_type,
				  giop_header_tvb, 7, 1,
				  header.message_type,
				  "Message type: %s", match_strval(header.message_type, giop_message_types));

      proto_tree_add_uint (clnp_tree,
			   hf_giop_message_size,
			   giop_header_tvb, 8, 4, message_size);

    }				/* tree */

  if (check_col (pinfo->fd, COL_INFO)) 
  { 
      col_add_fstr (pinfo->fd, COL_INFO, "GIOP %d.%d %s",
                    header.GIOP_version.major, header.GIOP_version.minor,
                    match_strval(header.message_type, giop_message_types));
  }

  switch (header.message_type)
    {

    case Request:
      if(header.GIOP_version.minor < 2)
      {
	   dissect_giop_request_1_1 (payload_tvb, pinfo, tree, clnp_tree, &header);
      }
      else
      {    
           dissect_giop_request_1_2 (payload_tvb, pinfo, tree, clnp_tree, &header);
      }
      
      break;


    case Reply:
      if(header.GIOP_version.minor < 2)
	{
           dissect_giop_reply (payload_tvb, pinfo, tree, clnp_tree, &header);
	}
      else
        {
	   dissect_giop_reply_1_2 (payload_tvb, pinfo, tree, clnp_tree, &header);
	}
      break;
    case CancelRequest:
        dissect_giop_cancel_request(payload_tvb, pinfo, tree, clnp_tree, &header);
	break;
    case LocateRequest:
	dissect_giop_locate_request(payload_tvb, tree, &header);
	break;
    case LocateReply:
	dissect_giop_locate_reply(payload_tvb, tree, &header);
	break;
    case Fragment:
        dissect_giop_fragment(payload_tvb, tree, &header);
        break;	
    default:
      break;

    }				/* switch message_type */
    return TRUE;
}

void
proto_register_giop (void)
{
  static hf_register_info hf[] = {
    {
     &hf_giop_message_type,
     {
      "Message type", "giop.type",
      FT_UINT8, BASE_DEC, NULL, 0x0, ""}
     }
    ,
    {
     &hf_giop_message_size,
     {
      "Message size", "giop.len",
      FT_UINT32, BASE_DEC, NULL, 0x0, ""}
     }
    ,
  };
  static gint *ett[] = {
    &ett_giop,
    &ett_giop_reply,
    &ett_giop_request,
    &ett_giop_cancel_request,
    &ett_giop_locate_request,
    &ett_giop_locate_reply,
    &ett_giop_fragment
  };
  proto_giop = proto_register_protocol ("General Inter-ORB Protocol", "giop");
  proto_register_field_array (proto_giop, hf, array_length (hf));
  proto_register_subtree_array (ett, array_length (ett));
}

void
proto_reg_handoff_giop (void)
{
  heur_dissector_add ("tcp", dissect_giop);
}