diff options
-rw-r--r-- | epan/dissectors/packet-cip.c | 313 | ||||
-rw-r--r-- | epan/dissectors/packet-cip.h | 13 | ||||
-rw-r--r-- | epan/dissectors/packet-mbtcp.c | 2 | ||||
-rw-r--r-- | epan/dissectors/packet-mbtcp.h | 2 |
4 files changed, 323 insertions, 7 deletions
diff --git a/epan/dissectors/packet-cip.c b/epan/dissectors/packet-cip.c index 03051bc247..8898a4e283 100644 --- a/epan/dissectors/packet-cip.c +++ b/epan/dissectors/packet-cip.c @@ -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: @@ -4352,6 +4403,216 @@ dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) /************************************************ * + * 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 ); diff --git a/epan/dissectors/packet-cip.h b/epan/dissectors/packet-cip.h index 46502fb456..33a9fe8847 100644 --- a/epan/dissectors/packet-cip.h +++ b/epan/dissectors/packet-cip.h @@ -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; diff --git a/epan/dissectors/packet-mbtcp.c b/epan/dissectors/packet-mbtcp.c index 4de9c64471..9bbfb1b971 100644 --- a/epan/dissectors/packet-mbtcp.c +++ b/epan/dissectors/packet-mbtcp.c @@ -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" }, diff --git a/epan/dissectors/packet-mbtcp.h b/epan/dissectors/packet-mbtcp.h index ea33e63e20..cd398b7aa6 100644 --- a/epan/dissectors/packet-mbtcp.h +++ b/epan/dissectors/packet-mbtcp.h @@ -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 |