From Martin Regner: fix dissection of non-standard parameters.
[obnox/wireshark/wip.git] / packet-enip.c
index aefdf3a6e0f26e70ba44d13943f475b08473b4c1..99c7500a1b5e800a03f6cf9aae6b2cfc2a046c5d 100644 (file)
@@ -1,4 +1,4 @@
-/* packet-cip.c
+/* packet-enip.c
  * Routines for EtherNet/IP (Industrial Protocol) dissection
  * EtherNet/IP Home: www.odva.org
  *
@@ -6,7 +6,7 @@
  * Magnus Hansson <mah@hms.se>
  * Joakim Wiberg <jow@hms.se>
  *
- * $Id: packet-enip.c,v 1.3 2003/07/25 04:17:36 gram Exp $
+ * $Id: packet-enip.c,v 1.5 2003/09/02 21:17:31 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -43,6 +43,7 @@
 
 #include <epan/packet.h>
 
+/* Defines */
 #define ENIP_ENCAP_PORT                44818   /* EtherNet/IP located on port 44818 */
 #define ENIP_IO_PORT              2222 /* EtherNet/IP IO located on port 2222  */
 
@@ -93,6 +94,7 @@
 #define SC_STOP                  0x07
 #define SC_CREATE                0x08
 #define SC_DELETE                0x09
+#define SC_MULT_SERV_PACK        0x0A
 #define SC_APPLY_ATTRIBUTES      0x0D
 #define SC_GET_ATT_SINGLE        0x0E
 #define SC_SET_ATT_SINGLE        0x10
@@ -225,7 +227,6 @@ static int hf_enip_cpf_lir_sinaddr     = -1;
 static int hf_enip_cpf_lir_sinzero     = -1;
 static int hf_enip_cpf_lir_devtype     = -1;
 static int hf_enip_cpf_lir_prodcode    = -1;
-static int hf_enip_cpf_lir_revision    = -1;
 static int hf_enip_cpf_lir_status      = -1;
 static int hf_enip_cpf_lir_sernbr      = -1;
 static int hf_enip_cpf_lir_namelength  = -1;
@@ -269,6 +270,7 @@ static gint ett_lsrcf      = -1;
 static gint ett_mes_req    = -1;
 static gint ett_cmd_data   = -1;
 static gint ett_port_path  = -1;
+static gint ett_mult_ser   = -1;
 
 
 
@@ -292,12 +294,12 @@ static const value_string encap_cmd_vals[] = {
 /* Translate function to string - Encapsulation status */
 static const value_string encap_status_vals[] = {
        { SUCCESS,                            "Success" },
-       { INVALID_CMD,           "Invalid command" },
-       { NO_RESOURCES,            "No memory resources" },
-       { INCORRECT_DATA,             "Incorrect data" },
-       { INVALID_SESSION,         "Invalid session handle" },
-       { INVALID_LENGTH,       "Invalid length" },
-       { UNSUPPORTED_PROT_REV, "Unsupported protocol revision" },
+       { INVALID_CMD,           "Invalid Command" },
+       { NO_RESOURCES,            "No Memory Resources" },
+       { INCORRECT_DATA,             "Incorrect Data" },
+       { INVALID_SESSION,         "Invalid Session Handle" },
+       { INVALID_LENGTH,       "Invalid Length" },
+       { UNSUPPORTED_PROT_REV, "Unsupported Protocol Revision" },
 
        { 0,                                     NULL }
 };
@@ -320,7 +322,7 @@ static const value_string cdf_type_vals[] = {
 /* Translate function to string - CIP Service codes */
 static const value_string encap_sc_vals[] = {
        { SC_GET_ATT_ALL,                "Get Attribute All" },
-       { SC_SET_ATT_ALL,                "Get Attribute All" },
+       { SC_SET_ATT_ALL,                "Set Attribute All" },
        { SC_GET_ATT_LIST,            "Get Attribute List" },
        { SC_SET_ATT_LIST,            "Set Attribute List" },
        { SC_RESET,                    "Reset" },
@@ -337,6 +339,7 @@ static const value_string encap_sc_vals[] = {
        { SC_NO_OP,                    "Nop" },
        { SC_GET_MEMBER,                 "Get Member" },
        { SC_SET_MEMBER,                 "Set Member" },
+       { SC_MULT_SERV_PACK,       "Multiple Service Packet" },
 
        /* Some class specific services */
        { SC_FWD_CLOSE,          "Forward Close" },
@@ -603,7 +606,8 @@ static const value_string enip_class_names_vals[] = {
 
 
 
-proto_item* add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
+static proto_item*
+add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
 {
   char   *tmp, *tmp2, *tmp2start;
   proto_item* pi;
@@ -765,7 +769,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
 
                /* Display the 8-bit class number */
-               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Class: %s (0x%02X)", val_to_str( temp_data, enip_class_names_vals , "" ), temp_data );
+               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Class: %s (0x%02X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
 
                temp_string = match_strval( temp_data, enip_class_names_vals );
 
@@ -784,13 +788,13 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
             {
                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Class Segment (0x%04X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Class Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the class */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
 
                /* Display the 16-bit class number */
-               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Class: %s (0x%04X)", val_to_str( temp_data, enip_class_names_vals , "" ), temp_data );
+               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Class: %s (0x%04X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
                temp_string = match_strval( temp_data, enip_class_names_vals );
 
                if( temp_string )
@@ -808,13 +812,13 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
             {
                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%08X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the class */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
 
                /* Display the 32-bit instance number */
-               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Class: %s (0x%08X)", val_to_str( temp_data, enip_class_names_vals , "" ), temp_data );
+               proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Class: %s (0x%08X)", val_to_str( temp_data, enip_class_names_vals , "Unknown class" ), temp_data );
                temp_string = match_strval( temp_data, enip_class_names_vals );
 
                if( temp_string )
@@ -860,7 +864,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
             {
                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Instance Segment (0x%04X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Instance Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the instance */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -875,7 +879,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
             {
                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%08X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Instance Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the instance */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -918,7 +922,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
             {
                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Attribute Segment (0x%04X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Attribute Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the attribute */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -933,7 +937,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
             {
                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Attribute Segment (0x%08X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Attribute Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the attribute */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -976,7 +980,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_16_BIT )
             {
                temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Connection Point Segment (0x%04X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 3, "16-Bit Logical Connection Point Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the connection point */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -991,7 +995,7 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
             else if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_32_BIT )
             {
                temp_data = tvb_get_letohl( tvb, offset + pathpos + 2 );
-               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Connection Point Segment (0x%08X)", segment_type );
+               cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 5, "32-Bit Logical Connection Point Segment (0x%02X)", segment_type );
 
                /* Create a sub tree for the connection point */
                cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
@@ -1202,465 +1206,628 @@ show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
 } /* end of show_epath() */
 
 
-/* Add Common Data Structure to tree */
+
 static void
-show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
+add_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length )
 {
-   proto_item *ri, *ci, *pi, *rrsci, *ncppi, *sockaddr_item, *ar_item, *temp_item;
-   proto_item *mr_data_item;
-       proto_tree *cip_tree, *temp_tree;
-       proto_tree *item_tree;
-   proto_tree *sockaddr_tree;
+   proto_item *pi, *rrsci, *ncppi, *ar_item, *temp_item, *temp_item2;
+       proto_tree *temp_tree;
    proto_tree *rrsci_tree;
    proto_tree *ncp_tree;
    proto_tree *cmd_data_tree;
-       int item_count;
-       int item;
-       int item_length;
        int req_path_size, conn_path_size, mr_req_path_size;
        int temp_data;
        unsigned char gen_stat;
-   unsigned char name_length;
    unsigned char add_stat_size;
    unsigned char temp_byte, route_path_size;
    unsigned char app_rep_size, i;
-   char temp_char;
-   int msg_req_siz;
+   int msg_req_siz, num_services, serv_offset;
 
 
-   /* Show Common Data Format sub tree */
-   item_count = tvb_get_letohs( tvb, offset );
-   ri = proto_tree_add_text( tree, tvb, offset, 2, "Item count: %d", item_count );
-   cip_tree = proto_item_add_subtree(ri, ett_cip);
+   /* Add Service code & Request/Response tree */
+       rrsci = proto_tree_add_text(item_tree, tvb, offset, 1, "Service: ");
+       rrsci_tree = proto_item_add_subtree(rrsci, ett_rrsc);
 
-   while( item_count-- )
-   {
-      /* Add item type tree */
-      ci = proto_tree_add_item(cip_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
-      item_tree = proto_item_add_subtree(ci, ett_cpf);
+       /* Add Request/Response */
+   proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
+                       tvb, offset, 1, TRUE );
 
-      /* Add length field */
-      temp_data = tvb_get_letohs( tvb, offset+4 );
-      proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", temp_data );
+   proto_item_append_text( rrsci, "%s (%s)",
+               val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
+                  encap_sc_vals , "Unknown Service Code (%x)"),
+               val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
+                  encap_sc_rr, "") );
+
+       /* Add Service code */
+       proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc,
+                       tvb, offset, 1, TRUE );
+
+
+       if( tvb_get_guint8( tvb, offset ) & 0x80 )
+       {
+          /* Response message */
+
+               /* Add general status */
+               gen_stat = tvb_get_guint8( tvb, offset+2 );
+
+               proto_tree_add_item(item_tree, hf_enip_ucm_genstat,
+                       tvb, offset+2, 1, TRUE );
 
-      item        = tvb_get_letohs( tvb, offset+2 );
-      item_length = tvb_get_letohs( tvb, offset+4 );
+      /* Add additional status size */
+      temp_data = tvb_get_guint8( tvb, offset+3 );
+      proto_tree_add_text( item_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)", temp_data );
 
-      if( item_length )
+               add_stat_size = tvb_get_guint8( tvb, offset+3 )*2;
+
+               if( add_stat_size )
+               {
+         /* Add additional status */
+         pi = proto_tree_add_text( item_tree, tvb, offset+4, add_stat_size, "Additional Status:" );
+
+         for( i=0; i < add_stat_size/2; i ++ )
+         {
+           proto_item_append_text( pi, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
+         }
+               }
+
+      /* If there is any command specific data create a sub-tree for it */
+      if( ( item_length-4-add_stat_size ) != 0 )
       {
-         /* Add item data field */
+         pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific data" );
+         cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
 
-        switch( item )
-        {
-            case CONNECTION_BASED:
+                  if( gen_stat == CI_GRC_SUCCESS )
+               {
+                       /* Success responses */
 
-               /* Add Connection identifier */
-               proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%04X", tvb_get_letohl( tvb, offset + 6 )  );
-               break;
+                       if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN )
+            {
+               /* Forward open Response (Success) */
+
+               /* Display originator to target connection ID */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
 
-            case UNCONNECTED_MSG:
+               /* Display target to originator connection ID */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
 
-               /* Add Service code & Request/Response tree */
-               rrsci = proto_tree_add_text(item_tree, tvb, offset+6, 1, "Service: ");
-               rrsci_tree = proto_item_add_subtree(rrsci, ett_rrsc);
+               /* Display connection serial number */
+               temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
 
-               /* Add Request/Response */
-               proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
-                                                       tvb, offset+6, 1, TRUE );
+               /* Display the originator vendor id */
+               proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+10, 2, TRUE);
 
-               proto_item_append_text( rrsci, "%s (%s)",
-                           val_to_str( ( tvb_get_guint8( tvb, offset+6 ) & 0x7F ),
-                              encap_sc_vals , "Unknown service code (%x)"),
-                           val_to_str( ( tvb_get_guint8( tvb, offset+6 ) & 0x80 )>>7,
-                              encap_sc_rr, "") );
+               /* Display the originator serial number */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
 
-               /* Add Service code */
-               proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc,
-                           tvb, offset+6, 1, TRUE );
+               /* Display originator to target actual packet interval */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+16, 4, "O->T API: %dms (0x%08X)", temp_data / 1000, temp_data );
 
-               if( tvb_get_guint8( tvb, offset+6 ) & 0x80 )
+               /* Display originator to target actual packet interval */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+20 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+20, 4, "T->O API: %dms (0x%08X)", temp_data / 1000, temp_data );
+
+               /* Display the application reply size */
+               app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+24 ) * 2;
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+24, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
+
+               /* Display the Reserved byte */
+               temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+25 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
+
+               if( app_rep_size != 0 )
                {
-                  /* Response */
-                  /* Add status */
-                  gen_stat = tvb_get_guint8( tvb, offset+8 );
+                  /* Display application Reply data */
+                  ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+26, app_rep_size, "Application Reply:" );
+
+                  for( i=0; i < app_rep_size; i++ )
+                  {
+                    temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+26+i );
+                    proto_item_append_text(ar_item, " 0x%02X", temp_byte );
+                  }
+
+                } /* End of if reply data */
+
+            } /* End of if forward open response */
+                       else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE )
+            {
+               /* Forward close response (Success) */
+
+               /* Display connection serial number */
+               temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
 
-                  proto_tree_add_item(item_tree, hf_enip_ucm_genstat,
-                           tvb, offset+8, 1, TRUE );
+               /* Display the originator vendor id */
+               proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
 
-                  temp_data = tvb_get_guint8( tvb, offset+9 );
-                  proto_tree_add_text( item_tree, tvb, offset+9, 1, "Additional status size: %d (word)", temp_data );
+               /* Display the originator serial number */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
 
-                  add_stat_size = tvb_get_guint8( tvb, offset+9 )*2;
+               /* Display the application reply size */
+               app_rep_size = tvb_get_guint8( tvb, offset+4+add_stat_size+8 ) * 2;
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Application Reply Size: %d (words)", app_rep_size / 2 );
 
-                  if( add_stat_size )
+               /* Display the Reserved byte */
+               temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
+
+               if( app_rep_size != 0 )
+               {
+                  /* Display application Reply data */
+                  ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+10, app_rep_size, "Application Reply:" );
+
+                  for( i=0; i < app_rep_size; i ++ )
                   {
-                     add_byte_array_text_to_proto_tree( item_tree, tvb, offset+10, add_stat_size, "Additional status: " );
+                    temp_byte = tvb_get_guint8( tvb, offset+4+add_stat_size+10+i );
+                    proto_item_append_text(ar_item, " 0x%02X", temp_byte );
                   }
 
-                  /* If there is any command specific data create a sub-tree for it */
-                  if( ( item_length-4-add_stat_size ) != 0 )
+                } /* End of if reply data */
+
+            } /* End of if forward close response */
+            else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
+            {
+               /* Unconnected send response (Success) */
+
+               /* Display service response data */
+               add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
+            }
+            else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_MULT_SERV_PACK )
+            {
+               /* Multiple Service Reply (Success)*/
+
+               /* Add number of replies */
+               num_services = tvb_get_letohs( tvb, offset+4+add_stat_size );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Number of Replies: %d", num_services );
+
+               /* Add replies */
+               temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+add_stat_size+4, num_services*2, "Offsets: " );
+
+               for( i=0; i < num_services; i++ )
+               {
+                  int serv_length;
+
+                  serv_offset = tvb_get_letohs( tvb, offset+6+add_stat_size+(i*2) );
+
+                  if( i == (num_services-1) )
+                  {
+                     /* Last service to add */
+                     proto_item_append_text(temp_item, "%d", serv_offset );
+                     serv_length = item_length-add_stat_size-serv_offset-4;
+                  }
+                  else
                   {
-                     pi = proto_tree_add_text( item_tree, tvb, offset+10+add_stat_size, item_length-4-add_stat_size, "Command specific data" );
-                     cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
-                     if( gen_stat == CI_GRC_SUCCESS )
-                     {
-                        if( ( tvb_get_guint8( tvb, offset+6 ) & 0x7F ) == SC_FWD_OPEN )
-                        {
-                           /* Forward open Response */
-
-                           /* Display originator to target connection ID */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size, 4, "O->T Network Connection ID: 0x%08X", temp_data );
-
-                           /* Display target to originator connection ID */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size+4 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+4, 4, "T->O Network Connection ID: 0x%08X", temp_data );
-
-                           /* Display connection serial number */
-                           temp_data = tvb_get_letohs( tvb, offset+10+add_stat_size+8 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+8, 2, "Connection Serial Number: 0x%04X", temp_data );
-
-                           /* Display the originator vendor id */
-                           proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+10+add_stat_size+10, 2, TRUE);
-
-                          /* Display the originator serial number */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size+12 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+12, 4, "Originator Serial Number: 0x%08X", temp_data );
-
-                           /* Display originator to target actual packet interval */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size+16 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+16, 4, "O->T API: %dms (0x%08X)", temp_data / 1000, temp_data );
-
-                           /* Display originator to target actual packet interval */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size+20 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+20, 4, "T->O API: %dms (0x%08X)", temp_data / 1000, temp_data );
-
-                           /* Display the application reply size */
-                           app_rep_size = tvb_get_guint8( tvb, offset+10+add_stat_size+24 ) * 2;
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+24, 1, "Application Reply Size: 0x%02X (words)", app_rep_size / 2 );
-
-                           /* Display the Reserved byte */
-                           temp_byte = tvb_get_guint8( tvb, offset+10+add_stat_size+25 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+25, 1, "Reserved: 0x%02X", temp_byte );
-
-                           if( app_rep_size != 0 )
-                           {
-                              /* Display application Reply data */
-                              ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+26, app_rep_size, "Application Reply:" );
-
-                              for( i=0; i < app_rep_size; i ++ )
-                              {
-                                temp_byte = tvb_get_guint8( tvb, offset+10+add_stat_size+26+i );
-                                proto_item_append_text(ar_item, " 0x%02X", temp_byte );
-                              }
-
-                            } /* End of if reply data */
-
-                        } /* End of if forward open response */
-                        else if( ( tvb_get_guint8( tvb, offset+6 ) & 0x7F ) == SC_FWD_CLOSE )
-                        {
-                           /* Forward close response */
-
-                           /* Display connection serial number */
-                           temp_data = tvb_get_letohs( tvb, offset+10+add_stat_size );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
-
-                           /* Display the originator vendor id */
-                           proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+10+add_stat_size+2, 2, TRUE);
-
-                           /* Display the originator serial number */
-                           temp_data = tvb_get_letohl( tvb, offset+10+add_stat_size+4 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
-
-                           /* Display the application reply size */
-                           app_rep_size = tvb_get_guint8( tvb, offset+10+add_stat_size+8 ) * 2;
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+8, 1, "Application Reply Size: 0x%02X (words)", app_rep_size / 2 );
-
-                           /* Display the Reserved byte */
-                           temp_byte = tvb_get_guint8( tvb, offset+10+add_stat_size+9 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+9, 1, "Reserved: 0x%02X", temp_byte );
-
-                           if( app_rep_size != 0 )
-                           {
-                              /* Display application Reply data */
-                              ar_item = proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+10, app_rep_size, "Application Reply:" );
-
-                              for( i=0; i < app_rep_size; i ++ )
-                              {
-                                temp_byte = tvb_get_guint8( tvb, offset+10+add_stat_size+10+i );
-                                proto_item_append_text(ar_item, " 0x%02X", temp_byte );
-                              }
-
-                            } /* End of if reply data */
-
-                        } /* End of if forward close response */
-                        else if( ( tvb_get_guint8( tvb, offset+6 ) & 0x7F ) == SC_UNCON_SEND )
-                        {
-                           /* Unconnected send response */
-
-                           /* Display reply service */
-                           temp_data = tvb_get_guint8( tvb, offset+10+add_stat_size );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size, 1, "Reply Service: 0x%02X", temp_data );
-
-                           /* Display reseved byte */
-                           temp_data = tvb_get_guint8( tvb, offset+10+add_stat_size+1 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+1, 1, "Reserved: 0x%02X", temp_data );
+                     proto_item_append_text(temp_item, "%d, ", serv_offset );
+                     serv_length = tvb_get_letohs( tvb, offset+6+add_stat_size+((i+1)*2) ) - serv_offset;
+                  }
+
+                  temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+4, serv_length, "Service Reply #%d", i+1 );
+                  temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
+                  add_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length );
+               }
+            } /* End if Multiple service Packet */
+            else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_GET_ATT_LIST )
+            {
+               /* Get Attribute List Reply (Success)*/
+
+               int att_count;
+
+               /* Add Attribute Count */
+               att_count = tvb_get_letohs( tvb, offset+4+add_stat_size );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Attribute Count: %d", att_count );
+
+               /* Add the data */
+               add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+6+add_stat_size, item_length-6-add_stat_size, "Data: " );
+
+            } /* End if Multiple service Packet */
+            else
+                       {
+                          /* Add data */
+               add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
+                  } /* end of check service code */
+
+          }
+         else
+         {
+            /* Error responses */
+
+            if( ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_OPEN ) ||
+                ( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_FWD_CLOSE ) )
+            {
+               /* Forward open and forward close error response look the same */
 
-                           /* Display general status */
-                           temp_data = tvb_get_guint8( tvb, offset+10+add_stat_size+2 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+2, 1, "General Status: 0x%02X", temp_data );
+               /* Display connection serial number */
+               temp_data = tvb_get_letohs( tvb, offset+4+add_stat_size );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 2, "Connection Serial Number: 0x%04X", temp_data );
 
-                           /* Display reseved byte */
-                           temp_data = tvb_get_guint8( tvb, offset+10+add_stat_size+3 );
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+10+add_stat_size+3, 1, "Reserved: 0x%02X", temp_data );
+               /* Display the originator vendor id */
+               proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE);
 
-                           /* Display service responce data */
-                           add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+10+add_stat_size+4, item_length-8-add_stat_size, "Data: " );
-                        }
-                        else
-                        {
-                           /* Add data */
-                           add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+10+add_stat_size, item_length-4-add_stat_size, "Data: " );
-                        } /* End of check service code */
+               /* Display the originator serial number */
+               temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+4, 4, "Originator Serial Number: 0x%08X", temp_data );
 
-                     } /* End of if CI_GRC_SUCCESS */
-
-                  } /* End of if command-specific data present */
+               /* Display remaining path size */
+               temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+8 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+8, 1, "Remaining Path Size: %d", temp_data );
 
-               } /* End of if reply */
+               /* Display reserved data */
+               temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size+9 );
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size+9, 1, "Reserved: 0x%02X", temp_data );
+            }
+            else if( ( tvb_get_guint8( tvb, offset ) & 0x7F ) == SC_UNCON_SEND )
+            {
+               /* Unconnected send response (Unsuccess) */
+
+               /* Display remaining path size */
+               temp_data = tvb_get_guint8( tvb, offset+4+add_stat_size);
+               proto_tree_add_text( cmd_data_tree, tvb, offset+4+add_stat_size, 1, "Remaining Path Size: %d", temp_data );
+            }
+            else
+            {
+               /* Add data */
+               add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Data: " );
+            }
+
+         } /* end of if-else( CI_CRC_SUCCESS ) */
+
+      } /* End of if command-specific data present */
+
+       } /* End of if reply */
+       else
+       {
+          /* Request */
+
+          /* Add path size */
+          req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
+          proto_tree_add_text( item_tree, tvb, offset+1, 1, "Request Path Size: %d (words)", req_path_size/2 );
+
+      /* Add the epath */
+      pi = proto_tree_add_text(item_tree, tvb, offset+2, req_path_size, "Request Path: ");
+      show_epath( tvb, pi, offset+2, req_path_size );
+
+      /* If there is any command specific data creat a sub-tree for it */
+      if( (item_length-req_path_size-2) != 0 )
+      {
+
+         pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
+         cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
+
+         /* Check what service code that recived */
+
+         if( tvb_get_guint8( tvb, offset ) == SC_FWD_OPEN )
+         {
+            /* Forward open Request*/
+
+            /* Display the priority/tick timer */
+            temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
+
+            /* Display the time-out ticks */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
+
+            /* Display the actual time out */
+            temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Actual Time Out: %dms", temp_data );
+
+            /* Display originator to taget connection ID */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+2 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
+
+            /* Display target to originator connection ID */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
+
+            /* Display connection serial number */
+            temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+10 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
+
+            /* Display the originator vendor id */
+            proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+12, 2, TRUE);
+
+            /* Display the originator serial number */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+14 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
+
+            /* Display the timeout multiplier */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+18 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+18, 1, "Connection Timeout Multiplier: %s (%d)", val_to_str( temp_data, enip_con_time_mult_vals , "Reserved" ), temp_data );
+
+            /* Put out an indicator for the reserved bytes */
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+19, 3, "Reserved Data" );
+
+            /* Display originator to target requested packet interval */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+22 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+22, 4, "O->T RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
+
+             /* Display originator to target network connection patameterts, in a tree */
+             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+26 );
+             ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+26, 2, "O->T Network Connection Parameters: 0x%04X", temp_data );
+             ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
+
+            /* Add the data to the tree */
+            proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
+                                       tvb, offset+2+req_path_size+26, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
+                                       tvb, offset+2+req_path_size+26, 2, TRUE );
+            proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
+                                       tvb, offset+2+req_path_size+26, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
+                                       tvb, offset+2+req_path_size+26, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
+                                       tvb, offset+2+req_path_size+26, 2, TRUE );
+
+            /* Display target to originator requested packet interval */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+28 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+28, 4, "T->O RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
+
+             /* Display target to originator network connection patameterts, in a tree */
+             temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+32 );
+             ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+32, 2, "T->O Network Connection Parameters: 0x%04X", temp_data );
+             ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
+
+            /* Add the data to the tree */
+            proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
+                                       tvb, offset+2+req_path_size+32, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
+                                       tvb, offset+2+req_path_size+32, 2, TRUE );
+            proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
+                                       tvb, offset+2+req_path_size+32, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
+                                       tvb, offset+2+req_path_size+32, 2, TRUE );
+                       proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
+                                       tvb, offset+2+req_path_size+32, 2, TRUE );
+
+            /* Transport type/trigger */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+6+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
+
+            /* Add path size */
+            conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+35 )*2;
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
+
+            /* Add the epath */
+            pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+36, conn_path_size, "Connection Path: ");
+            show_epath( tvb, pi, offset+2+req_path_size+36, conn_path_size );
+         }
+         else if( tvb_get_guint8( tvb, offset ) == SC_FWD_CLOSE )
+         {
+            /* Forward Close Request */
+
+            /* Display the priority/tick timer */
+            temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
+
+            /* Display the time-out ticks */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
+
+            /* Display connection serial number */
+            temp_data = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
+
+            /* Display the originator vendor id */
+            proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+2+req_path_size+4, 2, TRUE);
+
+            /* Display the originator serial number */
+            temp_data = tvb_get_letohl( tvb, offset+2+req_path_size+6 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
+
+            /* Add the path size */
+            conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+10 )*2;
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
+
+            /* Add the reserved byte */
+            temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size+11 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
+
+            /* Add the EPATH */
+            pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
+            show_epath( tvb, pi, offset+2+req_path_size+12, conn_path_size );
+
+         } /* End of forward close */
+         else if( tvb_get_guint8( tvb, offset ) == SC_UNCON_SEND )
+         {
+            /* Unconnected send */
+
+            /* Display the priority/tick timer */
+            temp_byte = tvb_get_guint8( tvb, offset+2+req_path_size );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
+
+            /* Display the time-out ticks */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+1 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
+
+            /* Message request size */
+            msg_req_siz = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
+
+            /* Message Request */
+            temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4, msg_req_siz, "Message Request" );
+            temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
+
+            /* MR - Service */
+            temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+4 );
+            proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+4, 1, "Service: %s (0x%02X)", val_to_str( temp_data, encap_sc_vals , "" ), temp_data );
+
+            /* MR - Request path Size */
+                  mr_req_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+5 )*2;
+                  proto_tree_add_text( temp_tree, tvb, offset+2+req_path_size+5, 1, "Request Path Size: %d (words)", mr_req_path_size/2 );
+
+            /* MR - EPATH */
+            temp_item = proto_tree_add_text(temp_tree, tvb, offset+2+req_path_size+6, mr_req_path_size, "Request Path: ");
+            show_epath( tvb, temp_item, offset+2+req_path_size+6, mr_req_path_size );
+
+            /* MR - Request data */
+            if( ( msg_req_siz-2-mr_req_path_size ) != 0 )
+            {
+               add_byte_array_text_to_proto_tree( temp_tree, tvb, offset+2+req_path_size+6+mr_req_path_size, msg_req_siz-2-mr_req_path_size, "Request Data: " );
+            }
+
+            if( msg_req_siz % 2 )
+            {
+               /* Pad byte */
+               proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz-3, 1, "Pad Byte (0x%02X)",
+                  tvb_get_guint8( tvb, offset+2+req_path_size+6+msg_req_siz-3 ) );
+            }
+
+            /* Route Path Size */
+                  route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+6+msg_req_siz-2 )*2;
+                  proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz-2, 1, "Route Path Size: %d (words)", route_path_size/2 );
+
+                  /* Reserved */
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz-1, 1, "Reserved (0x%02X)",
+                tvb_get_guint8( tvb, offset+2+req_path_size+6+msg_req_siz-1 ) );
+
+            /* Route Path */
+            temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path");
+            show_epath( tvb, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size );
+
+         } /* End if unconnected send */
+         else if( tvb_get_guint8( tvb, offset ) == SC_MULT_SERV_PACK )
+         {
+            /* Multiple service packet */
+
+            /* Add number of services */
+            num_services = tvb_get_letohs( tvb, offset+2+req_path_size );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Number of Services: %d", num_services );
+
+            /* Add services */
+            temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, num_services*2, "Offsets: " );
+
+            for( i=0; i < num_services; i++ )
+            {
+               int serv_length;
+
+               serv_offset = tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) );
+
+               if( i == (num_services-1) )
+               {
+                  /* Last service to add */
+                  serv_length = item_length-2-req_path_size-serv_offset;
+                  proto_item_append_text(temp_item, "%d", serv_offset );
+               }
                else
                {
-                  /* Request */
+                  serv_length = tvb_get_letohs( tvb, offset+4+req_path_size+((i+1)*2) ) - serv_offset;
+                  proto_item_append_text(temp_item, "%d, ", serv_offset );
+               }
 
-                  /* Add path size */
-                  req_path_size = tvb_get_guint8( tvb, offset+7 )*2;
-                  proto_tree_add_text( item_tree, tvb, offset+7, 1, "Request Path Size: %d (words)", req_path_size/2 );
+               temp_item2 = proto_tree_add_text( cmd_data_tree, tvb, offset+serv_offset+6, serv_length, "Service Packet #%d", i+1 );
+               temp_tree = proto_item_add_subtree( temp_item2, ett_mult_ser );
+               add_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length );
+            }
+         } /* End if Multiple service Packet */
+         else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
+         {
+            /* Get attribute list request */
 
-                  /* Add the epath */
-                  pi = proto_tree_add_text(item_tree, tvb, offset+8, req_path_size, "Request Path: ");
-                  show_epath( tvb, pi, offset+8, req_path_size );
+            int att_count;
 
-                  /* If there is any command specific data creat a sub-tree for it */
-                  if( (item_length-req_path_size-2) != 0 )
-                  {
+            /* Add number of services */
+            att_count = tvb_get_letohs( tvb, offset+2+req_path_size );
+            proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size, 2, "Attribute Count: %d", att_count );
+
+            /* Add Attribute List */
+            temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+2, att_count*2, "Attribute List: " );
+
+            for( i=0; i < att_count; i++ )
+            {
+               if( i == (att_count-1) )
+                  proto_item_append_text(temp_item, "%d",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
+               else
+                  proto_item_append_text(temp_item, "%d, ",tvb_get_letohs( tvb, offset+4+req_path_size+(i*2) ) );
+            }
+
+         } /* End of Get attribute list request */
+         else
+         {
+                     /* Add data */
+            add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Data: " );
+         } /* End of check service code */
+
+      } /* End of if command-specific data present */
 
-                     pi = proto_tree_add_text( item_tree, tvb, offset+8+req_path_size, item_length-req_path_size-2, "Command specific data" );
-                     cmd_data_tree = proto_item_add_subtree( pi, ett_cmd_data );
-
-                     /* Check what service code that recived */
-
-                     if( tvb_get_guint8( tvb, offset+6 ) == SC_FWD_OPEN )
-                     {
-                        /* Forward open Request*/
-
-                        /* Display the priority/tick timer */
-                        temp_byte = tvb_get_guint8( tvb, offset+8+req_path_size );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
-
-                        /* Display the time-out ticks */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+1 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
-
-                        /* Display the actual time out */
-                        temp_data = ( 1 << ( temp_byte & 0x0F ) ) * temp_data;
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size, 2, "Actual Time Out: %dms", temp_data );
-
-                        /* Display originator to taget connection ID */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+2 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+2, 4, "O->T Network Connection ID: 0x%08X", temp_data );
-
-                        /* Display target to originator connection ID */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+6 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+6, 4, "T->O Network Connection ID: 0x%08X", temp_data );
-
-                        /* Display connection serial number */
-                        temp_data = tvb_get_letohs( tvb, offset+8+req_path_size+10 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+10, 2, "Connection Serial Number: 0x%04X", temp_data );
-
-                        /* Display the originator vendor id */
-                        proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+8+req_path_size+12, 2, TRUE);
-
-                        /* Display the originator serial number */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+14 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+14, 4, "Originator Serial Number: 0x%08X", temp_data );
-
-                        /* Display the timeout multiplier */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+18 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+18, 1, "Connection Timeout Multiplier: %s (%d)", val_to_str( temp_data, enip_con_time_mult_vals , "Reserved" ), temp_data );
-
-                        /* Put out an indicator for the reserved bytes */
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+19, 3, "Reserved data" );
-
-                        /* Display originator to target requested packet interval */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+22 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+22, 4, "O->T RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
-
-                        /* Display originator to target network connection patameterts, in a tree */
-                        temp_data = tvb_get_letohs( tvb, offset+8+req_path_size+26 );
-                        ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+8+req_path_size+26, 2, "O->T Network Connection Parameters: 0x%04X", temp_data );
-                        ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
-
-                        /* Add the data to the tree */
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
-                           tvb, offset+8+req_path_size+26, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
-                           tvb, offset+8+req_path_size+26, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
-                           tvb, offset+8+req_path_size+26, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
-                           tvb, offset+8+req_path_size+26, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
-                           tvb, offset+8+req_path_size+26, 2, TRUE );
-
-                        /* Display target to originator requested packet interval */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+28 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+28, 4, "T->O RPI: %dms (0x%08X)", temp_data / 1000, temp_data );
-
-                        /* Display target to originator network connection patameterts, in a tree */
-                        temp_data = tvb_get_letohs( tvb, offset+8+req_path_size+32 );
-                        ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+8+req_path_size+32, 2, "T->O Network Connection Parameters: 0x%04X", temp_data );
-                        ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
-
-                        /* Add the data to the tree */
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_own,
-                           tvb, offset+8+req_path_size+32, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_typ,
-                           tvb, offset+8+req_path_size+32, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_prio,
-                           tvb, offset+8+req_path_size+32, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_fixed_var,
-                           tvb, offset+8+req_path_size+32, 2, TRUE );
-                        proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_con_size,
-                           tvb, offset+8+req_path_size+32, 2, TRUE );
-
-                        /* Transport type/trigger */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+34 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
-
-                        /* Add path size */
-                        conn_path_size = tvb_get_guint8( tvb, offset+8+req_path_size+35 )*2;
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+35, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
-
-                        /* Add the epath */
-                        pi = proto_tree_add_text(cmd_data_tree, tvb, offset+8+req_path_size+36, conn_path_size, "Connection Path: ");
-                        show_epath( tvb, pi, offset+8+req_path_size+36, conn_path_size );
-                     }
-                     else if( tvb_get_guint8( tvb, offset+6 ) == SC_FWD_CLOSE )
-                     {
-                        /* Forward Close Request */
-
-                        /* Display the priority/tick timer */
-                        temp_byte = tvb_get_guint8( tvb, offset+8+req_path_size );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
-
-                        /* Display the time-out ticks */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+1 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
-
-                        /* Display connection serial number */
-                        temp_data = tvb_get_letohs( tvb, offset+8+req_path_size+2 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+2, 2, "Connection Serial Number: 0x%04X", temp_data );
-
-                        /* Display the originator vendor id */
-                        proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+8+req_path_size+4, 2, TRUE);
-
-                        /* Display the originator serial number */
-                        temp_data = tvb_get_letohl( tvb, offset+8+req_path_size+6 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+6, 4, "Originator Serial Number: 0x%08X", temp_data );
-
-                        /* Add the path size */
-                        conn_path_size = tvb_get_guint8( tvb, offset+8+req_path_size+10 )*2;
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+10, 1, "Connection Path Size: %d (words)", conn_path_size / 2 );
-
-                        /* Add the reserved byte */
-                        temp_byte = tvb_get_guint8( tvb, offset+8+req_path_size+11 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+11, 1, "Reserved: 0x%02X", temp_byte );
-
-                        /* Add the EPATH */
-                        pi = proto_tree_add_text(cmd_data_tree, tvb, offset+8+req_path_size+12, conn_path_size, "Connection Path: ");
-                        show_epath( tvb, pi, offset+8+req_path_size+12, conn_path_size );
-
-                     } /* End of forward close */
-                     else if( tvb_get_guint8( tvb, offset+6 ) == SC_UNCON_SEND )
-                     {
-                        /* Unconnected send */
-
-                        /* Display the priority/tick timer */
-                        temp_byte = tvb_get_guint8( tvb, offset+8+req_path_size );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size, 1, "Priority/Time_tick: 0x%02X", temp_byte );
-
-                        /* Display the time-out ticks */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+1 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+1, 1, "Time-out_ticks: %d", temp_data );
-
-                        /* Message request size */
-                        msg_req_siz = tvb_get_letohs( tvb, offset+8+req_path_size+2 );
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+2, 2, "Message Request Size: 0x%04X", msg_req_siz );
-
-                        /* Message Request */
-                        temp_item = proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+4, msg_req_siz, "Message Request" );
-                        temp_tree = proto_item_add_subtree(temp_item, ett_mes_req );
-
-                        /* MR - Service */
-                        temp_data = tvb_get_guint8( tvb, offset+8+req_path_size+4 );
-                        proto_tree_add_text( temp_tree, tvb, offset+8+req_path_size+4, 1, "Service: %s (0x%02X)", val_to_str( temp_data, encap_sc_vals , "" ), temp_data );
-
-                        /* MR - Request path Size */
-                        mr_req_path_size = tvb_get_guint8( tvb, offset+8+req_path_size+5 )*2;
-                        proto_tree_add_text( temp_tree, tvb, offset+8+req_path_size+5, 1, "Request Path Size: %d (words)", mr_req_path_size/2 );
-
-                        /* MR - EPATH */
-                        temp_item = proto_tree_add_text(temp_tree, tvb, offset+8+req_path_size+6, mr_req_path_size, "Request Path: ");
-                        show_epath( tvb, temp_item, offset+8+req_path_size+6, mr_req_path_size );
-
-                        /* MR - Request data */
-
-                        i=0;
-
-                        if( ( msg_req_siz-2-mr_req_path_size ) != 0 )
-                        {
-                           mr_data_item = proto_tree_add_text( temp_tree, tvb, offset+8+req_path_size+6+mr_req_path_size, 0, "Request Data: " );
-
-                           for( i=0; i < msg_req_siz; i++ )
-                           {
-                             temp_byte = tvb_get_guint8( tvb, offset+8+req_path_size+6+mr_req_path_size+i );
-                             proto_item_append_text(mr_data_item, "%c", temp_byte );
-                           }
-                        }
+       } /* end of if-else( request ) */
 
-                        if( msg_req_siz % 2 )
-                        {
-                           /* PAD BYTE */
-                           proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+6+mr_req_path_size+i, 1, "Pad Byte (0x%02X)",
-                              tvb_get_guint8( tvb, offset+8+req_path_size+6+mr_req_path_size+i ) );
+} /* end of add_cip_data() */
 
-                           offset++;
-                        }
 
-                        /* Route Path Size */
-                        route_path_size = tvb_get_guint8( tvb, offset+8+req_path_size+6+mr_req_path_size+i )*2;
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+6+mr_req_path_size+i, 1, "Route Path Size: %d (words)", route_path_size/2 );
 
-                        /* Reserved */
-                        proto_tree_add_text( cmd_data_tree, tvb, offset+8+req_path_size+6+mr_req_path_size+i+1, 1, "Reserved (0x%02X)",
-                           tvb_get_guint8( tvb, offset+8+req_path_size+6+mr_req_path_size+i+1 ) );
+static void
+show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
+{
+   proto_item *temp_item, *ri, *ci;
+   proto_item *sockaddr_item;
+       proto_tree *temp_tree, *cip_tree, *item_tree, *sockaddr_tree;
+       int temp_data, item_count, item_length, item, i;
+       char temp_char;
+       unsigned char name_length;
+
+       /* Show Common Data Format sub tree */
+       item_count = tvb_get_letohs( tvb, offset );
+   ri = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
+       cip_tree = proto_item_add_subtree(ri, ett_cip);
+
+       while( item_count-- )
+       {
+               /* Add item type tree */
+               ci = proto_tree_add_item(cip_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
+               item_tree = proto_item_add_subtree(ci, ett_cpf);
+
+               /* Add length field */
+      temp_data = tvb_get_letohs( tvb, offset+4 );
+      proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", temp_data );
 
-                        /* Route Path */
-                        temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+8+req_path_size+6+mr_req_path_size+i+2, route_path_size, "Route Path");
-                        show_epath( tvb, temp_item, offset+8+req_path_size+6+mr_req_path_size+i+2, route_path_size );
+               item        = tvb_get_letohs( tvb, offset+2 );
+               item_length = tvb_get_letohs( tvb, offset+4 );
 
-                     } /* End if unconnected send */
-                     else
-                     {
-                        /* For all other service codes just display the data */
+               if( item_length )
+               {
+                  /* Add item data field */
 
-                        /* Add data */
-                        add_byte_array_text_to_proto_tree( cmd_data_tree, tvb, offset+8+req_path_size, item_length-req_path_size-2, "Data: " );
-                     } /* End of check service code */
+                       switch( item )
+                       {
+                          case CONNECTION_BASED:
 
-                  } /* End of if command-specific data present */
+                             /* Add Connection identifier */
+                             proto_tree_add_text( item_tree, tvb, offset+6, 4, "Connection Identifier: 0x%04X", tvb_get_letohl( tvb, offset + 6 )  );
+                             break;
 
-               } /* end of if-else( request ) */
+                          case UNCONNECTED_MSG:
+
+                                       /* Add CIP data tree*/
+                                       add_cip_data( item_tree, tvb, offset+6, item_length );
+
+                                       break;
+
+            case CONNECTION_TRANSPORT:
+
+               if( encap_service == SEND_UNIT_DATA )
+               {
+                  /*
+                  ** If the encapsulation service is SendUnit Data, this is a
+                  ** encapsulated connected message
+                  */
+
+                  /* Add sequence count ( Transport Class 1,2,3 )*/
+                  proto_tree_add_text( item_tree, tvb, offset+6, 2, "Sequence Count: 0x%04X", tvb_get_letohs( tvb, offset+6 ) );
+
+                  /* Add CIP data tree */
+                  add_cip_data( item_tree, tvb, offset+8, item_length-2 );
+               }
+               else
+               {
+                  /* Display data */
+                  add_byte_array_text_to_proto_tree( item_tree, tvb, offset+6, item_length, "Data: " );
+
+               } /* End of if send unit data */
 
                break;
 
@@ -1669,7 +1836,7 @@ show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
 
                /* Encapsulation version */
                temp_data = tvb_get_letohs( tvb, offset+6 );
-               proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation version: %d", temp_data );
+               proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
 
                /* Socket Address */
                sockaddr_item = proto_tree_add_text( item_tree, tvb, offset+8, 16, "Socket Address");
@@ -1704,8 +1871,8 @@ show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
                                                        tvb, offset+28, 2, TRUE );
 
                /* Revision */
-               proto_tree_add_item(item_tree, hf_enip_cpf_lir_revision,
-                                                       tvb, offset+30, 2, TRUE );
+               temp_data = tvb_get_letohs( tvb, offset+30 );
+               proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: v.%d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
 
                /* Status */
                proto_tree_add_item(item_tree, hf_enip_cpf_lir_status,
@@ -1767,7 +1934,7 @@ show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
                       col_clear(pinfo->cinfo, COL_INFO);
 
                   col_add_fstr(pinfo->cinfo, COL_INFO,
-                                        "Connection: ID=0x%04X, SEQ=%05d",
+                                        "Connection: ID=0x%08X, SEQ=%010d",
                                         tvb_get_letohl( tvb, offset+6 ),
                                         tvb_get_letohl( tvb, offset+10 ) );
                                   }
@@ -1778,7 +1945,7 @@ show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
 
                /* Encapsulation version */
                temp_data = tvb_get_letohs( tvb, offset+6 );
-               proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation version: %d", temp_data );
+               proto_tree_add_text( item_tree, tvb, offset+6, 2, "Encapsulation Version: %d", temp_data );
 
                /* Capability flags */
                temp_data = tvb_get_letohs( tvb, offset+8 );
@@ -1791,13 +1958,13 @@ show_cdf( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset )
                           tvb, offset+8, 2, TRUE );
 
                /* Name of service */
-               temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name of service: " );
+               temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name Of Service: " );
 
                for( i=0; i<16; i++ )
                {
                     temp_char = tvb_get_guint8( tvb, offset+10+i );
 
-                    if( temp_char == '\0' )
+                    if( temp_char == 0 )
                      break;
 
                     proto_item_append_text(temp_item, "%c", temp_char );
@@ -1879,13 +2046,13 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                }
 
                cmd_string = val_to_str(tvb_get_letohs( tvb, 0 ), encap_cmd_vals,
-           "Unknown command (%u)");
+           "Unknown Command (%u)");
 
                col_add_fstr(pinfo->cinfo, COL_INFO,
                                "%s: %s, Session=0x%08X",
                                pkt_type_str, cmd_string, tvb_get_letohl( tvb, 4 ) );
 
-               if( strstr( cmd_string, "Unknown command" ) != NULL )
+               if( strstr( cmd_string, "Unknown Command" ) != NULL )
                {
          /* Unknown command, since we don't have any information about this command
          just print the info column and the tree header. */
@@ -1924,10 +2091,10 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       proto_tree_add_text( headertree, tvb, 2, 2, "Length: %d", encap_data_length );
 
       temp_data = tvb_get_letohl( tvb, 4 );
-      proto_tree_add_text( headertree, tvb, 4, 4, "Session handle: 0x%08X", temp_data );
+      proto_tree_add_text( headertree, tvb, 4, 4, "Session Handle: 0x%08X", temp_data );
 
       temp_data = tvb_get_letohl( tvb, 8 );
-      proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)", val_to_str( temp_data, encap_status_vals , "Unknown status code" ), temp_data );
+      proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)", val_to_str( temp_data, encap_status_vals , "Unknown Status Code" ), temp_data );
 
       add_byte_array_text_to_proto_tree( headertree, tvb, 12, 8, "Sender context: " );
 
@@ -1949,27 +2116,27 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                   switch( encap_cmd )
                        {
             case NOP:
-                                  show_cdf( tvb, pinfo, csftree, 24 );
+                                  show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
                                        break;
 
                                case LIST_SERVICES:
-                                  show_cdf( tvb, pinfo, csftree, 24 );
+                                  show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
                                        break;
 
                                case LIST_IDENTITY:
-                                  show_cdf( tvb, pinfo, csftree, 24 );
+                                  show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
                                        break;
 
                                case LIST_INTERFACES:
-                                  show_cdf( tvb, pinfo, csftree, 24 );
+                                  show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
                                        break;
 
                                case REGISTER_SESSION:
                temp_data = tvb_get_letohs( tvb, 24 );
-               proto_tree_add_text( csftree, tvb, 24, 2, "Protocol version: 0x%04X", temp_data );
+               proto_tree_add_text( csftree, tvb, 24, 2, "Protocol Version: 0x%04X", temp_data );
 
                temp_data = tvb_get_letohs( tvb, 26 );
-               proto_tree_add_text( csftree, tvb, 26, 2, "Option flags: 0x%04X", temp_data );
+               proto_tree_add_text( csftree, tvb, 26, 2, "Option Flags: 0x%04X", temp_data );
 
                                        break;
 
@@ -1983,7 +2150,7 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                temp_data = tvb_get_letohs( tvb, 28 );
                proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %d", temp_data );
 
-                                       show_cdf( tvb, pinfo, csftree, 30 );
+                                       show_cdf( encap_cmd, tvb, pinfo, csftree, 30 );
                                        break;
 
                                case INDICATE_STATUS:
@@ -1991,7 +2158,7 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                           default:
 
                                   /* Can not decode - Just show the data */
-               add_byte_array_text_to_proto_tree( headertree, tvb, 24, encap_data_length, "Encap data: " );
+               add_byte_array_text_to_proto_tree( headertree, tvb, 24, encap_data_length, "Encap Data: " );
                break;
 
                        } /* end of switch() */
@@ -2001,7 +2168,8 @@ dissect_cipencap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        }
 
    /* If this protocol has a sub-dissector call it here, see section 1.8 */
-}
+
+} /* end of dissect_cipencap() */
 
 
 /* Code to actually dissect the io packets*/
@@ -2025,9 +2193,10 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
                cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
 
-      show_cdf( tvb, pinfo, cipencap_tree, 0 );
+      show_cdf( 0xFFFF, tvb, pinfo, cipencap_tree, 0 );
        }
-}
+
+} /* end of dissect_enipio() */
 
 
 /* Register the protocol with Ethereal */
@@ -2116,11 +2285,6 @@ proto_register_cipencap(void)
                        FT_UINT16, BASE_DEC, NULL, 0,
                        "Product Code", HFILL }
                },
-      { &hf_enip_cpf_lir_revision,
-                       { "Revision", "enip.lir.revision",
-                       FT_BYTES, BASE_DEC, NULL, 0,
-                       "Revision", HFILL }
-               },
       { &hf_enip_cpf_lir_status,
                        { "Status", "enip.lir.status",
                        FT_UINT16, BASE_HEX, NULL, 0,
@@ -2230,7 +2394,8 @@ proto_register_cipencap(void)
                &ett_lsrcf,
                &ett_mes_req,
                &ett_cmd_data,
-               &ett_port_path
+               &ett_port_path,
+               &ett_mult_ser
        };
 
 /* Register the protocol name and description */
@@ -2240,7 +2405,8 @@ proto_register_cipencap(void)
 /* Required function calls to register the header fields and subtrees used */
        proto_register_field_array(proto_cipencap, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
-}
+
+} /* end of proto_register_cipencap() */
 
 
 /* If this dissector uses sub-dissector registration add a registration routine.
@@ -2262,4 +2428,5 @@ proto_reg_handoff_cipencap(void)
        /* Register for IO data over UDP */
        enipio_handle = create_dissector_handle(dissect_enipio, proto_cipencap);
        dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
-}
+
+} /* end of proto_reg_handoff_cipencap() */