aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--epan/dissectors/packet-cip.c229
-rw-r--r--epan/dissectors/packet-cip.h40
-rw-r--r--epan/dissectors/packet-enip.c624
-rw-r--r--epan/dissectors/packet-enip.h9
4 files changed, 515 insertions, 387 deletions
diff --git a/epan/dissectors/packet-cip.c b/epan/dissectors/packet-cip.c
index 79e893610d..03051bc247 100644
--- a/epan/dissectors/packet-cip.c
+++ b/epan/dissectors/packet-cip.c
@@ -51,15 +51,6 @@
#define ENIP_CIP_INTERFACE 0
-typedef struct cip_req_info {
- dissector_handle_t dissector;
- guint8 bService;
- guint IOILen;
- void *pIOI;
- void *pData;
- cip_simple_request_info_t* ciaData;
-} cip_req_info_t;
-
typedef struct mr_mult_req_info {
guint8 service;
int num_services;
@@ -356,7 +347,7 @@ static gint ett_cco_rrsc = -1;
static gint ett_cco_cmd_data = -1;
static gint ett_cco_ttt = -1;
-static dissector_table_t subdissector_class_table;
+dissector_table_t subdissector_class_table;
static dissector_table_t subdissector_symbol_table;
/* Translate function to string - CIP Service codes */
@@ -484,10 +475,10 @@ static const value_string cip_con_class_vals[] = {
/* Translate function to string - Connection type */
static const value_string cip_con_type_vals[] = {
- { 0, "Null" },
- { 1, "Multicast" },
- { 2, "Point to Point" },
- { 3, "Reserved" },
+ { CONN_TYPE_NULL, "Null" },
+ { CONN_TYPE_MULTICAST, "Multicast" },
+ { CONN_TYPE_P2P, "Point to Point" },
+ { CONN_TYPE_RESERVED, "Reserved" },
{ 0, NULL }
};
@@ -2083,10 +2074,6 @@ static const value_string cip_devtype_vals[] = {
value_string_ext cip_devtype_vals_ext = VALUE_STRING_EXT_INIT(cip_devtype_vals);
-#define CI_CLS_MR 0x02 /* Message Router */
-#define CI_CLS_CM 0x06 /* Connection Manager */
-#define CI_CLS_CCO 0xF3 /* Connection Configuration Object */
-
/* Translate class names */
static const value_string cip_class_names_vals[] = {
{ 0x01, "Identity Object" },
@@ -3760,16 +3747,24 @@ dissect_cip_cm_timeout(proto_tree *cmd_tree, tvbuff_t *tvb, int offset)
}
static void
-dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gboolean large_fwd_open, packet_info *pinfo)
+dissect_cip_cm_fwd_open_req(cip_req_info_t *preq_info, proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gboolean large_fwd_open, packet_info *pinfo)
{
proto_item *pi;
int conn_path_size, rpi, net_param_offset = 0;
+ guint32 O2TConnID, T2OConnID, DeviceSerialNumber;
+ guint16 ConnSerialNumber, VendorID;
+ guint8 TransportClass, O2TType, T2OType;
dissect_cip_cm_timeout(cmd_tree, tvb, offset);
+ O2TConnID = tvb_get_letohl( tvb, offset+2 );
proto_tree_add_item( cmd_tree, hf_cip_cm_ot_connid, tvb, offset+2, 4, ENC_LITTLE_ENDIAN);
+ T2OConnID = tvb_get_letohl( tvb, offset+6 );
proto_tree_add_item( cmd_tree, hf_cip_cm_to_connid, tvb, offset+6, 4, ENC_LITTLE_ENDIAN);
+ ConnSerialNumber = tvb_get_letohs( tvb, offset+10 );
proto_tree_add_item( cmd_tree, hf_cip_cm_conn_serial_num, tvb, offset+10, 2, ENC_LITTLE_ENDIAN);
+ VendorID = tvb_get_letohs( tvb, offset+12 );
proto_tree_add_item( cmd_tree, hf_cip_cm_vendor, tvb, offset+12, 2, ENC_LITTLE_ENDIAN);
+ DeviceSerialNumber = tvb_get_letohl( tvb, offset+14 );
proto_tree_add_item( cmd_tree, hf_cip_cm_orig_serial_num, tvb, offset+14, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item( cmd_tree, hf_cip_cm_timeout_multiplier, tvb, offset+18, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item( cmd_tree, hf_cip_reserved24, tvb, offset+19, 3, ENC_LITTLE_ENDIAN);
@@ -3785,6 +3780,7 @@ dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gbo
hf_cip_cm_ot_net_params32, hf_cip_cm_lfwo_own, hf_cip_cm_lfwo_typ,
hf_cip_cm_lfwo_prio, hf_cip_cm_lfwo_fixed_var, hf_cip_cm_lfwo_con_size, ett_cm_ncp);
+ O2TType = (guint8)(((tvb_get_letohl( tvb, offset+26 ) & 0x60000000) >> 29) & 3);
net_param_offset = 4;
}
else
@@ -3793,6 +3789,7 @@ dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gbo
hf_cip_cm_ot_net_params16, hf_cip_cm_fwo_own, hf_cip_cm_fwo_typ,
hf_cip_cm_fwo_prio, hf_cip_cm_fwo_fixed_var, hf_cip_cm_fwo_con_size, ett_cm_ncp);
+ O2TType = (guint8)(((tvb_get_letohs( tvb, offset+26 ) & 0x6000) >> 13) & 3);
net_param_offset = 2;
}
@@ -3807,6 +3804,7 @@ dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gbo
hf_cip_cm_to_net_params32, hf_cip_cm_lfwo_own, hf_cip_cm_lfwo_typ,
hf_cip_cm_lfwo_prio, hf_cip_cm_lfwo_fixed_var, hf_cip_cm_lfwo_con_size, ett_cm_ncp);
+ T2OType = (guint8)(((tvb_get_letohl( tvb, offset+26+net_param_offset+4 ) & 0x60000000) >> 29) & 3);
net_param_offset += 4;
}
else
@@ -3815,9 +3813,11 @@ dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gbo
hf_cip_cm_to_net_params16, hf_cip_cm_fwo_own, hf_cip_cm_fwo_typ,
hf_cip_cm_fwo_prio, hf_cip_cm_fwo_fixed_var, hf_cip_cm_fwo_con_size, ett_cm_ncp);
+ T2OType = (guint8)(((tvb_get_letohs( tvb, offset+26+net_param_offset+4 ) & 0x6000) >> 13) & 3);
net_param_offset += 2;
}
+ TransportClass = tvb_get_guint8( tvb, offset+26+net_param_offset+4) & 0x0F;
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);
@@ -3828,6 +3828,94 @@ dissect_cip_cm_fwd_open_req(proto_tree *cmd_tree, tvbuff_t *tvb, int offset, gbo
/* 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);
+
+ if (pinfo->fd->flags.visited)
+ return;
+
+ if (preq_info != NULL)
+ {
+ DISSECTOR_ASSERT(preq_info->connInfo == NULL);
+ preq_info->connInfo = se_alloc(sizeof(cip_conn_info_t));
+
+ preq_info->connInfo->ConnSerialNumber = ConnSerialNumber;
+ preq_info->connInfo->VendorID = VendorID;
+ 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->T2O.type = T2OType;
+ preq_info->connInfo->O2T.type = O2TType;
+ /* To be filled in by Ethernet/IP encap layer */
+ preq_info->connInfo->O2T.ipaddress = 0;
+ preq_info->connInfo->O2T.port = 0;
+ preq_info->connInfo->T2O.ipaddress = 0;
+ preq_info->connInfo->T2O.port = 0;
+ }
+}
+
+static void
+dissect_cip_cm_fwd_open_rsp_success(cip_req_info_t *preq_info, proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo)
+{
+ int temp_data;
+ unsigned char app_rep_size;
+ guint32 O2TConnID, T2OConnID, DeviceSerialNumber;
+ guint16 ConnSerialNumber, VendorID;
+
+ /* Display originator to target connection ID */
+ O2TConnID = tvb_get_letohl( tvb, offset );
+ proto_tree_add_item( tree, hf_cip_cm_ot_connid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
+
+ /* Display target to originator connection ID */
+ T2OConnID = tvb_get_letohl( tvb, offset+4 );
+ proto_tree_add_item( tree, hf_cip_cm_to_connid, tvb, offset+4, 4, ENC_LITTLE_ENDIAN);
+
+ /* Display connection serial number */
+ ConnSerialNumber = tvb_get_letohs( tvb, offset+8 );
+ proto_tree_add_item( tree, hf_cip_cm_conn_serial_num, tvb, offset+8, 2, ENC_LITTLE_ENDIAN);
+
+ /* Display the originator vendor id */
+ VendorID = tvb_get_letohs( tvb, offset+10 );
+ proto_tree_add_item( tree, hf_cip_cm_vendor, tvb, offset+10, 2, ENC_LITTLE_ENDIAN);
+
+ /* Display the originator serial number */
+ DeviceSerialNumber = tvb_get_letohl( tvb, offset+12 );
+ proto_tree_add_item( tree, hf_cip_cm_orig_serial_num, tvb, offset+12, 4, ENC_LITTLE_ENDIAN);
+
+ /* Display originator to target actual packet interval */
+ temp_data = tvb_get_letohl( tvb, offset+16 );
+ proto_tree_add_uint_format_value(tree, hf_cip_cm_ot_api, tvb, offset+16, 4, temp_data, "%dms (0x%08X)", temp_data / 1000, temp_data);
+
+ /* Display originator to target actual packet interval */
+ temp_data = tvb_get_letohl( tvb, offset+20 );
+ proto_tree_add_uint_format_value(tree, hf_cip_cm_to_api, tvb, offset+20, 4, temp_data, "%dms (0x%08X)", temp_data / 1000, temp_data);
+
+ /* Display the application reply size */
+ app_rep_size = tvb_get_guint8( tvb, offset+24 ) * 2;
+ proto_tree_add_uint_format_value(tree, hf_cip_cm_app_reply_size, tvb, offset+24, 1, app_rep_size / 2, "%d (words)", app_rep_size / 2);
+
+ /* Display the Reserved byte */
+ proto_tree_add_item(tree, hf_cip_reserved8, tvb, offset+25, 1, ENC_LITTLE_ENDIAN );
+ if (app_rep_size > 0)
+ proto_tree_add_item(tree, hf_cip_cm_app_reply_data, tvb, offset+26, app_rep_size, ENC_NA );
+
+ /* See if we've captured the ForwardOpen request. If so some of the conversation data has already been
+ populated and we just need to update it. */
+ if (pinfo->fd->flags.visited)
+ return;
+
+ if ((preq_info != NULL) && (preq_info->connInfo != NULL))
+ {
+ /* Ensure the connection triad matches before updating the connection IDs */
+ if ((preq_info->connInfo->ConnSerialNumber == ConnSerialNumber) &&
+ (preq_info->connInfo->VendorID == VendorID) &&
+ (preq_info->connInfo->DeviceSerialNumber == DeviceSerialNumber))
+ {
+ /* Update the connection IDs as ForwardOpen reply is allows to update them from
+ the ForwardOpen request */
+ preq_info->connInfo->O2T.connID = O2TConnID;
+ preq_info->connInfo->T2O.connID = T2OConnID;
+ }
+ }
}
static void
@@ -3842,6 +3930,8 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
int i, msg_req_siz;
cip_req_info_t *preq_info;
cip_req_info_t *pembedded_req_info;
+ guint16 ConnSerialNumber, VendorID;
+ guint32 DeviceSerialNumber;
service = tvb_get_guint8( tvb, offset );
@@ -4014,61 +4104,11 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
{
case SC_CM_FWD_OPEN:
case SC_CM_LARGE_FWD_OPEN:
- {
- /* Forward open Response (Success) */
- guint32 O2TConnID;
- guint32 T2OConnID;
- guint16 ConnSerialNumber;
- guint32 DeviceSerialNumber;
- guint16 VendorID;
-
- /* Display originator to target connection ID */
- O2TConnID = tvb_get_letohl( tvb, offset+4+add_stat_size );
- proto_tree_add_item( cmd_data_tree, hf_cip_cm_ot_connid, tvb, offset+4+add_stat_size, 4, ENC_LITTLE_ENDIAN);
-
- /* Display target to originator connection ID */
- T2OConnID = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
- proto_tree_add_item( cmd_data_tree, hf_cip_cm_to_connid, tvb, offset+4+add_stat_size+4, 4, ENC_LITTLE_ENDIAN);
-
- /* Display connection serial number */
- ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size+8 );
- proto_tree_add_item( cmd_data_tree, hf_cip_cm_conn_serial_num, tvb, offset+4+add_stat_size+8, 2, ENC_LITTLE_ENDIAN);
-
- /* Display the originator vendor id */
- VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+10 );
- proto_tree_add_item( cmd_data_tree, hf_cip_cm_vendor, tvb, offset+4+add_stat_size+10, 2, ENC_LITTLE_ENDIAN);
-
- /* Display the originator serial number */
- DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+12 );
- proto_tree_add_item( cmd_data_tree, hf_cip_cm_orig_serial_num, tvb, offset+4+add_stat_size+12, 4, ENC_LITTLE_ENDIAN);
-
- /* Display originator to target actual packet interval */
- temp_data = tvb_get_letohl( tvb, offset+4+add_stat_size+16 );
- proto_tree_add_uint_format_value(cmd_data_tree, hf_cip_cm_ot_api, tvb, offset+4+add_stat_size+16, 4, temp_data, "%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_uint_format_value(cmd_data_tree, hf_cip_cm_to_api, tvb, offset+4+add_stat_size+20, 4, temp_data, "%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_uint_format_value(cmd_data_tree, hf_cip_cm_app_reply_size, tvb, offset+4+add_stat_size+24, 1, app_rep_size / 2, "%d (words)", app_rep_size / 2);
-
- /* Display the Reserved byte */
- proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset+4+add_stat_size+25, 1, ENC_LITTLE_ENDIAN );
- if (app_rep_size > 0)
- proto_tree_add_item(cmd_data_tree, hf_cip_cm_app_reply_data, tvb, offset+4+add_stat_size+26, app_rep_size, ENC_NA );
-
- enip_open_cip_connection( pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber, O2TConnID, T2OConnID );
-
- } /* End of if forward open response */
- break;
+ dissect_cip_cm_fwd_open_rsp_success(preq_info, cmd_data_tree, tvb, offset+4+add_stat_size, pinfo);
+ break;
case SC_CM_FWD_CLOSE:
{
/* Forward close response (Success) */
- guint16 ConnSerialNumber;
- guint32 DeviceSerialNumber;
- guint16 VendorID;
/* Display connection serial number */
ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size );
@@ -4098,7 +4138,6 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
case SC_CM_UNCON_SEND:
{
/* Unconnected send response (Success) */
-
/* Display service response data */
proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
}
@@ -4130,12 +4169,25 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
case SC_CM_FWD_OPEN:
case SC_CM_LARGE_FWD_OPEN:
case SC_CM_FWD_CLOSE:
+
/* Forward open and forward close error response look the same */
+ ConnSerialNumber = tvb_get_letohs( tvb, offset+4+add_stat_size );
proto_tree_add_item( cmd_data_tree, hf_cip_cm_conn_serial_num, tvb, offset+4+add_stat_size, 2, ENC_LITTLE_ENDIAN);
+ VendorID = tvb_get_letohs( tvb, offset+4+add_stat_size+2 );
proto_tree_add_item( cmd_data_tree, hf_cip_cm_vendor, tvb, offset+4+add_stat_size+2, 2, ENC_LITTLE_ENDIAN);
+ DeviceSerialNumber = tvb_get_letohl( tvb, offset+4+add_stat_size+4 );
proto_tree_add_item( cmd_data_tree, hf_cip_cm_orig_serial_num, tvb, offset+4+add_stat_size+4, 4, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cmd_data_tree, hf_cip_cm_remain_path_size, tvb, offset+4+add_stat_size+8, 1, ENC_LITTLE_ENDIAN);
proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset+4+add_stat_size+9, 1, ENC_LITTLE_ENDIAN);
+
+ /* With an error reply the connection will either never be established or it has since already closed
+ That means the conversation should end too */
+ enip_close_cip_connection(pinfo, ConnSerialNumber, VendorID, DeviceSerialNumber);
+ if (preq_info != NULL)
+ {
+ /* Remove any connection information */
+ preq_info->connInfo = NULL;
+ }
break;
case SC_CM_UNCON_SEND:
/* Unconnected send response (Unsuccess) */
@@ -4174,11 +4226,11 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
{
case SC_CM_FWD_OPEN:
/* Forward open Request*/
- dissect_cip_cm_fwd_open_req(cmd_data_tree, tvb, offset+2+req_path_size, FALSE, pinfo);
+ dissect_cip_cm_fwd_open_req(preq_info, cmd_data_tree, tvb, offset+2+req_path_size, FALSE, pinfo);
break;
case SC_CM_LARGE_FWD_OPEN:
/* Large Forward open Request*/
- dissect_cip_cm_fwd_open_req(cmd_data_tree, tvb, offset+2+req_path_size, TRUE, pinfo);
+ dissect_cip_cm_fwd_open_req(preq_info, cmd_data_tree, tvb, offset+2+req_path_size, TRUE, pinfo);
break;
case SC_CM_FWD_CLOSE:
/* Forward Close Request */
@@ -4229,12 +4281,7 @@ dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_
if ( preq_info->pData == NULL )
{
pembedded_req_info = (cip_req_info_t*)se_alloc(sizeof(cip_req_info_t));
- pembedded_req_info->bService = 0;
- pembedded_req_info->dissector = NULL;
- pembedded_req_info->IOILen = 0;
- pembedded_req_info->pIOI = NULL;
- pembedded_req_info->pData = NULL;
- pembedded_req_info->ciaData = NULL;
+ memset(pembedded_req_info, 0, sizeof(cip_req_info_t));
preq_info->pData = pembedded_req_info;
}
else
@@ -4294,14 +4341,11 @@ dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *ti;
proto_tree *class_tree;
- if( tree )
- {
- /* Create display subtree for the protocol */
- ti = proto_tree_add_item(tree, proto_cip_class_cm, tvb, 0, -1, ENC_NA);
- class_tree = proto_item_add_subtree( ti, ett_cip_class_cm );
+ /* Create display subtree for the protocol */
+ ti = proto_tree_add_item(tree, proto_cip_class_cm, tvb, 0, -1, ENC_NA);
+ class_tree = proto_item_add_subtree( ti, ett_cip_class_cm );
- dissect_cip_cm_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
- }
+ dissect_cip_cm_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
return tvb_length(tvb);
}
@@ -4912,7 +4956,7 @@ dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info
}
/* Check to see if service is 'generic' */
- match_strval_idx((service & 0x7F), cip_sc_vals, &service_index);
+ match_strval_idx(service, cip_sc_vals, &service_index);
if (service_index >= 0)
{
/* See if object dissector wants to override generic service handling */
@@ -4953,16 +4997,11 @@ dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
if ( enip_info )
{
- preq_info = (cip_req_info_t*)enip_info->cip_info;
+ preq_info = enip_info->cip_info;
if ( preq_info == NULL )
{
preq_info = se_alloc( sizeof( cip_req_info_t ) );
- preq_info->bService = 0;
- preq_info->dissector = NULL;
- preq_info->IOILen = 0;
- preq_info->pIOI = NULL;
- preq_info->pData = NULL;
- preq_info->ciaData = NULL;
+ memset(preq_info, 0, sizeof(cip_req_info_t));
enip_info->cip_info = preq_info;
}
dissect_cip_data( tree, tvb, 0, pinfo, enip_info->cip_info );
diff --git a/epan/dissectors/packet-cip.h b/epan/dissectors/packet-cip.h
index bf289f393b..46502fb456 100644
--- a/epan/dissectors/packet-cip.h
+++ b/epan/dissectors/packet-cip.h
@@ -53,6 +53,12 @@
#define SC_INSERT_MEMBER 0x1A
#define SC_REMOVE_MEMBER 0x1B
#define SC_GROUP_SYNC 0x1C
+
+/* Classes that have class-specfic dissectors */
+#define CI_CLS_MR 0x02 /* Message Router */
+#define CI_CLS_CM 0x06 /* Connection Manager */
+#define CI_CLS_CCO 0xF3 /* Connection Configuration Object */
+
/* Class specific services */
/* Connection Manager */
#define SC_CM_FWD_CLOSE 0x4E
@@ -163,6 +169,12 @@
#define CI_NETWORK_SEG_SAFETY 0x10
#define CI_NETWORK_SEG_EXTENDED 0x1F
+#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
@@ -263,6 +275,33 @@ typedef struct attribute_info {
attribute_dissector_func* pdissect;
} attribute_info_t;
+typedef struct cip_connID_info {
+ guint32 connID;
+ guint32 ipaddress;
+ guint16 port;
+ guint8 type;
+} cip_connID_info_t;
+
+
+typedef struct cip_conn_info {
+ guint16 ConnSerialNumber;
+ guint16 VendorID;
+ guint32 DeviceSerialNumber;
+ cip_connID_info_t O2T;
+ cip_connID_info_t T2O;
+ guint8 TransportClass;
+} cip_conn_info_t;
+
+typedef struct cip_req_info {
+ dissector_handle_t dissector;
+ guint8 bService;
+ guint IOILen;
+ void *pIOI;
+ void *pData;
+ cip_simple_request_info_t* ciaData;
+ cip_conn_info_t* connInfo;
+} cip_req_info_t;
+
/*
** Exported functions
*/
@@ -271,6 +310,7 @@ extern void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_
/*
** Exported variables
*/
+extern dissector_table_t subdissector_class_table;
extern value_string_ext cip_gs_vals_ext;
extern value_string_ext cip_cm_ext_st_vals_ext;
extern value_string_ext cip_vendor_vals_ext;
diff --git a/epan/dissectors/packet-enip.c b/epan/dissectors/packet-enip.c
index bc16ea1781..65707d04db 100644
--- a/epan/dissectors/packet-enip.c
+++ b/epan/dissectors/packet-enip.c
@@ -131,9 +131,14 @@ static int hf_enip_cpf_itemcount = -1;
static int hf_enip_cpf_typeid = -1;
static int hf_enip_cpf_length = -1;
static int hf_enip_cpf_cdi_seqcnt = -1;
+static int hf_enip_cpf_cdi_32bitheader = -1;
+static int hf_enip_cpf_cdi_32bitheader_roo = -1;
+static int hf_enip_cpf_cdi_32bitheader_coo = -1;
+static int hf_enip_cpf_cdi_32bitheader_run_idle = -1;
static int hf_enip_cpf_cai_connid = -1;
static int hf_enip_cpf_sai_connid = -1;
static int hf_enip_cpf_sai_seqnum = -1;
+
static int hf_enip_cpf_data = -1;
static int hf_enip_response_in = -1;
@@ -238,6 +243,7 @@ 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_32bitheader_tree = -1;
static gint ett_lsrcf = -1;
static gint ett_tcpip_status = -1;
static gint ett_tcpip_config_cap = -1;
@@ -245,13 +251,14 @@ static gint ett_tcpip_config_control = -1;
static gint ett_elink_interface_flags = -1;
static gint ett_elink_icontrol_bits = -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 heur_dissector_list_t heur_subdissector_conndata_table;
static gboolean enip_desegment = TRUE;
+static gboolean enip_OTrun_idle = TRUE;
+static gboolean enip_TOrun_idle = FALSE;
static int proto_dlr = -1;
@@ -331,6 +338,14 @@ static const value_string cdf_type_vals[] = {
{ 0, NULL }
};
+/* Translate function to string - Run/Idle */
+static const value_string enip_run_idle_vals[] = {
+ { 0, "Idle" },
+ { 1, "Run" },
+
+ { 0, NULL }
+};
+
static const value_string enip_tcpip_status_interface_config_vals[] = {
{ 0, "Not configured" },
{ 1, "BOOTP/DHCP/NVS" },
@@ -475,14 +490,12 @@ static const value_string dlr_lnk_nbr_status_vals[] = {
static GHashTable *enip_request_hashtable = NULL;
/* Return codes of function classifying packets as query/response */
-#define ENIP_REQUEST_PACKET 0
-#define ENIP_RESPONSE_PACKET 1
-#define ENIP_CANNOT_CLASSIFY 2
-
+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 {
- gint requesttype;
+ enum enip_packet_type requesttype;
enum enip_packet_data_type type;
guint32 session_handle;
guint64 sender_context;
@@ -645,6 +658,7 @@ typedef struct enip_conn_val {
guint32 DeviceSerialNumber;
guint32 O2TConnID;
guint32 T2OConnID;
+ guint8 TransportClass;
guint32 openframe;
guint32 closeframe;
guint32 connid;
@@ -685,61 +699,130 @@ enip_conn_hash (gconstpointer v)
}
void
-enip_open_cip_connection(packet_info *pinfo, guint16 ConnSerialNumber,
- guint16 VendorID, guint32 DeviceSerialNumber,
- guint32 O2TConnID, guint32 T2OConnID )
+enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo)
{
enip_conn_key_t *conn_key;
enip_conn_val_t *conn_val;
- conversation_t *conversation;
+ conversation_t *conversation, *conversationTO;
enip_conv_info_t *enip_info;
+ address dest_address;
if (pinfo->fd->flags.visited)
return;
conn_key = se_alloc(sizeof(enip_conn_key_t));
- conn_key->ConnSerialNumber = ConnSerialNumber;
- conn_key->VendorID = VendorID;
- conn_key->DeviceSerialNumber = DeviceSerialNumber;
+ conn_key->ConnSerialNumber = connInfo->ConnSerialNumber;
+ conn_key->VendorID = connInfo->VendorID;
+ conn_key->DeviceSerialNumber = connInfo->DeviceSerialNumber;
conn_val = g_hash_table_lookup( enip_conn_hashtable, conn_key );
if ( conn_val == NULL )
{
conn_val = se_alloc(sizeof(enip_conn_val_t));
- conn_val->ConnSerialNumber = ConnSerialNumber;
- conn_val->VendorID = VendorID;
- conn_val->DeviceSerialNumber = DeviceSerialNumber;
- conn_val->O2TConnID = O2TConnID;
- conn_val->T2OConnID = T2OConnID;
+ conn_val->ConnSerialNumber = connInfo->ConnSerialNumber;
+ conn_val->VendorID = connInfo->VendorID;
+ conn_val->DeviceSerialNumber = connInfo->DeviceSerialNumber;
+ conn_val->O2TConnID = connInfo->O2T.connID;
+ conn_val->T2OConnID = connInfo->T2O.connID;
+ conn_val->TransportClass = connInfo->TransportClass;
conn_val->openframe = pinfo->fd->num;
conn_val->closeframe = 0;
conn_val->connid = enip_unique_connid++;
g_hash_table_insert(enip_conn_hashtable, conn_key, conn_val );
- conversation = find_or_create_conversation(pinfo);
+ /* I/O connection */
+ if ((connInfo->TransportClass == 0) ||
+ (connInfo->TransportClass == 1))
+ {
+ /* default some information if not included */
+ if ((connInfo->O2T.port == 0) || (connInfo->O2T.type == CONN_TYPE_MULTICAST))
+ connInfo->O2T.port = ENIP_IO_PORT;
+ if ((connInfo->O2T.ipaddress == 0) || (connInfo->O2T.type != CONN_TYPE_MULTICAST))
+ connInfo->O2T.ipaddress = *((guint32*)pinfo->src.data);
+ if ((connInfo->T2O.port == 0) || (connInfo->T2O.type == CONN_TYPE_MULTICAST))
+ connInfo->T2O.port = ENIP_IO_PORT;
+ if ((connInfo->T2O.ipaddress == 0) || (connInfo->T2O.type != CONN_TYPE_MULTICAST))
+ connInfo->T2O.ipaddress = *((guint32*)pinfo->dst.data);
+
+ dest_address.type = AT_IPv4;
+ dest_address.len = 4;
+ dest_address.data = &connInfo->O2T.ipaddress;
+
+ /* check for O->T conversation */
+ /* 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) {
+
+ conversation = conversation_new(pinfo->fd->num, &pinfo->dst,
+ &dest_address, PT_UDP,
+ connInfo->O2T.port, connInfo->O2T.port, 0);
+ }
+
+ enip_info = conversation_get_proto_data(conversation, proto_enip);
+ if (enip_info == NULL)
+ {
+ enip_info = se_alloc(sizeof(enip_conv_info_t));
+ enip_info->O2TConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_O2T");
+ enip_info->T2OConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_T2O");
- /*
- * Do we already have a state structure for this conv
- */
- enip_info = conversation_get_proto_data(conversation, proto_enip);
- if (!enip_info)
+ conversation_add_proto_data(conversation, proto_enip, enip_info);
+ }
+ se_tree_insert32(enip_info->O2TConnIDs, connInfo->O2T.connID, (void *)conn_val);
+
+ /* Check if separate T->O conversation is necessary. If either side is multicast
+ 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) {
+
+ conversationTO = conversation_new(pinfo->fd->num, &pinfo->src,
+ &dest_address, PT_UDP,
+ connInfo->T2O.port, connInfo->T2O.port, 0);
+ }
+
+ enip_info = conversation_get_proto_data(conversationTO, proto_enip);
+ if (enip_info == NULL)
+ {
+ enip_info = se_alloc(sizeof(enip_conv_info_t));
+ enip_info->O2TConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_O2T");
+ enip_info->T2OConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_T2O");
+ conversation_add_proto_data(conversationTO, proto_enip, enip_info);
+ }
+ se_tree_insert32(enip_info->T2OConnIDs, connInfo->T2O.connID, (void *)conn_val);
+ }
+ else
{
- /*
- * No. Attach that information to the conversation, and add
- * it to the list of information structures.
- */
- enip_info = se_alloc(sizeof(enip_conv_info_t));
- enip_info->O2TConnIDs = se_tree_create_non_persistent(
- EMEM_TREE_TYPE_RED_BLACK, "enip_O2T");
- enip_info->T2OConnIDs = se_tree_create_non_persistent(
- EMEM_TREE_TYPE_RED_BLACK, "enip_T2O");
-
- conversation_add_proto_data(conversation, proto_enip, enip_info);
+ /* explicit message connection */
+ conversation = find_or_create_conversation(pinfo);
+
+ /* Do we already have a state structure for this conv */
+ enip_info = conversation_get_proto_data(conversation, proto_enip);
+ if (!enip_info)
+ {
+ /*
+ * No. Attach that information to the conversation, and add
+ * it to the list of information structures.
+ */
+ enip_info = se_alloc(sizeof(enip_conv_info_t));
+ enip_info->O2TConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_O2T");
+ enip_info->T2OConnIDs = se_tree_create_non_persistent(
+ EMEM_TREE_TYPE_RED_BLACK, "enip_T2O");
+
+ conversation_add_proto_data(conversation, proto_enip, enip_info);
+ }
+ se_tree_insert32(enip_info->O2TConnIDs, connInfo->O2T.connID, (void *)conn_val);
+ se_tree_insert32(enip_info->T2OConnIDs, connInfo->T2O.connID, (void *)conn_val);
}
- se_tree_insert32(enip_info->O2TConnIDs, O2TConnID, (void *)conn_val);
- se_tree_insert32(enip_info->O2TConnIDs, T2OConnID, (void *)conn_val);
}
}
@@ -765,7 +848,7 @@ enip_close_cip_connection(packet_info *pinfo, guint16 ConnSerialNumber,
}
static guint32
-enip_get_connid(packet_info *pinfo, enip_request_key_t *prequest_key, guint32 connid)
+enip_get_explicit_connid(packet_info *pinfo, enip_request_key_t *prequest_key, guint32 connid)
{
conversation_t *conversation;
enip_conv_info_t *enip_info;
@@ -807,17 +890,65 @@ enip_get_connid(packet_info *pinfo, enip_request_key_t *prequest_key, guint32 co
if ( conn_val == NULL )
conn_val = se_tree_lookup32( enip_info->O2TConnIDs, connid );
break;
+ case ENIP_CANNOT_CLASSIFY:
+ /* ignore */
+ break;
}
- if ( conn_val == NULL )
- return 0;
-
- if ( conn_val->openframe > pinfo->fd->num )
+ if ((conn_val == NULL ) || (conn_val->openframe > pinfo->fd->num))
return 0;
return conn_val->connid;
}
+static enip_conn_val_t*
+enip_get_io_connid(packet_info *pinfo, guint32 connid, enum enip_connid_type* pconnid_type)
+{
+ conversation_t *conversation;
+ enip_conv_info_t *enip_info;
+ 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);
+
+ if (conversation == NULL)
+ return NULL;
+
+ /*
+ * Do we already have a state structure for this conv
+ */
+ if ((enip_info = conversation_get_proto_data(conversation, proto_enip)) == NULL)
+ return NULL;
+
+ if (enip_info->O2TConnIDs != NULL)
+ conn_val = se_tree_lookup32( enip_info->O2TConnIDs, connid );
+
+ if ( conn_val == NULL )
+ {
+ if (enip_info->T2OConnIDs != NULL)
+ {
+ if ((conn_val = se_tree_lookup32( enip_info->T2OConnIDs, connid)) != NULL)
+ *pconnid_type = ECIDT_T2O;
+ }
+ }
+ else
+ {
+ *pconnid_type = ECIDT_O2T;
+ }
+
+ if ((conn_val == NULL) || ( conn_val->openframe > pinfo->fd->num ))
+ return NULL;
+
+ return conn_val;
+}
+
+
int dissect_tcpip_status(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
int offset, int total_len)
@@ -1124,15 +1255,19 @@ enip_init_protocol(void)
/* Disssect Common Packet Format */
static void
dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
- packet_info *pinfo, proto_tree *tree, int offset, guint32 ifacehndl)
+ packet_info *pinfo, proto_tree *tree, proto_tree *dissector_tree, int offset, guint32 ifacehndl)
{
- proto_item *temp_item, *count_item, *type_item, *sockaddr_item;
- proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree;
- int item_count, item_length, item;
+ proto_item *temp_item, *count_item, *type_item, *sockaddr_item, *io_item;
+ proto_tree *temp_tree, *count_tree, *item_tree, *sockaddr_tree, *io_tree;
+ int item_count, item_length, item, io_length;
unsigned char name_length;
tvbuff_t *next_tvb;
enip_request_info_t *request_info;
-
+ enip_conn_val_t* conn_info = NULL;
+ gboolean FwdOpen = FALSE,
+ FwdOpenReply = FALSE;
+ enum enip_connid_type connid_type = ECIDT_UNKNOWN;
+
/* Create item count tree */
item_count = tvb_get_letohs( tvb, offset );
count_item = proto_tree_add_item( tree, hf_enip_cpf_itemcount, tvb, offset, 2, ENC_LITTLE_ENDIAN );
@@ -1161,7 +1296,7 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
if ( request_key )
{
request_key->type = EPDT_CONNECTED_TRANSPORT;
- request_key->data.connected_transport.connid = enip_get_connid( pinfo, request_key, tvb_get_letohl( tvb, offset+6 ) );
+ request_key->data.connected_transport.connid = enip_get_explicit_connid( pinfo, request_key, tvb_get_letohl( tvb, offset+6 ) );
}
/* Add Connection identifier */
proto_tree_add_item(item_tree, hf_enip_cpf_cai_connid, tvb, offset+6, 4, ENC_LITTLE_ENDIAN );
@@ -1187,14 +1322,35 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
/* Call dissector for interface */
next_tvb = tvb_new_subset( tvb, offset+6, item_length, item_length );
p_add_proto_data(pinfo->fd, proto_enip, request_info);
- if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_uint(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, g_tree) )
+ if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_uint(subdissector_srrd_table, ifacehndl, next_tvb, pinfo, dissector_tree) )
{
/* Show the undissected payload */
if( tvb_length_remaining(tvb, offset) > 0 )
- call_dissector( data_handle, next_tvb, pinfo, g_tree );
+ call_dissector( data_handle, next_tvb, pinfo, dissector_tree);
}
- p_remove_proto_data(pinfo->fd, proto_enip);
+ /* Check if this is a ForwardOpen packet, because special handling is needed
+ to handle connection conversations */
+ if ((request_info != NULL) && (request_info->cip_info != NULL) &&
+ (request_info->cip_info->connInfo != NULL) &&
+ (request_key != NULL) &&
+ (((request_info->cip_info->bService & 0x7F) == SC_CM_FWD_OPEN) ||
+ ((request_info->cip_info->bService & 0x7F) == SC_CM_LARGE_FWD_OPEN))&&
+ (request_info->cip_info->dissector == dissector_get_uint_handle( subdissector_class_table, CI_CLS_CM)))
+ {
+ if (request_key->requesttype == ENIP_REQUEST_PACKET)
+ {
+ FwdOpen = TRUE;
+ }
+ else
+ {
+ FwdOpenReply = TRUE;
+ }
+ }
+ else
+ {
+ p_remove_proto_data(pinfo->fd, proto_enip);
+ }
break;
case CONNECTION_TRANSPORT:
@@ -1221,11 +1377,11 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
/* Call dissector for interface */
next_tvb = tvb_new_subset (tvb, offset+8, item_length-2, item_length-2);
p_add_proto_data(pinfo->fd, proto_enip, request_info);
- if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_uint(subdissector_sud_table, ifacehndl, next_tvb, pinfo, g_tree) )
+ if( tvb_length_remaining(next_tvb, 0) == 0 || !dissector_try_uint(subdissector_sud_table, ifacehndl, next_tvb, pinfo, dissector_tree) )
{
/* Show the undissected payload */
if( tvb_length_remaining(tvb, offset) > 0 )
- call_dissector( data_handle, next_tvb, pinfo, g_tree );
+ call_dissector( data_handle, next_tvb, pinfo, dissector_tree );
}
p_remove_proto_data(pinfo->fd, proto_enip);
}
@@ -1235,9 +1391,35 @@ 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);
- if(!dissector_try_heuristic(heur_subdissector_conndata_table, next_tvb, pinfo, g_tree))
+ if(!dissector_try_heuristic(heur_subdissector_conndata_table, next_tvb, pinfo, dissector_tree))
{
- proto_tree_add_item(item_tree, hf_enip_connection_transport_data, tvb, offset+6, item_length, ENC_NA);
+ if (conn_info == NULL)
+ {
+ proto_tree_add_item(item_tree, hf_enip_connection_transport_data, tvb, offset+6, item_length, ENC_NA);
+ }
+ else
+ {
+ io_length = item_length;
+
+ if (conn_info->TransportClass == 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;
+ }
+
+ if (((connid_type == ECIDT_O2T) && enip_OTrun_idle) ||
+ ((connid_type == ECIDT_T2O) && enip_TOrun_idle))
+ {
+ io_item = proto_tree_add_item( item_tree, hf_enip_cpf_cdi_32bitheader, tvb, offset+6+(item_length-io_length), 4, ENC_LITTLE_ENDIAN );
+ io_tree = proto_item_add_subtree( io_item, ett_32bitheader_tree );
+ proto_tree_add_item(io_tree, hf_enip_cpf_cdi_32bitheader_roo, tvb, offset+6+(item_length-io_length), 4, ENC_LITTLE_ENDIAN );
+ proto_tree_add_item(io_tree, hf_enip_cpf_cdi_32bitheader_coo, tvb, offset+6+(item_length-io_length), 4, ENC_LITTLE_ENDIAN );
+ proto_tree_add_item(io_tree, hf_enip_cpf_cdi_32bitheader_run_idle, tvb, offset+6+(item_length-io_length), 4, ENC_LITTLE_ENDIAN );
+ io_length -= 4;
+ }
+
+ proto_tree_add_item(item_tree, hf_enip_connection_transport_data, tvb, offset+6+(item_length-io_length), io_length, ENC_NA);
+ }
}
}
} /* End of if send unit data */
@@ -1334,18 +1516,33 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
/* Socket address struct - sin_zero */
proto_tree_add_item( item_tree, hf_enip_sinzero,
tvb, offset+14, 8, ENC_NA );
+
+ if ((FwdOpen == TRUE) || (FwdOpenReply == TRUE))
+ {
+ request_info = p_get_proto_data(pinfo->fd, proto_enip);
+ if (request_info != NULL)
+ {
+ if (item == SOCK_ADR_INFO_OT)
+ {
+ request_info->cip_info->connInfo->O2T.port = tvb_get_ntohs(tvb, offset+8);
+ request_info->cip_info->connInfo->O2T.ipaddress = tvb_get_ipv4(tvb, offset+10);
+ }
+ else
+ {
+ request_info->cip_info->connInfo->T2O.port = tvb_get_ntohs(tvb, offset+8);
+ request_info->cip_info->connInfo->T2O.ipaddress = tvb_get_ipv4(tvb, offset+10);
+ }
+ }
+ }
break;
case SEQ_ADDRESS:
- proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid,
- tvb, offset+6, 4, ENC_LITTLE_ENDIAN );
-
- proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum,
- tvb, offset+10, 4, ENC_LITTLE_ENDIAN );
+ conn_info = enip_get_io_connid( pinfo, tvb_get_letohl( tvb, offset+6 ), &connid_type);
+ proto_tree_add_item(item_tree, hf_enip_cpf_sai_connid, tvb, offset+6, 4, ENC_LITTLE_ENDIAN );
+ proto_tree_add_item(item_tree, hf_enip_cpf_sai_seqnum, tvb, offset+10, 4, ENC_LITTLE_ENDIAN );
/* Add info to column */
-
if(check_col(pinfo->cinfo, COL_INFO))
{
col_clear(pinfo->cinfo, COL_INFO);
@@ -1396,6 +1593,21 @@ dissect_cpf(enip_request_key_t *request_key, int command, tvbuff_t *tvb,
} /* end of while( item count ) */
+ /* See if there is a CIP connection to establish */
+ if (FwdOpenReply == TRUE)
+ {
+ request_info = p_get_proto_data(pinfo->fd, proto_enip);
+ if (request_info != NULL)
+ {
+ enip_open_cip_connection(pinfo, request_info->cip_info->connInfo);
+ }
+ p_remove_proto_data(pinfo->fd, proto_enip);
+ }
+ else if (FwdOpen == TRUE)
+ {
+ p_remove_proto_data(pinfo->fd, proto_enip);
+ }
+
} /* end of dissect_cpf() */
@@ -1468,6 +1680,7 @@ dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
pkt_type_str="Rsp";
break;
+ case ENIP_CANNOT_CLASSIFY:
default:
pkt_type_str="?";
}
@@ -1562,15 +1775,15 @@ dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
break;
case LIST_SERVICES:
- dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, 24, 0 );
+ dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, tree, 24, 0 );
break;
case LIST_IDENTITY:
- dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, 24, 0 );
+ dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, tree, 24, 0 );
break;
case LIST_INTERFACES:
- dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, 24, 0 );
+ dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, tree, 24, 0 );
break;
case REGISTER_SESSION:
@@ -1586,7 +1799,7 @@ dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_item( csftree, hf_enip_timeout, tvb, 28, 2, ENC_LITTLE_ENDIAN );
ifacehndl = tvb_get_letohl( tvb, 24 );
- dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
+ dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, tree, 30, ifacehndl );
break;
case SEND_UNIT_DATA:
@@ -1594,7 +1807,7 @@ dissect_enip_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_tree_add_item( csftree, hf_enip_timeout, tvb, 28, 2, ENC_LITTLE_ENDIAN );
ifacehndl = tvb_get_letohl( tvb, 24 );
- dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, 30, ifacehndl );
+ dissect_cpf( &request_key, encap_cmd, tvb, pinfo, csftree, tree, 30, ifacehndl );
break;
case INDICATE_STATUS:
@@ -1615,8 +1828,6 @@ 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;
@@ -1635,8 +1846,6 @@ 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;
@@ -1646,8 +1855,7 @@ dissect_enip_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, enip_desegment, 4,
- get_enip_pdu_len, dissect_enip_pdu);
+ tcp_dissect_pdus(tvb, pinfo, tree, enip_desegment, 4, get_enip_pdu_len, dissect_enip_pdu);
return tvb_length(tvb);
}
@@ -1659,8 +1867,6 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
proto_item *ti;
proto_tree *enip_tree;
- g_tree = tree;
-
/* Make entries in Protocol column and Info column on summary display */
col_set_str(pinfo->cinfo, COL_PROTOCOL, "ENIP");
@@ -1673,7 +1879,7 @@ dissect_enipio(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
enip_tree = proto_item_add_subtree(ti, ett_enip);
- dissect_cpf( NULL, 0xFFFF, tvb, pinfo, enip_tree, 0, 0 );
+ dissect_cpf( NULL, 0xFFFF, tvb, pinfo, enip_tree, tree, 0, 0 );
}
} /* end of dissect_enipio() */
@@ -1809,227 +2015,62 @@ proto_register_enip(void)
{
/* Setup list of header fields */
static hf_register_info hf[] = {
- { &hf_enip_command,
- { "Command", "enip.command",
- FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0,
- "Encapsulation command", HFILL }
- },
- { &hf_enip_length,
- { "Length", "enip.length",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Encapsulation length", HFILL }
- },
- { &hf_enip_session,
- { "Session Handle", "enip.session",
- FT_UINT32, BASE_HEX, NULL, 0,
- "Session identification", HFILL }
- },
- { &hf_enip_status,
- { "Status", "enip.status",
- FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0,
- "Status code", HFILL }
- },
- { &hf_enip_sendercontex,
- { "Sender Context", "enip.context",
- FT_BYTES, BASE_NONE, NULL, 0,
- "Information pertient to the sender", HFILL }
- },
- { &hf_enip_options,
- { "Options", "enip.options",
- FT_UINT32, BASE_HEX, NULL, 0,
- "Options flags", HFILL }
- },
- { &hf_enip_encapver,
- { "Encapsulation Version", "enip.encapver",
- FT_UINT16, BASE_DEC, NULL, 0,
- NULL, HFILL }
- },
- { &hf_enip_sinfamily,
- { "sin_family", "enip.sinfamily",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Socket Address.Sin Family", HFILL }
- },
- { &hf_enip_sinport,
- { "sin_port", "enip.sinport",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Socket Address.Sin Port", HFILL }
- },
- { &hf_enip_sinaddr,
- { "sin_addr", "enip.sinaddr",
- FT_IPv4, BASE_NONE, NULL, 0,
- "Socket Address.Sin Addr", HFILL }
- },
- { &hf_enip_sinzero,
- { "sin_zero", "enip.sinzero",
- FT_BYTES, BASE_NONE, NULL, 0,
- "Socket Address.Sin Zero", HFILL }
- },
- { &hf_enip_timeout,
- { "Timeout", "enip.timeout",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Encapsulation Timeout", HFILL }
- },
- { &hf_enip_encap_data,
- { "Encap Data", "enip.encap_data",
- FT_BYTES, BASE_NONE, NULL, 0,
- "Encapsulation Data", HFILL }
- },
+ { &hf_enip_command, { "Command", "enip.command", FT_UINT16, BASE_HEX, VALS(encap_cmd_vals), 0, "Encapsulation command", HFILL }},
+ { &hf_enip_length, { "Length", "enip.length", FT_UINT16, BASE_DEC, NULL, 0, "Encapsulation length", HFILL }},
+ { &hf_enip_session, { "Session Handle", "enip.session", FT_UINT32, BASE_HEX, NULL, 0, "Session identification", HFILL }},
+ { &hf_enip_status, { "Status", "enip.status", FT_UINT32, BASE_HEX, VALS(encap_status_vals), 0, "Status code", HFILL }},
+ { &hf_enip_sendercontex, { "Sender Context", "enip.context", FT_BYTES, BASE_NONE, NULL, 0, "Information pertient to the sender", HFILL }},
+ { &hf_enip_options, { "Options", "enip.options", FT_UINT32, BASE_HEX, NULL, 0, "Options flags", HFILL }},
+ { &hf_enip_encapver, { "Encapsulation Version", "enip.encapver", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
+ { &hf_enip_sinfamily, { "sin_family", "enip.sinfamily", FT_UINT16, BASE_DEC, NULL, 0, "Socket Address.Sin Family", HFILL }},
+ { &hf_enip_sinport, { "sin_port", "enip.sinport", FT_UINT16, BASE_DEC, NULL, 0, "Socket Address.Sin Port", HFILL }},
+ { &hf_enip_sinaddr, { "sin_addr", "enip.sinaddr", FT_IPv4, BASE_NONE, NULL, 0, "Socket Address.Sin Addr", HFILL }},
+ { &hf_enip_sinzero, { "sin_zero", "enip.sinzero", FT_BYTES, BASE_NONE, NULL, 0, "Socket Address.Sin Zero", HFILL }},
+ { &hf_enip_timeout, { "Timeout", "enip.timeout", FT_UINT16, BASE_DEC, NULL, 0, "Encapsulation Timeout", HFILL }},
+ { &hf_enip_encap_data, { "Encap Data", "enip.encap_data", FT_BYTES, BASE_NONE, NULL, 0, "Encapsulation Data", HFILL }},
/* List Services Reply */
- { &hf_enip_lsr_capaflags,
- { "Capability Flags", "enip.lsr.capaflags",
- FT_UINT16, BASE_HEX, NULL, 0,
- "ListServices Reply: Capability Flags", HFILL }
- },
- { &hf_enip_lsr_tcp,
- { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp",
- FT_UINT16, BASE_DEC, TFS(&tfs_true_false), 0x0020,
- "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }
- },
- { &hf_enip_lsr_udp,
- { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp",
- FT_UINT16, BASE_DEC, TFS(&tfs_true_false), 0x0100,
- "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }
- },
- { &hf_enip_lsr_servicename,
- { "Name of Service", "enip.lsr.servicename",
- FT_STRING, BASE_NONE, NULL, 0,
- "ListServices Reply: Name of Service", HFILL }
- },
+ { &hf_enip_lsr_capaflags, { "Capability Flags", "enip.lsr.capaflags", FT_UINT16, BASE_HEX, NULL, 0, "ListServices Reply: Capability Flags", HFILL }},
+ { &hf_enip_lsr_tcp, { "Supports CIP Encapsulation via TCP", "enip.lsr.capaflags.tcp", FT_UINT16, BASE_DEC, TFS(&tfs_true_false), 0x0020, "ListServices Reply: Supports CIP Encapsulation via TCP", HFILL }},
+ { &hf_enip_lsr_udp, { "Supports CIP Class 0 or 1 via UDP", "enip.lsr.capaflags.udp", FT_UINT16, BASE_DEC, TFS(&tfs_true_false), 0x0100, "ListServices Reply: Supports CIP Class 0 or 1 via UDP", HFILL }},
+ { &hf_enip_lsr_servicename, { "Name of Service", "enip.lsr.servicename", FT_STRING, BASE_NONE, NULL, 0, "ListServices Reply: Name of Service", HFILL }},
/* Register Session */
- { &hf_enip_rs_version,
- { "Protocol Version", "enip.rs.version",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Register Session: Protocol Version", HFILL }
- },
- { &hf_enip_rs_optionflags,
- { "Option Flags", "enip.rs.flags",
- FT_UINT16, BASE_HEX, NULL, 0,
- "Register Session: Option Flags", HFILL }
- },
+ { &hf_enip_rs_version, { "Protocol Version", "enip.rs.version", FT_UINT16, BASE_DEC, NULL, 0, "Register Session: Protocol Version", HFILL }},
+ { &hf_enip_rs_optionflags, { "Option Flags", "enip.rs.flags", FT_UINT16, BASE_HEX, NULL, 0, "Register Session: Option Flags", 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 }
- },
+ { &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 }
- },
+ { &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_vendor,
- { "Vendor ID", "enip.lir.vendor",
- FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0,
- "ListIdentity Reply: Vendor ID", HFILL }
- },
- { &hf_enip_lir_devtype,
- { "Device Type", "enip.lir.devtype",
- FT_UINT16, BASE_DEC|BASE_EXT_STRING, &cip_devtype_vals_ext, 0,
- "ListIdentity Reply: Device Type", HFILL }
- },
- { &hf_enip_lir_prodcode,
- { "Product Code", "enip.lir.prodcode",
- FT_UINT16, BASE_DEC, NULL, 0,
- "ListIdentity Reply: Product Code", HFILL }
- },
- { &hf_enip_lir_revision,
- { "Revision", "enip.lir.revision",
- FT_UINT16, BASE_CUSTOM, enip_fmt_lir_revision, 0,
- "ListIdentity Reply: Revision", HFILL }
- },
- { &hf_enip_lir_status,
- { "Status", "enip.lir.status",
- FT_UINT16, BASE_HEX, NULL, 0,
- "ListIdentity Reply: Status", HFILL }
- },
- { &hf_enip_lir_serial,
- { "Serial Number", "enip.lir.serial",
- FT_UINT32, BASE_HEX, NULL, 0,
- "ListIdentity Reply: Serial Number", HFILL }
- },
- { &hf_enip_lir_namelen,
- { "Product Name Length", "enip.lir.namelen",
- FT_UINT8, BASE_DEC, NULL, 0,
- "ListIdentity Reply: Product Name Length", HFILL }
- },
- { &hf_enip_lir_name,
- { "Product Name", "enip.lir.name",
- FT_STRING, BASE_NONE, NULL, 0,
- "ListIdentity Reply: Product Name", HFILL }
- },
- { &hf_enip_lir_state,
- { "State", "enip.lir.state",
- FT_UINT8, BASE_HEX, NULL, 0,
- "ListIdentity Reply: State", HFILL }
- },
+ { &hf_enip_lir_vendor, { "Vendor ID", "enip.lir.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, "ListIdentity Reply: Vendor ID", HFILL }},
+ { &hf_enip_lir_devtype, { "Device Type", "enip.lir.devtype", FT_UINT16, BASE_DEC|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, "ListIdentity Reply: Device Type", HFILL }},
+ { &hf_enip_lir_prodcode, { "Product Code", "enip.lir.prodcode", FT_UINT16, BASE_DEC, NULL, 0, "ListIdentity Reply: Product Code", HFILL }},
+ { &hf_enip_lir_revision, { "Revision", "enip.lir.revision", FT_UINT16, BASE_CUSTOM, enip_fmt_lir_revision, 0, "ListIdentity Reply: Revision", HFILL }},
+ { &hf_enip_lir_status, { "Status", "enip.lir.status", FT_UINT16, BASE_HEX, NULL, 0, "ListIdentity Reply: Status", HFILL }},
+ { &hf_enip_lir_serial, { "Serial Number", "enip.lir.serial", FT_UINT32, BASE_HEX, NULL, 0, "ListIdentity Reply: Serial Number", HFILL }},
+ { &hf_enip_lir_namelen, { "Product Name Length", "enip.lir.namelen", FT_UINT8, BASE_DEC, NULL, 0, "ListIdentity Reply: Product Name Length", HFILL }},
+ { &hf_enip_lir_name, { "Product Name", "enip.lir.name", FT_STRING, BASE_NONE, NULL, 0, "ListIdentity Reply: Product Name", HFILL }},
+ { &hf_enip_lir_state, { "State", "enip.lir.state", FT_UINT8, BASE_HEX, NULL, 0, "ListIdentity Reply: State", HFILL }},
/* Common Packet Format */
- { &hf_enip_cpf_itemcount,
- { "Item Count", "enip.cpf.itemcount",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Common Packet Format: Item Count", HFILL }
- },
- { &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 }
- },
- { &hf_enip_cpf_length,
- { "Length", "enip.cpf.length",
- FT_UINT16, BASE_DEC, NULL, 0,
- "Common Packet Format: Length", HFILL }
- },
+ { &hf_enip_cpf_itemcount, { "Item Count", "enip.cpf.itemcount", FT_UINT16, BASE_DEC, NULL, 0, "Common Packet Format: Item Count", HFILL }},
+ { &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 }},
+ { &hf_enip_cpf_length, { "Length", "enip.cpf.length", FT_UINT16, BASE_DEC, NULL, 0, "Common Packet Format: Length", HFILL }},
/* Connected Data Item */
- { &hf_enip_cpf_cdi_seqcnt,
- { "Connection ID", "enip.cpf.cdi.seqcnt",
- FT_UINT16, BASE_HEX, NULL, 0,
- "Common Packet Format: Connected Data Item, Sequence Count", HFILL }
- },
+ { &hf_enip_cpf_cdi_seqcnt, { "Sequence Count", "enip.cpf.cdi.seqcnt", FT_UINT16, BASE_HEX, NULL, 0, "Common Packet Format: Connected Data Item, Sequence Count", HFILL }},
+ { &hf_enip_cpf_cdi_32bitheader, { "32-bit Header", "enip.cpf.cdi.32bitheader", FT_UINT32, BASE_HEX, NULL, 0, "Common Packet Format: Connected Data Item, 32-bit Header", HFILL }},
+ { &hf_enip_cpf_cdi_32bitheader_roo, { "ROO", "enip.cpf.cdi.roo", FT_UINT32, BASE_HEX, NULL, 0xC, "Common Packet Format: Connected Data Item, Ready for Ownership of Outputs", HFILL }},
+ { &hf_enip_cpf_cdi_32bitheader_coo, { "COO", "enip.cpf.cdi.coo", FT_UINT32, BASE_HEX, NULL, 0x2, "Common Packet Format: Connected Data Item, Claim Output Ownership", HFILL }},
+ { &hf_enip_cpf_cdi_32bitheader_run_idle, { "Run/Idle", "enip.cpf.cdi.run_idle", FT_UINT32, BASE_HEX, VALS(enip_run_idle_vals), 0x1, "Common Packet Format: Connected Data Item, Run/Idle", HFILL }},
/* Connection Address Item */
- { &hf_enip_cpf_cai_connid,
- { "Connection ID", "enip.cpf.cai.connid",
- FT_UINT32, BASE_HEX, NULL, 0,
- "Common Packet Format: Connection Address Item, Connection Identifier", HFILL }
- },
+ { &hf_enip_cpf_cai_connid, { "Connection ID", "enip.cpf.cai.connid", FT_UINT32, BASE_HEX, NULL, 0, "Common Packet Format: Connection Address Item, Connection Identifier", HFILL }},
/* Sequenced Address Type */
- { &hf_enip_cpf_sai_connid,
- { "Connection ID", "enip.cpf.sai.connid",
- FT_UINT32, BASE_HEX, NULL, 0,
- "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }
- },
- { &hf_enip_cpf_sai_seqnum,
- { "Sequence Number", "enip.cpf.sai.seq",
- FT_UINT32, BASE_DEC, NULL, 0,
- "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }
- },
- { &hf_enip_cpf_data,
- { "Data", "enip.cpf.data",
- FT_BYTES, BASE_NONE, NULL, 0,
- "Common Packet Format: Unknown Data", HFILL }
- },
-
+ { &hf_enip_cpf_sai_connid, { "Connection ID", "enip.cpf.sai.connid", FT_UINT32, BASE_HEX, NULL, 0, "Common Packet Format: Sequenced Address Item, Connection Identifier", HFILL }},
+ { &hf_enip_cpf_sai_seqnum, { "Sequence Number", "enip.cpf.sai.seq", FT_UINT32, BASE_DEC, NULL, 0, "Common Packet Format: Sequenced Address Item, Sequence Number", HFILL }},
+ { &hf_enip_cpf_data, { "Data", "enip.cpf.data", FT_BYTES, BASE_NONE, NULL, 0, "Common Packet Format: Unknown Data", HFILL }},
/* Request/Response Matching */
- { &hf_enip_response_in,
- { "Response In", "enip.response_in",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "The response to this ENIP request is in this frame", HFILL }
- },
- { &hf_enip_response_to,
- { "Request In", "enip.response_to",
- FT_FRAMENUM, BASE_NONE, NULL, 0x0,
- "This is a response to the ENIP request in this frame", HFILL }
- },
- { &hf_enip_time,
- { "Time", "enip.time",
- FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,
- "The time between the Call and the Reply", HFILL }
- },
- { &hf_enip_connection_transport_data,
- { "Data", "enip.connection_transport_data",
- FT_BYTES, BASE_NONE, NULL, 0x0,
- "Connection Transport Data", HFILL }
- },
+ { &hf_enip_response_in, { "Response In", "enip.response_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The response to this ENIP request is in this frame", HFILL }},
+ { &hf_enip_response_to, { "Request In", "enip.response_to", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "This is a response to the ENIP request in this frame", HFILL }},
+ { &hf_enip_time, { "Time", "enip.time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0,"The time between the Call and the Reply", HFILL }},
+ { &hf_enip_connection_transport_data, { "Data", "enip.connection_transport_data", FT_BYTES, BASE_NONE, NULL, 0x0, "Connection Transport Data", HFILL }},
{ &hf_tcpip_status, { "Status", "cip.tcpip.status", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
{ &hf_tcpip_status_interface_config, { "Interface Configuration Status", "cip.tcpip.status.interface_config", FT_UINT32, BASE_DEC, enip_tcpip_status_interface_config_vals, 0x0000000F, NULL, HFILL }},
@@ -2131,6 +2172,7 @@ proto_register_enip(void)
&ett_type_tree,
&ett_command_tree,
&ett_sockadd,
+ &ett_32bitheader_tree,
&ett_lsrcf,
&ett_tcpip_status,
&ett_tcpip_config_cap,
@@ -2296,6 +2338,16 @@ proto_register_enip(void)
"Whether the EtherNet/IP dissector should desegment all messages spanning multiple TCP segments",
&enip_desegment);
+ prefs_register_bool_preference(enip_module, "o2t_run_idle",
+ "Dissect 32-bit header in the O->T direction",
+ "Determines whether all I/O connections will assume a 32-bit header in the O->T direction",
+ &enip_OTrun_idle);
+
+ prefs_register_bool_preference(enip_module, "t2o_run_idle",
+ "Dissect 32-bit header in the T->O direction",
+ "Determines whether all I/O connections will assume a 32-bit header in the T->O direction",
+ &enip_TOrun_idle);
+
subdissector_sud_table = register_dissector_table("enip.sud.iface",
"SendUnitData.Interface Handle", FT_UINT32, BASE_HEX);
diff --git a/epan/dissectors/packet-enip.h b/epan/dissectors/packet-enip.h
index 1d41d667a8..40354e1976 100644
--- a/epan/dissectors/packet-enip.h
+++ b/epan/dissectors/packet-enip.h
@@ -81,13 +81,10 @@
typedef struct {
guint32 req_num, rep_num;
nstime_t req_time;
- void *cip_info;
+ cip_req_info_t* cip_info;
} enip_request_info_t;
-void enip_open_cip_connection( packet_info *pinfo,
- guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber,
- guint32 O2TConnID, guint32 T2OConnID );
-void enip_close_cip_connection( packet_info *pinfo,
- guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber );
+void enip_open_cip_connection( packet_info *pinfo, cip_conn_info_t* connInfo);
+void enip_close_cip_connection( packet_info *pinfo, guint16 ConnSerialNumber, guint16 VendorID, guint32 DeviceSerialNumber );
extern attribute_info_t enip_attribute_vals[29];