From Michael Mann via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=6697
Modbus object support for CIP dissector Support for the Modbus object within the CIP dissector. Essentially wraps the Modbus protocol within a CIP object. Also included update to Modbus error code per http://www.wireshark.org/lists/wireshark-dev/201111/msg00187.html svn path=/trunk/; revision=40371
This commit is contained in:
parent
c3c5e75678
commit
00dd4b455e
|
@ -13,7 +13,7 @@
|
|||
* Jan Bartels, Siempelkamp Maschinen- und Anlagenbau GmbH & Co. KG
|
||||
* Copyright 2007
|
||||
*
|
||||
* Improved support for CoCo and CM objects
|
||||
* Improved support for CoCo, CM, MB objects
|
||||
* Heuristic object support for common services
|
||||
* Michael Mann * Copyright 2011
|
||||
*
|
||||
|
@ -48,6 +48,7 @@
|
|||
#include <epan/expert.h>
|
||||
#include "packet-cip.h"
|
||||
#include "packet-enip.h"
|
||||
#include "packet-mbtcp.h"
|
||||
|
||||
#define ENIP_CIP_INTERFACE 0
|
||||
|
||||
|
@ -60,6 +61,8 @@ typedef struct mr_mult_req_info {
|
|||
static dissector_handle_t cip_handle;
|
||||
static dissector_handle_t cip_class_generic_handle;
|
||||
static dissector_handle_t cip_class_cm_handle;
|
||||
static dissector_handle_t cip_class_mb_handle;
|
||||
static dissector_handle_t modbus_handle;
|
||||
static dissector_handle_t cip_class_cco_handle;
|
||||
static heur_dissector_list_t heur_subdissector_service;
|
||||
|
||||
|
@ -67,8 +70,10 @@ static heur_dissector_list_t heur_subdissector_service;
|
|||
static int proto_cip = -1;
|
||||
static int proto_cip_class_generic = -1;
|
||||
static int proto_cip_class_cm = -1;
|
||||
static int proto_cip_class_mb = -1;
|
||||
static int proto_cip_class_cco = -1;
|
||||
static int proto_enip = -1;
|
||||
static int proto_modbus = -1;
|
||||
|
||||
static int hf_cip_data = -1;
|
||||
static int hf_cip_service = -1;
|
||||
|
@ -135,6 +140,28 @@ static int hf_cip_cm_ext126_size = -1;
|
|||
static int hf_cip_cm_ext127_size = -1;
|
||||
static int hf_cip_cm_ext128_size = -1;
|
||||
|
||||
static int hf_cip_mb_sc = -1;
|
||||
static int hf_cip_mb_read_coils_start_addr = -1;
|
||||
static int hf_cip_mb_read_coils_num_coils = -1;
|
||||
static int hf_cip_mb_read_coils_data = -1;
|
||||
static int hf_cip_mb_read_discrete_inputs_start_addr = -1;
|
||||
static int hf_cip_mb_read_discrete_inputs_num_inputs = -1;
|
||||
static int hf_cip_mb_read_discrete_inputs_data = -1;
|
||||
static int hf_cip_mb_read_holding_register_start_addr = -1;
|
||||
static int hf_cip_mb_read_holding_register_num_registers = -1;
|
||||
static int hf_cip_mb_read_holding_register_data = -1;
|
||||
static int hf_cip_mb_read_input_register_start_addr = -1;
|
||||
static int hf_cip_mb_read_input_register_num_registers = -1;
|
||||
static int hf_cip_mb_read_input_register_data = -1;
|
||||
static int hf_cip_mb_write_coils_start_addr = -1;
|
||||
static int hf_cip_mb_write_coils_outputs_forced = -1;
|
||||
static int hf_cip_mb_write_coils_num_coils = -1;
|
||||
static int hf_cip_mb_write_coils_data = -1;
|
||||
static int hf_cip_mb_write_registers_start_addr = -1;
|
||||
static int hf_cip_mb_write_registers_outputs_forced = -1;
|
||||
static int hf_cip_mb_write_registers_num_registers = -1;
|
||||
static int hf_cip_mb_write_registers_data = -1;
|
||||
static int hf_cip_mb_data = -1;
|
||||
|
||||
static int hf_cip_cco_con_type = -1;
|
||||
static int hf_cip_cco_ot_rtf = -1;
|
||||
|
@ -307,6 +334,7 @@ static int hf_conn_mgr_conn_timouts = -1;
|
|||
static gint ett_cip = -1;
|
||||
static gint ett_cip_class_generic = -1;
|
||||
static gint ett_cip_class_cm = -1;
|
||||
static gint ett_cip_class_mb = -1;
|
||||
static gint ett_cip_class_cco = -1;
|
||||
|
||||
static gint ett_path = -1;
|
||||
|
@ -337,6 +365,9 @@ static gint ett_cm_cmd_data = -1;
|
|||
static gint ett_cm_ttt = -1;
|
||||
static gint ett_cm_add_status_item = -1;
|
||||
|
||||
static gint ett_mb_rrsc = -1;
|
||||
static gint ett_mb_cmd_data = -1;
|
||||
|
||||
static gint ett_cco_iomap = -1;
|
||||
static gint ett_cco_con_status = -1;
|
||||
static gint ett_cco_con_flag = -1;
|
||||
|
@ -371,6 +402,22 @@ static const value_string cip_sc_vals_cm[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Translate function to string - CIP Service codes for MB */
|
||||
static const value_string cip_sc_vals_mb[] = {
|
||||
GENERIC_SC_LIST
|
||||
|
||||
/* Some class specific services */
|
||||
{ SC_MB_READ_DISCRETE_INPUTS, "Read Discrete" },
|
||||
{ SC_MB_READ_COILS, "Read Coils" },
|
||||
{ SC_MB_READ_INPUT_REGISTERS, "Read Input Registers" },
|
||||
{ SC_MB_READ_HOLDING_REGISTERS, "Read Holding Registers" },
|
||||
{ SC_MB_WRITE_COILS, "Write Coils" },
|
||||
{ SC_MB_WRITE_HOLDING_REGISTERS, "Write Holding Registers" },
|
||||
{ SC_MB_PASSTHROUGH, "Modbus Passthrough" },
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Translate function to string - CIP Service codes for CCO */
|
||||
static const value_string cip_sc_vals_cco[] = {
|
||||
GENERIC_SC_LIST
|
||||
|
@ -389,7 +436,7 @@ static const value_string cip_sc_vals_cco[] = {
|
|||
};
|
||||
|
||||
/* Translate function to string - CIP Request/Response */
|
||||
static const value_string cip_sc_rr[] = {
|
||||
const value_string cip_sc_rr[3] = {
|
||||
{ 0, "Request" },
|
||||
{ 1, "Response" },
|
||||
|
||||
|
@ -404,7 +451,7 @@ static const value_string cip_com_bit_vals[] = {
|
|||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static const value_string cip_reset_type_vals[] = {
|
||||
const value_string cip_reset_type_vals[4] = {
|
||||
{ 0, "Cycle Power" },
|
||||
{ 1, "Factory Default" },
|
||||
{ 2, "Keep Communication Parameters" },
|
||||
|
@ -2913,14 +2960,18 @@ dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tv
|
|||
proto_tree_add_item(tree, *(attr->phf), tvb, offset, 2, ENC_LITTLE_ENDIAN);
|
||||
consumed = 2;
|
||||
break;
|
||||
case cip_usint_array:
|
||||
case cip_byte_array:
|
||||
proto_tree_add_item(tree, *(attr->phf), tvb, offset, total_len, ENC_NA);
|
||||
consumed = total_len;
|
||||
break;
|
||||
case cip_usint_array:
|
||||
for (i = 0; i < total_len; i++)
|
||||
proto_tree_add_item(tree, *(attr->phf), tvb, offset, total_len, ENC_NA);
|
||||
consumed = total_len;
|
||||
break;
|
||||
case cip_uint_array:
|
||||
for (i = 0; i < total_len; i+=2)
|
||||
proto_tree_add_item(tree, *(attr->phf), tvb, offset+i, 2, ENC_LITTLE_ENDIAN);
|
||||
|
||||
consumed = i;
|
||||
break;
|
||||
case cip_udint:
|
||||
|
@ -4350,6 +4401,216 @@ dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
|
|||
return tvb_length(tvb);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
*
|
||||
* Dissector for CIP Modbus Object
|
||||
*
|
||||
************************************************/
|
||||
static void
|
||||
dissect_cip_mb_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
|
||||
{
|
||||
proto_item *pi, *rrsc_item;
|
||||
proto_tree *rrsc_tree, *cmd_data_tree;
|
||||
tvbuff_t *next_tvb;
|
||||
int req_path_size;
|
||||
guint8 gen_status, add_stat_size, service;
|
||||
|
||||
col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP MB");
|
||||
|
||||
/* Add Service code & Request/Response tree */
|
||||
service = tvb_get_guint8( tvb, offset );
|
||||
rrsc_item = proto_tree_add_text( item_tree, tvb, offset, 1, "Service: " );
|
||||
rrsc_tree = proto_item_add_subtree( rrsc_item, ett_mb_rrsc );
|
||||
|
||||
/* Add Request/Response */
|
||||
proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN );
|
||||
|
||||
proto_item_append_text( rrsc_item, "%s (%s)",
|
||||
val_to_str( ( service & 0x7F ),
|
||||
cip_sc_vals_mb , "Unknown Service (0x%02x)"),
|
||||
val_to_str( ( service & 0x80 )>>7,
|
||||
cip_sc_rr, "") );
|
||||
|
||||
/* Add Service code */
|
||||
proto_tree_add_item(rrsc_tree, hf_cip_mb_sc, tvb, offset, 1, ENC_LITTLE_ENDIAN );
|
||||
|
||||
if( service & 0x80 )
|
||||
{
|
||||
/* Response message */
|
||||
gen_status = tvb_get_guint8( tvb, offset+2 );
|
||||
add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
|
||||
|
||||
/* If there is any command specific data create a sub-tree for it */
|
||||
if( ( item_length-4-add_stat_size ) != 0 )
|
||||
{
|
||||
pi = proto_tree_add_text( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, "Command Specific Data" );
|
||||
cmd_data_tree = proto_item_add_subtree( pi, ett_mb_cmd_data );
|
||||
|
||||
if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
|
||||
{
|
||||
/* Success responses */
|
||||
switch (service & 0x7F)
|
||||
{
|
||||
case SC_MB_READ_DISCRETE_INPUTS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_discrete_inputs_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_COILS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_coils_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_INPUT_REGISTERS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_input_register_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_HOLDING_REGISTERS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_holding_register_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
break;
|
||||
|
||||
case SC_MB_WRITE_COILS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_start_addr, tvb, offset+4+add_stat_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_outputs_forced, tvb, offset+4+add_stat_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_WRITE_HOLDING_REGISTERS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_start_addr, tvb, offset+4+add_stat_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_outputs_forced, tvb, offset+4+add_stat_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_PASSTHROUGH:
|
||||
/* Passthrough response (Success) */
|
||||
if( tvb_length_remaining(tvb, offset) > 0 )
|
||||
{
|
||||
/* dissect the Modbus PDU */
|
||||
next_tvb = tvb_new_subset( tvb, offset+4+add_stat_size, item_length-4-add_stat_size, item_length-4-add_stat_size);
|
||||
|
||||
/* keep packet context */
|
||||
p_add_proto_data(pinfo->fd, proto_modbus, (void*)RESPONSE_PACKET);
|
||||
|
||||
call_dissector(modbus_handle, next_tvb, pinfo, cmd_data_tree);
|
||||
p_remove_proto_data(pinfo->fd, proto_modbus);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
|
||||
}
|
||||
|
||||
} /* End of if command-specific data present */
|
||||
|
||||
} /* End of if reply */
|
||||
else
|
||||
{
|
||||
/* Request message */
|
||||
|
||||
/* Add service to info column */
|
||||
if(check_col(pinfo->cinfo, COL_INFO))
|
||||
{
|
||||
col_append_str( pinfo->cinfo, COL_INFO,
|
||||
val_to_str( ( tvb_get_guint8( tvb, offset ) & 0x7F ),
|
||||
cip_sc_vals_mb , "Unknown Service (0x%02x)") );
|
||||
}
|
||||
req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
|
||||
|
||||
/* If there is any command specific data creat a sub-tree for it */
|
||||
if( (item_length-req_path_size-2) != 0 )
|
||||
{
|
||||
pi = proto_tree_add_text( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2, "Command Specific Data" );
|
||||
cmd_data_tree = proto_item_add_subtree( pi, ett_mb_cmd_data );
|
||||
|
||||
/* Check what service code that received */
|
||||
switch (service)
|
||||
{
|
||||
case SC_MB_READ_DISCRETE_INPUTS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_discrete_inputs_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_discrete_inputs_num_inputs, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_COILS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_coils_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_coils_num_coils, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_INPUT_REGISTERS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_input_register_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_input_register_num_registers, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_READ_HOLDING_REGISTERS:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_holding_register_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_holding_register_num_registers, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
break;
|
||||
|
||||
case SC_MB_WRITE_COILS:
|
||||
{
|
||||
guint16 NumCoils;
|
||||
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
NumCoils = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_num_coils, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_data, tvb, offset+2+req_path_size+4, (NumCoils+7)/8, ENC_NA);
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_MB_WRITE_HOLDING_REGISTERS:
|
||||
{
|
||||
guint16 NumRegisters;
|
||||
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
|
||||
NumRegisters = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_num_registers, tvb, offset+2+req_path_size+2, 2, ENC_LITTLE_ENDIAN);
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_data, tvb, offset+2+req_path_size+4, NumRegisters*2, ENC_NA);
|
||||
}
|
||||
break;
|
||||
|
||||
case SC_MB_PASSTHROUGH:
|
||||
/* Passthrough Request */
|
||||
if( tvb_length_remaining(tvb, offset) > 0 )
|
||||
{
|
||||
/* dissect the Modbus PDU */
|
||||
next_tvb = tvb_new_subset( tvb, offset+2+req_path_size, item_length-req_path_size-2, item_length-req_path_size-2);
|
||||
|
||||
/* keep packet context */
|
||||
p_add_proto_data(pinfo->fd, proto_modbus, (void*)QUERY_PACKET);
|
||||
|
||||
call_dissector(modbus_handle, next_tvb, pinfo, cmd_data_tree);
|
||||
p_remove_proto_data(pinfo->fd, proto_modbus);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
proto_tree_add_item(cmd_data_tree, hf_cip_mb_data, tvb, offset+2+req_path_size, item_length-req_path_size-2, ENC_NA);
|
||||
}
|
||||
|
||||
} /* End of if command-specific data present */
|
||||
|
||||
} /* End of if-else( request ) */
|
||||
|
||||
} /* End of dissect_cip_mb_data() */
|
||||
|
||||
static int
|
||||
dissect_cip_class_mb(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_mb, tvb, 0, -1, FALSE);
|
||||
class_tree = proto_item_add_subtree( ti, ett_cip_class_mb );
|
||||
|
||||
dissect_cip_mb_data( class_tree, tvb, 0, tvb_length(tvb), pinfo );
|
||||
}
|
||||
|
||||
return tvb_length(tvb);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
*
|
||||
* Dissector for CIP Connection Configuration Object
|
||||
|
@ -5022,6 +5283,7 @@ static void
|
|||
cip_init_protocol(void)
|
||||
{
|
||||
proto_enip = proto_get_id_by_filter_name( "enip" );
|
||||
proto_modbus = proto_get_id_by_filter_name( "modbus" );
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5212,6 +5474,31 @@ proto_register_cip(void)
|
|||
{ &hf_cip_cm_ext128_size, { "Maximum Size", "cip.cm.ext128_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}
|
||||
};
|
||||
|
||||
static hf_register_info hf_mb[] = {
|
||||
{ &hf_cip_mb_sc, { "Service", "cip.mb.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_mb), 0x7F, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_coils_start_addr, { "Starting Address", "cip.mb.read_coils.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_coils_num_coils, { "Quantity of Coils", "cip.mb.read_coils.num_coils", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_coils_data, { "Data", "cip.mb.read_coils.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_discrete_inputs_start_addr, { "Starting Address", "cip.mb.read_discrete_inputs.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_discrete_inputs_num_inputs, { "Quantity of Inputs", "cip.mb.read_discrete_inputs.num_inputs", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_discrete_inputs_data, { "Data", "cip.mb.read_discrete_inputs.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_holding_register_start_addr, { "Starting Address", "cip.mb.read_holding_register.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_holding_register_num_registers, { "Quantity of Holding Registers", "cip.mb.read_holding_register.num_registers", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_holding_register_data, { "Data", "cip.mb.read_holding_register.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_input_register_start_addr, { "Starting Address", "cip.mb.read_input_register.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_input_register_num_registers, { "Quantity of Input Registers", "cip.mb.read_input_register.num_registers", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_read_input_register_data, { "Data", "cip.mb.read_input_register.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_coils_start_addr, { "Starting Address", "cip.mb.write_coils.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_coils_outputs_forced, { "Outputs Forced", "cip.mb.write_coils.outputs_forced", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_coils_num_coils, { "Quantity of Coils", "cip.mb.write_coils.num_coils", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_coils_data, { "Data", "cip.mb.write_coils.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_registers_start_addr, { "Starting Address", "cip.mb.write_registers.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_registers_outputs_forced, { "Outputs Forced", "cip.mb.write_registers.outputs_forced", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_registers_num_registers, { "Quantity of Holding Registers", "cip.mb.write_registers.num_registers", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_write_registers_data, { "Data", "cip.mb.write_registers.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
|
||||
{ &hf_cip_mb_data, { "Data", "cip.mb.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}
|
||||
};
|
||||
|
||||
static hf_register_info hf_cco[] = {
|
||||
{ &hf_cip_cco_sc, { "Service", "cip.cco.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_cco), 0x7F, NULL, HFILL }},
|
||||
{ &hf_cip_cco_format_number, { "Format Number", "cip.cco.format_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
|
||||
|
@ -5304,6 +5591,12 @@ proto_register_cip(void)
|
|||
&ett_cm_add_status_item
|
||||
};
|
||||
|
||||
static gint *ett_mb[] = {
|
||||
&ett_cip_class_mb,
|
||||
&ett_mb_rrsc,
|
||||
&ett_mb_cmd_data
|
||||
};
|
||||
|
||||
static gint *ett_cco[] = {
|
||||
&ett_cip_class_cco,
|
||||
&ett_cco_iomap,
|
||||
|
@ -5339,6 +5632,11 @@ proto_register_cip(void)
|
|||
proto_register_field_array(proto_cip_class_cm, hf_cm, array_length(hf_cm));
|
||||
proto_register_subtree_array(ett_cm, array_length(ett_cm));
|
||||
|
||||
proto_cip_class_mb = proto_register_protocol("CIP Modbus Object",
|
||||
"CIPMB", "cipmb");
|
||||
proto_register_field_array(proto_cip_class_mb, hf_mb, array_length(hf_mb));
|
||||
proto_register_subtree_array(ett_mb, array_length(ett_mb));
|
||||
|
||||
proto_cip_class_cco = proto_register_protocol("CIP Connection Configuration Object",
|
||||
"CIPCCO", "cipcco");
|
||||
proto_register_field_array(proto_cip_class_cco, hf_cco, array_length(hf_cco));
|
||||
|
@ -5371,6 +5669,11 @@ proto_reg_handoff_cip(void)
|
|||
cip_class_cm_handle = new_create_dissector_handle( dissect_cip_class_cm, proto_cip_class_cm );
|
||||
dissector_add_uint( "cip.class.iface", CI_CLS_CM, cip_class_cm_handle );
|
||||
|
||||
/* Create and register dissector handle for Modbus Object */
|
||||
cip_class_mb_handle = new_create_dissector_handle( dissect_cip_class_mb, proto_cip_class_mb );
|
||||
dissector_add_uint( "cip.class.iface", CI_CLS_MB, cip_class_mb_handle );
|
||||
modbus_handle = find_dissector("modbus");
|
||||
|
||||
/* Create and register dissector handle for Connection Configuration Object */
|
||||
cip_class_cco_handle = new_create_dissector_handle( dissect_cip_class_cco, proto_cip_class_cco );
|
||||
dissector_add_uint( "cip.class.iface", CI_CLS_CCO, cip_class_cco_handle );
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
/* Classes that have class-specfic dissectors */
|
||||
#define CI_CLS_MR 0x02 /* Message Router */
|
||||
#define CI_CLS_CM 0x06 /* Connection Manager */
|
||||
#define CI_CLS_MB 0x44 /* Modbus Object */
|
||||
#define CI_CLS_CCO 0xF3 /* Connection Configuration Object */
|
||||
|
||||
/* Class specific services */
|
||||
|
@ -67,6 +68,15 @@
|
|||
#define SC_CM_LARGE_FWD_OPEN 0x5B
|
||||
#define SC_CM_GET_CONN_OWNER 0x5A
|
||||
|
||||
/* Modbus Object services */
|
||||
#define SC_MB_READ_DISCRETE_INPUTS 0x4B
|
||||
#define SC_MB_READ_COILS 0x4C
|
||||
#define SC_MB_READ_INPUT_REGISTERS 0x4D
|
||||
#define SC_MB_READ_HOLDING_REGISTERS 0x4E
|
||||
#define SC_MB_WRITE_COILS 0x4F
|
||||
#define SC_MB_WRITE_HOLDING_REGISTERS 0x50
|
||||
#define SC_MB_PASSTHROUGH 0x51
|
||||
|
||||
/* Connection Configuration Object services */
|
||||
#define SC_CCO_KICK_TIMER 0x4B
|
||||
#define SC_CCO_OPEN_CONN 0x4C
|
||||
|
@ -248,6 +258,7 @@ enum cip_datatype {
|
|||
cip_short_string,
|
||||
cip_string,
|
||||
cip_byte,
|
||||
cip_byte_array,
|
||||
cip_word,
|
||||
cip_dword,
|
||||
cip_lword,
|
||||
|
@ -311,6 +322,8 @@ extern void dissect_epath( tvbuff_t *tvb, packet_info *pinfo, proto_item *epath_
|
|||
** Exported variables
|
||||
*/
|
||||
extern dissector_table_t subdissector_class_table;
|
||||
extern const value_string cip_sc_rr[3];
|
||||
extern const value_string cip_reset_type_vals[4];
|
||||
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;
|
||||
|
|
|
@ -150,7 +150,7 @@ static const value_string exception_code_vals[] = {
|
|||
{ ILLEGAL_FUNCTION, "Illegal function" },
|
||||
{ ILLEGAL_ADDRESS, "Illegal data address" },
|
||||
{ ILLEGAL_VALUE, "Illegal data value" },
|
||||
{ ILLEGAL_RESPONSE, "Illegal response length" },
|
||||
{ SLAVE_FAILURE, "Slave device failure" },
|
||||
{ ACKNOWLEDGE, "Acknowledge" },
|
||||
{ SLAVE_BUSY, "Slave device busy" },
|
||||
{ MEMORY_ERR, "Memory parity error" },
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
#define ILLEGAL_FUNCTION 0x01
|
||||
#define ILLEGAL_ADDRESS 0x02
|
||||
#define ILLEGAL_VALUE 0x03
|
||||
#define ILLEGAL_RESPONSE 0x04
|
||||
#define SLAVE_FAILURE 0x04
|
||||
#define ACKNOWLEDGE 0x05
|
||||
#define SLAVE_BUSY 0x06
|
||||
#define MEMORY_ERR 0x08
|
||||
|
|
Loading…
Reference in New Issue