diff options
author | Guy Harris <guy@alum.mit.edu> | 2003-08-16 01:53:41 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 2003-08-16 01:53:41 +0000 |
commit | bf258889fb959c5a21c11d636541f902b19d8301 (patch) | |
tree | a2b8e99c6703795aa73f58f5adcb11e4386d3375 /packet-enip.c | |
parent | 45208cd1d52c01cf499ee698583079965175c838 (diff) |
From Joakim Wiberg: various fixes and cleanups, including fixes to
malformed packets caused by unconnected send and support for connected
class 3 data.
svn path=/trunk/; revision=8173
Diffstat (limited to 'packet-enip.c')
-rw-r--r-- | packet-enip.c | 1074 |
1 files changed, 618 insertions, 456 deletions
diff --git a/packet-enip.c b/packet-enip.c index aefdf3a6e0..eff8b3ac6e 100644 --- a/packet-enip.c +++ b/packet-enip.c @@ -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.4 2003/08/16 01:53:41 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,623 @@ 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 */ + add_byte_array_text_to_proto_tree( item_tree, tvb, offset+4, add_stat_size, "Additional Status: " ); + } + + /* 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 ); + + /* 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 ); + + /* 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 ); + + /* Display the originator vendor id */ + proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+10, 2, TRUE); - case UNCONNECTED_MSG: + /* 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 & 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 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 ); - /* Add Request/Response */ - proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr, - tvb, offset+6, 1, TRUE ); + /* 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 ); - 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 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 ); - /* Add Service code */ - proto_tree_add_item(rrsci_tree, hf_enip_ucm_sc, - tvb, offset+6, 1, TRUE ); + /* 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( tvb_get_guint8( tvb, offset+6 ) & 0x80 ) + 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:" ); - proto_tree_add_item(item_tree, hf_enip_ucm_genstat, - tvb, offset+8, 1, TRUE ); + 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) */ - 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 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 ); - add_stat_size = tvb_get_guint8( tvb, offset+9 )*2; + /* 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 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 ); + + /* 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 ); + + /* 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:" ); - if( add_stat_size ) + 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) ) { - 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 ); + /* Last service to add */ + proto_item_append_text(temp_item, "%d", serv_offset ); + serv_length = item_length-add_stat_size-serv_offset-4; + } + else + { + 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 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 the originator vendor id */ + proto_tree_add_item( cmd_data_tree, hf_enip_vendors, tvb, offset+4+add_stat_size+2, 2, TRUE); + + /* 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 ); + + /* 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 ); + + /* 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 ); - /* 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 ); + /* Check what service code that recived */ - /* 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 ); + 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 ); - /* 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 */ + /* 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 if CI_GRC_SUCCESS */ - - } /* End of if command-specific data present */ + } /* 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 ); - } /* End of if reply */ + /* 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 ); + } + + 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 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 ); + int att_count; - /* 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 ); + /* 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 ); - /* If there is any command specific data creat a sub-tree for it */ - if( (item_length-req_path_size-2) != 0 ) - { + /* 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 +1831,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 +1866,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 +1929,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 +1940,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 +1953,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 +2041,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 +2086,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 +2111,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 +2145,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 +2153,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 +2163,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 +2188,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 +2280,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 +2389,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 +2400,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 +2423,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() */ |