diff options
author | Michael Mann <mmann78@netscape.net> | 2016-01-20 10:50:44 -0500 |
---|---|---|
committer | Michael Mann <mmann78@netscape.net> | 2016-01-22 12:37:15 +0000 |
commit | fc511c3f11d1e744adbf8fff6b1e46adc9776c94 (patch) | |
tree | 162df846828d5c27edd7fac082077099355bd05b /epan/dissectors/packet-cip.c | |
parent | db111c4d9063bf145778ef41b139a6b9fdc0114c (diff) |
CIP: Add support for Get Attributes All
Get Attributes All is a predefined list of existing attribute IDs for a given class. Add a new index for each attribute for their place in GetAttributesAll response. Then a hash table of classes for existing attributes are created to handle the GetAttributesAll service.
Added more TCP/IP object attributes since more have been added to the spec.
Moved TCP/IP object attributes all to ENIP dissector.
Bug: 11996
Change-Id: I7f50c9aadf04efdb17ef31f39e6a991c0a84bef2
Reviewed-on: https://code.wireshark.org/review/13186
Petri-Dish: Michael Mann <mmann78@netscape.net>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Michael Mann <mmann78@netscape.net>
Diffstat (limited to 'epan/dissectors/packet-cip.c')
-rw-r--r-- | epan/dissectors/packet-cip.c | 331 |
1 files changed, 253 insertions, 78 deletions
diff --git a/epan/dissectors/packet-cip.c b/epan/dissectors/packet-cip.c index 2eedd44926..6bee51db8a 100644 --- a/epan/dissectors/packet-cip.c +++ b/epan/dissectors/packet-cip.c @@ -70,15 +70,15 @@ static int proto_cip_class_cco = -1; static int proto_enip = -1; static int proto_modbus = -1; -static int hf_attr_class_revision = -1; -static int hf_attr_class_max_instance = -1; -static int hf_attr_class_num_instance = -1; -static int hf_attr_class_opt_attr_num = -1; -static int hf_attr_class_attr_num = -1; -static int hf_attr_class_opt_service_num = -1; -static int hf_attr_class_service_code = -1; -static int hf_attr_class_num_class_attr = -1; -static int hf_attr_class_num_inst_attr = -1; +int hf_attr_class_revision = -1; +int hf_attr_class_max_instance = -1; +int hf_attr_class_num_instance = -1; +int hf_attr_class_opt_attr_num = -1; +int hf_attr_class_attr_num = -1; +int hf_attr_class_opt_service_num = -1; +int hf_attr_class_service_code = -1; +int hf_attr_class_num_class_attr = -1; +int hf_attr_class_num_inst_attr = -1; static int hf_cip_data = -1; static int hf_cip_service = -1; static int hf_cip_service_code = -1; @@ -314,6 +314,7 @@ static int hf_cip_reserved8 = -1; static int hf_cip_reserved24 = -1; static int hf_cip_pad8 = -1; +static int hf_cip_sc_get_attr_all_attr_item = -1; static int hf_cip_sc_get_attr_list_attr_count = -1; static int hf_cip_sc_get_attr_list_attr_item = -1; static int hf_cip_sc_get_attr_list_attr_status = -1; @@ -487,6 +488,7 @@ static gint ett_status_item = -1; static gint ett_add_status_item = -1; static gint ett_cmd_data = -1; +static gint ett_cip_get_attributes_all_item = -1; static gint ett_cip_get_attribute_list = -1; static gint ett_cip_get_attribute_list_item = -1; static gint ett_cip_set_attribute_list = -1; @@ -2530,7 +2532,7 @@ static const value_string cip_class_names_vals[] = { { 0xF3, "Connection Configuration Object" }, { 0xF4, "Port Object" }, { 0xF5, "TCP/IP Interface Object" }, - { 0xF6, "EtherNet Link Object" }, + { 0xF6, "Ethernet Link Object" }, { 0xF7, "CompoNet Object" }, { 0xF8, "CompoNet Repeater Object" }, @@ -3040,7 +3042,7 @@ static int dissect_time_sync_sys_time_and_offset(packet_info *pinfo, proto_tree return 16; } -static int dissect_optional_attr_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, +int dissect_optional_attr_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int total_len) { guint32 i; @@ -3062,7 +3064,7 @@ static int dissect_optional_attr_list(packet_info *pinfo, proto_tree *tree, prot return 2 + num_attr * 2; } -static int dissect_optional_service_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, +int dissect_optional_service_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset, int total_len) { guint32 i; @@ -3087,61 +3089,96 @@ static int dissect_optional_service_list(packet_info *pinfo, proto_tree *tree, p static attribute_info_t cip_attribute_vals[] = { - /* Identity Object */ - {0x01, FALSE, 1, "Vendor ID", cip_uint, &hf_id_vendor_id, NULL}, - {0x01, FALSE, 2, "Device Type", cip_uint, &hf_id_device_type, NULL}, - {0x01, FALSE, 3, "Product Code", cip_uint, &hf_id_produce_code, NULL}, - {0x01, FALSE, 4, "Revision", cip_dissector_func, NULL, dissect_id_revision}, - {0x01, FALSE, 5, "Status", cip_word, &hf_id_status, NULL}, - {0x01, FALSE, 6, "Serial Number", cip_udint, &hf_id_serial_number, NULL}, - {0x01, FALSE, 7, "Product Name", cip_short_string, &hf_id_product_name, NULL}, - - /* Message Router Object */ - {0x02, FALSE, 1, "Object List", cip_dissector_func, NULL, dissect_msg_rout_num_classes}, - {0x02, FALSE, 2, "Number Available", cip_uint, &hf_msg_rout_num_available, NULL}, - {0x02, FALSE, 3, "Number Active", cip_uint, &hf_msg_rout_num_active, NULL}, - {0x02, FALSE, 4, "Active Connections", cip_uint_array, &hf_msg_rout_active_connections, NULL}, - - /* Connection Manager Object */ - {0x06, FALSE, 1, "Open Requests", cip_uint, &hf_conn_mgr_open_requests, NULL}, - {0x06, FALSE, 2, "Open Format Rejects", cip_uint, &hf_conn_mgr_open_format_rejects, NULL}, - {0x06, FALSE, 3, "Open Resource Rejects", cip_uint, &hf_conn_mgr_open_resource_rejects, NULL}, - {0x06, FALSE, 4, "Other Open Rejects", cip_uint, &hf_conn_mgr_other_open_rejects, NULL}, - {0x06, FALSE, 5, "Close Requests", cip_uint, &hf_conn_mgr_close_requests, NULL}, - {0x06, FALSE, 6, "Close Format Requests", cip_uint, &hf_conn_close_format_requests, NULL}, - {0x06, FALSE, 7, "Close Other Requests", cip_uint, &hf_conn_mgr_close_other_requests, NULL}, - {0x06, FALSE, 8, "Connection Timeouts", cip_uint, &hf_conn_mgr_conn_timouts, NULL}, - - /* Time Sync Object */ - {0x43, FALSE, 1, "PTP Enable", cip_bool, &hf_time_sync_ptp_enable, NULL}, - {0x43, FALSE, 2, "Is Synchronized", cip_bool, &hf_time_sync_is_synchronized, NULL}, - {0x43, FALSE, 3, "System Time (Microseconds)", cip_ulint, &hf_time_sync_sys_time_micro, NULL}, - {0x43, FALSE, 4, "System Time (Nanoseconds)", cip_ulint, &hf_time_sync_sys_time_nano, NULL}, - {0x43, FALSE, 5, "Offset from Master", cip_lint, &hf_time_sync_offset_from_master, NULL}, - {0x43, FALSE, 6, "Max Offset from Master", cip_ulint, &hf_time_sync_max_offset_from_master, NULL}, - {0x43, FALSE, 7, "Mean Path Delay To Master", cip_lint, &hf_time_sync_mean_path_delay_to_master, NULL}, - {0x43, FALSE, 8, "Grand Master Clock Info", cip_dissector_func, NULL, dissect_time_sync_grandmaster_clock}, - {0x43, FALSE, 9, "Parent Clock Info", cip_dissector_func, NULL, dissect_time_sync_parent_clock}, - {0x43, FALSE, 10, "Local Clock Info", cip_dissector_func, NULL, dissect_time_sync_local_clock}, - {0x43, FALSE, 11, "Number of Ports", cip_uint, &hf_time_sync_num_ports, NULL}, - {0x43, FALSE, 12, "Port State Info", cip_dissector_func, NULL, dissect_time_sync_port_state_info}, - {0x43, FALSE, 13, "Port Enable Cfg", cip_dissector_func, NULL, dissect_time_sync_port_enable_cfg}, - {0x43, FALSE, 14, "Port Log Announcement Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_announce}, - {0x43, FALSE, 15, "Port Log Sync Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_sync}, - {0x43, FALSE, 16, "Priority1", cip_usint, &hf_time_sync_priority1, NULL}, - {0x43, FALSE, 17, "Priority2", cip_usint, &hf_time_sync_priority2, NULL}, - {0x43, FALSE, 18, "Domain number", cip_usint, &hf_time_sync_domain_number, NULL}, - {0x43, FALSE, 19, "Clock Type", cip_dissector_func, NULL, dissect_time_sync_clock_type}, - {0x43, FALSE, 20, "Manufacture Identity", cip_dissector_func, NULL, dissect_time_sync_manufacture_id}, - {0x43, FALSE, 21, "Product Description", cip_dissector_func, NULL, dissect_time_sync_prod_desc}, - {0x43, FALSE, 22, "Revision Data", cip_dissector_func, NULL, dissect_time_sync_revision_data}, - {0x43, FALSE, 23, "User Description", cip_dissector_func, NULL, dissect_time_sync_user_desc}, - {0x43, FALSE, 24, "Port Profile Identity Info", cip_dissector_func, NULL, dissect_time_sync_port_profile_id_info}, - {0x43, FALSE, 25, "Port Physical Address Info", cip_dissector_func, NULL, dissect_time_sync_port_phys_addr_info}, - {0x43, FALSE, 26, "Port Protocol Address Info", cip_dissector_func, NULL, dissect_time_sync_port_proto_addr_info}, - {0x43, FALSE, 27, "Steps Removed", cip_uint, &hf_time_sync_steps_removed, NULL}, - {0x43, FALSE, 28, "System Time and Offset", cip_dissector_func, NULL, dissect_time_sync_sys_time_and_offset}, - + /* Identity Object (class attributes) */ + {0x01, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL }, + {0x01, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL }, + {0x01, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL }, + {0x01, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list }, + {0x01, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list }, + {0x01, TRUE, 6, 2, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL }, + {0x01, TRUE, 7, 3, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL }, + + /* Identity Object (instance attributes) */ + {0x01, FALSE, 1, 0, "Vendor ID", cip_uint, &hf_id_vendor_id, NULL}, + {0x01, FALSE, 2, 1, "Device Type", cip_uint, &hf_id_device_type, NULL}, + {0x01, FALSE, 3, 2, "Product Code", cip_uint, &hf_id_produce_code, NULL}, + {0x01, FALSE, 4, 3, "Revision", cip_dissector_func, NULL, dissect_id_revision}, + {0x01, FALSE, 5, 4, "Status", cip_word, &hf_id_status, NULL}, + {0x01, FALSE, 6, 5, "Serial Number", cip_udint, &hf_id_serial_number, NULL}, + {0x01, FALSE, 7, 6, "Product Name", cip_short_string, &hf_id_product_name, NULL}, + + /* Message Router Object (class attributes) */ + {0x02, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL }, + {0x02, TRUE, 2, -1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL }, + {0x02, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL }, + {0x02, TRUE, 4, 1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list }, + {0x02, TRUE, 5, 2, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list }, + {0x02, TRUE, 6, 3, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL }, + {0x02, TRUE, 7, 4, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL }, + + /* Message Router Object (instance attributes) */ + {0x02, FALSE, 1, 0, "Object List", cip_dissector_func, NULL, dissect_msg_rout_num_classes}, + {0x02, FALSE, 2, 1, "Number Available", cip_uint, &hf_msg_rout_num_available, NULL}, + {0x02, FALSE, 3, 2, "Number Active", cip_uint, &hf_msg_rout_num_active, NULL}, + {0x02, FALSE, 4, 3, "Active Connections", cip_uint_array, &hf_msg_rout_active_connections, NULL}, + + /* Connection Manager Object (class attributes) */ + {0x06, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL }, + {0x06, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL }, + {0x06, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL }, + {0x06, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list }, + {0x06, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list }, + {0x06, TRUE, 6, 2, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL }, + {0x06, TRUE, 7, 3, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL }, + + /* Connection Manager Object (instance attributes) */ + {0x06, FALSE, 1, 0, "Open Requests", cip_uint, &hf_conn_mgr_open_requests, NULL}, + {0x06, FALSE, 2, 1, "Open Format Rejects", cip_uint, &hf_conn_mgr_open_format_rejects, NULL}, + {0x06, FALSE, 3, 2, "Open Resource Rejects", cip_uint, &hf_conn_mgr_open_resource_rejects, NULL}, + {0x06, FALSE, 4, 3, "Other Open Rejects", cip_uint, &hf_conn_mgr_other_open_rejects, NULL}, + {0x06, FALSE, 5, 4, "Close Requests", cip_uint, &hf_conn_mgr_close_requests, NULL}, + {0x06, FALSE, 6, 5, "Close Format Requests", cip_uint, &hf_conn_close_format_requests, NULL}, + {0x06, FALSE, 7, 6, "Close Other Requests", cip_uint, &hf_conn_mgr_close_other_requests, NULL}, + {0x06, FALSE, 8, 7, "Connection Timeouts", cip_uint, &hf_conn_mgr_conn_timouts, NULL}, + + /* Time Sync Object (class attributes) */ + {0x43, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL }, + {0x43, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL }, + {0x43, TRUE, 3, 2, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL }, + {0x43, TRUE, 4, 3, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list }, + {0x43, TRUE, 5, 4, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list }, + {0x43, TRUE, 6, 5, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL }, + {0x43, TRUE, 7, 6, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL }, + + /* Time Sync Object (instance attributes) */ + {0x43, FALSE, 1, -1, "PTP Enable", cip_bool, &hf_time_sync_ptp_enable, NULL}, + {0x43, FALSE, 2, -1, "Is Synchronized", cip_bool, &hf_time_sync_is_synchronized, NULL}, + {0x43, FALSE, 3, -1, "System Time (Microseconds)", cip_ulint, &hf_time_sync_sys_time_micro, NULL}, + {0x43, FALSE, 4, -1, "System Time (Nanoseconds)", cip_ulint, &hf_time_sync_sys_time_nano, NULL}, + {0x43, FALSE, 5, -1, "Offset from Master", cip_lint, &hf_time_sync_offset_from_master, NULL}, + {0x43, FALSE, 6, -1, "Max Offset from Master", cip_ulint, &hf_time_sync_max_offset_from_master, NULL}, + {0x43, FALSE, 7, -1, "Mean Path Delay To Master", cip_lint, &hf_time_sync_mean_path_delay_to_master, NULL}, + {0x43, FALSE, 8, -1, "Grand Master Clock Info", cip_dissector_func, NULL, dissect_time_sync_grandmaster_clock}, + {0x43, FALSE, 9, -1, "Parent Clock Info", cip_dissector_func, NULL, dissect_time_sync_parent_clock}, + {0x43, FALSE, 10, -1, "Local Clock Info", cip_dissector_func, NULL, dissect_time_sync_local_clock}, + {0x43, FALSE, 11, -1, "Number of Ports", cip_uint, &hf_time_sync_num_ports, NULL}, + {0x43, FALSE, 12, -1, "Port State Info", cip_dissector_func, NULL, dissect_time_sync_port_state_info}, + {0x43, FALSE, 13, -1, "Port Enable Cfg", cip_dissector_func, NULL, dissect_time_sync_port_enable_cfg}, + {0x43, FALSE, 14, -1, "Port Log Announcement Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_announce}, + {0x43, FALSE, 15, -1, "Port Log Sync Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_sync}, + {0x43, FALSE, 16, -1, "Priority1", cip_usint, &hf_time_sync_priority1, NULL}, + {0x43, FALSE, 17, -1, "Priority2", cip_usint, &hf_time_sync_priority2, NULL}, + {0x43, FALSE, 18, -1, "Domain number", cip_usint, &hf_time_sync_domain_number, NULL}, + {0x43, FALSE, 19, -1, "Clock Type", cip_dissector_func, NULL, dissect_time_sync_clock_type}, + {0x43, FALSE, 20, -1, "Manufacture Identity", cip_dissector_func, NULL, dissect_time_sync_manufacture_id}, + {0x43, FALSE, 21, -1, "Product Description", cip_dissector_func, NULL, dissect_time_sync_prod_desc}, + {0x43, FALSE, 22, -1, "Revision Data", cip_dissector_func, NULL, dissect_time_sync_revision_data}, + {0x43, FALSE, 23, -1, "User Description", cip_dissector_func, NULL, dissect_time_sync_user_desc}, + {0x43, FALSE, 24, -1, "Port Profile Identity Info", cip_dissector_func, NULL, dissect_time_sync_port_profile_id_info}, + {0x43, FALSE, 25, -1, "Port Physical Address Info", cip_dissector_func, NULL, dissect_time_sync_port_phys_addr_info}, + {0x43, FALSE, 26, -1, "Port Protocol Address Info", cip_dissector_func, NULL, dissect_time_sync_port_proto_addr_info}, + {0x43, FALSE, 27, -1, "Steps Removed", cip_uint, &hf_time_sync_steps_removed, NULL}, + {0x43, FALSE, 28, -1, "System Time and Offset", cip_dissector_func, NULL, dissect_time_sync_sys_time_and_offset}, }; typedef struct attribute_val_array { @@ -3149,22 +3186,19 @@ typedef struct attribute_val_array { attribute_info_t* attrs; } attribute_val_array_t; +/* Each entry in this table (eg: cip_attribute_vals) is a list of: + Attribute information (class_id/class_instance/attribute) to attribute property + + Note: If more items are added to the individual tables, it may make sense + to switch to a more efficient implementation (eg: hash table). +*/ + static attribute_val_array_t all_attribute_vals[] = { {sizeof(cip_attribute_vals)/sizeof(attribute_info_t), cip_attribute_vals}, {sizeof(enip_attribute_vals)/sizeof(attribute_info_t), enip_attribute_vals}, {sizeof(cip_safety_attribute_vals)/sizeof(attribute_info_t), cip_safety_attribute_vals} }; -attribute_info_t class_attribute_vals[] = { - { 0, TRUE, 1, "Revision", cip_uint, &hf_attr_class_revision, NULL }, - { 0, TRUE, 2, "Max Instance", cip_uint, &hf_attr_class_max_instance, NULL }, - { 0, TRUE, 3, "Number of Instances", cip_uint, &hf_attr_class_num_instance, NULL }, - { 0, TRUE, 4, "Optional Attribute List", cip_dissector_func, NULL, dissect_optional_attr_list }, - { 0, TRUE, 5, "Optional Service List", cip_dissector_func, NULL, dissect_optional_service_list }, - { 0, TRUE, 6, "Maximum ID Number Class Attributes", cip_uint, &hf_attr_class_num_class_attr, NULL }, - { 0, TRUE, 7, "Maximum ID Number Instance Attributes", cip_uint, &hf_attr_class_num_inst_attr, NULL }, -}; - static void dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t *preq_info ); @@ -3174,6 +3208,16 @@ attribute_info_t* cip_get_attribute(guint class_id, guint instance, guint attrib attribute_val_array_t* att_array; attribute_info_t* pattr; + static attribute_info_t class_attribute_vals[] = { + { 0, TRUE, 1, -1, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL }, + { 0, TRUE, 2, -1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL }, + { 0, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL }, + { 0, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list }, + { 0, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list }, + { 0, TRUE, 6, -1, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL }, + { 0, TRUE, 7, -1, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL }, + }; + for (i = 0; i < sizeof(all_attribute_vals)/sizeof(attribute_val_array_t); i++) { att_array = &all_attribute_vals[i]; @@ -4587,6 +4631,134 @@ dissect_cip_generic_service_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t return tvb_reported_length(tvb); } +typedef struct cip_gaa_key { + guint32 cip_class; + gboolean class_instance; +} cip_gaa_key_t; + +typedef struct cip_gaa_val { + GList *attributes; +} cip_gaa_val_t; + +static wmem_map_t *cip_gaa_hashtable = NULL; + +static guint +cip_gaa_hash (gconstpointer v) +{ + const cip_gaa_key_t *key = (const cip_gaa_key_t *)v; + guint val; + + val = (guint)((key->cip_class << 1) & 0xFFFFFFFE); + val |= (key->class_instance & 1); + + return val; +} + +static gint +cip_gaa_equal(gconstpointer v, gconstpointer w) +{ + const cip_gaa_key_t *v1 = (const cip_gaa_key_t *)v; + const cip_gaa_key_t *v2 = (const cip_gaa_key_t *)w; + + if ((v1->cip_class == v2->cip_class) && + (v1->class_instance == v2->class_instance)) + return 1; + + return 0; +} + +static void build_get_attr_all_table(void) +{ + size_t i, j; + attribute_val_array_t* att_array; + attribute_info_t* pattr; + cip_gaa_key_t key; + cip_gaa_key_t* new_key; + cip_gaa_val_t *gaa_val; + int last_attribute_index = -1; + + cip_gaa_hashtable = wmem_map_new(wmem_epan_scope(), cip_gaa_hash, cip_gaa_equal); + + for (i = 0; i < sizeof(all_attribute_vals)/sizeof(attribute_val_array_t); i++) + { + att_array = &all_attribute_vals[i]; + for (j = 0; j < att_array->size; j++) + { + pattr = &att_array->attrs[j]; + key.cip_class = pattr->class_id; + key.class_instance = pattr->class_instance; + + gaa_val = (cip_gaa_val_t *)wmem_map_lookup( cip_gaa_hashtable, &key ); + if (gaa_val == NULL) + { + new_key = (cip_gaa_key_t*)wmem_memdup(wmem_epan_scope(), &key, sizeof(cip_gaa_key_t)); + gaa_val = wmem_new0(wmem_epan_scope(), cip_gaa_val_t); + + wmem_map_insert(cip_gaa_hashtable, new_key, gaa_val ); + last_attribute_index = -1; + } + + if ((pattr->gaa_index >= 0) && (pattr->gaa_index > last_attribute_index)) + { + gaa_val->attributes = g_list_append(gaa_val->attributes, pattr); + last_attribute_index = pattr->gaa_index; + } + } + } +} + +static void +dissect_cip_get_attribute_all_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, + int offset, cip_simple_request_info_t* req_data) +{ + int att_size; + gint len_remain; + attribute_info_t* attr; + proto_item *att_item; + proto_tree *att_tree; + cip_gaa_key_t key; + cip_gaa_val_t *gaa_val; + GList *attribute_list; + + key.cip_class = req_data->iClass; + key.class_instance = (req_data->iInstance == 0); + + gaa_val = (cip_gaa_val_t *)wmem_map_lookup( cip_gaa_hashtable, &key ); + if (gaa_val == NULL) + { + proto_tree_add_item(tree, hf_cip_sc_get_attribute_all_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA); + return; + } + + for (attribute_list = g_list_first(gaa_val->attributes); + (attribute_list != NULL); + attribute_list = g_list_next(attribute_list)) + { + attr = (attribute_info_t *)attribute_list->data; + len_remain = tvb_reported_length_remaining(tvb, offset); + + /* If there are no more attributes defined or there is no data left. */ + if (attr == NULL || len_remain <= 0) + break; + + att_item = proto_tree_add_uint_format_value(tree, hf_cip_sc_get_attr_all_attr_item, + tvb, offset, 0, 0, "%d (%s)", attr->attribute, attr->text); + att_tree = proto_item_add_subtree(att_item, ett_cip_get_attributes_all_item); + + att_size = dissect_cip_attribute(pinfo, att_tree, att_item, tvb, attr, offset, len_remain); + offset += att_size; + + proto_item_set_len(att_item, att_size); + } + + /* Add whatever is left as raw data. */ + len_remain = tvb_reported_length_remaining(tvb, offset); + if (len_remain > 0) + { + proto_tree_add_item(tree, hf_cip_sc_get_attribute_all_data, tvb, offset, len_remain, ENC_NA); + } +} + static void dissect_cip_get_attribute_list_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item, int offset, cip_simple_request_info_t* req_data) @@ -4875,7 +5047,7 @@ dissect_cip_generic_service_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t switch(service) { case SC_GET_ATT_ALL: - proto_tree_add_item(cmd_data_tree, hf_cip_sc_get_attribute_all_data, tvb, offset+4+add_stat_size, tvb_reported_length_remaining(tvb, offset+4+add_stat_size), ENC_NA); + dissect_cip_get_attribute_all_rsp(tvb, pinfo, cmd_data_tree, offset+4+add_stat_size, &req_data); break; case SC_SET_ATT_ALL: proto_tree_add_item(cmd_data_tree, hf_cip_sc_set_attribute_all_data, tvb, offset+4+add_stat_size, tvb_reported_length_remaining(tvb, offset+4+add_stat_size), ENC_NA); @@ -6663,6 +6835,7 @@ proto_register_cip(void) { &hf_cip_reserved24, { "Reserved", "cip.reserved", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL }}, { &hf_cip_pad8, { "Pad Byte", "cip.pad", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }}, + { &hf_cip_sc_get_attr_all_attr_item, { "Attribute", "cip.getall.attr_item", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } }, { &hf_cip_sc_get_attr_list_attr_count, { "Attribute Count", "cip.getlist.attr_count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_cip_sc_get_attr_list_attr_item, { "Attribute", "cip.getlist.attr_item", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}, { &hf_cip_sc_get_attr_list_attr_status, { "General Status", "cip.getlist.attr_status", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_gs_vals_ext, 0, NULL, HFILL }}, @@ -6986,6 +7159,7 @@ proto_register_cip(void) &ett_cip_seg_safety_ounid_ssn, &ett_status_item, &ett_add_status_item, + &ett_cip_get_attributes_all_item, &ett_cip_get_attribute_list, &ett_cip_get_attribute_list_item, &ett_cip_set_attribute_list, @@ -7136,6 +7310,7 @@ proto_register_cip(void) * can override the dissector for common services */ heur_subdissector_service = register_heur_dissector_list("cip.sc"); + build_get_attr_all_table(); } /* end of proto_register_cip() */ |