diff options
Diffstat (limited to 'epan/dissectors/packet-enip.c')
-rw-r--r-- | epan/dissectors/packet-enip.c | 2253 |
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() */ |