aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-enip.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2004-09-23 17:34:35 +0000
committerGuy Harris <guy@alum.mit.edu>2004-09-23 17:34:35 +0000
commit12d310a458f504770c7a4fc7fc7c416d5ea9c507 (patch)
tree537310b4d4e9b73c1931323812c4779ad3decc2f /epan/dissectors/packet-enip.c
parentc2fbce13fba1484df0a1e92212e0783585ab6254 (diff)
From Magnus Hansson:
move CIP protocol to own dissector clean up code and fix variable names add more info to info column fixed decoding of embedded messages in Unconnected send and Multiple Service packets add more info to path decoding add more filter options/clean up complete CIP vendor codes svn path=/trunk/; revision=12070
Diffstat (limited to 'epan/dissectors/packet-enip.c')
-rw-r--r--epan/dissectors/packet-enip.c2253
1 files changed, 278 insertions, 1975 deletions
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() */