From Michael Mann:

a dissector for the ODVA protocol: CIP Safety. More information
about the protocol can be found here: 

http://www.odva.org/Home/ODVATECHNOLOGIES/CIP/CIPTechnologyOverview/CIPSafety/CIPSafetyOverview/tabid/131/lng/en-US/Default.aspx

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6862

svn path=/trunk/; revision=41201
This commit is contained in:
Anders Broman 2012-02-27 09:30:26 +00:00
parent 06cee2dfe3
commit 6b2b82d213
8 changed files with 2492 additions and 117 deletions

View File

@ -408,6 +408,7 @@ set(DISSECTOR_SRC
dissectors/packet-cimetrics.c
dissectors/packet-cip.c
dissectors/packet-cipmotion.c
dissectors/packet-cipsafety.c
dissectors/packet-cisco-erspan.c
dissectors/packet-cisco-oui.c
dissectors/packet-cisco-sm.c

View File

@ -326,6 +326,7 @@ DISSECTOR_SRC = \
packet-cimetrics.c \
packet-cip.c \
packet-cipmotion.c \
packet-cipsafety.c \
packet-cisco-erspan.c \
packet-cisco-oui.c \
packet-cisco-sm.c \
@ -1139,6 +1140,7 @@ DISSECTOR_INCLUDES = \
packet-chdlc.h \
packet-cimd.h \
packet-cip.h \
packet-cipsafety.h \
packet-clearcase.h \
packet-clip.h \
packet-cmip.h \

View File

@ -48,6 +48,7 @@
#include <epan/expert.h>
#include "packet-cip.h"
#include "packet-enip.h"
#include "packet-cipsafety.h"
#include "packet-mbtcp.h"
#define ENIP_CIP_INTERFACE 0
@ -263,6 +264,41 @@ static int hf_cip_network_seg_type = -1;
static int hf_cip_seg_schedule = -1;
static int hf_cip_seg_fixed_tag = -1;
static int hf_cip_seg_prod_inhibit_time = -1;
static int hf_cip_seg_network_size = -1;
static int hf_cip_seg_safety_format = -1;
static int hf_cip_seg_safety_reserved = -1;
static int hf_cip_seg_safety_configuration_crc = -1;
static int hf_cip_seg_safety_configuration_timestamp = -1;
static int hf_cip_seg_safety_configuration_date = -1;
static int hf_cip_seg_safety_configuration_time = -1;
static int hf_cip_seg_safety_time_correction_epi = -1;
static int hf_cip_seg_safety_time_correction_net_params = -1;
static int hf_cip_seg_safety_time_correction_own = -1;
static int hf_cip_seg_safety_time_correction_typ = -1;
static int hf_cip_seg_safety_time_correction_prio = -1;
static int hf_cip_seg_safety_time_correction_fixed_var = -1;
static int hf_cip_seg_safety_time_correction_con_size = -1;
static int hf_cip_seg_safety_tunid = -1;
static int hf_cip_seg_safety_tunid_ssn_timestamp = -1;
static int hf_cip_seg_safety_tunid_ssn_date = -1;
static int hf_cip_seg_safety_tunid_ssn_time = -1;
static int hf_cip_seg_safety_tunid_macid = -1;
static int hf_cip_seg_safety_ounid = -1;
static int hf_cip_seg_safety_ounid_ssn_timestamp = -1;
static int hf_cip_seg_safety_ounid_ssn_date = -1;
static int hf_cip_seg_safety_ounid_ssn_time = -1;
static int hf_cip_seg_safety_ounid_macid = -1;
static int hf_cip_seg_safety_ping_eri_multiplier = -1;
static int hf_cip_seg_safety_time_coord_msg_min_multiplier = -1;
static int hf_cip_seg_safety_network_time_expected_multiplier = -1;
static int hf_cip_seg_safety_timeout_multiplier = -1;
static int hf_cip_seg_safety_max_consumer_number = -1;
static int hf_cip_seg_safety_conn_param_crc = -1;
static int hf_cip_seg_safety_time_correction_conn_id = -1;
static int hf_cip_seg_safety_max_fault_number = -1;
static int hf_cip_seg_safety_init_timestamp = -1;
static int hf_cip_seg_safety_init_rollover = -1;
static int hf_cip_seg_safety_data = -1;
static int hf_cip_class_rev = -1;
static int hf_cip_class_max_inst32 = -1;
static int hf_cip_class_num_inst32 = -1;
@ -346,6 +382,12 @@ static gint ett_data_seg = -1;
static gint ett_data_seg_data = -1;
static gint ett_port_path = -1;
static gint ett_network_seg = -1;
static gint ett_network_seg_safety = -1;
static gint ett_network_seg_safety_time_correction_net_params = -1;
static gint ett_cip_seg_safety_tunid = -1;
static gint ett_cip_seg_safety_tunid_ssn = -1;
static gint ett_cip_seg_safety_ounid = -1;
static gint ett_cip_seg_safety_ounid_ssn = -1;
static gint ett_rrsc = -1;
static gint ett_status_item = -1;
@ -651,6 +693,14 @@ static const value_string cip_network_segment_type_vals[] = {
{ 0, NULL }
};
static const value_string cip_safety_segment_format_type_vals[] = {
{0, "Target Format"},
{1, "Router Format"},
{2, "Extended Format"},
{ 0, NULL }
};
static const value_string cip_cm_rpi_type_vals[] = {
{0, "RPI acceptable"},
{1, "Unspecified"},
@ -781,6 +831,21 @@ value_string_ext cip_gs_vals_ext = VALUE_STRING_EXT_INIT(cip_gs_vals);
#define CM_ES_NO_CONSUMER_RES_AVAIL_IN_PROD_MODULE 0x31E
#define CM_ES_NO_CONSUMER_RES_CONF_IN_PROD_MODULE 0x31F
#define CM_ES_NETWORK_LINK_OFFLINE 0x800
#define CM_ES_INCOMPATIBLE_MULTICAST_RPI 0x801
#define CM_ES_INVALID_SAFETY_CONN_SIZE 0x802
#define CM_ES_INVALID_SAFETY_CONN_FORMAT 0x803
#define CM_ES_INVALID_TIME_CORRECTION_CONN_PARAM 0x804
#define CM_ES_INVALID_PING_INTERVAL_EPI_MULTIPLIER 0x805
#define CM_ES_TIME_COORDINATION_MSG_MIN_MULTIPLIER 0x806
#define CM_ES_NETWORK_TIME_EXPECTATION_MULTIPLIER 0x807
#define CM_ES_TIMEOUT_MULTIPLIER 0x808
#define CM_ES_INVALID_MAX_CONSUMER_NUMBER 0x809
#define CM_ES_INVALID_CPCRC 0x80A
#define CM_ES_TIME_CORRECTION_CONN_ID_INVALID 0x80B
#define CM_ES_SCID_MISMATCH 0x80C
#define CM_ES_TUNID_NOT_SET 0x80D
#define CM_ES_TUNID_MISMATCH 0x80E
#define CM_ES_CONFIGURATION_OPERATION_NOT_ALLOWED 0x80F
#define CM_ES_NO_TARGET_APP_DATA_AVAILABLE 0x810
#define CM_ES_NO_ORIG_APP_DATA_AVAILABLE 0x811
#define CM_ES_NODE_ADDRESS_CHANGED_AFTER_SCHEDULED 0x812
@ -854,6 +919,21 @@ static const value_string cip_cm_ext_st_vals[] = {
{ CM_ES_REDUNDANT_CONNECTION_MISMATCH, "Redundant connection mismatch" },
{ CM_ES_NO_CONSUMER_RES_AVAIL_IN_PROD_MODULE, "No more user configurable link consumer resources available in the producing module" },
{ CM_ES_NO_CONSUMER_RES_CONF_IN_PROD_MODULE, "No more user configurable link consumer resources configured in the producing module" },
{ CM_ES_INCOMPATIBLE_MULTICAST_RPI, "Incompatible Multicast RPI" },
{ CM_ES_INVALID_SAFETY_CONN_SIZE, "Invalid Safety Connection Size" },
{ CM_ES_INVALID_SAFETY_CONN_FORMAT, "Invalid Safety Connection Format" },
{ CM_ES_INVALID_TIME_CORRECTION_CONN_PARAM, "Invalid Time Correction Connection Parameters" },
{ CM_ES_INVALID_PING_INTERVAL_EPI_MULTIPLIER, "Invalid Ping Interval EPI Multiplier" },
{ CM_ES_TIME_COORDINATION_MSG_MIN_MULTIPLIER, "Time Coordination Msg Min Multiplier" },
{ CM_ES_NETWORK_TIME_EXPECTATION_MULTIPLIER, "Network Time Expectation Multiplier" },
{ CM_ES_TIMEOUT_MULTIPLIER, "Timeout Multiplier" },
{ CM_ES_INVALID_MAX_CONSUMER_NUMBER, "Invalid Max Consumer Number" },
{ CM_ES_INVALID_CPCRC, "Invalid CPCRC" },
{ CM_ES_TIME_CORRECTION_CONN_ID_INVALID, "Time Correction Connection ID Invalid" },
{ CM_ES_SCID_MISMATCH, "SCID Mismatch" },
{ CM_ES_TUNID_NOT_SET, "TUNID not set" },
{ CM_ES_TUNID_MISMATCH, "TUNID Mismatch" },
{ CM_ES_CONFIGURATION_OPERATION_NOT_ALLOWED, "Configuration operation not allowed" },
{ CM_ES_NETWORK_LINK_OFFLINE, "Network link offline" },
{ CM_ES_NO_TARGET_APP_DATA_AVAILABLE, "No target application data available" },
{ CM_ES_NO_ORIG_APP_DATA_AVAILABLE, "No originator application data available" },
@ -2095,26 +2175,45 @@ static const value_string cip_vendor_vals[] = {
value_string_ext cip_vendor_vals_ext = VALUE_STRING_EXT_INIT(cip_vendor_vals);
/* Translate Device Profile:s */
/* Translate Device Profile's */
static const value_string cip_devtype_vals[] = {
{ DP_GEN_DEV, "Generic Device" },
{ DP_AC_DRIVE, "AC Drive" },
{ DP_MOTOR_OVERLOAD, "Motor Overload" },
{ DP_LIMIT_SWITCH, "Limit Switch" },
{ DP_IND_PROX_SWITCH, "Inductive Proximity Switch" },
{ DP_PHOTO_SENSOR, "Photoelectric Sensor" },
{ DP_GENP_DISC_IO, "General Purpose Discrete 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, "Vacuum Pressure Gauge" },
{ 0x00, "Generic Device (deprecated)" },
{ 0x02, "AC Drive" },
{ 0x03, "Motor Overload" },
{ 0x04, "Limit Switch" },
{ 0x05, "Inductive Proximity Switch" },
{ 0x06, "Photoelectric Sensor" },
{ 0x07, "General Purpose Discrete I/O"},
{ 0x09, "Resolver" },
{ 0x0C, "Communications Adapter" },
{ 0x0E, "Programmable Logic Controller" },
{ 0x10, "Position Controller", },
{ 0x13, "DC Drive" },
{ 0x15, "Contactor", },
{ 0x16, "Motor Starter", },
{ 0x17, "Soft Start", },
{ 0x18, "Human-Machine Interface" },
{ 0x1A, "Mass Flow Controller" },
{ 0x1B, "Pneumatic Valve" },
{ 0x1C, "Vacuum Pressure Gauge" },
{ 0x1D, "Process Control Value" },
{ 0x1E, "Residual Gas Analyzer" },
{ 0x1F, "DC Power Generator" },
{ 0x20, "RF Power Generator" },
{ 0x21, "Turbomolecular Vacuum Pump" },
{ 0x22, "Encoder" },
{ 0x23, "Safety Discrete I/O Device" },
{ 0x24, "Fluid Flow Controller" },
{ 0x25, "CIP Motion Drive" },
{ 0x26, "CompoNet Repeater" },
{ 0x27, "Mass Flow Controller, Enhanced" },
{ 0x28, "CIP Modbus Device" },
{ 0x29, "CIP Modbus Translator" },
{ 0x2A, "Safety Analog I/O Device" },
{ 0x2B, "Generic Device (keyable)" },
{ 0x2C, "Managed Switch" },
{ 0x32, "ControlNet Physical Layer Component" },
{ 0, NULL }
};
@ -2180,6 +2279,10 @@ static const value_string cip_class_names_vals[] = {
{ 0x46, "Modbus Serial Link Object" },
{ 0x47, "Device Level Ring (DLR) Object" },
{ 0x48, "QoS Object" },
{ 0x49, "Safety Analog Input Point Object" },
{ 0x4A, "Safety Analog Input Group Object" },
{ 0x4B, "Safety Dual Channel Analog Input Object" },
{ 0x4C, "Sercos III Link Object" },
{ 0xF0, "ControlNet Object" },
{ 0xF1, "ControlNet Keeper Object" },
{ 0xF2, "ControlNet Scheduling Object" },
@ -2252,7 +2355,7 @@ static attribute_info_t cip_attribute_vals[] = {
{0x06, FALSE, 5, "Close Requests", cip_uint, &hf_conn_mgr_close_requests, NULL},
{0x06, FALSE, 6, "Close Format Requests", cip_uint, &hf_conn_close_format_requests, NULL},
{0x06, FALSE, 7, "Close Other Requests", cip_uint, &hf_conn_mgr_close_other_requests, NULL},
{0x06, FALSE, 8, "Connection Timeouts", cip_uint, &hf_conn_mgr_conn_timouts, NULL},
{0x06, FALSE, 8, "Connection Timeouts", cip_uint, &hf_conn_mgr_conn_timouts, NULL}
};
typedef struct attribute_val_array {
@ -2262,7 +2365,8 @@ typedef struct attribute_val_array {
static attribute_val_array_t all_attribute_vals[] = {
{sizeof(cip_attribute_vals)/sizeof(attribute_info_t), cip_attribute_vals},
{sizeof(enip_attribute_vals)/sizeof(attribute_info_t), enip_attribute_vals}
{sizeof(enip_attribute_vals)/sizeof(attribute_info_t), enip_attribute_vals},
{sizeof(cip_safety_attribute_vals)/sizeof(attribute_info_t), cip_safety_attribute_vals}
};
static void
@ -2295,7 +2399,7 @@ static attribute_info_t* cip_get_attribute(guint class_id, guint instance, guint
static gboolean
dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
gboolean generate, packet_info *pinfo, proto_item *epath_item,
gboolean generate, gboolean packed, packet_info *pinfo, proto_item *epath_item,
proto_item *item, proto_tree *tree, proto_item *path_item, proto_item ** ret_item,
const char* segment_name, const value_string* vals, int* value,
int hf8, int hf16, int hf32)
@ -2338,7 +2442,14 @@ dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
(*pathpos) += 2;
break;
case CI_LOGICAL_SEG_16_BIT:
temp_data = tvb_get_letohs( tvb, offset + *pathpos + 2 );
if (packed)
{
temp_data = tvb_get_letohs( tvb, offset + *pathpos + 1 );
}
else
{
temp_data = tvb_get_letohs( tvb, offset + *pathpos + 2 );
}
if ( generate )
{
@ -2347,7 +2458,15 @@ dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
}
else
{
*ret_item = proto_tree_add_item( tree, hf16, tvb, offset + *pathpos + 2, 2, ENC_LITTLE_ENDIAN);
if (packed)
{
*ret_item = proto_tree_add_item( tree, hf16, tvb, offset + *pathpos + 1, 2, ENC_LITTLE_ENDIAN);
}
else
{
*ret_item = proto_tree_add_item( tree, hf16, tvb, offset + *pathpos + 2, 2, ENC_LITTLE_ENDIAN);
}
}
if (vals == NULL)
{
@ -2364,12 +2483,28 @@ dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
if (value != NULL)
*value = temp_data;
proto_item_set_len( item, 4);
proto_item_set_len( path_item, 4);
(*pathpos) += 4;
if (packed)
{
proto_item_set_len( item, 3);
proto_item_set_len( path_item, 3);
(*pathpos) += 3;
}
else
{
proto_item_set_len( item, 4);
proto_item_set_len( path_item, 4);
(*pathpos) += 4;
}
break;
case CI_LOGICAL_SEG_32_BIT:
temp_data = tvb_get_letohl( tvb, offset + *pathpos + 2 );
if (packed)
{
temp_data = tvb_get_letohl( tvb, offset + *pathpos + 1 );
}
else
{
temp_data = tvb_get_letohl( tvb, offset + *pathpos + 2 );
}
if ( generate )
{
@ -2378,7 +2513,14 @@ dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
}
else
{
*ret_item = proto_tree_add_item( tree, hf32, tvb, offset + *pathpos + 2, 4, ENC_LITTLE_ENDIAN);
if (packed)
{
*ret_item = proto_tree_add_item( tree, hf32, tvb, offset + *pathpos + 1, 4, ENC_LITTLE_ENDIAN);
}
else
{
*ret_item = proto_tree_add_item( tree, hf32, tvb, offset + *pathpos + 2, 4, ENC_LITTLE_ENDIAN);
}
}
if (vals == NULL)
@ -2396,9 +2538,18 @@ dissect_cia(tvbuff_t *tvb, int offset, int* pathpos, unsigned char segment_type,
if (value != NULL)
*value = temp_data;
proto_item_set_len( item, 6);
proto_item_set_len( path_item, 6);
(*pathpos) += 6;
if (packed)
{
proto_item_set_len( item, 5);
proto_item_set_len( path_item, 5);
(*pathpos) += 5;
}
else
{
proto_item_set_len( item, 6);
proto_item_set_len( path_item, 6);
(*pathpos) += 6;
}
break;
default:
expert_add_info_format(pinfo, epath_item, PI_PROTOCOL, PI_ERROR, "Unsupported Logical Segment Format");
@ -2491,14 +2642,15 @@ dissect_transport_type_trigger(tvbuff_t *tvb, int offset, proto_tree *tree,
}
/* Dissect EPATH */
void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, int offset, int path_length, gboolean generate, cip_simple_request_info_t* req_data)
void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, int offset, int path_length,
gboolean generate, gboolean packed, cip_simple_request_info_t* req_data, cip_safety_epath_info_t* safety)
{
int pathpos, temp_data, temp_data2, seg_size, i;
unsigned char segment_type, opt_link_size;
proto_tree *path_tree, *port_tree, *net_tree;
proto_tree *cia_tree, *ds_tree, *ds_data_tree, *path_seg_tree;
proto_tree *cia_tree, *ds_tree, *ds_data_tree, *path_seg_tree, *safety_tree;
proto_item *it, *cia_item, *cia_ret_item, *port_item, *ds_item, *ds_data_item;
proto_item *net_item, *hidden_item, *path_seg_item;
proto_item *net_item, *hidden_item, *path_seg_item, *safety_item;
attribute_info_t* att_info;
@ -2513,6 +2665,8 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
req_data->iAttribute = (guint32)-1;
req_data->iMember = (guint32)-1;
}
if (safety != NULL)
safety->safety_seg = FALSE;
if ( !generate )
{
@ -2661,7 +2815,7 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
switch( segment_type & CI_LOGICAL_SEG_TYPE_MASK )
{
case CI_LOGICAL_SEG_CLASS_ID:
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, pinfo,
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, packed, pinfo,
epath_item, cia_item, cia_tree, path_seg_item, &cia_ret_item,
"Class", cip_class_names_vals, (req_data == NULL) ? NULL : &req_data->iClass,
hf_cip_class8, hf_cip_class16, hf_cip_class32) == FALSE)
@ -2669,7 +2823,7 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
break;
case CI_LOGICAL_SEG_INST_ID:
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, pinfo,
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, packed, pinfo,
epath_item, cia_item, cia_tree, path_seg_item, &cia_ret_item,
"Instance", NULL, (req_data == NULL) ? NULL : &req_data->iInstance,
hf_cip_instance8, hf_cip_instance16, hf_cip_instance32) == FALSE)
@ -2677,7 +2831,7 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
break;
case CI_LOGICAL_SEG_MBR_ID:
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, pinfo,
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, packed, pinfo,
epath_item, cia_item, cia_tree, path_seg_item, &cia_ret_item,
"Member", NULL, (req_data == NULL) ? NULL : &req_data->iMember,
hf_cip_member8, hf_cip_member16, hf_cip_member32) == FALSE)
@ -2685,7 +2839,7 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
break;
case CI_LOGICAL_SEG_ATTR_ID:
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, pinfo,
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, packed, pinfo,
epath_item, cia_item, cia_tree, path_seg_item, &cia_ret_item,
"Attribute", NULL, (req_data == NULL) ? NULL : &req_data->iAttribute,
hf_cip_attribute8, hf_cip_attribute16, hf_cip_attribute32) == FALSE)
@ -2704,7 +2858,7 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
break;
case CI_LOGICAL_SEG_CON_POINT:
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, pinfo,
if (dissect_cia(tvb, offset, &pathpos, segment_type & CI_LOGICAL_SEG_FORMAT_MASK, generate, packed, pinfo,
epath_item, cia_item, cia_tree, path_seg_item, &cia_ret_item,
"Connection Point", NULL, NULL,
hf_cip_conpoint8, hf_cip_conpoint16, hf_cip_conpoint32) == FALSE)
@ -2907,6 +3061,115 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
pathpos += 2;
break;
case CI_NETWORK_SEG_SAFETY:
proto_item_append_text(epath_item, "[Safety]" );
/* Segment size */
seg_size = tvb_get_guint8( tvb, offset + pathpos+1 )*2;
proto_tree_add_uint_format_value(net_tree, hf_cip_seg_network_size,
tvb, offset + pathpos+1, 1, seg_size/2, "%d (words)", seg_size/2);
proto_tree_add_item(net_tree, hf_cip_seg_safety_format, tvb, offset+pathpos+2, 1, ENC_LITTLE_ENDIAN );
/* Safety Network Segment Format */
temp_data = tvb_get_guint8( tvb, offset + pathpos + 2 );
if (temp_data < 3)
{
safety_item = proto_tree_add_text(net_tree, tvb, offset + pathpos+3, seg_size-1, "%s", val_to_str(temp_data, cip_safety_segment_format_type_vals, "Reserved"));
safety_tree = proto_item_add_subtree( safety_item, ett_network_seg_safety );
switch (temp_data)
{
case 0:
/* Target Format */
if (safety != NULL)
safety->format = CIP_SAFETY_BASE_FORMAT;
proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset+pathpos+3, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_configuration_crc, tvb, offset+pathpos+4, 4, ENC_LITTLE_ENDIAN );
dissect_cipsafety_ssn(safety_tree, tvb, pinfo, offset+pathpos+8, hf_cip_seg_safety_configuration_timestamp, hf_cip_seg_safety_configuration_date, hf_cip_seg_safety_configuration_time);
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_epi, tvb, offset+pathpos+14, 4, ENC_LITTLE_ENDIAN );
dissect_net_param16(tvb, offset+pathpos+18, safety_tree,
hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
ett_network_seg_safety_time_correction_net_params);
it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_tunid, tvb, offset+pathpos+20, 10, ENC_NA);
dissect_unid(tvb, pinfo, offset+pathpos+20, it, "Target UNID SNN", hf_cip_seg_safety_tunid_ssn_timestamp,
hf_cip_seg_safety_tunid_ssn_date, hf_cip_seg_safety_tunid_ssn_time, hf_cip_seg_safety_tunid_macid,
ett_cip_seg_safety_tunid, ett_cip_seg_safety_tunid_ssn);
it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_ounid, tvb, offset+pathpos+30, 10, ENC_NA);
dissect_unid(tvb, pinfo, offset+pathpos+30, it, "Originator UNID SSN", hf_cip_seg_safety_ounid_ssn_timestamp,
hf_cip_seg_safety_ounid_ssn_date, hf_cip_seg_safety_ounid_ssn_time, hf_cip_seg_safety_ounid_macid,
ett_cip_seg_safety_ounid, ett_cip_seg_safety_ounid_ssn);
proto_tree_add_item(safety_tree, hf_cip_seg_safety_ping_eri_multiplier, tvb, offset+pathpos+40, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_coord_msg_min_multiplier, tvb, offset+pathpos+42, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_network_time_expected_multiplier, tvb, offset+pathpos+44, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_timeout_multiplier, tvb, offset+pathpos+46, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_consumer_number, tvb, offset+pathpos+47, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_conn_param_crc, tvb, offset+pathpos+48, 4, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset+pathpos+52, 4, ENC_LITTLE_ENDIAN );
break;
case 1:
/* Router Format */
if (safety != NULL)
safety->format = CIP_SAFETY_BASE_FORMAT;
proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset+pathpos+3, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset+pathpos+4, 4, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_ping_eri_multiplier, tvb, offset+pathpos+8, 2, ENC_LITTLE_ENDIAN );
dissect_net_param16(tvb, offset+pathpos+10, safety_tree,
hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
ett_network_seg_safety_time_correction_net_params);
break;
case 2:
/* Extended Format */
if (safety != NULL)
safety->format = CIP_SAFETY_EXTENDED_FORMAT;
proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset+pathpos+3, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_configuration_crc, tvb, offset+pathpos+4, 4, ENC_LITTLE_ENDIAN );
dissect_cipsafety_ssn(safety_tree, tvb, pinfo, offset+pathpos+8, hf_cip_seg_safety_configuration_timestamp, hf_cip_seg_safety_configuration_date, hf_cip_seg_safety_configuration_time);
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_epi, tvb, offset+pathpos+14, 4, ENC_LITTLE_ENDIAN );
dissect_net_param16(tvb, offset+pathpos+18, safety_tree,
hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
ett_network_seg_safety_time_correction_net_params);
it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_tunid, tvb, offset+pathpos+20, 10, ENC_NA);
dissect_unid(tvb, pinfo, offset+pathpos+20, it, "Target UNID SNN", hf_cip_seg_safety_tunid_ssn_timestamp,
hf_cip_seg_safety_tunid_ssn_date, hf_cip_seg_safety_tunid_ssn_time, hf_cip_seg_safety_tunid_macid,
ett_cip_seg_safety_tunid, ett_cip_seg_safety_tunid_ssn);
it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_ounid, tvb, offset+pathpos+30, 10, ENC_NA);
dissect_unid(tvb, pinfo, offset+pathpos+30, it, "Originator UNID SSN", hf_cip_seg_safety_ounid_ssn_timestamp,
hf_cip_seg_safety_ounid_ssn_date, hf_cip_seg_safety_ounid_ssn_time, hf_cip_seg_safety_ounid_macid,
ett_cip_seg_safety_ounid, ett_cip_seg_safety_ounid_ssn);
proto_tree_add_item(safety_tree, hf_cip_seg_safety_ping_eri_multiplier, tvb, offset+pathpos+40, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_coord_msg_min_multiplier, tvb, offset+pathpos+42, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_network_time_expected_multiplier, tvb, offset+pathpos+44, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_timeout_multiplier, tvb, offset+pathpos+46, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_consumer_number, tvb, offset+pathpos+47, 1, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_fault_number, tvb, offset+pathpos+48, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_conn_param_crc, tvb, offset+pathpos+50, 4, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset+pathpos+54, 4, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_init_timestamp, tvb, offset+pathpos+58, 2, ENC_LITTLE_ENDIAN );
proto_tree_add_item(safety_tree, hf_cip_seg_safety_init_rollover, tvb, offset+pathpos+60, 2, ENC_LITTLE_ENDIAN );
break;
}
}
else
{
proto_tree_add_item(net_tree, hf_cip_seg_safety_data, tvb, offset+pathpos+3, seg_size-1, ENC_LITTLE_ENDIAN );
}
if (safety != NULL)
safety->safety_seg = TRUE;
proto_item_set_len( net_item, seg_size+2);
proto_item_set_len( path_seg_item, seg_size+2);
pathpos += (seg_size+2);
break;
default:
expert_add_info_format(pinfo, epath_item, PI_PROTOCOL, PI_ERROR, "Unsupported Sub-Segment Type");
return;
@ -2929,12 +3192,42 @@ void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, i
} /* end of dissect_epath() */
/* Number of seconds between Jan 1, 1970 00:00:00 epoch and CIP's epoch time of Jan 1, 1972 00:00:00 */
#define CIP_TIMEBASE 63003600
void dissect_cip_date_and_time(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_datetime)
{
nstime_t computed_time;
guint16 num_days_since_1972;
guint32 num_ms_today;
num_days_since_1972 = tvb_get_letohs( tvb, offset);
num_ms_today = tvb_get_letohl( tvb, offset+2 );
if ((num_days_since_1972 != 0) || (num_ms_today != 0))
{
computed_time.secs = CIP_TIMEBASE+(num_days_since_1972*60*60*24);
computed_time.secs += num_ms_today/1000;
computed_time.nsecs = (num_ms_today%1000)*1000000;
}
else
{
computed_time.secs = 0;
computed_time.nsecs = 0;
}
proto_tree_add_time(tree, hf_datetime, tvb, offset, 6, &computed_time);
}
static int
dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
attribute_info_t* attr, int offset, int total_len)
{
int i, temp_data,
int i, temp_data, temp_time, hour, min, sec, ms,
consumed = 0;
time_t computed_time;
struct tm* date;
char date_str[20];
/* sanity check */
if (((attr->datatype == cip_dissector_func) && (attr->pdissect == NULL)) ||
@ -3004,14 +3297,36 @@ dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tv
case cip_dissector_func:
consumed = attr->pdissect(pinfo, tree, item, tvb, offset, total_len);
break;
case cip_date:
case cip_time_of_day:
case cip_date_and_time:
dissect_cip_date_and_time(tree, tvb, offset, *(attr->phf));
consumed = 6;
break;
case cip_date:
temp_data = tvb_get_letohs( tvb, offset);
/* Convert to nstime epoch */
computed_time = CIP_TIMEBASE+(temp_data*60*60*24);
date = gmtime(&computed_time);
strftime(date_str, 20, "%b %d, %Y", date);
proto_tree_add_uint_format_value(tree, *(attr->phf), tvb, offset, 2, temp_data, "%s", date_str);
consumed = 2;
break;
case cip_time_of_day:
temp_time = temp_data = tvb_get_letohl( tvb, offset);
hour = temp_time/(60*60*1000);
temp_time %= (60*60*1000);
min = temp_time/(60*1000);
temp_time %= (60*1000);
sec = temp_time/1000;
ms = temp_time%1000;
proto_tree_add_uint_format_value(tree, *(attr->phf), tvb, offset, 4, temp_data, "%02d:%02d:%02d.%03d", hour, min, sec, ms);
consumed = 4;
break;
case cip_string2:
case cip_stringN:
case cip_stringi:
/* CURRENTLY NOT SUPPORTED */
expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, "Unsupported Datatype");
consumed = total_len;
break;
}
@ -3804,7 +4119,8 @@ dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvb
int conn_path_size, rpi, net_param_offset = 0;
guint32 O2TConnID, T2OConnID, DeviceSerialNumber;
guint16 ConnSerialNumber, VendorID;
guint8 TransportClass, O2TType, T2OType;
guint8 TransportClass_trigger, O2TType, T2OType;
cip_safety_epath_info_t safety_fwdopen;
dissect_cip_cm_timeout(cmd_tree, tvb, offset);
O2TConnID = tvb_get_letohl( tvb, offset+2 );
@ -3868,7 +4184,7 @@ dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvb
net_param_offset += 2;
}
TransportClass = tvb_get_guint8( tvb, offset+26+net_param_offset+4) & 0x0F;
TransportClass_trigger = tvb_get_guint8( tvb, offset+26+net_param_offset+4);
dissect_transport_type_trigger(tvb, offset+26+net_param_offset+4, cmd_tree, hf_cip_cm_transport_type_trigger,
hf_cip_cm_fwo_dir, hf_cip_cm_fwo_trigg, hf_cip_cm_fwo_class, ett_cm_ttt);
@ -3878,7 +4194,7 @@ dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvb
/* Add the epath */
pi = proto_tree_add_text(cmd_tree, tvb, offset+26+net_param_offset+6, conn_path_size, "Connection Path: ");
dissect_epath( tvb, pinfo, pi, offset+26+net_param_offset+6, conn_path_size, FALSE, NULL);
dissect_epath( tvb, pinfo, pi, offset+26+net_param_offset+6, conn_path_size, FALSE, FALSE, NULL, &safety_fwdopen);
if (pinfo->fd->flags.visited)
return;
@ -3893,9 +4209,10 @@ dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvb
preq_info->connInfo->DeviceSerialNumber = DeviceSerialNumber;
preq_info->connInfo->O2T.connID = O2TConnID;
preq_info->connInfo->T2O.connID = T2OConnID;
preq_info->connInfo->TransportClass = TransportClass;
preq_info->connInfo->TransportClass_trigger = TransportClass_trigger;
preq_info->connInfo->T2O.type = T2OType;
preq_info->connInfo->O2T.type = O2TType;
preq_info->connInfo->safety = safety_fwdopen;
/* To be filled in by Ethernet/IP encap layer */
preq_info->connInfo->O2T.ipaddress = 0;
preq_info->connInfo->O2T.port = 0;
@ -4300,7 +4617,7 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
/* Add the EPATH */
pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+12, conn_path_size, "Connection Path: ");
dissect_epath( tvb, pinfo, pi, offset+2+req_path_size+12, conn_path_size, FALSE, NULL );
dissect_epath( tvb, pinfo, pi, offset+2+req_path_size+12, conn_path_size, FALSE, FALSE, NULL, NULL );
break;
case SC_CM_UNCON_SEND:
{
@ -4358,7 +4675,7 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
/* Route Path */
temp_item = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+6+msg_req_siz, route_path_size, "Route Path: ");
dissect_epath( tvb, pinfo, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size, FALSE, NULL );
dissect_epath( tvb, pinfo, temp_item, offset+2+req_path_size+6+msg_req_siz, route_path_size, FALSE, FALSE, NULL, NULL );
}
break;
case SC_CM_GET_CONN_OWNER:
@ -4373,7 +4690,7 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
/* Add the epath */
pi = proto_tree_add_text(cmd_data_tree, tvb, offset+2+req_path_size+2, conn_path_size, "Connection Path: ");
dissect_epath( tvb, pinfo, pi, offset+2+req_path_size+2, conn_path_size, FALSE, NULL );
dissect_epath( tvb, pinfo, pi, offset+2+req_path_size+2, conn_path_size, FALSE, FALSE, NULL, NULL );
break;
default:
/* Add data */
@ -4685,7 +5002,7 @@ dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, tvbuff_t *tvb, int o
/* Add the epath */
pi = proto_tree_add_text(cmd_tree, tvb, offset+30, conn_path_size, "Connection Path: ");
dissect_epath( tvb, pinfo, pi, offset+30, conn_path_size, FALSE, NULL );
dissect_epath( tvb, pinfo, pi, offset+30, conn_path_size, FALSE, FALSE, NULL, NULL );
variable_data_size += (conn_path_size+30);
@ -5135,7 +5452,7 @@ dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info
PROTO_ITEM_SET_GENERATED(pi);
preq_info->ciaData = se_alloc(sizeof(cip_simple_request_info_t));
dissect_epath( tvbIOI, pinfo, pi, 0, preq_info->IOILen*2, TRUE, preq_info->ciaData);
dissect_epath( tvbIOI, pinfo, pi, 0, preq_info->IOILen*2, TRUE, FALSE, preq_info->ciaData, NULL);
tvb_free(tvbIOI);
}
}
@ -5174,12 +5491,12 @@ dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info
if (preq_info)
{
preq_info->ciaData = se_alloc(sizeof(cip_simple_request_info_t));
dissect_epath( tvb, pinfo, pi, offset+2, req_path_size*2, FALSE, preq_info->ciaData);
dissect_epath( tvb, pinfo, pi, offset+2, req_path_size*2, FALSE, FALSE, preq_info->ciaData, NULL);
memcpy(&path_info, preq_info->ciaData, sizeof(cip_simple_request_info_t));
}
else
{
dissect_epath( tvb, pinfo, pi, offset+2, req_path_size*2, FALSE, &path_info);
dissect_epath( tvb, pinfo, pi, offset+2, req_path_size*2, FALSE, FALSE, &path_info, NULL);
}
ioilen = tvb_get_guint8( tvb, offset + 1 );
@ -5338,12 +5655,47 @@ proto_register_cip(void)
{ &hf_cip_ekey_minorrev, { "Minor Revision", "cip.ekey.minor_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_data_seg_type, { "Data Segment Type", "cip.data_segment.type", FT_UINT8, BASE_DEC, VALS(cip_data_segment_type_vals), CI_DATA_SEG_TYPE_MASK, NULL, HFILL }},
{ &hf_cip_data_seg_size, { "Data Size", "cip.data_segment.size", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_data_seg_item, { "Data", "cip.cip.data_segment.data", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_data_seg_item, { "Data", "cip.data_segment.data", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_symbol, { "Symbol", "cip.symbol", FT_STRING, BASE_NONE, NULL, 0, "ANSI Extended Symbol Segment", HFILL }},
{ &hf_cip_network_seg_type, { "Network Segment Type", "cip.network_segment.type", FT_UINT8, BASE_DEC, VALS(cip_network_segment_type_vals), CI_NETWORK_SEG_TYPE_MASK, NULL, HFILL }},
{ &hf_cip_seg_schedule, { "Multiplier/Phase", "cip.network_segment.schedule", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_fixed_tag, { "Fixed Tag", "cip.network_segment.fixed_tag", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_prod_inhibit_time, { "Production Inhibit Time", "cip.network_segment.prod_inhibit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_network_size, { "Network Segment Length", "cip.network_segment.length", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_format, { "Safety Format", "cip.safety_segment.format", FT_UINT8, BASE_DEC, VALS(cip_safety_segment_format_type_vals), 0, NULL, HFILL }},
{ &hf_cip_seg_safety_reserved, { "Reserved", "cip.safety_segment.reserved", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_configuration_crc, { "Configuration CRC", "cip.safety_segment.configuration_crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_configuration_timestamp, { "Configuration Timestamp", "cip.safety_segment.configuration_timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_configuration_date, { "Configuration (Manual) Date", "cip.safety_segment.configuration_date", FT_UINT16, BASE_HEX, VALS(cipsafety_ssn_date_vals), 0, NULL, HFILL }},
{ &hf_cip_seg_safety_configuration_time, { "Configuration (Manual) Time", "cip.safety_segment.configuration_time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_time_correction_epi, { "Time Correction EPI", "cip.safety_segment.time_correction_eri", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_time_correction_net_params, { "Time Correction Network Connection Parameters", "cip.safety_segment.time_correction.net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_time_correction_own, { "Owner", "cip.safety_segment.time_correction.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, "Time Correction: Redundant owner bit", HFILL }},
{ &hf_cip_seg_safety_time_correction_typ, { "Connection Type", "cip.safety_segment.time_correction.type", FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000, "Time Correction: Connection type", HFILL }},
{ &hf_cip_seg_safety_time_correction_prio, { "Priority", "cip.safety_segment.time_correction.prio", FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00, "Time Correction: Connection priority", HFILL }},
{ &hf_cip_seg_safety_time_correction_fixed_var, { "Connection Size Type", "cip.safety_segment.time_correction.f_v", FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200, "Time Correction: Fixed or variable connection size", HFILL }},
{ &hf_cip_seg_safety_time_correction_con_size, { "Connection Size", "cip.safety_segment.time_correction.consize", FT_UINT16, BASE_DEC, NULL, 0x01FF, "Time Correction: Connection size", HFILL }},
{ &hf_cip_seg_safety_tunid, { "Target UNID", "cip.safety_segment.tunid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_tunid_ssn_timestamp, { "SSN Timestamp", "cip.safety_segment.tunid.ssn.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_tunid_ssn_date, { "SSN (Manual) Date", "cip.safety_segment.tunid.ssn.date", FT_UINT16, BASE_HEX, VALS(cipsafety_ssn_date_vals), 0, NULL, HFILL }},
{ &hf_cip_seg_safety_tunid_ssn_time, { "SSN (Manual) Time", "cip.safety_segment.tunid.ssn.time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_tunid_macid, { "MAC ID", "cip.safety_segment.tunid.macid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ounid, { "Originator UNID", "cip.safety_segment.ounid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ounid_ssn_timestamp, { "SSN Timestamp", "cip.safety_segment.tunid.ssn.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ounid_ssn_date, { "SSN (Manual) Date", "cip.safety_segment.tunid.ssn.date", FT_UINT16, BASE_HEX, VALS(cipsafety_ssn_date_vals), 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ounid_ssn_time, { "SSN (Manual) Time", "cip.safety_segment.tunid.ssn.time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ounid_macid, { "MAC ID", "cip.safety_segment.ounid.macid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_ping_eri_multiplier, { "Ping Interval EPI Multiplier", "cip.safety_segment.ping_eri_multiplier", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_time_coord_msg_min_multiplier, { "Time Coord Msg Min Multiplier", "cip.safety_segment.time_coord_msg_min_multiplier", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_network_time_expected_multiplier, { "Network Time Expectation Multiplier", "cip.safety_segment.network_time_expected_multiplier", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_timeout_multiplier, { "Timeout Multiplier", "cip.safety_segment.timeout_multiplier", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_max_consumer_number, { "Max Consumer Number", "cip.safety_segment.max_consumer_number", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_conn_param_crc, { "Connection Param CRC", "cip.safety_segment.conn_param_crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_time_correction_conn_id, { "Time Correction Connection ID", "cip.safety_segment.time_correction_conn_id", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_max_fault_number, { "Max Fault Number", "cip.safety_segment.max_fault_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_init_timestamp, { "Initial Timestamp", "cip.safety_segment.init_timestamp", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_init_rollover, { "Initial Rollover Value", "cip.safety_segment.init_rollover", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_cip_seg_safety_data, { "Safety Data", "cip.safety_segment.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
{ &hf_cip_vendor, { "Vendor ID", "cip.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
{ &hf_cip_devtype, { "Device Type", "cip.devtype", FT_UINT16, BASE_DEC|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, NULL, HFILL }},
@ -5459,9 +5811,9 @@ proto_register_cip(void)
{ &hf_cip_cm_lfwo_typ, { "Connection Type", "cip.cm.fwo.type", FT_UINT32, BASE_DEC, VALS(cip_con_type_vals), 0x60000000, "Large Fwd Open: Connection type", HFILL }},
{ &hf_cip_cm_fwo_own, { "Owner", "cip.cm.fwo.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, "Fwd Open: Redundant owner bit", HFILL }},
{ &hf_cip_cm_lfwo_own, { "Owner", "cip.cm.fwo.owner", FT_UINT32, BASE_DEC, VALS(cip_con_owner_vals), 0x80000000, "Large Fwd Open: Redundant owner bit", HFILL }},
{ &hf_cip_cm_fwo_dir, { "Direction", "cip.cm.fwo.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80, "Fwd Open: Direction", HFILL }},
{ &hf_cip_cm_fwo_trigg, { "Trigger", "cip.cm.fwo.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70, "Fwd Open: Production trigger", HFILL }},
{ &hf_cip_cm_fwo_class, { "Class", "cip.cm.fwo.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F, "Fwd Open: Transport Class", HFILL }},
{ &hf_cip_cm_fwo_dir, { "Direction", "cip.cm.fwo.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), CI_PRODUCTION_DIR_MASK, "Fwd Open: Direction", HFILL }},
{ &hf_cip_cm_fwo_trigg, { "Trigger", "cip.cm.fwo.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), CI_PRODUCTION_TRIGGER_MASK, "Fwd Open: Production trigger", HFILL }},
{ &hf_cip_cm_fwo_class, { "Class", "cip.cm.fwo.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), CI_TRANSPORT_CLASS_MASK, "Fwd Open: Transport Class", HFILL }},
{ &hf_cip_cm_gco_conn, { "Number of Connections", "cip.cm.gco.conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: Number of Connections", HFILL }},
{ &hf_cip_cm_gco_coo_conn, { "COO Connections", "cip.cm.gco.coo_conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: COO Connections", HFILL }},
{ &hf_cip_cm_gco_roo_conn, { "ROO Connections", "cip.cm.gco.roo_conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: ROO Connections", HFILL }},
@ -5541,9 +5893,9 @@ proto_register_cip(void)
{ &hf_cip_cco_lfwo_typ, { "Connection Type", "cip.cco.type", FT_UINT32, BASE_DEC, VALS(cip_con_type_vals), 0x60000000, NULL, HFILL }},
{ &hf_cip_cco_fwo_own, { "Owner", "cip.cco.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, NULL, HFILL }},
{ &hf_cip_cco_lfwo_own, { "Owner", "cip.cco.owner", FT_UINT32, BASE_DEC, VALS(cip_con_owner_vals), 0x80000000, NULL, HFILL }},
{ &hf_cip_cco_fwo_dir, { "Direction", "cip.cco.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), 0x80, NULL, HFILL }},
{ &hf_cip_cco_fwo_trigger, { "Trigger", "cip.cco.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), 0x70, NULL, HFILL }},
{ &hf_cip_cco_fwo_class, { "Class", "cip.cco.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), 0x0F, NULL, HFILL }},
{ &hf_cip_cco_fwo_dir, { "Direction", "cip.cco.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), CI_PRODUCTION_DIR_MASK, NULL, HFILL }},
{ &hf_cip_cco_fwo_trigger, { "Trigger", "cip.cco.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), CI_PRODUCTION_TRIGGER_MASK, NULL, HFILL }},
{ &hf_cip_cco_fwo_class, { "Class", "cip.cco.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), CI_TRANSPORT_CLASS_MASK, NULL, HFILL }},
{ &hf_cip_cco_conn_path_size, { "Connection Path Size", "cip.cco.connpath_size", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_cco_proxy_config_size, { "Proxy Config Data Size", "cip.cco.proxy_config_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
{ &hf_cip_cco_target_config_size, { "Target Config Data Size", "cip.cco.proxy_config_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
@ -5573,6 +5925,12 @@ proto_register_cip(void)
&ett_cmd_data,
&ett_port_path,
&ett_network_seg,
&ett_network_seg_safety,
&ett_network_seg_safety_time_correction_net_params,
&ett_cip_seg_safety_tunid,
&ett_cip_seg_safety_tunid_ssn,
&ett_cip_seg_safety_ounid,
&ett_cip_seg_safety_ounid_ssn,
&ett_status_item,
&ett_add_status_item,
&ett_cip_get_attribute_list,

View File

@ -179,32 +179,15 @@
#define CI_NETWORK_SEG_SAFETY 0x10
#define CI_NETWORK_SEG_EXTENDED 0x1F
#define CI_TRANSPORT_CLASS_MASK 0x0F
#define CI_PRODUCTION_TRIGGER_MASK 0x70
#define CI_PRODUCTION_DIR_MASK 0x80
#define CONN_TYPE_NULL 0
#define CONN_TYPE_MULTICAST 1
#define CONN_TYPE_P2P 2
#define CONN_TYPE_RESERVED 3
/* Device Profiles */
#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
/* Define common services */
#define GENERIC_SC_LIST \
{ SC_GET_ATT_ALL, "Get Attribute All" }, \
@ -262,12 +245,12 @@ enum cip_datatype {
cip_word,
cip_dword,
cip_lword,
cip_dissector_func,
/* Currently not supported */
cip_date,
cip_time_of_day,
cip_date_and_time,
cip_dissector_func,
/* Currently not supported */
cip_string2,
cip_stringN,
cip_stringi
@ -293,6 +276,12 @@ typedef struct cip_connID_info {
guint8 type;
} cip_connID_info_t;
enum cip_safety_format_type {CIP_SAFETY_BASE_FORMAT, CIP_SAFETY_EXTENDED_FORMAT};
typedef struct cip_safety_epath_info {
gboolean safety_seg;
enum cip_safety_format_type format;
} cip_safety_epath_info_t;
typedef struct cip_conn_info {
guint16 ConnSerialNumber;
@ -300,7 +289,8 @@ typedef struct cip_conn_info {
guint32 DeviceSerialNumber;
cip_connID_info_t O2T;
cip_connID_info_t T2O;
guint8 TransportClass;
guint8 TransportClass_trigger;
cip_safety_epath_info_t safety;
} cip_conn_info_t;
typedef struct cip_req_info {
@ -316,7 +306,9 @@ typedef struct cip_req_info {
/*
** Exported functions
*/
extern void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, int offset, int path_length, gboolean generate, cip_simple_request_info_t* req_data);
extern void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_item, int offset, int path_length,
gboolean generate, gboolean packed, cip_simple_request_info_t* req_data, cip_safety_epath_info_t* safety);
extern void dissect_cip_date_and_time(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_datetime);
/*
** Exported variables

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
/* packet-cipsafety.h
* Routines for CIP (Common Industrial Protocol) Safety dissection
* CIP Safety Home: www.odva.org
*
* Copyright 2011
* Michael Mann <mmann@pyramidsolutions.com>
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* Classes that have class-specfic dissectors */
#define CI_CLS_SAFETY_SUPERVISOR 0x39 /* Safety Supervisor */
#define CI_CLS_SAFETY_VALIDATOR 0x3A /* Safety Validator */
/* Class specific services */
/* Safety Supervisor */
#define SC_SSUPER_RECOVER 0x4C
#define SC_SSUPER_PERFORM_DIAGNOSTICS 0x4E
#define SC_SSUPER_CONFIGURE_REQUEST 0x4F
#define SC_SSUPER_VALIDATE_CONFIGURATION 0x50
#define SC_SSUPER_SET_PASSWORD 0x51
#define SC_SSUPER_CONFIGURATION_LOCK 0x52
#define SC_SSUPER_MODE_CHANGE 0x53
#define SC_SSUPER_SAFETY_RESET 0x54
#define SC_SSUPER_RESET_PASSWORD 0x55
#define SC_SSUPER_PROPOSE_TUNID 0x56
#define SC_SSUPER_APPLY_TUNID 0x57
typedef struct cip_safety_info {
enum enip_connid_type conn_type;
enum cip_safety_format_type format;
gboolean server_dir;
} cip_safety_info_t;
/*
** Exported functions
*/
extern void dissect_unid(tvbuff_t *tvb, packet_info *pinfo, int offset, proto_item *pi, const char* ssn_name, int hf_ssn_timestamp,
int hf_ssn_date, int hf_ssn_time, int hf_macid, gint ett, gint ett_ssn);
extern void dissect_cipsafety_ssn(proto_tree *tree, tvbuff_t *tvb, packet_info *pinfo, int offset, int hf_real_datetime, int hf_date, int hf_time);
/*
** Exported variables
*/
extern const value_string cipsafety_ssn_date_vals[8];
extern attribute_info_t cip_safety_attribute_vals[52];

View File

@ -50,6 +50,7 @@
#include "packet-tcp.h"
#include "packet-cip.h"
#include "packet-enip.h"
#include "packet-cipsafety.h"
/* Communication Ports */
#define ENIP_ENCAP_PORT 44818 /* EtherNet/IP located on port 44818 */
@ -90,6 +91,7 @@
/* Initialize the protocol and registered fields */
static int proto_enip = -1;
static int proto_cipsafety = -1;
static int hf_enip_command = -1;
static int hf_enip_length = -1;
@ -254,6 +256,7 @@ static gint ett_elink_icontrol_bits = -1;
static dissector_table_t subdissector_srrd_table;
static dissector_table_t subdissector_sud_table;
static dissector_handle_t data_handle;
static dissector_handle_t arp_handle;
static heur_dissector_list_t heur_subdissector_conndata_table;
static gboolean enip_desegment = TRUE;
@ -492,7 +495,6 @@ static GHashTable *enip_request_hashtable = NULL;
/* Return codes of function classifying packets as query/response */
enum enip_packet_type {ENIP_REQUEST_PACKET, ENIP_RESPONSE_PACKET, ENIP_CANNOT_CLASSIFY};
enum enip_packet_data_type { EPDT_UNKNOWN, EPDT_CONNECTED_TRANSPORT, EPDT_UNCONNECTED };
enum enip_connid_type {ECIDT_UNKNOWN, ECIDT_O2T, ECIDT_T2O};
typedef struct enip_request_key {
enum enip_packet_type requesttype;
@ -551,9 +553,16 @@ enip_request_hash (gconstpointer v)
const enip_request_key_t *key = (const enip_request_key_t *)v;
guint val;
val = (guint)( key->conversation * 37 + key->session_handle * 93 + key->type * 765
+ key->sender_context * 23
+ key->data.connected_transport.connid * 87 + key->data.connected_transport.sequence * 834 );
val = (guint)(key->conversation * 37 + key->session_handle * 93 + key->type * 765);
if (key->type == EPDT_UNCONNECTED)
{
val += ((guint)(key->sender_context * 23));
}
else if (key->type == EPDT_CONNECTED_TRANSPORT)
{
val += ((guint)(key->data.connected_transport.connid * 87 + key->data.connected_transport.sequence * 834));
}
return val;
}
@ -650,6 +659,8 @@ typedef struct enip_conn_key {
guint16 ConnSerialNumber;
guint16 VendorID;
guint32 DeviceSerialNumber;
guint32 O2TConnID;
guint32 T2OConnID;
} enip_conn_key_t;
typedef struct enip_conn_val {
@ -658,10 +669,11 @@ typedef struct enip_conn_val {
guint32 DeviceSerialNumber;
guint32 O2TConnID;
guint32 T2OConnID;
guint8 TransportClass;
guint8 TransportClass_trigger;
guint32 openframe;
guint32 closeframe;
guint32 connid;
cip_safety_epath_info_t safety;
} enip_conn_val_t;
typedef struct _enip_conv_info_t {
@ -678,10 +690,11 @@ enip_conn_equal(gconstpointer v, gconstpointer w)
const enip_conn_key_t *v1 = (const enip_conn_key_t *)v;
const enip_conn_key_t *v2 = (const enip_conn_key_t *)w;
if ( v1->ConnSerialNumber == v2->ConnSerialNumber
&& v1->VendorID == v2->VendorID
&& v1->DeviceSerialNumber == v2->DeviceSerialNumber
)
if ((v1->ConnSerialNumber == v2->ConnSerialNumber) &&
(v1->VendorID == v2->VendorID) &&
(v1->DeviceSerialNumber == v2->DeviceSerialNumber) &&
((v1->O2TConnID == 0) || (v2->O2TConnID == 0) || (v1->O2TConnID == v2->O2TConnID)) &&
((v1->T2OConnID == 0) || (v2->T2OConnID == 0) || (v1->T2OConnID == v2->T2OConnID)))
return 1;
return 0;
@ -714,6 +727,8 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
conn_key->ConnSerialNumber = connInfo->ConnSerialNumber;
conn_key->VendorID = connInfo->VendorID;
conn_key->DeviceSerialNumber = connInfo->DeviceSerialNumber;
conn_key->O2TConnID = connInfo->O2T.connID;
conn_key->T2OConnID = connInfo->T2O.connID;
conn_val = g_hash_table_lookup( enip_conn_hashtable, conn_key );
if ( conn_val == NULL )
@ -725,7 +740,8 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
conn_val->DeviceSerialNumber = connInfo->DeviceSerialNumber;
conn_val->O2TConnID = connInfo->O2T.connID;
conn_val->T2OConnID = connInfo->T2O.connID;
conn_val->TransportClass = connInfo->TransportClass;
conn_val->TransportClass_trigger = connInfo->TransportClass_trigger;
conn_val->safety = connInfo->safety;
conn_val->openframe = pinfo->fd->num;
conn_val->closeframe = 0;
conn_val->connid = enip_unique_connid++;
@ -733,8 +749,8 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
g_hash_table_insert(enip_conn_hashtable, conn_key, conn_val );
/* I/O connection */
if ((connInfo->TransportClass == 0) ||
(connInfo->TransportClass == 1))
if (((connInfo->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 0) ||
((connInfo->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 1))
{
/* default some information if not included */
if ((connInfo->O2T.port == 0) || (connInfo->O2T.type == CONN_TYPE_MULTICAST))
@ -754,12 +770,10 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
/* similar logic to find_or_create_conversation(), but since I/O traffic
is on UDP, the pinfo parameter doesn't have the correct information */
if((conversation = find_conversation(pinfo->fd->num, &pinfo->dst, &dest_address,
PT_UDP, connInfo->O2T.port,
connInfo->O2T.port, 0)) == NULL) {
PT_UDP, connInfo->O2T.port, 0, NO_PORT_B)) == NULL) {
conversation = conversation_new(pinfo->fd->num, &pinfo->dst,
&dest_address, PT_UDP,
connInfo->O2T.port, connInfo->O2T.port, 0);
conversation = conversation_new(pinfo->fd->num, &pinfo->dst, &dest_address,
PT_UDP, connInfo->O2T.port, 0, NO_PORT2);
}
enip_info = conversation_get_proto_data(conversation, proto_enip);
@ -779,12 +793,11 @@ enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
or ports aren't equal, a separate conversation must be generated */
dest_address.data = &connInfo->T2O.ipaddress;
if((conversationTO = find_conversation(pinfo->fd->num, &pinfo->src, &dest_address,
PT_UDP, connInfo->T2O.port,
connInfo->T2O.port, 0)) == NULL) {
PT_UDP, connInfo->T2O.port, 0, NO_PORT_B)) == NULL) {
conversationTO = conversation_new(pinfo->fd->num, &pinfo->src,
&dest_address, PT_UDP,
connInfo->T2O.port, connInfo->T2O.port, 0);
connInfo->T2O.port, 0, NO_PORT2);
}
enip_info = conversation_get_proto_data(conversationTO, proto_enip);
@ -839,6 +852,8 @@ enip_close_cip_connection(packet_info *pinfo, guint16 ConnSerialNumber,
conn_key.ConnSerialNumber = ConnSerialNumber;
conn_key.VendorID = VendorID;
conn_key.DeviceSerialNumber = DeviceSerialNumber;
conn_key.O2TConnID = 0;
conn_key.T2OConnID = 0;
conn_val = g_hash_table_lookup( enip_conn_hashtable, &conn_key );
if ( conn_val )
@ -909,13 +924,14 @@ enip_get_io_connid(packet_info *pinfo, guint32 connid, enum enip_connid_type* pc
enip_conn_val_t *conn_val = NULL;
*pconnid_type = ECIDT_UNKNOWN;
/*
* Do we have a conversation for this connection?
*/
conversation = find_conversation(pinfo->fd->num,
&pinfo->src, &pinfo->dst,
pinfo->ptype,
pinfo->srcport, pinfo->destport, 0);
pinfo->destport, 0, NO_PORT_B);
if (conversation == NULL)
return NULL;
@ -1040,7 +1056,7 @@ int dissect_tcpip_physical_link(packet_info *pinfo, proto_tree *tree, proto_item
}
path_item = proto_tree_add_text(tree, tvb, offset+2, path_size, "Path: ");
dissect_epath( tvb, pinfo, path_item, offset+2, path_size, FALSE, NULL);
dissect_epath( tvb, pinfo, path_item, offset+2, path_size, FALSE, FALSE, NULL, NULL);
return path_size+2;
}
@ -1090,6 +1106,8 @@ int dissect_tcpip_last_conflict(packet_info *pinfo, proto_tree *tree, proto_item
int offset, int total_len)
{
tvbuff_t *next_tvb;
if (total_len < 35)
{
expert_add_info_format(pinfo, item, PI_MALFORMED, PI_ERROR, "Malformed TCP/IP Attribute 11");
@ -1098,8 +1116,16 @@ int dissect_tcpip_last_conflict(packet_info *pinfo, proto_tree *tree, proto_item
proto_tree_add_item(tree, hf_tcpip_lcd_acd_activity, tvb, offset, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tree, hf_tcpip_lcd_remote_mac, tvb, offset+1, 6, ENC_LITTLE_ENDIAN);
/* Call ARP dissector? */
proto_tree_add_item(tree, hf_tcpip_lcd_arp_pdu, tvb, offset+7, 28, ENC_LITTLE_ENDIAN);
if( tvb_get_guint8(tvb, offset) == 0 )
proto_tree_add_item(tree, hf_tcpip_lcd_arp_pdu, tvb, offset+7, 28, ENC_LITTLE_ENDIAN);
else
{
/* Call ARP dissector */
next_tvb = tvb_new_subset(tvb, offset+7, 28, 28);
call_dissector(arp_handle, next_tvb, pinfo, tree);
}
return 35;
}
@ -1202,6 +1228,7 @@ int dissect_elink_interface_control(packet_info *pinfo, proto_tree *tree, proto_
attribute_info_t enip_attribute_vals[29] = {
/* TCP/IP object */
{0xF5, FALSE, 1, "Status", cip_dissector_func, NULL, dissect_tcpip_status},
{0xF5, FALSE, 2, "Configuration Capability", cip_dissector_func, NULL, dissect_tcpip_config_cap},
{0xF5, FALSE, 3, "Configuration Control", cip_dissector_func, NULL, dissect_tcpip_config_control},
@ -1212,11 +1239,12 @@ attribute_info_t enip_attribute_vals[29] = {
{0xF5, FALSE, 9, "Multicast Configuration", cip_dissector_func, NULL, dissect_tcpip_mcast_config},
{0xF5, FALSE, 10, "Select ACD", cip_bool, &hf_tcpip_select_acd, NULL},
{0xF5, FALSE, 11, "Last Conflict Detected", cip_dissector_func, NULL, dissect_tcpip_last_conflict},
{0xF5, FALSE, 12, "Ethernet/IP Quick Connect", cip_bool, &hf_tcpip_quick_connect, NULL},
{0xF5, FALSE, 12, "EtherNet/IP Quick Connect", cip_bool, &hf_tcpip_quick_connect, NULL},
/* Ethernet Link object */
{0xF6, FALSE, 1, "Interface Speed", cip_dword, &hf_elink_interface_speed, NULL},
{0xF6, FALSE, 2, "Interface Flags", cip_dissector_func, NULL, dissect_elink_interface_flags},
{0xF6, FALSE, 3, "Physical Address", cip_usint_array, &hf_elink_physical_address, NULL},
{0xF6, FALSE, 3, "Physical Address", cip_byte_array, &hf_elink_physical_address, NULL},
{0xF6, FALSE, 4, "Interface Counters", cip_dissector_func, NULL, dissect_elink_interface_counters},
{0xF6, FALSE, 5, "Media Counters", cip_dissector_func, NULL, dissect_elink_media_counters},
{0xF6, FALSE, 6, "Interface Control", cip_dissector_func, NULL, dissect_elink_interface_control},
@ -1225,6 +1253,7 @@ attribute_info_t enip_attribute_vals[29] = {
{0xF6, FALSE, 9, "Admin State", cip_usint, &hf_elink_admin_state, NULL},
{0xF6, FALSE, 10, "Interface Label", cip_short_string, &hf_elink_interface_label, NULL},
/* QoS object */
{0x48, FALSE, 1, "802.1Q Tag Enable", cip_usint, &hf_qos_8021q_enable, NULL},
{0x48, FALSE, 2, "DSCP PTP Event", cip_usint, &hf_qos_dscp_ptp_event, NULL},
{0x48, FALSE, 3, "DSCP PTP General", cip_usint, &hf_qos_dscp_ptp_general, NULL},
@ -1250,6 +1279,8 @@ enip_init_protocol(void)
if (enip_conn_hashtable)
g_hash_table_destroy(enip_conn_hashtable);
enip_conn_hashtable = g_hash_table_new(enip_conn_hash, enip_conn_equal);
proto_cipsafety = proto_get_id_by_filter_name( "cipsafety" );
}
/* Disssect Common Packet Format */
@ -1267,6 +1298,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
gboolean FwdOpen = FALSE,
FwdOpenReply = FALSE;
enum enip_connid_type connid_type = ECIDT_UNKNOWN;
cip_safety_info_t* cip_safety;
/* Create item count tree */
item_count = tvb_get_letohs( tvb, offset );
@ -1391,6 +1423,16 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
if (tvb_length_remaining(tvb, offset+6) > 0)
{
next_tvb = tvb_new_subset(tvb, offset+6, item_length, item_length);
/* Add any possible safety related data */
if ((conn_info != NULL) && (conn_info->safety.safety_seg == TRUE))
{
cip_safety = se_alloc(sizeof(cip_safety_info_t));
cip_safety->conn_type = connid_type;
cip_safety->server_dir = (conn_info->TransportClass_trigger & CI_PRODUCTION_DIR_MASK) ? TRUE : FALSE;
cip_safety->format = conn_info->safety.format;
p_add_proto_data(pinfo->fd, proto_cipsafety, cip_safety);
}
if(!dissector_try_heuristic(heur_subdissector_conndata_table, next_tvb, pinfo, dissector_tree))
{
if (conn_info == NULL)
@ -1401,7 +1443,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
{
io_length = item_length;
if (conn_info->TransportClass == 1)
if ((conn_info->TransportClass_trigger & CI_TRANSPORT_CLASS_MASK) == 1)
{
proto_tree_add_item( item_tree, hf_enip_cpf_cdi_seqcnt, tvb, offset+6+(item_length-io_length), 2, ENC_LITTLE_ENDIAN );
io_length -= 2;
@ -2325,8 +2367,7 @@ proto_register_enip(void)
module_t *enip_module;
/* Register the protocol name and description */
proto_enip = proto_register_protocol("EtherNet/IP (Industrial Protocol)",
"ENIP", "enip");
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_enip, hf, array_length(hf));
@ -2396,6 +2437,9 @@ proto_reg_handoff_enip(void)
/* Find dissector for data packet */
data_handle = find_dissector("data");
/* Find ARP dissector for TCP/IP object */
arp_handle = find_dissector("arp");
/* Register for EtherNet/IP Device Level Ring protocol */
dlr_handle = new_create_dissector_handle(dissect_dlr, proto_dlr);
dissector_add_uint("ethertype", ETHERTYPE_DLR, dlr_handle);

View File

@ -84,7 +84,8 @@ typedef struct {
cip_req_info_t* cip_info;
} enip_request_info_t;
void enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo);
enum enip_connid_type {ECIDT_UNKNOWN, ECIDT_O2T, ECIDT_T2O};
void enip_close_cip_connection( packet_info *pinfo, guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber );
extern attribute_info_t enip_attribute_vals[29];