aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors
diff options
context:
space:
mode:
Diffstat (limited to 'epan/dissectors')
-rw-r--r--epan/dissectors/Makefile.common1
-rw-r--r--epan/dissectors/packet-cip.c1809
-rw-r--r--epan/dissectors/packet-enip.c2253
3 files changed, 2088 insertions, 1975 deletions
diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common
index 500c2a073e..3b2d95c6ad 100644
--- a/epan/dissectors/Makefile.common
+++ b/epan/dissectors/Makefile.common
@@ -98,6 +98,7 @@ DISSECTOR_SRC = \
packet-cdp.c \
packet-cgmp.c \
packet-chdlc.c \
+ packet-cip.c \
packet-cisco-oui.c \
packet-clearcase.c \
packet-clip.c \
diff --git a/epan/dissectors/packet-cip.c b/epan/dissectors/packet-cip.c
new file mode 100644
index 0000000000..64106cad71
--- /dev/null
+++ b/epan/dissectors/packet-cip.c
@@ -0,0 +1,1809 @@
+/* packet-cip.c
+ * Routines for Common Industrial Protocol (CIP) dissection
+ * CIP Home: www.odva.org
+ *
+ * Copyright 2004
+ * Magnus Hansson <mah@hms.se>
+ * Joakim Wiberg <jow@hms.se>
+ *
+ * $Id$
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
+#include <prefs.h>
+#include "packet-tcp.h"
+#include "packet-cip.h"
+
+#define ENIP_CIP_INTERFACE 0
+
+/* Initialize the protocol and registered fields */
+static int proto_cip = -1;
+
+static int hf_cip_sc = -1;
+static int hf_cip_rr = -1;
+static int hf_cip_epath = -1;
+static int hf_cip_genstat = -1;
+
+static int hf_cip_fwo_comp = -1;
+static int hf_cip_fwo_mrev = -1;
+static int hf_cip_fwo_con_size = -1;
+static int hf_cip_fwo_fixed_var = -1;
+static int hf_cip_fwo_prio = -1;
+static int hf_cip_fwo_typ = -1;
+static int hf_cip_fwo_own = -1;
+static int hf_cip_fwo_dir = -1;
+static int hf_cip_fwo_trigg = -1;
+static int hf_cip_fwo_class = -1;
+
+static int hf_cip_vendor = -1;
+static int hf_cip_devtype = -1;
+static int hf_cip_port = -1;
+static int hf_cip_link_address_byte = -1;
+static int hf_cip_link_address_string = -1;
+static int hf_cip_class8 = -1;
+static int hf_cip_class16 = -1;
+static int hf_cip_class32 = -1;
+static int hf_cip_instance8 = -1;
+static int hf_cip_instance16 = -1;
+static int hf_cip_instance32 = -1;
+static int hf_cip_attribute8 = -1;
+static int hf_cip_attribute16 = -1;
+static int hf_cip_attribute32 = -1;
+static int hf_cip_conpoint8 = -1;
+static int hf_cip_conpoint16 = -1;
+static int hf_cip_conpoint32 = -1;
+static int hf_cip_symbol = -1;
+
+/* Initialize the subtree pointers */
+static gint ett_cip = -1;
+static gint ett_ekey_path = -1;
+static gint ett_cia_path = -1;
+static gint ett_data_seg = -1;
+static gint ett_rrsc = -1;
+static gint ett_mcsc = -1;
+static gint ett_ncp = -1;
+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;
+static gint ett_path = -1;
+static gint ett_status_item = -1;
+
+
+/* Translate function to string - CIP Service codes */
+static const value_string cip_sc_vals[] = {
+ { SC_GET_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" },
+ { SC_START, "Start" },
+ { SC_STOP, "Stop" },
+ { SC_CREATE, "Create" },
+ { SC_DELETE, "Delete" },
+ { SC_APPLY_ATTRIBUTES, "Apply Attributes" },
+ { SC_GET_ATT_SINGLE, "Get Attribute Single" },
+ { SC_SET_ATT_SINGLE, "Set Attribute Single" },
+ { SC_FIND_NEXT_OBJ_INST, "Find Next Object Instance" },
+ { SC_RESTOR, "Restore" },
+ { SC_SAVE, "Save" },
+ { 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" },
+ { SC_FWD_OPEN, "Forward Open" },
+ { SC_UNCON_SEND, "Unconnected Send" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - CIP Request/Response */
+static const value_string cip_sc_rr[] = {
+ { 0, "Request" },
+ { 1, "Response" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Compatibility */
+static const value_string cip_com_bit_vals[] = {
+ { 0, "Bit Cleared" },
+ { 1, "Bit Set" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Connection priority */
+static const value_string cip_con_prio_vals[] = {
+ { 0, "Low Priority" },
+ { 1, "High Priority" },
+ { 2, "Scheduled" },
+ { 3, "Urgent" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Connection size fixed or variable */
+static const value_string cip_con_fw_vals[] = {
+ { 0, "Fixed" },
+ { 1, "Variable" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Connection owner */
+static const value_string cip_con_owner_vals[] = {
+ { 0, "Exclusive" },
+ { 1, "Redundant" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Connection direction */
+static const value_string cip_con_dir_vals[] = {
+ { 0, "Client" },
+ { 1, "Server" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Production trigger */
+static const value_string cip_con_trigg_vals[] = {
+ { 0, "Cyclic" },
+ { 1, "Change-Of-State" },
+ { 2, "Application Object" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Transport class */
+static const value_string cip_con_class_vals[] = {
+ { 0, "0" },
+ { 1, "1" },
+ { 2, "2" },
+ { 3, "3" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Connection type */
+static const value_string cip_con_type_vals[] = {
+ { 0, "Null" },
+ { 1, "Multicast" },
+ { 2, "Point to Point" },
+ { 3, "Reserved" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - Timeout Multiplier */
+static const value_string cip_con_time_mult_vals[] = {
+ { 0, "*4" },
+ { 1, "*8" },
+ { 2, "*16" },
+ { 3, "*32" },
+ { 4, "*64" },
+ { 5, "*128" },
+ { 6, "*256" },
+ { 7, "*512" },
+
+ { 0, NULL }
+};
+
+/* Translate function to string - CIP General Status codes */
+static const value_string cip_gs_vals[] = {
+ { CI_GRC_SUCCESS, "Success" },
+ { CI_GRC_FAILURE, "Connection failure" },
+ { CI_GRC_NO_RESOURCE, "Resource unavailable" },
+ { CI_GRC_BAD_DATA, "Invalid parameter value" },
+ { CI_GRC_BAD_PATH, "Path segment error" },
+ { CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
+ { CI_GRC_PARTIAL_DATA, "Partial transfer" },
+ { CI_GRC_CONN_LOST, "Connection lost" },
+ { CI_GRC_BAD_SERVICE, "Service not supported" },
+ { CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
+ { CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
+ { CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
+ { CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
+ { CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
+ { CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
+ { CI_GRC_PERMISSION_DENIED, "Privilege violation" },
+ { CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
+ { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
+ { CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
+ { CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
+ { CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
+ { CI_GRC_CONFIG_TOO_BIG, "Too much data" },
+ { CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
+ { CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
+ { CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
+ { CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
+ { CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
+ { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
+ { CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
+ { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
+ { CI_GRC_SERVICE_ERROR, "Embedded service error" },
+ { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
+ { CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
+ { CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
+ { CI_GRC_INVALID_REPLY, "Invalid Reply Received" },
+ { CI_GRC_BAD_KEY_IN_PATH, "Key Failure in path" },
+ { CI_GRC_BAD_PATH_SIZE, "Path Size Invalid" },
+ { CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
+ { CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
+ { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
+
+ { 0, NULL }
+};
+
+/* Translate Vendor ID:s */
+const value_string cip_vendor_vals[] = {
+ VENDOR_ID_LIST
+
+ { 0, NULL }
+};
+
+/* Translate Device Profile:s */
+const value_string cip_devtype_vals[] = {
+ { DP_GEN_DEV, "Generic Device" },
+ { DP_AC_DRIVE, "AC Drive" },
+ { DP_MOTOR_OVERLOAD, "Motor Overload" },
+ { DP_LIMIT_SWITCH, "Limit Switch" },
+ { DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
+ { DP_PHOTO_SENSOR, "Photoelectric Sensor" },
+ { DP_GENP_DISC_IO, "General Purpose Dicrete I/O" },
+ { DP_RESOLVER, "Resolver" },
+ { DP_COM_ADAPTER, "Communications Adapter" },
+ { DP_POS_CNT, "Position Controller", },
+ { DP_DC_DRIVE, "DC Drive" },
+ { DP_CONTACTOR, "Contactor", },
+ { DP_MOTOR_STARTER, "Motor Starter", },
+ { DP_SOFT_START, "Soft Start", },
+ { DP_HMI, "Human-Machine Interface" },
+ { DP_MASS_FLOW_CNT, "Mass Flow Controller" },
+ { DP_PNEUM_VALVE, "Pneumatic Valve" },
+ { DP_VACUUM_PRES_GAUGE, "Vaccuum Pressure Gauge" },
+
+ { 0, NULL }
+};
+
+/* Translate class names */
+static const value_string cip_class_names_vals[] = {
+ { 0x01, "Identity Object" },
+ { 0x02, "Message Router" },
+ { 0x03, "DeviceNet Object" },
+ { 0x04, "Assembly Object" },
+ { 0x05, "Connection Object" },
+ { 0x06, "Connection Manager" },
+ { 0x07, "Register Object" },
+ { 0x08, "Discrete Input Point Object" },
+ { 0x09, "Discrete Output Point Object" },
+ { 0x0A, "Analog Input Point Object" },
+ { 0x0B, "Analog Output Point Object" },
+ { 0x0E, "Presence Sensing Object" },
+ { 0x0F, "Parameter Object" },
+ { 0x10, "Parameter Group Object" },
+ { 0x12, "Group Object" },
+ { 0x1D, "Discrete Input Group Object" },
+ { 0x1E, "Discrete Output Group Object" },
+ { 0x1F, "Discrete Group Object" },
+ { 0x20, "Analog Input Group Object" },
+ { 0x21, "Analog Output Group Object" },
+ { 0x22, "Analog Group Object" },
+ { 0x23, "Position Sensor Object" },
+ { 0x24, "Position Controller Supervisor Object" },
+ { 0x25, "Position Controller Object" },
+ { 0x26, "Block Sequencer Object" },
+ { 0x27, "Command Block Object" },
+ { 0x28, "Motor Data Object" },
+ { 0x29, "Control Supervisor Object" },
+ { 0x2A, "AC/DC Drive Object" },
+ { 0x2B, "Acknowledge Handler Object" },
+ { 0x2C, "Overload Object" },
+ { 0x2D, "Softstart Object" },
+ { 0x2E, "Selection Object" },
+ { 0x30, "S-Device Supervisor Object" },
+ { 0x31, "S-Analog Sensor Object" },
+ { 0x32, "S-Analog Actuator Object" },
+ { 0x33, "S-Single Stage Controller Object" },
+ { 0x34, "S-Gas Calibration Object" },
+ { 0x35, "Trip Point Object" },
+ { 0x37, "File Object" },
+ { 0x38, "S-Partial Pressure Object" },
+ { 0xF0, "ControlNet Object" },
+ { 0xF1, "ControlNet Keeper Object" },
+ { 0xF2, "ControlNet Scheduling Object" },
+ { 0xF3, "Connection Configuration Object" },
+ { 0xF4, "Port Object" },
+ { 0xF5, "TCP/IP Interface Object" },
+ { 0xF6, "EtherNet Link Object" },
+
+ { 0, NULL }
+};
+
+
+static proto_item*
+add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
+{
+ const char *tmp;
+ char *tmp2, *tmp2start;
+ proto_item *pi;
+ int i,tmp_length,tmp2_length;
+ guint32 octet;
+ /* At least one version of Apple's C compiler/linker is buggy, causing
+ a complaint from the linker about the "literal C string section"
+ not ending with '\0' if we initialize a 16-element "char" array with
+ a 16-character string, the fact that initializing such an array with
+ such a string is perfectly legitimate ANSI C nonwithstanding, the 17th
+ '\0' byte in the string nonwithstanding. */
+ static const char my_hex_digits[16] =
+ { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+
+
+ if( ( length * 2 ) > 32 )
+ {
+ tmp_length = 16;
+ tmp2_length = 36;
+ }
+ else
+ {
+ tmp_length = length;
+ tmp2_length = ( length * 2 ) + 1;
+ }
+
+ tmp = tvb_get_ptr( tvb, start, tmp_length );
+ tmp2 = (char*)g_malloc( tmp2_length );
+
+ tmp2start = tmp2;
+
+ for( i = 0; i < tmp_length; i++ )
+ {
+ octet = tmp[i];
+ octet >>= 4;
+ *tmp2++ = my_hex_digits[octet&0xF];
+ octet = tmp[i];
+ *tmp2++ = my_hex_digits[octet&0xF];
+ }
+
+ if( tmp_length != length )
+ {
+ *tmp2++ = '.';
+ *tmp2++ = '.';
+ *tmp2++ = '.';
+ }
+
+ *tmp2 = 0;
+
+ pi = proto_tree_add_text( tree, tvb, start, length, "%s%s", str, tmp2start );
+
+ g_free( tmp2start );
+
+ return( pi );
+
+} /* end of add_byte_array_text_to_proto_tree() */
+
+
+/* Dissect EPATH */
+static void
+dissect_epath( tvbuff_t *tvb, proto_item *epath_item, int offset, int path_length )
+{
+ int pathpos, temp_data, temp_data2, seg_size, i, temp_word;
+ unsigned char segment_type, opt_link_size;
+ proto_tree *path_tree, *port_tree, *net_tree;
+ proto_item *qi, *cia_item, *ds_item;
+ proto_tree *e_key_tree, *cia_tree, *ds_tree;
+ proto_item *mcpi, *port_item, *net_item;
+ proto_tree *mc_tree;
+
+ /* Create a sub tree for the epath */
+ path_tree = proto_item_add_subtree( epath_item, ett_path );
+
+ proto_tree_add_item_hidden(path_tree, hf_cip_epath,
+ tvb, offset, path_length, TRUE );
+
+ pathpos = 0;
+
+ while( pathpos < path_length )
+ {
+ /* Get segement type */
+ segment_type = tvb_get_guint8( tvb, offset + pathpos );
+
+ /* Determine the segment type */
+
+ switch( segment_type & CI_SEGMENT_TYPE_MASK )
+ {
+ case CI_PORT_SEGMENT:
+
+ port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
+ port_tree = proto_item_add_subtree( port_item, ett_port_path );
+
+ /* Add port number */
+ proto_tree_add_item( port_tree, hf_cip_port, tvb, offset + pathpos, 1, TRUE );
+ proto_item_append_text( epath_item, "Port: %d", ( segment_type & 0x0F ) );
+ proto_item_append_text( port_item, ": Port: %d", ( segment_type & 0x0F ) );
+
+ if( segment_type & 0x10 )
+ {
+ /* Add Extended Link Address flag */
+ proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: TRUE" );
+
+ /* Add size of extended link address */
+ opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
+ proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
+
+ /* Add extended link address */
+ proto_tree_add_item( port_tree, hf_cip_link_address_string, tvb, offset+pathpos+2, opt_link_size, FALSE );
+ proto_item_append_text( epath_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
+ proto_item_append_text( port_item, ", Address: %s", tvb_format_text(tvb, offset+pathpos+2, opt_link_size) );
+
+ /* Pad byte */
+ if( opt_link_size % 2 )
+ {
+ proto_item_set_len( port_item, 3 + opt_link_size );
+ pathpos = pathpos + 3 + opt_link_size;
+ }
+ else
+ {
+ proto_item_set_len( port_item, 2 + opt_link_size );
+ pathpos = pathpos + 2 + opt_link_size;
+ }
+ }
+ else
+ {
+ /* Add Extended Link Address flag */
+ proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: FALSE" );
+
+ /* Add Link Address */
+ proto_tree_add_item( port_tree, hf_cip_link_address_byte, tvb, offset+pathpos+1, 1, FALSE );
+ proto_item_append_text( epath_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
+ proto_item_append_text( port_item, ", Address: %d",tvb_get_guint8( tvb, offset + pathpos + 1 ) );
+
+ proto_item_set_len( port_item, 2 );
+ pathpos += 2;
+ }
+
+ break;
+
+ case CI_LOGICAL_SEGMENT:
+
+ /* Logical segment, determin the logical type */
+
+ switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
+ {
+ case CI_LOGICAL_SEG_CLASS_ID:
+
+ /* Logical Class ID, do a format check */
+
+ if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
+ {
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
+ cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 8-bit class number */
+ proto_tree_add_item( cia_tree, hf_cip_class8, tvb, offset + pathpos + 1, 1, TRUE );
+ proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%02X" ) );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ }
+ 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, 4, "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_item( cia_tree, hf_cip_class16, tvb, offset + pathpos + 2, 2, TRUE );
+ proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%04X" ) );
+
+ /* 4 bytes of path used */
+ pathpos += 4;
+ }
+ 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, 6, "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 class number */
+ proto_tree_add_item( cia_tree, hf_cip_class32, tvb, offset + pathpos + 2, 4, TRUE );
+ proto_item_append_text( epath_item, "%s", val_to_str( temp_data, cip_class_names_vals , "Class: 0x%08X" ) );
+
+ /* 6 bytes of path used */
+ pathpos += 6;
+ }
+ else
+ {
+ /* Unsupported logical segment format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
+ return;
+ }
+ break;
+
+
+ case CI_LOGICAL_SEG_INST_ID:
+
+ /* Logical Instance ID, do a format check */
+
+ if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
+ {
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
+ cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
+
+ /* Display the 8-bit instance number */
+ proto_tree_add_item( cia_tree, hf_cip_instance8, tvb, offset + pathpos + 1, 1, TRUE );
+ proto_item_append_text( epath_item, "Instance: 0x%02X", temp_data );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ }
+ 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, 4, "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 );
+
+ /* Display the 16-bit instance number */
+ proto_tree_add_item( cia_tree, hf_cip_instance16, tvb, offset + pathpos + 2, 2, TRUE );
+ proto_item_append_text( epath_item, "Instance: 0x%04X", temp_data );
+
+ /* 4 bytes of path used */
+ pathpos += 4;
+ }
+ 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, 6, "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 );
+
+ /* Display the 32-bit instance number */
+ proto_tree_add_item( cia_tree, hf_cip_instance32, tvb, offset + pathpos + 2, 4, TRUE );
+ proto_item_append_text( epath_item, "Instance: 0x%08X", temp_data );
+
+
+ /* 6 bytes of path used */
+ pathpos += 6;
+ }
+ else
+ {
+ /* Unsupported logical segment format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
+ return;
+ }
+ break;
+
+
+ case CI_LOGICAL_SEG_ATTR_ID:
+
+ /* Logical Attribute ID, do a format check */
+
+ if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
+ {
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
+ cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
+
+ /* Display the 8-bit attribute number */
+ proto_tree_add_item( cia_tree, hf_cip_attribute8, tvb, offset + pathpos + 1, 1, TRUE );
+ proto_item_append_text( epath_item, "Attribute: 0x%02X", temp_data );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ }
+ 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, 4, "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 );
+
+ /* Display the 16-bit attribute number */
+ proto_tree_add_item( cia_tree, hf_cip_attribute16, tvb, offset + pathpos + 2, 2, TRUE );
+ proto_item_append_text( epath_item, "Attribute: 0x%04X", temp_data );
+
+ /* 4 bytes of path used */
+ pathpos += 4;
+ }
+ 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, 6, "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 );
+
+ /* Display the 32-bit attribute number */
+ proto_tree_add_item( cia_tree, hf_cip_attribute32, tvb, offset + pathpos + 2, 4, TRUE );
+ proto_item_append_text( epath_item, "Attribute: 0x%08X", temp_data );
+
+ /* 6 bytes of path used */
+ pathpos += 6;
+ }
+ else
+ {
+ /* Unsupported logical segment format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
+ return;
+ }
+ break;
+
+
+ case CI_LOGICAL_SEG_CON_POINT:
+
+ /* Logical Connection point , do a format check */
+
+ if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
+ {
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
+ cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
+
+ /* Display the 8-bit connection point number */
+ proto_tree_add_item( cia_tree, hf_cip_conpoint8, tvb, offset + pathpos + 1, 1, TRUE );
+ proto_item_append_text( epath_item, "Connection Point: 0x%02X", temp_data );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ }
+ 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, 4, "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 );
+
+ /* Display the 16-bit connection point number */
+ proto_tree_add_item( cia_tree, hf_cip_conpoint16, tvb, offset + pathpos + 2, 2, TRUE );
+ proto_item_append_text( epath_item, "Connection Point: 0x%04X", temp_data );
+
+ /* 4 bytes of path used */
+ pathpos += 4;
+ }
+ 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, 6, "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 );
+
+ /* Display the 32-bit connection point number */
+ proto_tree_add_item( cia_tree, hf_cip_conpoint32, tvb, offset + pathpos + 2, 4, TRUE );
+ proto_item_append_text( epath_item, "Connection Point: 0x%08X", temp_data );
+
+ /* 6 bytes of path used */
+ pathpos += 6;
+ }
+ else
+ {
+ /* Unsupported logical segment format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
+ return;
+ }
+ break;
+
+
+ case CI_LOGICAL_SEG_SPECIAL:
+
+ /* Logical Special ID, the only logical format sepcifyed is electronic key */
+
+ if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
+ {
+ /* Get the Key Format */
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
+
+ if( temp_data == CI_E_KEY_FORMAT_VAL )
+ {
+ qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
+
+ /* Create a sub tree for the IOI */
+ e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
+
+ /* Print the key type */
+ proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
+
+ /* Get the Vendor ID */
+ temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
+ proto_tree_add_item( e_key_tree, hf_cip_vendor, tvb, offset + pathpos + 2, 2, TRUE);
+ proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
+
+ /* Get Device Type */
+ temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
+ proto_tree_add_item( e_key_tree, hf_cip_devtype, tvb, offset + pathpos + 4, 2, TRUE);
+ proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
+
+ /* Product Code */
+ temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
+ proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
+
+ /* Major revision/Compatibility */
+ temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
+
+ /* Add Major revision/Compatibility tree */
+ mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
+ mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
+
+ /* Add Compatibility bit info */
+ proto_tree_add_item(mc_tree, hf_cip_fwo_comp,
+ tvb, offset + pathpos + 8, 1, TRUE );
+
+ proto_item_append_text( mcpi, "%s, Major Revision: %d",
+ val_to_str( ( temp_data & 0x80 )>>7, cip_com_bit_vals , "" ),
+ temp_data & 0x7F );
+
+ /* Major revision */
+ proto_tree_add_item(mc_tree, hf_cip_fwo_mrev,
+ tvb, offset + pathpos + 8, 1, TRUE );
+
+ /* Minor revision */
+ temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
+ proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
+
+ proto_item_append_text( qi, ", %d.%d", ( temp_data & 0x7F ), temp_data2 );
+
+ proto_item_append_text(epath_item, "[Key]" );
+
+ /* Increment the path pointer */
+ pathpos += 10;
+ }
+ else
+ {
+ /* Unsupported electronic key format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
+ return;
+ }
+ }
+ else
+ {
+ /* Unsupported special segment format */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
+ return;
+ }
+ break;
+
+ default:
+
+ /* Unsupported logical segment type */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
+ return;
+
+ } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
+ break;
+
+
+ case CI_DATA_SEGMENT:
+
+ /* Data segment, determin the logical type */
+
+ switch( segment_type )
+ {
+ case CI_DATA_SEG_SIMPLE:
+
+ /* Simple data segment */
+ ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
+
+ /* Create a sub tree */
+ ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
+
+ /* Segment size */
+ seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
+ proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
+
+ /* Segment data */
+ if( seg_size != 0 )
+ {
+ qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
+
+ for( i=0; i < seg_size/2; i ++ )
+ {
+ temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
+ proto_item_append_text(qi, " 0x%04X", temp_word );
+ }
+
+ proto_item_set_len(qi, seg_size);
+ }
+
+ proto_item_set_len( ds_item, 2 + seg_size );
+ pathpos = pathpos + 2 + seg_size;
+
+ proto_item_append_text(epath_item, "[Data]" );
+
+ break;
+
+ case CI_DATA_SEG_SYMBOL:
+
+ /* ANSI extended symbol segment */
+ ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
+
+ /* Create a sub tree */
+ ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
+
+ /* Segment size */
+ seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
+ proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
+
+ /* Segment data */
+ if( seg_size != 0 )
+ {
+ qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2, seg_size, "Data: %s",
+ tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
+
+ proto_item_append_text(epath_item, "%s", tvb_format_text(tvb, offset + pathpos + 2, seg_size ) );
+ proto_tree_add_item_hidden( ds_tree, hf_cip_symbol, tvb, offset + pathpos + 2, seg_size, FALSE );
+
+ if( seg_size %2 )
+ {
+ /* We have a PAD BYTE */
+ proto_tree_add_text( ds_tree, tvb, offset + pathpos + 2 + seg_size, 1, "Pad Byte (0x%02X)",
+ tvb_get_guint8( tvb, offset + pathpos + 2 + seg_size ) );
+ pathpos++;
+ seg_size++;
+ }
+ }
+
+ proto_item_set_len( ds_item, 2 + seg_size );
+ pathpos = pathpos + 2 + seg_size;
+
+ break;
+
+ default:
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
+ return;
+
+ } /* End of switch sub-type */
+
+ break;
+
+ case CI_NETWORK_SEGMENT:
+
+ /* Network segment -Determine the segment sub-type */
+
+ switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
+ {
+ case CI_NETWORK_SEG_SCHEDULE:
+ net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
+ net_tree = proto_item_add_subtree( net_item, ett_port_path );
+
+ proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ break;
+
+ case CI_NETWORK_SEG_FIXED_TAG:
+ net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
+ net_tree = proto_item_add_subtree( net_item, ett_port_path );
+
+ proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ break;
+
+ case CI_NETWORK_SEG_PROD_INHI:
+ net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
+ net_tree = proto_item_add_subtree( net_item, ett_port_path );
+
+ proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
+
+ /* 2 bytes of path used */
+ pathpos += 2;
+ break;
+
+ default:
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
+ return;
+
+ } /* End of switch sub-type */
+
+ break;
+
+ default:
+
+ /* Unsupported segment type */
+ proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
+ return;
+
+ } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
+
+ /* Next path segment */
+ if( pathpos < path_length )
+ proto_item_append_text( epath_item, ", " );
+
+ } /* end of while( pathpos < path_length ) */
+
+} /* end of dissect_epath() */
+
+
+static void
+dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
+{
+ proto_item *pi, *rrsc_item, *ncppi, *ar_item, *temp_item, *temp_item2, *status_item;
+ proto_tree *temp_tree, *rrsc_tree, *ncp_tree, *cmd_data_tree, *status_tree;
+ int req_path_size, conn_path_size, temp_data;
+ unsigned char gen_status;
+ unsigned char add_stat_size;
+ unsigned char temp_byte, route_path_size;
+ unsigned char app_rep_size, i;
+ int msg_req_siz, num_services, serv_offset;
+
+
+ /* Add Service code & Request/Response tree */
+ rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
+ rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
+
+ /* Add Request/Response */
+ proto_tree_add_item( rrsc_tree, hf_cip_rr, tvb, offset, 1, TRUE );
+
+ proto_item_append_text( rrsc_item, "%s (%s)",
+ val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
+ cip_sc_vals , "Unknown Service (%x)"),
+ val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x80 )>>7,
+ cip_sc_rr, "") );
+
+ /* Add Service code */
+ proto_tree_add_item(rrsc_tree, hf_cip_sc, tvb, offset, 1, TRUE );
+
+ if( tvb_get_guint8( tvb, offset ) & 0x80 )
+ {
+ /* Response message */
+ status_item = proto_tree_add_text( item_tree, tvb, offset+2, 1, "Status: " );
+ status_tree = proto_item_add_subtree( status_item, ett_status_item );
+
+ /* Add general status */
+ gen_status = tvb_get_guint8( tvb, offset+2 );
+ proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, TRUE );
+ proto_item_append_text( status_item, "%s", val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
+ cip_gs_vals , "Unknown Response (%x)") );
+
+ /* Add reply status to info column */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
+ val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
+ cip_gs_vals , "Unknown Response (%x)") );
+ }
+
+ /* Add additional status size */
+ proto_tree_add_text( status_tree, tvb, offset+3, 1, "Additional Status Size: %d (word)",
+ tvb_get_guint8( tvb, offset+3 ) );
+
+ add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
+
+ if( add_stat_size )
+ {
+ proto_item_append_text( status_item, ", Extended:" );
+
+ /* Add additional status */
+ pi = proto_tree_add_text( status_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) ) );
+ proto_item_append_text( status_item, " 0x%04X", tvb_get_letohs( tvb, offset+4+(i*2) ) );
+ }
+ }
+
+ proto_item_set_len( status_item, 2 + add_stat_size );
+
+ /* If there is any command specific data create a sub-tree for it */
+ if( ( item_length-4-add_stat_size ) != 0 )
+ {
+ 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 );
+
+ if( gen_status == CI_GRC_SUCCESS )
+ {
+ /* Success responses */
+
+ 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_cip_vendor, tvb, offset+4+add_stat_size+10, 2, TRUE);
+
+ /* 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 );
+
+ /* 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 );
+
+ /* 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 )
+ {
+ /* 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 );
+
+ /* Display the originator vendor id */
+ proto_tree_add_item( cmd_data_tree, hf_cip_vendor, 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:" );
+
+ for( i=0; i < app_rep_size; i ++ )
+ {
+ temp_byte = tvb_get_guint8( tvb, offset+4+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 ) & 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
+ {
+ 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 );
+
+ /*
+ ** We call our selves again to disect embedded packet
+ */
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
+
+ dissect_cip_data( temp_tree, tvb, offset+serv_offset+4, serv_length, pinfo );
+ }
+ } /* 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_cip_vendor, 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 message */
+
+ /* Add service to info column */
+ if(check_col(pinfo->cinfo, COL_INFO))
+ {
+ col_append_fstr( pinfo->cinfo, COL_INFO, "%s",
+ val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
+ cip_sc_vals , "Unknown Service (%x)") );
+ }
+
+ /* Add path size to tree */
+ 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: ");
+ dissect_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_cip_vendor, 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, cip_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_cip_fwo_own,
+ tvb, offset+2+req_path_size+26, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
+ tvb, offset+2+req_path_size+26, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
+ tvb, offset+2+req_path_size+26, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
+ tvb, offset+2+req_path_size+26, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_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_cip_fwo_own,
+ tvb, offset+2+req_path_size+32, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_typ,
+ tvb, offset+2+req_path_size+32, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_prio,
+ tvb, offset+2+req_path_size+32, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_fixed_var,
+ tvb, offset+2+req_path_size+32, 2, TRUE );
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_con_size,
+ tvb, offset+2+req_path_size+32, 2, TRUE );
+
+ /* Transport type/trigger in tree*/
+ temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
+
+ ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", temp_data );
+ ncp_tree = proto_item_add_subtree(ncppi, ett_ncp);
+
+ /* Add the data to the tree */
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_dir,
+ tvb, offset+2+req_path_size+34, 1, TRUE );
+
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_trigg,
+ tvb, offset+2+req_path_size+34, 1, TRUE );
+
+ proto_tree_add_item(ncp_tree, hf_cip_fwo_class,
+ tvb, offset+2+req_path_size+34, 1, TRUE );
+
+ /* 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: ");
+ dissect_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 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 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_cip_vendor, 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: ");
+ dissect_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 );
+
+ /* 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 );
+
+ /* 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 );
+
+ /*
+ ** We call our selves again to disect embedded packet
+ */
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr( pinfo->cinfo, COL_INFO, ": ");
+
+ dissect_cip_data( temp_tree, tvb, offset+2+req_path_size+4, msg_req_siz, pinfo );
+
+ if( msg_req_siz % 2 )
+ {
+ /* Pad byte */
+ proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
+ tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
+ msg_req_siz++; /* include the padding */
+ }
+
+ /* Route Path Size */
+ route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
+ proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Route Path Size: %d (words)", route_path_size/2 );
+
+ /* Reserved */
+ proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
+ tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
+
+ /* 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: ");
+ dissect_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
+ {
+ 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 );
+
+ /*
+ ** We call our selves again to disect embedded packet
+ */
+
+ if(check_col(pinfo->cinfo, COL_INFO))
+ col_append_fstr( pinfo->cinfo, COL_INFO, ", ");
+
+ dissect_cip_data( temp_tree, tvb, offset+serv_offset+6, serv_length, pinfo );
+ }
+ } /* End if Multiple service Packet */
+ else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
+ {
+ /* Get attribute list request */
+
+ int att_count;
+
+ /* 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 */
+
+ } /* End of if-else( request ) */
+
+} /* End of dissect_cip_data() */
+
+
+static int
+dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_item *ti;
+ proto_tree *cip_tree;
+
+ /* Make entries in Protocol column and Info column on summary display */
+ if( check_col( pinfo->cinfo, COL_PROTOCOL ) )
+ col_set_str( pinfo->cinfo, COL_PROTOCOL, "CIP" );
+
+ if (check_col( pinfo->cinfo, COL_INFO ) )
+ col_clear( pinfo->cinfo, COL_INFO );
+
+ if( tree )
+ {
+ /* Create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_cip, tvb, 0, -1, FALSE);
+ cip_tree = proto_item_add_subtree( ti, ett_cip );
+
+ dissect_cip_data( cip_tree, tvb, 0, tvb_length(tvb), pinfo );
+ }
+
+ return tvb_length(tvb);
+}
+
+
+void
+proto_register_cip(void)
+{
+ /* Setup list of header fields */
+ static hf_register_info hf[] = {
+
+ { &hf_cip_rr,
+ { "Request/Response", "cip.rr",
+ FT_UINT8, BASE_HEX, VALS(cip_sc_rr), 0x80,
+ "Request or Response message", HFILL }
+ },
+ { &hf_cip_sc,
+ { "Service", "cip.sc",
+ FT_UINT8, BASE_HEX, VALS(cip_sc_vals), 0x7F,
+ "Service Code", HFILL }
+ },
+ { &hf_cip_epath,
+ { "EPath", "cip.epath",
+ FT_BYTES, BASE_HEX, NULL, 0,
+ "EPath", HFILL }
+ },
+ { &hf_cip_genstat,
+ { "General Status", "cip.genstat",
+ FT_UINT8, BASE_HEX, VALS(cip_gs_vals), 0,
+ "General Status", HFILL }
+ },
+ { &hf_cip_port,
+ { "Port", "cip.port",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "Port Identifier", HFILL }
+ },
+ { &hf_cip_link_address_byte,
+ { "Link Address", "cip.linkaddress",
+ FT_UINT8, BASE_DEC, NULL, 0,
+ "Link Address", HFILL }
+ },
+ { &hf_cip_link_address_string,
+ { "Link Address", "cip.linkaddress",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "Link Address", HFILL }
+ },
+ { &hf_cip_class8,
+ { "Class", "cip.class",
+ FT_UINT8, BASE_HEX, VALS(cip_class_names_vals), 0,
+ "Class", HFILL }
+ },
+ { &hf_cip_class16,
+ { "Class", "cip.class",
+ FT_UINT16, BASE_HEX, VALS(cip_class_names_vals), 0,
+ "Class", HFILL }
+ },
+ { &hf_cip_class32,
+ { "Class", "cip.class",
+ FT_UINT32, BASE_HEX, VALS(cip_class_names_vals), 0,
+ "Class", HFILL }
+ },
+ { &hf_cip_instance8,
+ { "Instance", "cip.instance",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "Instance", HFILL }
+ },
+ { &hf_cip_instance16,
+ { "Instance", "cip.instance",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Instance", HFILL }
+ },
+ { &hf_cip_instance32,
+ { "Instance", "cip.instance",
+ FT_UINT32, BASE_HEX, NULL, 0,
+ "Instance", HFILL }
+ },
+ { &hf_cip_attribute8,
+ { "Attribute", "cip.attribute",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "Attribute", HFILL }
+ },
+ { &hf_cip_attribute16,
+ { "Attribute", "cip.attribute",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Attribute", HFILL }
+ },
+ { &hf_cip_attribute32,
+ { "Attribute", "cip.attribute",
+ FT_UINT32, BASE_HEX, NULL, 0,
+ "Attribute", HFILL }
+ },
+ { &hf_cip_conpoint8,
+ { "Connection Point", "cip.connpoint",
+ FT_UINT8, BASE_HEX, NULL, 0,
+ "Connection Point", HFILL }
+ },
+ { &hf_cip_conpoint16,
+ { "Connection Point", "cip.connpoint",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Connection Point", HFILL }
+ },
+ { &hf_cip_conpoint32,
+ { "Connection Point", "cip.connpoint",
+ FT_UINT16, BASE_HEX, NULL, 0,
+ "Connection Point", HFILL }
+ },
+ { &hf_cip_symbol,
+ { "Symbol", "cip.symbol",
+ FT_STRING, BASE_NONE, NULL, 0,
+ "ANSI Extended Symbol Segment", HFILL }
+ },
+ { &hf_cip_vendor,
+ { "Vendor ID", "cip.vendor",
+ FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
+ "Vendor ID", HFILL }
+ },
+ { &hf_cip_devtype,
+ { "Device Type", "cip.devtype",
+ FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
+ "Device Type", HFILL }
+ },
+ { &hf_cip_fwo_comp,
+ { "Compatibility", "cip.fwo.cmp",
+ FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80,
+ "Fwd Open: Compatibility bit", HFILL }
+ },
+ { &hf_cip_fwo_mrev,
+ { "Major Revision", "cip.fwo.major",
+ FT_UINT8, BASE_DEC, NULL, 0x7F,
+ "Fwd Open: Major Revision", HFILL }
+ },
+ { &hf_cip_fwo_con_size,
+ { "Connection Size", "cip.fwo.consize",
+ FT_UINT16, BASE_DEC, NULL, 0x01FF,
+ "Fwd Open: Connection size", HFILL }
+ },
+ { &hf_cip_fwo_fixed_var,
+ { "Connection Size Type", "cip.fwo.f_v",
+ FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200,
+ "Fwd Open: Fixed or variable connection size", HFILL }
+ },
+ { &hf_cip_fwo_prio,
+ { "Priority", "cip.fwo.prio",
+ FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00,
+ "Fwd Open: Connection priority", HFILL }
+ },
+ { &hf_cip_fwo_typ,
+ { "Connection Type", "cip.fwo.type",
+ FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000,
+ "Fwd Open: Connection type", HFILL }
+ },
+ { &hf_cip_fwo_own,
+ { "Owner", "cip.fwo.owner",
+ FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000,
+ "Fwd Open: Redundant owner bit", HFILL }
+ },
+ { &hf_cip_fwo_dir,
+ { "Direction", "cip.fwo.dir",
+ FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80,
+ "Fwd Open: Direction", HFILL }
+ },
+ { &hf_cip_fwo_trigg,
+ { "Trigger", "cip.fwo.trigger",
+ FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70,
+ "Fwd Open: Production trigger", HFILL }
+ },
+ { &hf_cip_fwo_class,
+ { "Class", "cip.fwo.transport",
+ FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F,
+ "Fwd Open: Transport Class", HFILL }
+ }
+ };
+
+ /* Setup protocol subtree array */
+ static gint *ett[] = {
+ &ett_cip,
+ &ett_path,
+ &ett_ekey_path,
+ &ett_rrsc,
+ &ett_mcsc,
+ &ett_ncp,
+ &ett_cia_path,
+ &ett_data_seg,
+ &ett_lsrcf,
+ &ett_mes_req,
+ &ett_cmd_data,
+ &ett_port_path,
+ &ett_mult_ser,
+ &ett_path,
+ &ett_status_item
+ };
+
+ /* Register the protocol name and description */
+ proto_cip = proto_register_protocol("Common Industrial Protocol",
+ "CIP", "cip");
+
+ /* Required function calls to register the header fields and subtrees used */
+ proto_register_field_array(proto_cip, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+
+} /* end of proto_register_cip() */
+
+
+void
+proto_reg_handoff_cip(void)
+{
+ dissector_handle_t cip_handle;
+
+ /* Create dissector handles */
+ cip_handle = new_create_dissector_handle( dissect_cip, proto_cip );
+
+ /* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
+ dissector_add( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
+
+ /* Register for Connected CIP data, using EtherNet/IP SendUnitData service*/
+ dissector_add( "enip.sud.iface", ENIP_CIP_INTERFACE, cip_handle );
+
+} /* end of proto_reg_handoff_cip() */
diff --git a/epan/dissectors/packet-enip.c b/epan/dissectors/packet-enip.c
index cebc342f43..3a0ede14a2 100644
--- a/epan/dissectors/packet-enip.c
+++ b/epan/dissectors/packet-enip.c
@@ -44,17 +44,19 @@
#include <epan/packet.h>
#include <prefs.h>
#include "packet-tcp.h"
+#include "packet-cip.h"
-/* Defines */
-#define ENIP_ENCAP_PORT 44818 /* EtherNet/IP located on port 44818 */
+
+/* Communication Ports */
+#define ENIP_ENCAP_PORT 44818 /* EtherNet/IP located on port 44818 */
#define ENIP_IO_PORT 2222 /* EtherNet/IP IO located on port 2222 */
-/* return codes of function classifying packets as query/response */
+/* Return codes of function classifying packets as query/response */
#define REQUEST_PACKET 0
#define RESPONSE_PACKET 1
#define CANNOT_CLASSIFY 2
-/* CIP Encapsulation function codes */
+/* EtherNet/IP function codes */
#define NOP 0x0000
#define LIST_SERVICES 0x0004
#define LIST_IDENTITY 0x0063
@@ -66,7 +68,7 @@
#define INDICATE_STATUS 0x0072
#define CANCEL 0x0073
-/* CIP Encapsulation status codes */
+/* EtherNet/IP status codes */
#define SUCCESS 0x0000
#define INVALID_CMD 0x0001
#define NO_RESOURCES 0x0002
@@ -75,7 +77,7 @@
#define INVALID_LENGTH 0x0065
#define UNSUPPORTED_PROT_REV 0x0069
-/* CIP Common Data Format Type IDs */
+/* EtherNet/IP Common Data Format Type IDs */
#define CDF_NULL 0x0000
#define LIST_IDENTITY_RESP 0x000C
#define CONNECTION_BASED 0x00A1
@@ -86,204 +88,54 @@
#define SOCK_ADR_INFO_TO 0x8001
#define SEQ_ADDRESS 0x8002
-/* CIP Service Codes */
-#define SC_GET_ATT_ALL 0x01
-#define SC_SET_ATT_ALL 0x02
-#define SC_GET_ATT_LIST 0x03
-#define SC_SET_ATT_LIST 0x04
-#define SC_RESET 0x05
-#define SC_START 0x06
-#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
-#define SC_FIND_NEXT_OBJ_INST 0x11
-#define SC_RESTOR 0x15
-#define SC_SAVE 0x16
-#define SC_NO_OP 0x17
-#define SC_GET_MEMBER 0x18
-#define SC_SET_MEMBER 0x19
-
-#define SC_FWD_CLOSE 0x4E
-#define SC_UNCON_SEND 0x52
-#define SC_FWD_OPEN 0x54
-
-
-
-/* CIP Genral status codes */
-#define CI_GRC_SUCCESS 0x00
-#define CI_GRC_FAILURE 0x01
-#define CI_GRC_NO_RESOURCE 0x02
-#define CI_GRC_BAD_DATA 0x03
-#define CI_GRC_BAD_PATH 0x04
-#define CI_GRC_BAD_CLASS_INSTANCE 0x05
-#define CI_GRC_PARTIAL_DATA 0x06
-#define CI_GRC_CONN_LOST 0x07
-#define CI_GRC_BAD_SERVICE 0x08
-#define CI_GRC_BAD_ATTR_DATA 0x09
-#define CI_GRC_ATTR_LIST_ERROR 0x0A
-#define CI_GRC_ALREADY_IN_MODE 0x0B
-#define CI_GRC_BAD_OBJ_MODE 0x0C
-#define CI_GRC_OBJ_ALREADY_EXISTS 0x0D
-#define CI_GRC_ATTR_NOT_SETTABLE 0x0E
-#define CI_GRC_PERMISSION_DENIED 0x0F
-#define CI_GRC_DEV_IN_WRONG_STATE 0x10
-#define CI_GRC_REPLY_DATA_TOO_LARGE 0x11
-#define CI_GRC_FRAGMENT_PRIMITIVE 0x12
-#define CI_GRC_CONFIG_TOO_SMALL 0x13
-#define CI_GRC_UNDEFINED_ATTR 0x14
-#define CI_GRC_CONFIG_TOO_BIG 0x15
-#define CI_GRC_OBJ_DOES_NOT_EXIST 0x16
-#define CI_GRC_NO_FRAGMENTATION 0x17
-#define CI_GRC_DATA_NOT_SAVED 0x18
-#define CI_GRC_DATA_WRITE_FAILURE 0x19
-#define CI_GRC_REQUEST_TOO_LARGE 0x1A
-#define CI_GRC_RESPONSE_TOO_LARGE 0x1B
-#define CI_GRC_MISSING_LIST_DATA 0x1C
-#define CI_GRC_INVALID_LIST_STATUS 0x1D
-#define CI_GRC_SERVICE_ERROR 0x1E
-#define CI_GRC_CONN_RELATED_FAILURE 0x1F
-#define CI_GRC_INVALID_PARAMETER 0x20
-#define CI_GRC_WRITE_ONCE_FAILURE 0x21
-#define CI_GRC_INVALID_REPLY 0x22
-#define CI_GRC_BAD_KEY_IN_PATH 0x25
-#define CI_GRC_BAD_PATH_SIZE 0x26
-#define CI_GRC_UNEXPECTED_ATTR 0x27
-#define CI_GRC_INVALID_MEMBER 0x28
-#define CI_GRC_MEMBER_NOT_SETTABLE 0x29
-
-#define CI_GRC_STILL_PROCESSING 0xFF
-
-
-/* IOI Path types */
-#define CI_SEGMENT_TYPE_MASK 0xE0
-
-#define CI_PATH_SEGMENT 0x00
-#define CI_LOGICAL_SEGMENT 0x20
-#define CI_NETWORK_SEGMENT 0x40
-#define CI_SYMBOLIC_SEGMENT 0x60
-#define CI_DATA_SEGMENT 0x80
-
-#define CI_LOGICAL_SEG_TYPE_MASK 0x1C
-#define CI_LOGICAL_SEG_CLASS_ID 0x00
-#define CI_LOGICAL_SEG_INST_ID 0x04
-#define CI_LOGICAL_SEG_MBR_ID 0x08
-#define CI_LOGICAL_SEG_CON_POINT 0x0C
-#define CI_LOGICAL_SEG_ATTR_ID 0x10
-#define CI_LOGICAL_SEG_SPECIAL 0x14
-#define CI_LOGICAL_SEG_SERV_ID 0x18
-#define CI_LOGICAL_SEG_RES_1 0x1C
-
-#define CI_LOGICAL_SEG_FORMAT_MASK 0x03
-#define CI_LOGICAL_SEG_8_BIT 0x00
-#define CI_LOGICAL_SEG_16_BIT 0x01
-#define CI_LOGICAL_SEG_32_BIT 0x02
-#define CI_LOGICAL_SEG_RES_2 0x03
-#define CI_LOGICAL_SEG_E_KEY 0x00
-
-#define CI_E_KEY_FORMAT_VAL 0x04
-
-#define CI_DATA_SEG_SIMPLE 0x80
-#define CI_DATA_SEG_SYMBOL 0x91
-
-#define CI_NETWORK_SEG_TYPE_MASK 0x07
-#define CI_NETWORK_SEG_SCHEDULE 0x01
-#define CI_NETWORK_SEG_FIXED_TAG 0x02
-#define CI_NETWORK_SEG_PROD_INHI 0x03
-
-
-/* Device Profile:s */
-#define DP_GEN_DEV 0x00
-#define DP_AC_DRIVE 0x02
-#define DP_MOTOR_OVERLOAD 0x03
-#define DP_LIMIT_SWITCH 0x04
-#define DP_IND_PROX_SWITCH 0x05
-#define DP_PHOTO_SENSOR 0x06
-#define DP_GENP_DISC_IO 0x07
-#define DP_RESOLVER 0x09
-#define DP_COM_ADAPTER 0x0C
-#define DP_POS_CNT 0x10
-#define DP_DC_DRIVE 0x13
-#define DP_CONTACTOR 0x15
-#define DP_MOTOR_STARTER 0x16
-#define DP_SOFT_START 0x17
-#define DP_HMI 0x18
-#define DP_MASS_FLOW_CNT 0x1A
-#define DP_PNEUM_VALVE 0x1B
-#define DP_VACUUM_PRES_GAUGE 0x1C
+/* Initialize the protocol and registered fields */
+static int proto_enip = -1;
+
+static int hf_enip_command = -1;
+static int hf_enip_options = -1;
+static int hf_enip_sendercontex = -1;
+static int hf_enip_status = -1;
+static int hf_enip_session = -1;
+static int hf_enip_lir_sinfamily = -1;
+static int hf_enip_lir_sinport = -1;
+static int hf_enip_lir_sinaddr = -1;
+static int hf_enip_lir_sinzero = -1;
-/* Initialize the protocol and registered fields */
-static int proto_cipencap = -1;
-static int hf_enip_command = -1;
-static int hf_enip_ifacehnd = -1;
-
-static int hf_enip_cpf_typeid = -1;
-
-static int hf_enip_ucm_sc = -1;
-static int hf_enip_ucm_rr = -1;
-static int hf_enip_ucm_path = -1;
-static int hf_enip_ucm_genstat = -1;
-static int hf_enip_cpf_lir_sinfamily = -1;
-static int hf_enip_cpf_lir_sinport = -1;
-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_status = -1;
-static int hf_enip_cpf_lir_sernbr = -1;
-static int hf_enip_cpf_lir_namelength = -1;
-static int hf_enip_cpf_lir_name = -1;
-static int hf_enip_cpf_lir_state = -1;
-
-static int hf_enip_cpf_sat_connid = -1;
-static int hf_enip_cpf_sat_seqnum = -1;
-
-static int hf_enip_vendors = -1;
-
-static int hf_enip_ucm_fwo_comp = -1;
-static int hf_enip_ucm_fwo_mrev = -1;
-
-static int hf_enip_ucm_fwo_con_size = -1;
-static int hf_enip_ucm_fwo_fixed_var = -1;
-static int hf_enip_ucm_fwo_prio = -1;
-static int hf_enip_ucm_fwo_typ = -1;
-static int hf_enip_ucm_fwo_own = -1;
-
-static int hf_enip_ucm_fwo_dir = -1;
-static int hf_enip_ucm_fwo_trigg = -1;
-static int hf_enip_ucm_fwo_class = -1;
-
-static int hf_enip_cpf_lsr_tcp = -1;
-static int hf_enip_cpf_lsr_udp = -1;
+static int hf_enip_lir_vendor = -1;
+static int hf_enip_lir_devtype = -1;
+static int hf_enip_lir_prodcode = -1;
+static int hf_enip_lir_status = -1;
+static int hf_enip_lir_serial = -1;
+static int hf_enip_lir_name = -1;
+static int hf_enip_lir_state = -1;
+
+static int hf_enip_lsr_tcp = -1;
+static int hf_enip_lsr_udp = -1;
+
+static int hf_enip_srrd_ifacehnd = -1;
+
+static int hf_enip_sud_ifacehnd = -1;
+static int hf_enip_cpf_typeid = -1;
+static int hf_enip_cpf_sai_connid = -1;
+static int hf_enip_cpf_sai_seqnum = -1;
/* Initialize the subtree pointers */
-static gint ett_cipencap = -1;
-static gint ett_cip = -1;
-static gint ett_cpf = -1;
-static gint ett_path = -1;
-static gint ett_ekey_path = -1;
-static gint ett_cia_path = -1;
-static gint ett_data_seg = -1;
-
-static gint ett_cipencaph = -1;
-static gint ett_csf = -1;
-static gint ett_rrsc = -1;
-static gint ett_sockadd = -1;
-static gint ett_mcsc = -1;
-static gint ett_ncp = -1;
-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;
-
-static gboolean cipencap_desegment = TRUE;
+static gint ett_enip = -1;
+static gint ett_count_tree = -1;
+static gint ett_type_tree = -1;
+static gint ett_command_tree = -1;
+static gint ett_sockadd = -1;
+static gint ett_lsrcf = -1;
+
+static proto_tree *g_tree;
+static dissector_table_t subdissector_srrd_table;
+static dissector_table_t subdissector_sud_table;
+static dissector_handle_t data_handle;
+
+static gboolean enip_desegment = TRUE;
/* Translate function to string - Encapsulation commands */
static const value_string encap_cmd_vals[] = {
@@ -301,7 +153,6 @@ static const value_string encap_cmd_vals[] = {
{ 0, NULL }
};
-
/* Translate function to string - Encapsulation status */
static const value_string encap_status_vals[] = {
{ SUCCESS, "Success" },
@@ -330,52 +181,6 @@ static const value_string cdf_type_vals[] = {
{ 0, NULL }
};
-/* 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, "Set Attribute All" },
- { SC_GET_ATT_LIST, "Get Attribute List" },
- { SC_SET_ATT_LIST, "Set Attribute List" },
- { SC_RESET, "Reset" },
- { SC_START, "Start" },
- { SC_STOP, "Stop" },
- { SC_CREATE, "Create" },
- { SC_DELETE, "Delete" },
- { SC_APPLY_ATTRIBUTES, "Apply Attributes" },
- { SC_GET_ATT_SINGLE, "Get Attribute Single" },
- { SC_SET_ATT_SINGLE, "Set Attribute Single" },
- { SC_FIND_NEXT_OBJ_INST, "Find Next Object Instance" },
- { SC_RESTOR, "Restore" },
- { SC_SAVE, "Save" },
- { 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" },
- { SC_FWD_OPEN, "Forward Open" },
- { SC_UNCON_SEND, "Unconnected Send" },
-
- { 0, NULL }
-};
-
-/* Translate function to string - CIP Request/Response */
-static const value_string encap_sc_rr[] = {
- { 0, "Request" },
- { 1, "Response" },
-
- { 0, NULL }
-};
-
-
-/* Translate function to string - Compatibility */
-static const value_string enip_com_bit_vals[] = {
- { 0, "Bit Cleared" },
- { 1, "Bit Set" },
-
- { 0, NULL }
-};
/* Translate function to string - True/False */
static const value_string enip_true_false_vals[] = {
@@ -386,278 +191,14 @@ static const value_string enip_true_false_vals[] = {
};
-/* Translate function to string - Connection priority */
-static const value_string enip_con_prio_vals[] = {
- { 0, "Low Priority" },
- { 1, "High Priority" },
- { 2, "Scheduled" },
- { 3, "Urgent" },
-
- { 0, NULL }
-};
-
-
-/* Translate function to string - Connection size fixed or variable */
-static const value_string enip_con_fw_vals[] = {
- { 0, "Fixed" },
- { 1, "Variable" },
-
- { 0, NULL }
-};
-
-
-/* Translate function to string - Connection owner */
-static const value_string enip_con_owner_vals[] = {
- { 0, "Exclusive" },
- { 1, "Redundant" },
-
- { 0, NULL }
-};
-
-/* Translate function to string - Connection direction */
-static const value_string enip_con_dir_vals[] = {
- { 0, "Client" },
- { 1, "Server" },
-
- { 0, NULL }
-};
-
-/* Translate function to string - Production trigger */
-static const value_string enip_con_trigg_vals[] = {
- { 0, "Cyclic" },
- { 1, "Change-Of-State" },
- { 2, "Application Object" },
-
- { 0, NULL }
-};
-
-/* Translate function to string - Transport class */
-static const value_string enip_con_class_vals[] = {
- { 0, "0" },
- { 1, "1" },
- { 2, "2" },
- { 3, "3" },
-
- { 0, NULL }
-};
-
-
-/* Translate function to string - Connection type */
-static const value_string enip_con_type_vals[] = {
- { 0, "Null" },
- { 1, "Multicast" },
- { 2, "Point to Point" },
- { 3, "Reserved" },
-
- { 0, NULL }
-};
-
-/* Translate function to string - Timeout Multiplier */
-static const value_string enip_con_time_mult_vals[] = {
- { 0, "*4" },
- { 1, "*8" },
- { 2, "*16" },
- { 3, "*32" },
- { 4, "*64" },
- { 5, "*128" },
- { 6, "*256" },
- { 7, "*512" },
-
- { 0, NULL }
-};
-
-
-/* Translate function to string - CIP General Status codes */
-static const value_string encap_cip_gs_vals[] = {
- { CI_GRC_SUCCESS, "Success" },
- { CI_GRC_FAILURE, "Connection failure" },
- { CI_GRC_NO_RESOURCE, "Resource unavailable" },
- { CI_GRC_BAD_DATA, "Invalid parameter value" },
- { CI_GRC_BAD_PATH, "Path segment error" },
- { CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
- { CI_GRC_PARTIAL_DATA, "Partial transfer" },
- { CI_GRC_CONN_LOST, "Connection lost" },
- { CI_GRC_BAD_SERVICE, "Service not supported" },
- { CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
- { CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
- { CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
- { CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
- { CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
- { CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
- { CI_GRC_PERMISSION_DENIED, "Privilege violation" },
- { CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
- { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
- { CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
- { CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
- { CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
- { CI_GRC_CONFIG_TOO_BIG, "Too much data" },
- { CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
- { CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
- { CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
- { CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
- { CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
- { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
- { CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
- { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
- { CI_GRC_SERVICE_ERROR, "Embedded service error" },
- { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
- { CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
- { CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
- { CI_GRC_INVALID_REPLY, "Invalid Reply Received" },
- { CI_GRC_BAD_KEY_IN_PATH, "Key Failure in path" },
- { CI_GRC_BAD_PATH_SIZE, "Path Size Invalid" },
- { CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
- { CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
- { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
-
- { 0, NULL }
-};
-
-
-/* Translate Vendor ID:s */
-static const value_string encap_cip_vendor_vals[] = {
- { 1, "Rockwell Automation/Allen-Bradley" },
- { 5, "Rockwell Automation/Reliance Electric" },
- { 24, "ODVA Special Reserve" },
- { 26, "Festo Corporation" },
- { 40, "WAGO Corporation" },
- { 48, "Turck, Inc." },
- { 49, "Grayhill Inc." },
- { 50, "Real Time Automation (C&ID)" },
- { 52, "Numatics, Inc." },
- { 57, "Pepperl + Fuchs" },
- { 81, "IXXAT Automation GmbH" },
- { 90, "HMS Industrial Networks AB" },
- { 96, "Digital Electronics Corp" },
- { 128, "MAC Valves, Inc." },
- { 133, "Balogh T.A.G., Corporation" },
- { 170, "Pyramid Solutions, Inc." },
- { 256, "InterlinkBT LLC" },
- { 258, "Hardy Instruments, Inc." },
- { 275, "Lantronix, Inc." },
- { 283, "Hilscher GmbH" },
- { 287, "Bosch Rexroth Corporation, Indramat" },
- { 356, "Fanuc Robotics America" },
- { 553, "Control Techniques PLC-NA" },
- { 562, "Phoenix Contact" },
- { 579, "Applicom international" },
- { 588, "West Instruments Limited" },
- { 590, "Delta Computer Systems Inc." },
- { 596, "Wire-Pro, Inc." },
- { 635, "The Siemon Company" },
- { 638, "Woodhead Connectivity" },
- { 651, "Fife Corporation" },
- { 668, "Rockwell Automation/Entek IRD Intl." },
- { 678, "Cognex Corporation" },
- { 691, "Startco Engineering Ltd" },
- { 734, "Hakko Electronics Co., Ltd" },
- { 735, "Tang & Associates" },
- { 743, "Linux Network Services" },
- { 748, "DVT Corporation" },
- { 759, "FLS Automation A/S" },
- { 768, "CSIRO Mining Automation" },
- { 778, "Harting, Inc. NA" },
- { 784, "Ci Technologies Pty Ltd (for Pelamos Industries)" },
- { 796, "Siemens Energy & Automation, Inc." },
- { 798, "Tyco Electronics" },
- { 803, "ICP DAS Co., LTD" },
- { 805, "Digi International, Inc." },
- { 808, "SICK AG" },
- { 809, "Ethernet Peripherals, Inc." },
- { 812, "Process Control Corporation" },
- { 832, "Quest Technical Solutions, Inc." },
- { 841, "Panduit Corporation" },
- { 850, "Datalogic, Inc." },
- { 851, "SoftPLC Corporation" },
- { 854, "Frontline Test Equipment, Inc." },
- { 857, "RVSI" },
- { 859, "Tennessee Rand Automation" },
- { 866, "ATR Industrie-Elektronik GmbH Co." },
- { 875, "FieldServer Technologies (Div Sierra Monitor Corp)" },
- { 883, "Automa SRL" },
-
- { 0, NULL }
-};
-
-/* Translate Device Profile:s */
-static const value_string encap_cip_devtype_vals[] = {
- { DP_GEN_DEV, "Generic Device" },
- { DP_AC_DRIVE, "AC Drive" },
- { DP_MOTOR_OVERLOAD, "Motor Overload" },
- { DP_LIMIT_SWITCH, "Limit Switch" },
- { DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
- { DP_PHOTO_SENSOR, "Photoelectric Sensor" },
- { DP_GENP_DISC_IO, "General Purpose Dicrete I/O" },
- { DP_RESOLVER, "Resolver" },
- { DP_COM_ADAPTER, "Communications Adapter" },
- { DP_POS_CNT, "Position Controller", },
- { DP_DC_DRIVE, "DC Drive" },
- { DP_CONTACTOR, "Contactor", },
- { DP_MOTOR_STARTER, "Motor Starter", },
- { DP_SOFT_START, "Soft Start", },
- { DP_HMI, "Human-Machine Interface" },
- { DP_MASS_FLOW_CNT, "Mass Flow Controller" },
- { DP_PNEUM_VALVE, "Pneumatic Valve" },
- { DP_VACUUM_PRES_GAUGE, "Vaccuum Pressure Gauge" },
-
- { 0, NULL }
-};
-
+/* Translate interface handle to string */
+static const value_string enip_interface_handle_vals[] = {
+ { 0, "CIP" },
-/* Translate class names */
-static const value_string enip_class_names_vals[] = {
- { 0x01, "Identity Object" },
- { 0x02, "Message Router" },
- { 0x03, "DeviceNet Object" },
- { 0x04, "Assembly Object" },
- { 0x05, "Connection Object" },
- { 0x06, "Connection Manager" },
- { 0x07, "Register Object" },
- { 0x08, "Discrete Input Point Object" },
- { 0x09, "Discrete Output Point Object" },
- { 0x0A, "Analog Input Point Object" },
- { 0x0B, "Analog Output Point Object" },
- { 0x0E, "Presence Sensing Object" },
- { 0x0F, "Parameter Object" },
- { 0x10, "Parameter Group Object" },
- { 0x12, "Group Object" },
- { 0x1D, "Discrete Input Group Object" },
- { 0x1E, "Discrete Output Group Object" },
- { 0x1F, "Discrete Group Object" },
- { 0x20, "Analog Input Group Object" },
- { 0x21, "Analog Output Group Object" },
- { 0x22, "Analog Group Object" },
- { 0x23, "Position Sensor Object" },
- { 0x24, "Position Controller Supervisor Object" },
- { 0x25, "Position Controller Object" },
- { 0x26, "Block Sequencer Object" },
- { 0x27, "Command Block Object" },
- { 0x28, "Motor Data Object" },
- { 0x29, "Control Supervisor Object" },
- { 0x2A, "AC/DC Drive Object" },
- { 0x2B, "Acknowledge Handler Object" },
- { 0x2C, "Overload Object" },
- { 0x2D, "Softstart Object" },
- { 0x2E, "Selection Object" },
- { 0x30, "S-Device Supervisor Object" },
- { 0x31, "S-Analog Sensor Object" },
- { 0x32, "S-Analog Actuator Object" },
- { 0x33, "S-Single Stage Controller Object" },
- { 0x34, "S-Gas Calibration Object" },
- { 0x35, "Trip Point Object" },
- { 0xF0, "ControlNet Object" },
- { 0xF1, "ControlNet Keeper Object" },
- { 0xF2, "ControlNet Scheduling Object" },
- { 0xF3, "Connection Configuration Object" },
- { 0xF4, "Port Object" },
- { 0xF5, "TCP/IP Interface Object" },
- { 0xF6, "EtherNet Link Object" },
-
- { 0, NULL }
+ { 0, NULL }
};
-
static proto_item*
add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start, gint length, const char* str )
{
@@ -719,1220 +260,29 @@ add_byte_array_text_to_proto_tree( proto_tree *tree, tvbuff_t *tvb, gint start,
} /* end of add_byte_array_text_to_proto_tree() */
-
-
-/* Decode and add epath to tree */
-static void
-show_epath( tvbuff_t *tvb, proto_item *pi, int offset, int path_length )
-{
- int pathpos;
- int temp_data;
- int temp_data2;
- unsigned char segment_type, temp_byte, opt_link_size;
- proto_tree *path_tree, *port_tree, *net_tree;
- proto_item *qi, *cia_item, *ds_item;
- proto_tree *e_key_tree, *cia_tree, *ds_tree;
- proto_item *mcpi, *temp_item, *port_item, *ext_link_item, *net_item;
- proto_tree *mc_tree;
- int seg_size, i, temp_word;
- char *temp_string;
-
- /* Create a sub tree for the epath */
- path_tree = proto_item_add_subtree( pi, ett_path );
-
- proto_tree_add_item_hidden(path_tree, hf_enip_ucm_path,
- tvb, offset, path_length, TRUE );
-
- pathpos = 0;
-
- while( pathpos < path_length )
- {
- /* Get segement type */
- segment_type = tvb_get_guint8( tvb, offset + pathpos );
-
- /* Determine the segment type */
-
- switch( segment_type & CI_SEGMENT_TYPE_MASK )
- {
- case CI_PATH_SEGMENT:
-
- port_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 0, "Port Segment" );
- port_tree = proto_item_add_subtree( port_item, ett_port_path );
-
- /* Add port number */
- proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Port Identifier: %d", (segment_type & 0x0F) );
- proto_item_append_text( pi, ", Port: %d", (segment_type & 0x0F) );
-
- /* Add Extended Link Address flag */
- temp_item = proto_tree_add_text( port_tree, tvb, offset+pathpos, 1, "Extended Link Address: " );
-
- if( segment_type & 0x10 )
- {
- proto_item_append_text(temp_item, "TRUE");
- opt_link_size = tvb_get_guint8( tvb, offset + pathpos + 1 );
-
- proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address Size: %d", opt_link_size );
- ext_link_item = proto_tree_add_text( port_tree, tvb, offset+pathpos+2, opt_link_size, "Link Address: " );
-
- proto_item_append_text(pi, ", Addess: " );
-
- /* Add extended link address */
- for( i=0; i < opt_link_size; i++ )
- {
- temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
- proto_item_append_text(ext_link_item, "%c", temp_byte );
- proto_item_append_text(pi, "%c", temp_byte );
- }
-
- /* Pad byte */
- if( opt_link_size % 2 )
- {
- pathpos = pathpos + 3 + opt_link_size;
- proto_item_set_len(port_item, 3+opt_link_size);
- }
- else
- {
- pathpos = pathpos + 2 + opt_link_size;
- proto_item_set_len(port_item, 2+opt_link_size);
- }
-
- }
- else
- {
- proto_item_append_text(pi, ", Address: %d", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
-
- proto_item_append_text(temp_item, "FALSE");
- proto_tree_add_text( port_tree, tvb, offset+pathpos+1, 1, "Link Address: %d", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
- proto_item_set_len(port_item, 2);
- pathpos += 2;
- }
-
- break;
-
- case CI_LOGICAL_SEGMENT:
-
- /* Logical segment, determin the logical type */
-
- switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
- {
- case CI_LOGICAL_SEG_CLASS_ID:
-
- /* Logical Class ID, do a format check */
-
- if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
- {
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
- cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 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 , "Unknown class" ), temp_data );
-
- temp_string = match_strval( temp_data, enip_class_names_vals );
-
- if( temp_string )
- {
- proto_item_append_text(pi, "%s", temp_string );
- }
- else
- {
- proto_item_append_text(pi, "Class: 0x%02X", temp_data );
- }
-
- /* 2 bytes of path used */
- pathpos += 2;
- }
- 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%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 , "Unknown class" ), temp_data );
- temp_string = match_strval( temp_data, enip_class_names_vals );
-
- if( temp_string )
- {
- proto_item_append_text(pi, "%s", temp_string );
- }
- else
- {
- proto_item_append_text(pi, "Class: 0x%04X", temp_data );
- }
-
- /* 4 bytes of path used */
- pathpos += 4;
- }
- 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%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 , "Unknown class" ), temp_data );
- temp_string = match_strval( temp_data, enip_class_names_vals );
-
- if( temp_string )
- {
- proto_item_append_text(pi, "%s", temp_string );
- }
- else
- {
- proto_item_append_text(pi, "Class: 0x%08X", temp_data );
- }
-
- /* 6 bytes of path used */
- pathpos += 6;
- }
- else
- {
- /* Unsupported logical segment format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
- return;
- }
- break;
-
-
- case CI_LOGICAL_SEG_INST_ID:
-
- /* Logical Instance ID, do a format check */
-
- if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
- {
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
- cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
-
- /* Display the 8-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Instance: 0x%02X", temp_data );
- proto_item_append_text(pi, ", Inst: 0x%02X", temp_data );
-
- /* 2 bytes of path used */
- pathpos += 2;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the instance */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Instance: 0x%04X", temp_data );
- proto_item_append_text(pi, ", Inst: 0x%04X", temp_data );
-
- /* 4 bytes of path used */
- pathpos += 4;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the instance */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Instance: 0x%08X", temp_data );
- proto_item_append_text(pi, ", Inst: 0x%08X", temp_data );
-
- /* 6 bytes of path used */
- pathpos += 6;
- }
- else
- {
- /* Unsupported logical segment format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
- return;
- }
- break;
-
-
- case CI_LOGICAL_SEG_ATTR_ID:
-
- /* Logical Attribute ID, do a format check */
-
- if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
- {
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
- cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
-
- /* Display the 8-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Attribute: 0x%02X", temp_data );
- proto_item_append_text(pi, ", Att: 0x%02X", temp_data );
-
- /* 2 bytes of path used */
- pathpos += 2;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the attribute */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Attribute: 0x%04X", temp_data );
- proto_item_append_text(pi, ", Att: 0x%04X", temp_data );
-
- /* 4 bytes of path used */
- pathpos += 4;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the attribute */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Attribute: 0x%08X", temp_data );
- proto_item_append_text(pi, ", Att: 0x%08X", temp_data );
-
- /* 6 bytes of path used */
- pathpos += 6;
- }
- else
- {
- /* Unsupported logical segment format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
- return;
- }
- break;
-
-
- case CI_LOGICAL_SEG_CON_POINT:
-
- /* Logical Connection point , do a format check */
-
- if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_8_BIT )
- {
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
- cia_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "8-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 );
-
- /* Display the 8-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 1, 1, "Connection Point: 0x%02X", temp_data );
- proto_item_append_text(pi, ", ConPnt: 0x%02X", temp_data );
-
- /* 2 bytes of path used */
- pathpos += 2;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the connection point */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 2, "Connection Point: 0x%04X", temp_data );
- proto_item_append_text(pi, ", ConPnt: 0x%04X", temp_data );
-
- /* 4 bytes of path used */
- pathpos += 4;
- }
- 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%02X)", segment_type );
-
- /* Create a sub tree for the connection point */
- cia_tree = proto_item_add_subtree( cia_item, ett_cia_path );
-
- /* Display the 16-bit instance number */
- proto_tree_add_text( cia_tree, tvb, offset + pathpos + 2, 4, "Connection Point (0x%08X)", temp_data );
- proto_item_append_text(pi, ", ConPnt: 0x%08X", temp_data );
-
- /* 6 bytes of path used */
- pathpos += 6;
- }
- else
- {
- /* Unsupported logical segment format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Format" );
- return;
- }
- break;
-
-
- case CI_LOGICAL_SEG_SPECIAL:
-
- /* Logical Special ID, the only logical format sepcifyed is electronic key */
-
- if( ( segment_type & CI_LOGICAL_SEG_FORMAT_MASK ) == CI_LOGICAL_SEG_E_KEY )
- {
-
- /* Get the Key Format */
-
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 1 );
-
- if( temp_data == CI_E_KEY_FORMAT_VAL )
- {
- qi = proto_tree_add_text( path_tree, tvb, offset + pathpos, 10, "Electronic Key Segment (0x%02X): ",segment_type );
-
- /* Create a sub tree for the IOI */
- e_key_tree = proto_item_add_subtree( qi, ett_ekey_path );
-
- /* Print the key type */
- proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 1, 1, "Key Format: 0x%02X", temp_data );
-
- /* Get the Vendor ID */
- temp_data = tvb_get_letohs( tvb, offset + pathpos + 2 );
- proto_tree_add_item( e_key_tree, hf_enip_vendors, tvb, offset + pathpos + 2, 2, TRUE);
- proto_item_append_text( qi, "VendorID: 0x%04X", temp_data );
-
- /* Get Device Type */
- temp_data = tvb_get_letohs( tvb, offset + pathpos + 4 );
- proto_tree_add_item( e_key_tree, hf_enip_cpf_lir_devtype, tvb, offset + pathpos + 4, 2, TRUE);
- proto_item_append_text( qi, ", DevTyp: 0x%04X", temp_data );
-
- /* Product Code */
- temp_data = tvb_get_letohs( tvb, offset + pathpos + 6 );
- proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 6, 2, "Product Code: 0x%04X", temp_data );
-
- /* Major revision/Compatibility */
- temp_data = tvb_get_guint8( tvb, offset + pathpos + 8 );
-
- /* Add Major revision/Compatibility tree */
- mcpi = proto_tree_add_text(e_key_tree, tvb, offset + pathpos + 8, 1, "Compatibility ");
- mc_tree = proto_item_add_subtree(mcpi, ett_mcsc);
-
- /* Add Compatibility bit info */
- proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_comp,
- tvb, offset + pathpos + 8, 1, TRUE );
-
- proto_item_append_text( mcpi, "%s, Major Revision: %d",
- val_to_str( ( temp_data & 0x80 )>>7, enip_com_bit_vals , "" ),
- temp_data & 0x7F );
-
- /* Major revision */
- proto_tree_add_item(mc_tree, hf_enip_ucm_fwo_mrev,
- tvb, offset + pathpos + 8, 1, TRUE );
-
- /* Minor revision */
- temp_data2 = tvb_get_guint8( tvb, offset + pathpos + 9 );
- proto_tree_add_text( e_key_tree, tvb, offset + pathpos + 9, 1, "Minor Revision: %d", temp_data2 );
-
- proto_item_append_text( qi, ", V.%d.%d", ( temp_data & 0x7F ), temp_data2 );
-
- /* Increment the path pointer */
- pathpos += 10;
-
- }
- else
- {
- /* Unsupported electronic key format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Electronic Key Format" );
- return;
- }
-
- }
- else
- {
- /* Unsupported special segment format */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Special Segment Format" );
- return;
- }
- break;
-
-
- default:
-
- /* Unsupported logical segment type */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Logical Segment Type" );
- return;
-
- } /* end of switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK ) */
- break;
-
-
- case CI_DATA_SEGMENT:
-
- /* Data segment, determin the logical type */
-
- switch( segment_type )
- {
-
- case CI_DATA_SEG_SIMPLE:
-
- /* Simple data segment */
- ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Simple Data Segment (0x%02X)", segment_type );
-
- /* Create a sub tree */
- ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
-
- /* Segment size */
- seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
- proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d (words)", seg_size/2 );
-
- /* Segment data */
- if( seg_size != 0 )
- {
- qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
-
- for( i=0; i < seg_size/2; i ++ )
- {
- temp_word = tvb_get_letohs( tvb, offset + pathpos+2+(i*2) );
- proto_item_append_text(qi, " 0x%04X", temp_word );
- }
-
- proto_item_set_len(qi, seg_size);
- }
-
- proto_item_set_len( ds_item, 2 + seg_size );
- pathpos = pathpos + 2 + seg_size;
-
- break;
-
- case CI_DATA_SEG_SYMBOL:
-
- /* ANSI extended symbol segment */
- ds_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 1, "Extended Symbol Segment (0x%02X)", segment_type );
-
- /* Create a sub tree */
- ds_tree = proto_item_add_subtree( ds_item, ett_data_seg );
-
- /* Segment size */
- seg_size = tvb_get_guint8( tvb, offset + pathpos+1 );
- proto_tree_add_text( ds_tree, tvb, offset + pathpos+1, 1, "Data Size: %d", seg_size );
-
- /* Segment data */
- if( seg_size != 0 )
- {
- qi = proto_tree_add_text( ds_tree, tvb, offset + pathpos+2, 0, "Data: " );
-
- for( i=0; i < seg_size; i++ )
- {
- temp_byte = tvb_get_guint8( tvb, offset + pathpos+2+i );
- proto_item_append_text(qi, "%c", temp_byte );
- }
-
- proto_item_set_len(qi, seg_size);
-
- if( seg_size %2 )
- {
- /* We have a PAD BYTE */
- proto_tree_add_text( ds_tree, tvb, offset + pathpos+2+i, 1, "Pad Byte (0x%02X)",
- tvb_get_guint8( tvb, offset + pathpos+2+i ) );
- pathpos++;
- seg_size++;
- }
- }
-
- proto_item_set_len( ds_item, 2 + seg_size );
- pathpos = pathpos + 2 + seg_size;
-
- break;
-
- default:
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
- return;
-
- } /* End of switch sub-type */
-
- break;
-
- case CI_NETWORK_SEGMENT:
-
- /* Network segment -Determine the segment sub-type */
-
- switch( segment_type & CI_NETWORK_SEG_TYPE_MASK )
- {
- case CI_NETWORK_SEG_SCHEDULE:
- net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Schedule" );
- net_tree = proto_item_add_subtree( net_item, ett_port_path );
-
- proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Multiplier/Phase: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
-
- /* 2 bytes of path used */
- pathpos += 2;
- break;
-
- case CI_NETWORK_SEG_FIXED_TAG:
- net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Fixed Tag" );
- net_tree = proto_item_add_subtree( net_item, ett_port_path );
-
- proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Fixed Tag: %02X", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
-
- /* 2 bytes of path used */
- pathpos += 2;
- break;
-
- case CI_NETWORK_SEG_PROD_INHI:
- net_item = proto_tree_add_text( path_tree, tvb, offset + pathpos, 2, "Network Segment - Production Inhibit" );
- net_tree = proto_item_add_subtree( net_item, ett_port_path );
-
- proto_tree_add_text( net_tree, tvb, offset + pathpos + 1, 1, "Production Inhibit Time: %dms", tvb_get_guint8( tvb, offset + pathpos + 1 ) );
-
- /* 2 bytes of path used */
- pathpos += 2;
- break;
-
- default:
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Sub-Segment Type" );
- return;
-
- } /* End of switch sub-type */
-
- break;
-
- default:
-
- /* Unsupported segment type */
- proto_tree_add_text( path_tree, tvb, 0, 0, "Unsupported Segment Type" );
- return;
-
- } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
-
- } /* end of while( pathpos < path_length ) */
-
-} /* end of show_epath() */
-
-
-
+/* Disssect Common Packet Format */
static void
-add_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
+dissect_cpf( int command, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl )
{
- 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 req_path_size, conn_path_size, mr_req_path_size;
- int temp_data;
- unsigned char gen_stat;
- unsigned char add_stat_size;
- unsigned char temp_byte, route_path_size;
- unsigned char app_rep_size, i;
- int msg_req_siz, num_services, serv_offset;
-
-
- /* 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);
-
- /* Add Request/Response */
- proto_tree_add_item(rrsci_tree, hf_enip_ucm_rr,
- tvb, offset, 1, TRUE );
-
- proto_item_append_text( rrsci, "%s (%s)",
- val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
- encap_sc_vals , "Unknown Service (%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 );
-
- /* Add reply status to info column */
- if(check_col(pinfo->cinfo, COL_INFO))
- {
- col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
- val_to_str( ( tvb_get_guint8( tvb, offset+2 ) ),
- encap_cip_gs_vals , "Unknown Response (%x)") );
- }
-
-
- /* 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 );
-
- 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 )
- {
- 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 );
-
- if( gen_stat == CI_GRC_SUCCESS )
- {
- /* Success responses */
-
- 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);
-
- /* 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 );
-
- /* 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 );
-
- /* 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 )
- {
- /* 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 );
-
- /* 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:" );
-
- for( i=0; i < app_rep_size; i ++ )
- {
- temp_byte = tvb_get_guint8( tvb, offset+4+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 ) & 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
- {
- 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, pinfo );
- }
- } /* 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 message */
-
- /* Add service to info column */
- if(check_col(pinfo->cinfo, COL_INFO))
- {
- col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
- val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
- encap_sc_vals , "Unknown Service (%x)") );
- }
-
- /* Add path size to tree */
- 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 in tree*/
- temp_data = tvb_get_guint8( tvb, offset+2+req_path_size+34 );
-
- ncppi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+34, 1, "Transport Type/Trigger: 0x%02X", 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_dir,
- tvb, offset+2+req_path_size+34, 1, TRUE );
-
- proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_trigg,
- tvb, offset+2+req_path_size+34, 1, TRUE );
-
- proto_tree_add_item(ncp_tree, hf_enip_ucm_fwo_class,
- tvb, offset+2+req_path_size+34, 1, TRUE );
-
- /* 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 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 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 );
-
- /* 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 );
-
- /* 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 );
-
- /* Add service to info column */
- if(check_col(pinfo->cinfo, COL_INFO))
- {
- col_append_fstr( pinfo->cinfo, COL_INFO, ", %s",
- val_to_str( ( temp_data & 0x7F ),
- encap_sc_vals , ", Unknown Service (%x)") );
- }
-
- /* 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+4+msg_req_siz, 1, "Pad Byte (0x%02X)",
- tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz ) );
- msg_req_siz++; /* include the padding */
- }
-
- /* Route Path Size */
- route_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+4+msg_req_siz )*2;
- proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+4+msg_req_siz, 1, "Route Path Size: %d (words)", route_path_size/2 );
-
- /* Reserved */
- proto_tree_add_text( cmd_data_tree, tvb, offset+2+req_path_size+5+msg_req_siz, 1, "Reserved (0x%02X)",
- tvb_get_guint8( tvb, offset+2+req_path_size+5+msg_req_siz ) );
-
- /* 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
- {
- 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, pinfo );
- }
- } /* End if Multiple service Packet */
- else if( tvb_get_guint8( tvb, offset ) == SC_GET_ATT_LIST )
- {
- /* Get attribute list request */
-
- int att_count;
-
- /* 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 */
-
- } /* end of if-else( request ) */
-
-} /* end of add_cip_data() */
-
-
-
-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;
+ proto_item *temp_item, *count_item, *type_item, *sockaddr_item;
+ proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree;
int temp_data, item_count, item_length, item;
unsigned char name_length;
+ tvbuff_t *next_tvb;
- /* Show Common Data Format sub tree */
+ /* Create item count 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);
+ count_item = proto_tree_add_text( tree, tvb, offset, 2, "Item Count: %d", item_count );
+ count_tree = proto_item_add_subtree( count_item, ett_count_tree );
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 item type tree to item count tree*/
+ type_item = proto_tree_add_item( count_tree, hf_enip_cpf_typeid, tvb, offset+2, 2, TRUE );
+ item_tree = proto_item_add_subtree( type_item, ett_type_tree );
- /* 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 );
+ /* Add length field to item type tree*/
+ proto_tree_add_text( item_tree, tvb, offset+4, 2, "Length: %d", tvb_get_letohs( tvb, offset+4 ) );
item = tvb_get_letohs( tvb, offset+2 );
item_length = tvb_get_letohs( tvb, offset+4 );
@@ -1960,14 +310,21 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
case UNCONNECTED_MSG:
- /* Add CIP data tree*/
- add_cip_data( item_tree, tvb, offset+6, item_length, pinfo );
+ /* Call dissector for interface */
+ next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
+
+ if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
+ {
+ /* Show the undissected payload */
+ if( tvb_length_remaining(tvb, offset) > 0 )
+ call_dissector( data_handle, next_tvb, pinfo, g_tree );
+ }
break;
case CONNECTION_TRANSPORT:
- if( encap_service == SEND_UNIT_DATA )
+ if( command == SEND_UNIT_DATA )
{
/*
** If the encapsulation service is SendUnit Data, this is a
@@ -1977,19 +334,16 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
/* 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, pinfo );
+ /* Call dissector for interface */
+ next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
- /* Add SEQ Count to Info col */
+ if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_port(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
+ {
+ /* Show the undissected payload */
+ if( tvb_length_remaining(tvb, offset) > 0 )
+ call_dissector( data_handle, next_tvb, pinfo, g_tree );
+ }
- /*
- if(check_col(pinfo->cinfo, COL_INFO))
- {
- col_append_fstr(pinfo->cinfo, COL_INFO,
- ", SEQ=0x%04X",
- tvb_get_letohs( tvb, offset+6 ) );
- }
- */
}
else
{
@@ -2012,31 +366,31 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
sockaddr_tree = proto_item_add_subtree( sockaddr_item, ett_sockadd );
/* Socket address struct - sin_family */
- proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinfamily,
+ proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinfamily,
tvb, offset+8, 2, FALSE );
/* Socket address struct - sin_port */
- proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinport,
+ proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinport,
tvb, offset+10, 2, FALSE );
/* Socket address struct - sin_address */
- proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinaddr,
+ proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinaddr,
tvb, offset+12, 4, FALSE );
/* Socket address struct - sin_zero */
- proto_tree_add_item(sockaddr_tree, hf_enip_cpf_lir_sinzero,
+ proto_tree_add_item(sockaddr_tree, hf_enip_lir_sinzero,
tvb, offset+16, 8, FALSE );
/* Vendor ID */
- proto_tree_add_item(item_tree, hf_enip_vendors,
+ proto_tree_add_item(item_tree, hf_enip_lir_vendor,
tvb, offset+24, 2, TRUE );
/* Device Type */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_devtype,
+ proto_tree_add_item(item_tree, hf_enip_lir_devtype,
tvb, offset+26, 2, TRUE );
/* Product Code */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_prodcode,
+ proto_tree_add_item(item_tree, hf_enip_lir_prodcode,
tvb, offset+28, 2, TRUE );
/* Revision */
@@ -2044,22 +398,19 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
proto_tree_add_text( item_tree, tvb, offset+30, 2, "Revision: %d.%02d", temp_data & 0xFF, ( temp_data & 0xFF00 ) >> 8 );
/* Status */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_status,
+ proto_tree_add_item(item_tree, hf_enip_lir_status,
tvb, offset+32, 2, TRUE );
/* Serial Number */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_sernbr,
+ proto_tree_add_item(item_tree, hf_enip_lir_serial,
tvb, offset+34, 4, TRUE );
/* Product Name Length */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_namelength,
- tvb, offset+38, 1, TRUE );
-
- /* Get the lenth of the name */
name_length = tvb_get_guint8( tvb, offset+38 );
+ proto_tree_add_text( item_tree, tvb, offset+38, 1, "Product Name Length: %d", name_length );
/* Product Name */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_name,
+ proto_tree_add_item(item_tree, hf_enip_lir_name,
tvb, offset+39, name_length, TRUE );
/* Append product name to info column */
@@ -2070,7 +421,7 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
}
/* State */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_state,
+ proto_tree_add_item(item_tree, hf_enip_lir_state,
tvb, offset+name_length+39, 1, TRUE );
break;
@@ -2079,28 +430,28 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
case SOCK_ADR_INFO_TO:
/* Socket address struct - sin_family */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinfamily,
+ proto_tree_add_item(item_tree, hf_enip_lir_sinfamily,
tvb, offset+6, 2, FALSE );
/* Socket address struct - sin_port */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinport,
+ proto_tree_add_item(item_tree, hf_enip_lir_sinport,
tvb, offset+8, 2, FALSE );
/* Socket address struct - sin_address */
- proto_tree_add_item(item_tree, hf_enip_cpf_lir_sinaddr,
+ proto_tree_add_item(item_tree, hf_enip_lir_sinaddr,
tvb, offset+10, 4, FALSE );
/* Socket address struct - sin_zero */
- proto_tree_add_item( item_tree, hf_enip_cpf_lir_sinzero,
+ proto_tree_add_item( item_tree, hf_enip_lir_sinzero,
tvb, offset+14, 8, FALSE );
break;
case SEQ_ADDRESS:
- proto_tree_add_item(item_tree, hf_enip_cpf_sat_connid,
+ proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
tvb, offset+6, 4, TRUE );
- proto_tree_add_item(item_tree, hf_enip_cpf_sat_seqnum,
+ proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
tvb, offset+10, 4, TRUE );
/* Add info to column */
@@ -2128,13 +479,13 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
temp_item = proto_tree_add_text(item_tree, tvb, offset+8, 2, "Capability Flags: 0x%04X", temp_data );
temp_tree = proto_item_add_subtree(temp_item, ett_lsrcf);
- proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_tcp,
+ proto_tree_add_item(temp_tree, hf_enip_lsr_tcp,
tvb, offset+8, 2, TRUE );
- proto_tree_add_item(temp_tree, hf_enip_cpf_lsr_udp,
+ proto_tree_add_item(temp_tree, hf_enip_lsr_udp,
tvb, offset+8, 2, TRUE );
/* Name of service */
- temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name Of Service: %s",
+ temp_item = proto_tree_add_text( item_tree, tvb, offset+10, 16, "Name of Service: %s",
tvb_format_stringzpad(tvb, offset+10, 16) );
/* Append service name to info column */
@@ -2160,7 +511,7 @@ show_cdf( int encap_service, tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree
} /* end of while( item count ) */
-} /* end of show_cdf() */
+} /* end of dissect_cpf() */
@@ -2181,7 +532,7 @@ classify_packet(packet_info *pinfo)
}
static guint
-get_cipencap_pdu_len(tvbuff_t *tvb, int offset)
+get_enip_pdu_len(tvbuff_t *tvb, int offset)
{
guint16 plen;
@@ -2199,16 +550,16 @@ get_cipencap_pdu_len(tvbuff_t *tvb, int offset)
/* Code to actually dissect the packets */
static void
-dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
- int packet_type;
+ int packet_type;
guint16 encap_cmd, encap_data_length;
char pkt_type_str[9] = "";
- guint32 status;
+ guint32 ifacehndl;
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *ti, *encaph, *csf;
- proto_tree *cipencap_tree, *headertree, *csftree;
+ proto_tree *enip_tree, *header_tree, *csftree;
/* Make entries in Protocol column and Info column on summary display */
if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -2238,7 +589,7 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
/* Add service and request/response to info column */
col_add_fstr(pinfo->cinfo, COL_INFO,
- "%-20s (%s)",
+ "%s (%s)",
val_to_str(encap_cmd, encap_cmd_vals, "Unknown (0x%04x)"),
pkt_type_str );
@@ -2250,33 +601,28 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (tree) {
/* create display subtree for the protocol */
- ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
+ ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
- cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
+ enip_tree = proto_item_add_subtree(ti, ett_enip);
/* Add encapsulation header tree */
- encaph = proto_tree_add_text( cipencap_tree, tvb, 0, 24, "Encapsulation Header");
- headertree = proto_item_add_subtree(encaph, ett_cipencaph);
+ encaph = proto_tree_add_text( enip_tree, tvb, 0, 24, "Encapsulation Header");
+ header_tree = proto_item_add_subtree(encaph, ett_enip);
- /* CIP header information */
- proto_tree_add_uint(headertree, hf_enip_command, tvb, 0, 2, encap_cmd);
+ /* Add EtherNet/IP encapsulation header */
+ proto_tree_add_item( header_tree, hf_enip_command, tvb, 0, 2, TRUE );
encap_data_length = tvb_get_letohs( tvb, 2 );
- proto_tree_add_text( headertree, tvb, 2, 2, "Length: %u", encap_data_length );
+ proto_tree_add_text( header_tree, tvb, 2, 2, "Length: %u", encap_data_length );
- proto_tree_add_text( headertree, tvb, 4, 4, "Session Handle: 0x%08X",
- tvb_get_letohl( tvb, 4 ) );
+ proto_tree_add_item( header_tree, hf_enip_session, tvb, 4, 4, TRUE );
+ proto_tree_add_item( header_tree, hf_enip_status, tvb, 8, 4, TRUE );
+ proto_tree_add_item( header_tree, hf_enip_sendercontex, tvb, 12, 8, TRUE );
+ proto_tree_add_item( header_tree, hf_enip_options, tvb, 20, 4, TRUE );
- status = tvb_get_letohl( tvb, 8 );
- proto_tree_add_text( headertree, tvb, 8, 4, "Status: %s (0x%08X)",
- val_to_str( status, encap_status_vals,
- "Unknown Status Code" ),
- status);
-
- add_byte_array_text_to_proto_tree( headertree, tvb, 12, 8, "Sender context: " );
-
- proto_tree_add_text( headertree, tvb, 20, 4, "Options: 0x%08X",
- tvb_get_letohl( tvb, 20 ) );
+ /* Append session and command to the protocol tree */
+ proto_item_append_text( ti, ", Session: 0x%08X, %s", tvb_get_letohl( tvb, 4 ),
+ val_to_str( encap_cmd, encap_cmd_vals, "Unknown (0x%04x)" ) );
/*
** For some commands we want to add some info to the info column
@@ -2301,10 +647,10 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* The packet have some command specific data, buid a sub tree for it */
- csf = proto_tree_add_text( cipencap_tree, tvb, 24, encap_data_length,
+ csf = proto_tree_add_text( enip_tree, tvb, 24, encap_data_length,
"Command Specific Data");
- csftree = proto_item_add_subtree(csf, ett_csf);
+ csftree = proto_item_add_subtree(csf, ett_command_tree);
switch( encap_cmd )
{
@@ -2312,15 +658,15 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
break;
case LIST_SERVICES:
- show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
+ dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
break;
case LIST_IDENTITY:
- show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
+ dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
break;
case LIST_INTERFACES:
- show_cdf( encap_cmd, tvb, pinfo, csftree, 24 );
+ dissect_cpf( encap_cmd, tvb, pinfo, csftree, 24, 0 );
break;
case REGISTER_SESSION:
@@ -2336,13 +682,23 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
break;
case SEND_RR_DATA:
+ proto_tree_add_item(csftree, hf_enip_srrd_ifacehnd, tvb, 24, 4, TRUE);
+
+ proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
+ tvb_get_letohs( tvb, 28 ) );
+
+ ifacehndl = tvb_get_letohl( tvb, 24 );
+ dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
+ break;
+
case SEND_UNIT_DATA:
- proto_tree_add_item(csftree, hf_enip_ifacehnd, tvb, 24, 4, TRUE);
+ proto_tree_add_item(csftree, hf_enip_sud_ifacehnd, tvb, 24, 4, TRUE);
proto_tree_add_text( csftree, tvb, 28, 2, "Timeout: %u",
tvb_get_letohs( tvb, 28 ) );
- show_cdf( encap_cmd, tvb, pinfo, csftree, 30 );
+ ifacehndl = tvb_get_letohl( tvb, 24 );
+ dissect_cpf( encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
break;
case INDICATE_STATUS:
@@ -2350,7 +706,7 @@ dissect_cipencap_pdu(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( header_tree, tvb, 24, encap_data_length, "Encap Data: " );
break;
} /* end of switch() */
@@ -2358,13 +714,15 @@ dissect_cipencap_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
} /* end of if( encapsulated data ) */
}
-} /* end of dissect_cipencap() */
+} /* end of dissect_enip_pdu() */
static int
-dissect_cipencap_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_enip_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint16 encap_cmd;
+ g_tree = tree;
+
/* An ENIP packet is at least 4 bytes long - we need the command type. */
if (!tvb_bytes_exist(tvb, 0, 4))
return 0;
@@ -2374,15 +732,17 @@ dissect_cipencap_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
return 0; /* not a known command */
- dissect_cipencap_pdu(tvb, pinfo, tree);
+ dissect_enip_pdu(tvb, pinfo, tree);
return tvb_length(tvb);
}
static int
-dissect_cipencap_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+dissect_enip_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
guint16 encap_cmd;
+ g_tree = tree;
+
/* An ENIP packet is at least 4 bytes long - we need the command type. */
if (!tvb_bytes_exist(tvb, 0, 4))
return 0;
@@ -2392,8 +752,8 @@ dissect_cipencap_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (match_strval(encap_cmd, encap_cmd_vals) == NULL)
return 0; /* not a known command */
- tcp_dissect_pdus(tvb, pinfo, tree, cipencap_desegment, 4,
- get_cipencap_pdu_len, dissect_cipencap_pdu);
+ tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4,
+ get_enip_pdu_len, dissect_enip_pdu);
return tvb_length(tvb);
}
@@ -2403,7 +763,9 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
{
/* Set up structures needed to add the protocol subtree and manage it */
proto_item *ti;
- proto_tree *cipencap_tree;
+ proto_tree *enip_tree;
+
+ g_tree = tree;
/* Make entries in Protocol column and Info column on summary display */
if (check_col(pinfo->cinfo, COL_PROTOCOL))
@@ -2414,11 +776,11 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if (tree)
{
/* create display subtree for the protocol */
- ti = proto_tree_add_item(tree, proto_cipencap, tvb, 0, -1, FALSE);
+ ti = proto_tree_add_item(tree, proto_enip, tvb, 0, -1, FALSE);
- cipencap_tree = proto_item_add_subtree(ti, ett_cipencap);
+ enip_tree = proto_item_add_subtree(ti, ett_enip);
- show_cdf( 0xFFFF, tvb, pinfo, cipencap_tree, 0 );
+ dissect_cpf( 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
}
} /* end of dissect_enipio() */
@@ -2431,229 +793,165 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
*/
void
-proto_register_cipencap(void)
+proto_register_enip(void)
{
-
-/* Setup list of header fields lengthSee Section 1.6.1 for details*/
+ /* Setup list of header fields */
static hf_register_info hf[] = {
{ &hf_enip_command,
- { "Command", "enip.command",
+ { "Command", "enip.command",
FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
"Encapsulation command", HFILL }
},
-
- /* Encapsulated data headers */
- /* Common Packet Format */
- { &hf_enip_cpf_typeid,
- { "Type ID", "enip.cpf.typeid",
- FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
- "Type of encapsulated item", HFILL }
- },
-
- /* Send RR Data */
- { &hf_enip_ifacehnd,
- { "Interface Handle", "enip.cpf.rr.ifacehnd",
+ { &hf_enip_session,
+ { "Session Handle", "enip.session",
FT_UINT32, BASE_HEX, NULL, 0,
- "Interface handle", HFILL }
+ "Session identification", HFILL }
},
-
- /* Unconnected message */
- { &hf_enip_ucm_rr,
- { "Request/Response", "enip.cip.rr",
- FT_UINT8, BASE_HEX, VALS(encap_sc_rr), 0x80,
- "Request or Response message", HFILL }
- },
- { &hf_enip_ucm_sc,
- { "Service", "enip.cip.sc",
- FT_UINT8, BASE_HEX, VALS(encap_sc_vals), 0x7F,
- "CIP Service code", HFILL }
+ { &hf_enip_status,
+ { "Status", "enip.status",
+ FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
+ "Status code", HFILL }
},
- { &hf_enip_ucm_path,
- { "Request Path", "enip.cip.path",
+ { &hf_enip_sendercontex,
+ { "Sender Context", "enip.context",
FT_BYTES, BASE_HEX, NULL, 0,
- "Request path", HFILL }
+ "Information pertient to the sender", HFILL }
+ },
+ { &hf_enip_options,
+ { "Options", "enip.options",
+ FT_UINT32, BASE_HEX, NULL, 0,
+ "Options flags", HFILL }
},
- { &hf_enip_ucm_genstat,
- { "General Status", "enip.cip.genstat",
- FT_UINT8, BASE_HEX, VALS(encap_cip_gs_vals), 0,
- "General Status", HFILL }
+ { &hf_enip_lsr_tcp,
+ { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp",
+ FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
+ "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }
},
-
- /* List identity response */
- { &hf_enip_cpf_lir_sinfamily,
- { "sin_family", "enip.lir.sinfamily",
+ { &hf_enip_lsr_udp,
+ { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp",
+ FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
+ "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }
+ },
+ /* Send Request/Reply Data */
+ { &hf_enip_srrd_ifacehnd,
+ { "Interface Handle", "enip.srrd.iface",
+ FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
+ "SendRRData: Interface handle", HFILL }
+ },
+ /* Send Unit Data */
+ { &hf_enip_sud_ifacehnd,
+ { "Interface Handle", "enip.sud.iface",
+ FT_UINT32, BASE_HEX, VALS(enip_interface_handle_vals), 0,
+ "SendUnitData: Interface handle", HFILL }
+ },
+ /* List identity reply */
+ { &hf_enip_lir_sinfamily,
+ { "sin_family", "enip.lir.sa.sinfamily",
FT_UINT16, BASE_DEC, NULL, 0,
- "Socket Address Sin Family", HFILL }
+ "ListIdentity Reply: Socket Address.Sin Family", HFILL }
},
- { &hf_enip_cpf_lir_sinport,
- { "sin_port", "enip.lir.sinport",
+ { &hf_enip_lir_sinport,
+ { "sin_port", "enip.lir.sa.sinport",
FT_UINT16, BASE_DEC, NULL, 0,
- "Socket Address Sin Port", HFILL }
+ "ListIdentity Reply: Socket Address.Sin Port", HFILL }
},
- { &hf_enip_cpf_lir_sinaddr,
- { "sin_addr", "enip.lir.sinaddr",
+ { &hf_enip_lir_sinaddr,
+ { "sin_addr", "enip.lir.sa.sinaddr",
FT_IPv4, BASE_HEX, NULL, 0,
- "Socket Address Sin Addr", HFILL }
+ "ListIdentity Reply: Socket Address.Sin Addr", HFILL }
},
- { &hf_enip_cpf_lir_sinzero,
- { "sin_zero", "enip.lir.sinzero",
+ { &hf_enip_lir_sinzero,
+ { "sin_zero", "enip.lir.sa.sinzero",
FT_BYTES, BASE_HEX, NULL, 0,
- "Socket Address Sin Zero", HFILL }
+ "ListIdentity Reply: Socket Address.Sin Zero", HFILL }
+ },
+ { &hf_enip_lir_vendor,
+ { "Vendor ID", "enip.lir.vendor",
+ FT_UINT16, BASE_HEX, VALS(cip_vendor_vals), 0,
+ "ListIdentity Reply: Vendor ID", HFILL }
},
- { &hf_enip_cpf_lir_devtype,
+ { &hf_enip_lir_devtype,
{ "Device Type", "enip.lir.devtype",
- FT_UINT16, BASE_DEC, VALS(encap_cip_devtype_vals), 0,
- "Device Type", HFILL }
+ FT_UINT16, BASE_DEC, VALS(cip_devtype_vals), 0,
+ "ListIdentity Reply: Device Type", HFILL }
},
- { &hf_enip_cpf_lir_prodcode,
+ { &hf_enip_lir_prodcode,
{ "Product Code", "enip.lir.prodcode",
FT_UINT16, BASE_DEC, NULL, 0,
- "Product Code", HFILL }
+ "ListIdentity Reply: Product Code", HFILL }
},
- { &hf_enip_cpf_lir_status,
+ { &hf_enip_lir_status,
{ "Status", "enip.lir.status",
FT_UINT16, BASE_HEX, NULL, 0,
- "Status", HFILL }
+ "ListIdentity Reply: Status", HFILL }
},
- { &hf_enip_cpf_lir_sernbr,
- { "Serial Number", "enip.lir.ser",
+ { &hf_enip_lir_serial,
+ { "Serial Number", "enip.lir.serial",
FT_UINT32, BASE_HEX, NULL, 0,
- "Serial Number", HFILL }
- },
- { &hf_enip_cpf_lir_namelength,
- { "Product Name Length", "enip.lir.namelength",
- FT_UINT8, BASE_DEC, NULL, 0,
- "Product Name Length", HFILL }
+ "ListIdentity Reply: Serial Number", HFILL }
},
- { &hf_enip_cpf_lir_name,
+ { &hf_enip_lir_name,
{ "Product Name", "enip.lir.name",
FT_STRING, BASE_NONE, NULL, 0,
- "Product Name", HFILL }
+ "ListIdentity Reply: Product Name", HFILL }
},
- { &hf_enip_cpf_lir_state,
+ { &hf_enip_lir_state,
{ "State", "enip.lir.state",
FT_UINT8, BASE_HEX, NULL, 0,
- "State", HFILL }
+ "ListIdentity Reply: State", HFILL }
},
- /* Vendor ID number */
- { &hf_enip_vendors,
- { "Vendor ID", "enip.vnd",
- FT_UINT16, BASE_HEX, VALS(encap_cip_vendor_vals), 0,
- "Vendor ID number", HFILL }
- },
- { &hf_enip_ucm_fwo_comp,
- { "Compatibility", "enip.cip.fwo.cmp",
- FT_UINT8, BASE_HEX, VALS(enip_com_bit_vals), 0x80,
- "Compatibility bit", HFILL }
- },
- { &hf_enip_ucm_fwo_mrev,
- { "Major Revision", "enip.cip.fwo.mrev",
- FT_UINT8, BASE_DEC, NULL, 0x7F,
- "Major Revision", HFILL }
- },
- { &hf_enip_ucm_fwo_con_size,
- { "Connection Size", "enip.cip.fwo.consize",
- FT_UINT16, BASE_DEC, NULL, 0x01FF,
- "Connection size", HFILL }
- },
- { &hf_enip_ucm_fwo_fixed_var,
- { "Connection Size Type", "enip.cip.fwo.f_v",
- FT_UINT16, BASE_DEC, VALS(enip_con_fw_vals), 0x0200,
- "Fixed or variable connection size", HFILL }
- },
- { &hf_enip_ucm_fwo_prio,
- { "Priority", "enip.cip.fwo.prio",
- FT_UINT16, BASE_DEC, VALS(enip_con_prio_vals), 0x0C00,
- "Connection priority", HFILL }
- },
- { &hf_enip_ucm_fwo_typ,
- { "Connection Type", "enip.cip.fwo.typ",
- FT_UINT16, BASE_DEC, VALS(enip_con_type_vals), 0x6000,
- "Connection type", HFILL }
- },
- { &hf_enip_ucm_fwo_own,
- { "Owner", "enip.cip.fwo.own",
- FT_UINT16, BASE_DEC, VALS(enip_con_owner_vals), 0x8000,
- "Redundant owner bit", HFILL }
- },
- { &hf_enip_ucm_fwo_dir,
- { "Direction", "enip.cip.fwo.dir",
- FT_UINT8, BASE_DEC, VALS(enip_con_dir_vals), 0x80,
- "Direction", HFILL }
- },
- { &hf_enip_ucm_fwo_trigg,
- { "Trigger", "enip.cip.fwo.trigg",
- FT_UINT8, BASE_DEC, VALS(enip_con_trigg_vals), 0x70,
- "Production trigger", HFILL }
- },
- { &hf_enip_ucm_fwo_class,
- { "Class", "enip.cip.fwo.class",
- FT_UINT8, BASE_DEC, VALS(enip_con_class_vals), 0x0F,
- "Transport Class", HFILL }
+ /* Common Packet Format */
+ { &hf_enip_cpf_typeid,
+ { "Type ID", "enip.cpf.typeid",
+ FT_UINT16, BASE_HEX, VALS(cdf_type_vals), 0,
+ "Common Packet Format: Type of encapsulated item", HFILL }
},
/* Sequenced Address Type */
- { &hf_enip_cpf_sat_connid,
- { "Connection ID", "enip.sat.connid",
+ { &hf_enip_cpf_sai_connid,
+ { "Connection ID", "enip.cpf.sai.connid",
FT_UINT32, BASE_HEX, NULL, 0,
- "Connection ID from forward open reply", HFILL }
+ "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }
},
- { &hf_enip_cpf_sat_seqnum,
- { "Sequence Number", "enip.sat.seq",
+ { &hf_enip_cpf_sai_seqnum,
+ { "Sequence Number", "enip.cpf.sai.seq",
FT_UINT32, BASE_DEC, NULL, 0,
- "Sequence Number", HFILL }
- },
- { &hf_enip_cpf_lsr_tcp,
- { "Supports CIP Encapsultion via TCP", "enip.ls.tcp",
- FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0020,
- "Supports CIP Encapsultion via TCP", HFILL }
- },
- { &hf_enip_cpf_lsr_udp,
- { "Supports CIP Class 0 or 1 via UDP", "enip.ls.udp",
- FT_UINT16, BASE_DEC, VALS(enip_true_false_vals), 0x0100,
- "Supports CIP Class 0 or 1 via UDP", HFILL }
+ "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }
}
-
};
/* Setup protocol subtree array */
static gint *ett[] = {
- &ett_cipencap,
- &ett_cip,
- &ett_cpf,
- &ett_path,
- &ett_ekey_path,
- &ett_cipencaph,
- &ett_csf,
- &ett_rrsc,
+ &ett_enip,
+ &ett_count_tree,
+ &ett_type_tree,
+ &ett_command_tree,
&ett_sockadd,
- &ett_mcsc,
- &ett_ncp,
- &ett_cia_path,
- &ett_data_seg,
&ett_lsrcf,
- &ett_mes_req,
- &ett_cmd_data,
- &ett_port_path,
- &ett_mult_ser
};
- module_t *cipencap_module;
+ module_t *enip_module;
/* Register the protocol name and description */
- proto_cipencap = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
+ proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
"ENIP", "enip");
/* Required function calls to register the header fields and subtrees used */
- proto_register_field_array(proto_cipencap, hf, array_length(hf));
+ proto_register_field_array(proto_enip, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
- cipencap_module = prefs_register_protocol(proto_cipencap, NULL);
- prefs_register_bool_preference(cipencap_module, "desegment",
- "Reassemble EtherNet/IP messages spanning multiple TCP segments",
- "Whether the EtherNet/IP dissector should reassemble messages spanning multiple TCP segments."
- " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
- &cipencap_desegment);
-} /* end of proto_register_cipencap() */
+ enip_module = prefs_register_protocol(proto_enip, NULL);
+ prefs_register_bool_preference(enip_module, "desegment",
+ "Desegment all EtherNet/IP messages spanning multiple TCP segments",
+ "Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
+ &enip_desegment);
+
+ subdissector_sud_table = register_dissector_table("enip.sud.iface",
+ "SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
+
+ subdissector_srrd_table = register_dissector_table("enip.srrd.iface",
+ "SendRequestReplyData.Interface Handle", FT_UINT32, BASE_HEX);
+
+} /* end of proto_register_enip() */
/* If this dissector uses sub-dissector registration add a registration routine.
@@ -2661,19 +959,24 @@ proto_register_cipencap(void)
create the code that calls these routines.
*/
void
-proto_reg_handoff_cipencap(void)
+proto_reg_handoff_enip(void)
{
- dissector_handle_t cipencap_udp_handle, cipencap_tcp_handle;
+ dissector_handle_t enip_udp_handle, enip_tcp_handle;
dissector_handle_t enipio_handle;
- /* Register for encapsulated CIP data, using both TCP/UDP */
- cipencap_tcp_handle = new_create_dissector_handle(dissect_cipencap_tcp, proto_cipencap);
- dissector_add("tcp.port", ENIP_ENCAP_PORT, cipencap_tcp_handle);
- cipencap_udp_handle = new_create_dissector_handle(dissect_cipencap_udp, proto_cipencap);
- dissector_add("udp.port", ENIP_ENCAP_PORT, cipencap_udp_handle);
+ /* Register for EtherNet/IP, using TCP */
+ enip_tcp_handle = new_create_dissector_handle(dissect_enip_tcp, proto_enip);
+ dissector_add("tcp.port", ENIP_ENCAP_PORT, enip_tcp_handle);
+
+ /* Register for EtherNet/IP, using UDP */
+ enip_udp_handle = new_create_dissector_handle(dissect_enip_udp, proto_enip);
+ dissector_add("udp.port", ENIP_ENCAP_PORT, enip_udp_handle);
- /* Register for IO data over UDP */
- enipio_handle = create_dissector_handle(dissect_enipio, proto_cipencap);
+ /* Register for EtherNet/IP IO data (UDP) */
+ enipio_handle = create_dissector_handle(dissect_enipio, proto_enip);
dissector_add("udp.port", ENIP_IO_PORT, enipio_handle);
-} /* end of proto_reg_handoff_cipencap() */
+ /* Find dissector for data packet */
+ data_handle = find_dissector("data");
+
+} /* end of proto_reg_handoff_enip() */