1 /* packet-cip.c
2 * Routines for Common Industrial Protocol (CIP) dissection
3 * CIP Home: www.odva.org
4 *
5 * This dissector includes items from:
6 * CIP Volume 1: Common Industrial Protocol, Edition 3.30
7 * CIP Volume 5: Integration of Modbus Devices into the CIP Architecture, Edition 2.17
8 * CIP Volume 7: CIP Safety, Edition 1.9
9 * CIP Volume 8: CIP Security, Edition 1.11
10 *
11 * Copyright 2004
12 * Magnus Hansson <mah@hms.se>
13 * Joakim Wiberg <jow@hms.se>
14 *
15 * Added support for Connection Configuration Object
16 * ryan wamsley * Copyright 2007
17 *
18 * Object dependend services based on IOI
19 * Jan Bartels, Siempelkamp Maschinen- und Anlagenbau GmbH & Co. KG
20 * Copyright 2007
21 *
22 * Improved support for CoCo, CM, MB objects
23 * Heuristic object support for common services
24 * Michael Mann * Copyright 2011
25 *
26 * Added support for PCCC Objects
27 * Jared Rittle - Cisco Talos
28 * Copyright 2017
29 *
30 * Wireshark - Network traffic analyzer
31 * By Gerald Combs <gerald@wireshark.org>
32 * Copyright 1998 Gerald Combs
33 *
34 * SPDX-License-Identifier: GPL-2.0-or-later
35 */
36
37 #include "config.h"
38
39 #include <epan/packet.h>
40 #include <epan/expert.h>
41 #include <epan/prefs.h>
42 #include <epan/proto_data.h>
43 #include <epan/wmem_scopes.h>
44 #include "packet-cip.h"
45 #include "packet-cipmotion.h"
46 #include "packet-cipsafety.h"
47 #include "packet-mbtcp.h"
48
49 void proto_register_cip(void);
50 void proto_reg_handoff_cip(void);
51
52 typedef struct mr_mult_req_info {
53 guint8 service;
54 int num_services;
55 cip_req_info_t *requests;
56 } mr_mult_req_info_t;
57
58 static dissector_handle_t cip_handle;
59 static dissector_handle_t cip_class_generic_handle;
60 static dissector_handle_t cip_class_cm_handle;
61 static dissector_handle_t cip_class_pccc_handle;
62 static dissector_handle_t modbus_handle;
63 static dissector_handle_t cip_class_cco_handle;
64 static heur_dissector_list_t heur_subdissector_service;
65
66 static gboolean cip_enhanced_info_column = TRUE;
67
68 /* Initialize the protocol and registered fields */
69 static int proto_cip = -1;
70 static int proto_cip_class_generic = -1;
71 static int proto_cip_class_cm = -1;
72 static int proto_cip_class_pccc = -1;
73 static int proto_cip_class_mb = -1;
74 static int proto_cip_class_cco = -1;
75 static int proto_enip = -1;
76 static int proto_modbus = -1;
77
78 int hf_attr_class_revision = -1;
79 int hf_attr_class_max_instance = -1;
80 int hf_attr_class_num_instance = -1;
81 int hf_attr_class_opt_attr_num = -1;
82 int hf_attr_class_attr_num = -1;
83 int hf_attr_class_opt_service_num = -1;
84 int hf_attr_class_service_code = -1;
85 int hf_attr_class_num_class_attr = -1;
86 int hf_attr_class_num_inst_attr = -1;
87 static int hf_cip_data = -1;
88 static int hf_cip_service = -1;
89 static int hf_cip_service_code = -1;
90 static int hf_cip_reqrsp = -1;
91 static int hf_cip_epath = -1;
92 static int hf_cip_genstat = -1;
93 static int hf_cip_addstat_size = -1;
94 static int hf_cip_add_stat = -1;
95 static int hf_cip_request_path_size = -1;
96
97 static int hf_cip_cm_sc = -1;
98 static int hf_cip_cm_genstat = -1;
99 static int hf_cip_cm_addstat_size = -1;
100 static int hf_cip_cm_add_status = -1;
101 static int hf_cip_cm_ext_status = -1;
102 static int hf_cip_cm_priority = -1;
103 static int hf_cip_cm_tick_time = -1;
104 static int hf_cip_cm_timeout_tick = -1;
105 static int hf_cip_cm_timeout = -1;
106 static int hf_cip_cm_ot_connid = -1;
107 static int hf_cip_cm_to_connid = -1;
108 static int hf_cip_connid = -1;
109 static int hf_cip_cm_conn_serial_num = -1;
110 static int hf_cip_cm_orig_serial_num = -1;
111 static int hf_cip_cm_vendor = -1;
112 static int hf_cip_cm_timeout_multiplier = -1;
113 static int hf_cip_cm_ot_rpi = -1;
114 static int hf_cip_cm_ot_net_params32 = -1;
115 static int hf_cip_cm_ot_net_params16 = -1;
116 static int hf_cip_cm_to_rpi = -1;
117 static int hf_cip_cm_to_net_params32 = -1;
118 static int hf_cip_cm_to_net_params16 = -1;
119 static int hf_cip_cm_transport_type_trigger = -1;
120 static int hf_cip_cm_conn_path_size = -1;
121 static int hf_cip_cm_ot_api = -1;
122 static int hf_cip_cm_to_api = -1;
123 static int hf_cip_cm_app_reply_size = -1;
124 static int hf_cip_cm_app_reply_data = -1;
125 static int hf_cip_cm_consumer_number = -1;
126 static int hf_cip_cm_targ_vendor_id = -1;
127 static int hf_cip_cm_targ_dev_serial_num = -1;
128 static int hf_cip_cm_targ_conn_serial_num = -1;
129 static int hf_cip_cm_initial_timestamp = -1;
130 static int hf_cip_cm_initial_rollover = -1;
131 static int hf_cip_cm_remain_path_size = -1;
132 static int hf_cip_cm_msg_req_size = -1;
133 static int hf_cip_cm_route_path_size = -1;
134 static int hf_cip_cm_fwo_con_size = -1;
135 static int hf_cip_cm_lfwo_con_size = -1;
136 static int hf_cip_cm_fwo_fixed_var = -1;
137 static int hf_cip_cm_lfwo_fixed_var = -1;
138 static int hf_cip_cm_fwo_prio = -1;
139 static int hf_cip_cm_lfwo_prio = -1;
140 static int hf_cip_cm_fwo_typ = -1;
141 static int hf_cip_cm_lfwo_typ = -1;
142 static int hf_cip_cm_fwo_own = -1;
143 static int hf_cip_cm_lfwo_own = -1;
144 static int hf_cip_cm_fwo_dir = -1;
145 static int hf_cip_cm_fwo_trigg = -1;
146 static int hf_cip_cm_fwo_class = -1;
147 static int hf_cip_cm_gco_conn = -1;
148 static int hf_cip_cm_gco_coo_conn = -1;
149 static int hf_cip_cm_gco_roo_conn = -1;
150 static int hf_cip_cm_gco_last_action = -1;
151 static int hf_cip_cm_ext112_ot_rpi_type = -1;
152 static int hf_cip_cm_ext112_to_rpi_type = -1;
153 static int hf_cip_cm_ext112_ot_rpi = -1;
154 static int hf_cip_cm_ext112_to_rpi = -1;
155 static int hf_cip_cm_ext126_size = -1;
156 static int hf_cip_cm_ext127_size = -1;
157 static int hf_cip_cm_ext128_size = -1;
158
159 static int hf_cip_pccc_sc = -1;
160 static int hf_cip_pccc_req_id_len = -1;
161 static int hf_cip_pccc_cip_vend_id = -1;
162 static int hf_cip_pccc_cip_serial_num = -1;
163 static int hf_cip_pccc_cmd_code = -1;
164 static int hf_cip_pccc_sts_code = -1;
165 static int hf_cip_pccc_ext_sts_code = -1;
166 static int hf_cip_pccc_tns_code = -1;
167 static int hf_cip_pccc_fnc_code_06 = -1;
168 static int hf_cip_pccc_fnc_code_07 = -1;
169 static int hf_cip_pccc_fnc_code_0f = -1;
170 static int hf_cip_pccc_byte_size = -1;
171 static int hf_cip_pccc_file_num = -1;
172 static int hf_cip_pccc_file_type = -1;
173 static int hf_cip_pccc_element_num = -1;
174 static int hf_cip_pccc_subelement_num = -1;
175 #if 0
176 static int hf_cip_pccc_cpu_mode_3a = -1;
177 #endif
178 static int hf_cip_pccc_cpu_mode_80 = -1;
179 static int hf_cip_pccc_resp_code = -1;
180 static int hf_cip_pccc_execute_multi_count = -1;
181 static int hf_cip_pccc_execute_multi_len = -1;
182 static int hf_cip_pccc_execute_multi_fnc = -1;
183 static int hf_cip_pccc_data = -1;
184
185 static int hf_cip_mb_sc = -1;
186 static int hf_cip_mb_read_coils_start_addr = -1;
187 static int hf_cip_mb_read_coils_num_coils = -1;
188 static int hf_cip_mb_read_coils_data = -1;
189 static int hf_cip_mb_read_discrete_inputs_start_addr = -1;
190 static int hf_cip_mb_read_discrete_inputs_num_inputs = -1;
191 static int hf_cip_mb_read_discrete_inputs_data = -1;
192 static int hf_cip_mb_read_holding_register_start_addr = -1;
193 static int hf_cip_mb_read_holding_register_num_registers = -1;
194 static int hf_cip_mb_read_holding_register_data = -1;
195 static int hf_cip_mb_read_input_register_start_addr = -1;
196 static int hf_cip_mb_read_input_register_num_registers = -1;
197 static int hf_cip_mb_read_input_register_data = -1;
198 static int hf_cip_mb_write_coils_start_addr = -1;
199 static int hf_cip_mb_write_coils_outputs_forced = -1;
200 static int hf_cip_mb_write_coils_num_coils = -1;
201 static int hf_cip_mb_write_coils_data = -1;
202 static int hf_cip_mb_write_registers_start_addr = -1;
203 static int hf_cip_mb_write_registers_outputs_forced = -1;
204 static int hf_cip_mb_write_registers_num_registers = -1;
205 static int hf_cip_mb_write_registers_data = -1;
206 static int hf_cip_mb_data = -1;
207
208 static int hf_cip_cco_con_type = -1;
209 static int hf_cip_cco_ot_rtf = -1;
210 static int hf_cip_cco_to_rtf = -1;
211 static int hf_cip_cco_sc = -1;
212 static int hf_cip_cco_format_number = -1;
213 static int hf_cip_cco_edit_signature = -1;
214 static int hf_cip_cco_con_flags = -1;
215 static int hf_cip_cco_tdi_vendor = -1;
216 static int hf_cip_cco_tdi_devtype = -1;
217 static int hf_cip_cco_tdi_prodcode = -1;
218 static int hf_cip_cco_tdi_compatibility = -1;
219 static int hf_cip_cco_tdi_comp_bit = -1;
220 static int hf_cip_cco_tdi_majorrev = -1;
221 static int hf_cip_cco_tdi_minorrev = -1;
222 static int hf_cip_cco_pdi_vendor = -1;
223 static int hf_cip_cco_pdi_devtype = -1;
224 static int hf_cip_cco_pdi_prodcode = -1;
225 static int hf_cip_cco_pdi_compatibility = -1;
226 static int hf_cip_cco_pdi_comp_bit = -1;
227 static int hf_cip_cco_pdi_majorrev = -1;
228 static int hf_cip_cco_pdi_minorrev = -1;
229 static int hf_cip_cco_cs_data_index = -1;
230 static int hf_cip_cco_ot_rpi = -1;
231 static int hf_cip_cco_to_rpi = -1;
232 static int hf_cip_cco_ot_net_param16 = -1;
233 static int hf_cip_cco_to_net_param16 = -1;
234 static int hf_cip_cco_fwo_own = -1;
235 static int hf_cip_cco_fwo_typ = -1;
236 static int hf_cip_cco_fwo_prio = -1;
237 static int hf_cip_cco_fwo_fixed_var = -1;
238 static int hf_cip_cco_fwo_con_size = -1;
239 static int hf_cip_cco_ot_net_param32 = -1;
240 static int hf_cip_cco_to_net_param32 = -1;
241 static int hf_cip_cco_lfwo_own = -1;
242 static int hf_cip_cco_lfwo_typ = -1;
243 static int hf_cip_cco_lfwo_prio = -1;
244 static int hf_cip_cco_lfwo_fixed_var = -1;
245 static int hf_cip_cco_lfwo_con_size = -1;
246 static int hf_cip_cco_conn_path_size = -1;
247 static int hf_cip_cco_proxy_config_size = -1;
248 static int hf_cip_cco_target_config_size = -1;
249 static int hf_cip_cco_iomap_format_number = -1;
250 static int hf_cip_cco_iomap_size = -1;
251 static int hf_cip_cco_connection_disable = -1;
252 static int hf_cip_cco_net_conn_param_attr = -1;
253 static int hf_cip_cco_timeout_multiplier = -1;
254 static int hf_cip_cco_transport_type_trigger = -1;
255 static int hf_cip_cco_fwo_dir = -1;
256 static int hf_cip_cco_fwo_trigger = -1;
257 static int hf_cip_cco_fwo_class = -1;
258 static int hf_cip_cco_proxy_config_data = -1;
259 static int hf_cip_cco_target_config_data = -1;
260 static int hf_cip_cco_iomap_attribute = -1;
261 static int hf_cip_cco_safety = -1;
262 static int hf_cip_cco_change_type = -1;
263 static int hf_cip_cco_connection_name = -1;
264 static int hf_cip_cco_ext_status = -1;
265
266 static int hf_cip_path_segment = -1;
267 static int hf_cip_path_segment_type = -1;
268 static int hf_cip_port_ex_link_addr = -1;
269 static int hf_cip_port = -1;
270 static int hf_cip_port_extended = -1;
271 static int hf_cip_link_address_size = -1;
272 static int hf_cip_link_address_byte = -1;
273 static int hf_cip_link_address_string = -1;
274 static int hf_cip_logical_seg_type = -1;
275 static int hf_cip_logical_seg_format = -1;
276 static int hf_cip_class8 = -1;
277 static int hf_cip_class16 = -1;
278 static int hf_cip_class32 = -1;
279 static int hf_cip_instance8 = -1;
280 static int hf_cip_instance16 = -1;
281 static int hf_cip_instance32 = -1;
282 static int hf_cip_member8 = -1;
283 static int hf_cip_member16 = -1;
284 static int hf_cip_member32 = -1;
285 static int hf_cip_attribute8 = -1;
286 static int hf_cip_attribute16 = -1;
287 static int hf_cip_attribute32 = -1;
288 static int hf_cip_conpoint8 = -1;
289 static int hf_cip_conpoint16 = -1;
290 static int hf_cip_conpoint32 = -1;
291 static int hf_cip_serviceid8 = -1;
292 static int hf_cip_ekey_format = -1;
293 static int hf_cip_ekey_vendor = -1;
294 static int hf_cip_ekey_devtype = -1;
295 static int hf_cip_ekey_prodcode = -1;
296 static int hf_cip_ekey_compatibility = -1;
297 static int hf_cip_ekey_comp_bit = -1;
298 static int hf_cip_ekey_majorrev = -1;
299 static int hf_cip_ekey_minorrev = -1;
300 static int hf_cip_ekey_serial_number = -1;
301 static int hf_cip_ext_logical8 = -1;
302 static int hf_cip_ext_logical16 = -1;
303 static int hf_cip_ext_logical32 = -1;
304 static int hf_cip_ext_logical_type = -1;
305 static int hf_cip_data_seg_type = -1;
306 static int hf_cip_data_seg_size_simple = -1;
307 static int hf_cip_data_seg_size_extended = -1;
308 static int hf_cip_data_seg_item = -1;
309 static int hf_cip_symbol = -1;
310 static int hf_cip_symbol_size = -1;
311 static int hf_cip_symbol_ascii = -1;
312 static int hf_cip_symbol_extended_format = -1;
313 static int hf_cip_symbol_numeric_format = -1;
314 static int hf_cip_symbol_double_size = -1;
315 static int hf_cip_symbol_triple_size = -1;
316 static int hf_cip_numeric_usint = -1;
317 static int hf_cip_numeric_uint = -1;
318 static int hf_cip_numeric_udint = -1;
319 static int hf_cip_network_seg_type = -1;
320 static int hf_cip_seg_schedule = -1;
321 static int hf_cip_seg_fixed_tag = -1;
322 static int hf_cip_seg_prod_inhibit_time = -1;
323 static int hf_cip_seg_prod_inhibit_time_us = -1;
324 static int hf_cip_seg_network_size = -1;
325 static int hf_cip_seg_network_subtype = -1;
326 static int hf_cip_seg_safety_format = -1;
327 static int hf_cip_seg_safety_reserved = -1;
328 static int hf_cip_seg_safety_configuration_crc = -1;
329 static int hf_cip_seg_safety_configuration_timestamp = -1;
330 static int hf_cip_seg_safety_configuration_date = -1;
331 static int hf_cip_seg_safety_configuration_time = -1;
332 static int hf_cip_seg_safety_time_correction_epi = -1;
333 static int hf_cip_seg_safety_time_correction_net_params = -1;
334 static int hf_cip_seg_safety_time_correction_own = -1;
335 static int hf_cip_seg_safety_time_correction_typ = -1;
336 static int hf_cip_seg_safety_time_correction_prio = -1;
337 static int hf_cip_seg_safety_time_correction_fixed_var = -1;
338 static int hf_cip_seg_safety_time_correction_con_size = -1;
339 static int hf_cip_seg_safety_tunid = -1;
340 static int hf_cip_seg_safety_tunid_snn_timestamp = -1;
341 static int hf_cip_seg_safety_tunid_snn_date = -1;
342 static int hf_cip_seg_safety_tunid_snn_time = -1;
343 static int hf_cip_seg_safety_tunid_nodeid = -1;
344 static int hf_cip_seg_safety_ounid = -1;
345 static int hf_cip_seg_safety_ounid_snn_timestamp = -1;
346 static int hf_cip_seg_safety_ounid_snn_date = -1;
347 static int hf_cip_seg_safety_ounid_snn_time = -1;
348 static int hf_cip_seg_safety_ounid_nodeid = -1;
349 static int hf_cip_seg_safety_ping_eri_multiplier = -1;
350 static int hf_cip_seg_safety_time_coord_msg_min_multiplier = -1;
351 static int hf_cip_seg_safety_network_time_expected_multiplier = -1;
352 static int hf_cip_seg_safety_timeout_multiplier = -1;
353 static int hf_cip_seg_safety_max_consumer_number = -1;
354 static int hf_cip_seg_safety_conn_param_crc = -1;
355 static int hf_cip_seg_safety_time_correction_conn_id = -1;
356 static int hf_cip_seg_safety_max_fault_number = -1;
357 static int hf_cip_seg_safety_init_timestamp = -1;
358 static int hf_cip_seg_safety_init_rollover = -1;
359 static int hf_cip_seg_safety_data = -1;
360 static int hf_cip_class_max_inst32 = -1;
361 static int hf_cip_class_num_inst32 = -1;
362 static int hf_cip_reserved8 = -1;
363 static int hf_cip_reserved24 = -1;
364 static int hf_cip_pad8 = -1;
365
366 static int hf_cip_sc_get_attr_list_attr_count = -1;
367 static int hf_cip_sc_get_attr_list_attr_status = -1;
368 static int hf_cip_sc_set_attr_list_attr_count = -1;
369 static int hf_cip_sc_set_attr_list_attr_status = -1;
370 static int hf_cip_sc_reset_param = -1;
371 static int hf_cip_sc_create_instance = -1;
372 static int hf_cip_sc_mult_serv_pack_num_services = -1;
373 static int hf_cip_sc_mult_serv_pack_offset = -1;
374 static int hf_cip_find_next_object_max_instance = -1;
375 static int hf_cip_find_next_object_num_instances = -1;
376 static int hf_cip_find_next_object_instance_item = -1;
377 static int hf_cip_sc_group_sync_is_sync = -1;
378
379 /* Parsed Attributes */
380 static int hf_id_vendor_id = -1;
381 static int hf_id_device_type = -1;
382 static int hf_id_product_code = -1;
383 static int hf_id_major_rev = -1;
384 static int hf_id_minor_rev = -1;
385 static int hf_id_status = -1;
386 static int hf_id_serial_number = -1;
387 static int hf_id_product_name = -1;
388 static int hf_id_state = -1;
389 static int hf_id_config_value = -1;
390 static int hf_id_heartbeat = -1;
391 static int hf_id_status_owned = -1;
392 static int hf_id_status_conf = -1;
393 static int hf_id_status_extended1 = -1;
394 static int hf_id_status_minor_fault_rec = -1;
395 static int hf_id_status_minor_fault_unrec = -1;
396 static int hf_id_status_major_fault_rec = -1;
397 static int hf_id_status_major_fault_unrec = -1;
398 static int hf_id_status_extended2 = -1;
399 static int hf_msg_rout_num_classes = -1;
400 static int hf_msg_rout_classes = -1;
401 static int hf_msg_rout_num_available = -1;
402 static int hf_msg_rout_num_active = -1;
403 static int hf_msg_rout_active_connections = -1;
404 static int hf_conn_mgr_open_requests = -1;
405 static int hf_conn_mgr_open_format_rejects = -1;
406 static int hf_conn_mgr_open_resource_rejects = -1;
407 static int hf_conn_mgr_other_open_rejects = -1;
408 static int hf_conn_mgr_close_requests = -1;
409 static int hf_conn_close_format_requests = -1;
410 static int hf_conn_mgr_close_other_requests = -1;
411 static int hf_conn_mgr_conn_timouts = -1;
412 static int hf_conn_mgr_num_conn_entries = -1;
413 static int hf_conn_mgr_num_conn_entries_bytes = -1;
414 static int hf_conn_mgr_conn_open_bits = -1;
415 static int hf_conn_mgr_cpu_utilization = -1;
416 static int hf_conn_mgr_max_buff_size = -1;
417 static int hf_conn_mgr_buff_size_remaining = -1;
418 static int hf_stringi_number_char = -1;
419 static int hf_stringi_language_char = -1;
420 static int hf_stringi_char_string_struct = -1;
421 static int hf_stringi_char_set = -1;
422 static int hf_stringi_international_string = -1;
423 static int hf_file_filename = -1;
424 static int hf_time_sync_ptp_enable = -1;
425 static int hf_time_sync_is_synchronized = -1;
426 static int hf_time_sync_sys_time_micro = -1;
427 static int hf_time_sync_sys_time_nano = -1;
428 static int hf_time_sync_offset_from_master = -1;
429 static int hf_time_sync_max_offset_from_master = -1;
430 static int hf_time_sync_mean_path_delay_to_master = -1;
431 static int hf_time_sync_gm_clock_clock_id = -1;
432 static int hf_time_sync_gm_clock_clock_class = -1;
433 static int hf_time_sync_gm_clock_time_accuracy = -1;
434 static int hf_time_sync_gm_clock_offset_scaled_log_variance = -1;
435 static int hf_time_sync_gm_clock_current_utc_offset = -1;
436 static int hf_time_sync_gm_clock_time_property_flags = -1;
437 static int hf_time_sync_gm_clock_time_property_flags_leap61 = -1;
438 static int hf_time_sync_gm_clock_time_property_flags_leap59 = -1;
439 static int hf_time_sync_gm_clock_time_property_flags_current_utc_valid = -1;
440 static int hf_time_sync_gm_clock_time_property_flags_ptp_timescale = -1;
441 static int hf_time_sync_gm_clock_time_property_flags_time_traceable = -1;
442 static int hf_time_sync_gm_clock_time_property_flags_freq_traceable = -1;
443 static int hf_time_sync_gm_clock_time_source = -1;
444 static int hf_time_sync_gm_clock_priority1 = -1;
445 static int hf_time_sync_gm_clock_priority2 = -1;
446 static int hf_time_sync_parent_clock_clock_id = -1;
447 static int hf_time_sync_parent_clock_port_number = -1;
448 static int hf_time_sync_parent_clock_observed_offset_scaled_log_variance = -1;
449 static int hf_time_sync_parent_clock_observed_phase_change_rate = -1;
450 static int hf_time_sync_local_clock_clock_id = -1;
451 static int hf_time_sync_local_clock_clock_class = -1;
452 static int hf_time_sync_local_clock_time_accuracy = -1;
453 static int hf_time_sync_local_clock_offset_scaled_log_variance = -1;
454 static int hf_time_sync_local_clock_current_utc_offset = -1;
455 static int hf_time_sync_local_clock_time_property_flags = -1;
456 static int hf_time_sync_local_clock_time_property_flags_leap61 = -1;
457 static int hf_time_sync_local_clock_time_property_flags_leap59 = -1;
458 static int hf_time_sync_local_clock_time_property_flags_current_utc_valid = -1;
459 static int hf_time_sync_local_clock_time_property_flags_ptp_timescale = -1;
460 static int hf_time_sync_local_clock_time_property_flags_time_traceable = -1;
461 static int hf_time_sync_local_clock_time_property_flags_freq_traceable = -1;
462 static int hf_time_sync_local_clock_time_source = -1;
463 static int hf_time_sync_num_ports = -1;
464 static int hf_time_sync_port_state_info_num_ports = -1;
465 static int hf_time_sync_port_state_info_port_num = -1;
466 static int hf_time_sync_port_state_info_port_state = -1;
467 static int hf_time_sync_port_enable_cfg_num_ports = -1;
468 static int hf_time_sync_port_enable_cfg_port_num = -1;
469 static int hf_time_sync_port_enable_cfg_port_enable = -1;
470 static int hf_time_sync_port_log_announce_num_ports = -1;
471 static int hf_time_sync_port_log_announce_port_num = -1;
472 static int hf_time_sync_port_log_announce_interval = -1;
473 static int hf_time_sync_port_log_sync_num_ports = -1;
474 static int hf_time_sync_port_log_sync_port_num = -1;
475 static int hf_time_sync_port_log_sync_port_log_sync_interval = -1;
476 static int hf_time_sync_priority1 = -1;
477 static int hf_time_sync_priority2 = -1;
478 static int hf_time_sync_domain_number = -1;
479 static int hf_time_sync_clock_type = -1;
480 static int hf_time_sync_clock_type_ordinary = -1;
481 static int hf_time_sync_clock_type_boundary = -1;
482 static int hf_time_sync_clock_type_end_to_end = -1;
483 static int hf_time_sync_clock_type_management = -1;
484 static int hf_time_sync_clock_type_slave_only = -1;
485 static int hf_time_sync_manufacture_id_oui = -1;
486 static int hf_time_sync_manufacture_id_reserved = -1;
487 static int hf_time_sync_prod_desc_size = -1;
488 static int hf_time_sync_prod_desc_str = -1;
489 static int hf_time_sync_revision_data_size = -1;
490 static int hf_time_sync_revision_data_str = -1;
491 static int hf_time_sync_user_desc_size = -1;
492 static int hf_time_sync_user_desc_str = -1;
493 static int hf_time_sync_port_profile_id_info_num_ports = -1;
494 static int hf_time_sync_port_profile_id_info_port_num = -1;
495 static int hf_time_sync_port_profile_id_info_profile_id = -1;
496 static int hf_time_sync_port_phys_addr_info_num_ports = -1;
497 static int hf_time_sync_port_phys_addr_info_port_num = -1;
498 static int hf_time_sync_port_phys_addr_info_phys_proto = -1;
499 static int hf_time_sync_port_phys_addr_info_addr_size = -1;
500 static int hf_time_sync_port_phys_addr_info_phys_addr = -1;
501 static int hf_time_sync_port_proto_addr_info_num_ports = -1;
502 static int hf_time_sync_port_proto_addr_info_port_num = -1;
503 static int hf_time_sync_port_proto_addr_info_network_proto = -1;
504 static int hf_time_sync_port_proto_addr_info_addr_size = -1;
505 static int hf_time_sync_port_proto_addr_info_port_proto_addr = -1;
506 static int hf_time_sync_steps_removed = -1;
507 static int hf_time_sync_sys_time_and_offset_time = -1;
508 static int hf_time_sync_sys_time_and_offset_offset = -1;
509 static int hf_port_entry_port = -1;
510 static int hf_port_type = -1;
511 static int hf_port_number = -1;
512 static int hf_port_min_node_num = -1;
513 static int hf_port_max_node_num = -1;
514 static int hf_port_name = -1;
515 static int hf_port_num_comm_object_entries = -1;
516 static int hf_path_len_usint = -1;
517 static int hf_path_len_uint = -1;
518
519 static int hf_32bitheader = -1;
520 static int hf_32bitheader_roo = -1;
521 static int hf_32bitheader_coo = -1;
522 static int hf_32bitheader_run_idle = -1;
523
524 static int hf_cip_connection = -1;
525
526 /* Initialize the subtree pointers */
527 static gint ett_cip = -1;
528 static gint ett_cip_class_generic = -1;
529 static gint ett_cip_class_cm = -1;
530 static gint ett_cip_class_pccc = -1;
531 static gint ett_cip_class_mb = -1;
532 static gint ett_cip_class_cco = -1;
533
534 static gint ett_path = -1;
535 static gint ett_path_seg = -1;
536 static gint ett_mcsc = -1;
537 static gint ett_cia_path = -1;
538 static gint ett_data_seg = -1;
539 static gint ett_port_path = -1;
540 static gint ett_network_seg = -1;
541 static gint ett_network_seg_safety = -1;
542 static gint ett_network_seg_safety_time_correction_net_params = -1;
543 static gint ett_cip_seg_safety_tunid = -1;
544 static gint ett_cip_seg_safety_tunid_snn = -1;
545 static gint ett_cip_seg_safety_ounid = -1;
546 static gint ett_cip_seg_safety_ounid_snn = -1;
547
548 static gint ett_rrsc = -1;
549 static gint ett_status_item = -1;
550 static gint ett_add_status_item = -1;
551 static gint ett_cmd_data = -1;
552
553 static gint ett_cip_get_attributes_all_item = -1;
554 static gint ett_cip_get_attribute_list = -1;
555 static gint ett_cip_get_attribute_list_item = -1;
556 static gint ett_cip_set_attribute_list = -1;
557 static gint ett_cip_set_attribute_list_item = -1;
558 static gint ett_cip_mult_service_packet = -1;
559 static gint ett_cip_msp_offset = -1;
560
561 static gint ett_cm_rrsc = -1;
562 static gint ett_cm_ncp = -1;
563 static gint ett_cm_mes_req = -1;
564 static gint ett_cm_cmd_data = -1;
565 static gint ett_cm_ttt = -1;
566 static gint ett_cm_add_status_item = -1;
567 static gint ett_cip_cm_pid = -1;
568 static gint ett_cip_cm_safety = -1;
569
570 static gint ett_pccc_rrsc = -1;
571 static gint ett_pccc_req_id = -1;
572 static gint ett_pccc_cmd_data = -1;
573
574 static gint ett_mb_rrsc = -1;
575 static gint ett_mb_cmd_data = -1;
576
577 static gint ett_cco_iomap = -1;
578 static gint ett_cco_con_status = -1;
579 static gint ett_cco_con_flag = -1;
580 static gint ett_cco_tdi = -1;
581 static gint ett_cco_pdi = -1;
582 static gint ett_cco_ncp = -1;
583 static gint ett_cco_rrsc = -1;
584 static gint ett_cco_cmd_data = -1;
585 static gint ett_cco_ttt = -1;
586
587 static gint ett_time_sync_gm_clock_flags = -1;
588 static gint ett_time_sync_local_clock_flags = -1;
589 static gint ett_time_sync_port_state_info = -1;
590 static gint ett_time_sync_port_enable_cfg = -1;
591 static gint ett_time_sync_port_log_announce = -1;
592 static gint ett_time_sync_port_log_sync = -1;
593 static gint ett_time_sync_clock_type = -1;
594 static gint ett_time_sync_port_profile_id_info = -1;
595 static gint ett_time_sync_port_phys_addr_info = -1;
596 static gint ett_time_sync_port_proto_addr_info = -1;
597 static gint ett_id_status = -1;
598 static gint ett_32bitheader_tree = -1;
599
600 static gint ett_connection_info = -1;
601
602 static const unit_name_string units_safety_128us = { " (128 us increment)", " (128 us increments)" };
603
604 static expert_field ei_mal_identity_revision = EI_INIT;
605 static expert_field ei_mal_identity_status = EI_INIT;
606 static expert_field ei_mal_msg_rout_num_classes = EI_INIT;
607 static expert_field ei_mal_time_sync_gm_clock = EI_INIT;
608 static expert_field ei_mal_time_sync_parent_clock = EI_INIT;
609 static expert_field ei_mal_time_sync_local_clock = EI_INIT;
610 static expert_field ei_mal_time_sync_port_state_info = EI_INIT;
611 static expert_field ei_mal_time_sync_port_state_info_ports = EI_INIT;
612 static expert_field ei_mal_time_sync_port_enable_cfg = EI_INIT;
613 static expert_field ei_mal_time_sync_port_enable_cfg_ports = EI_INIT;
614 static expert_field ei_mal_time_sync_port_log_announce = EI_INIT;
615 static expert_field ei_mal_time_sync_port_log_announce_ports = EI_INIT;
616 static expert_field ei_mal_time_sync_port_log_sync = EI_INIT;
617 static expert_field ei_mal_time_sync_port_log_sync_ports = EI_INIT;
618 static expert_field ei_mal_time_sync_clock_type = EI_INIT;
619 static expert_field ei_mal_time_sync_manufacture_id = EI_INIT;
620 static expert_field ei_mal_time_sync_prod_desc = EI_INIT;
621 static expert_field ei_mal_time_sync_prod_desc_64 = EI_INIT;
622 static expert_field ei_mal_time_sync_prod_desc_size = EI_INIT;
623 static expert_field ei_mal_time_sync_revision_data = EI_INIT;
624 static expert_field ei_mal_time_sync_revision_data_32 = EI_INIT;
625 static expert_field ei_mal_time_sync_revision_data_size = EI_INIT;
626 static expert_field ei_mal_time_sync_user_desc = EI_INIT;
627 static expert_field ei_mal_time_sync_user_desc_128 = EI_INIT;
628 static expert_field ei_mal_time_sync_user_desc_size = EI_INIT;
629 static expert_field ei_mal_time_sync_port_profile_id_info = EI_INIT;
630 static expert_field ei_mal_time_sync_port_profile_id_info_ports = EI_INIT;
631 static expert_field ei_mal_time_sync_port_phys_addr_info = EI_INIT;
632 static expert_field ei_mal_time_sync_port_phys_addr_info_ports = EI_INIT;
633 static expert_field ei_mal_time_sync_port_proto_addr_info = EI_INIT;
634 static expert_field ei_mal_time_sync_port_proto_addr_info_ports = EI_INIT;
635 static expert_field ei_mal_time_sync_sys_time_and_offset = EI_INIT;
636 static expert_field ei_proto_log_seg_format = EI_INIT;
637 static expert_field ei_mal_incomplete_epath = EI_INIT;
638 static expert_field ei_proto_electronic_key_format = EI_INIT;
639 static expert_field ei_proto_special_segment_format = EI_INIT;
640 static expert_field ei_proto_log_seg_type = EI_INIT;
641 static expert_field ei_proto_log_sub_seg_type = EI_INIT;
642 static expert_field ei_proto_ext_string_format = EI_INIT;
643 static expert_field ei_proto_ext_network = EI_INIT;
644 static expert_field ei_proto_seg_type = EI_INIT;
645 static expert_field ei_proto_unsupported_datatype = EI_INIT;
646 static expert_field ei_mal_serv_gal = EI_INIT;
647 static expert_field ei_mal_serv_gal_count = EI_INIT;
648 static expert_field ei_mal_serv_sal = EI_INIT;
649 static expert_field ei_mal_serv_sal_count = EI_INIT;
650 static expert_field ei_mal_msp_services = EI_INIT;
651 static expert_field ei_mal_msp_inv_offset = EI_INIT;
652 static expert_field ei_mal_msp_missing_services = EI_INIT;
653 static expert_field ei_mal_serv_find_next_object = EI_INIT;
654 static expert_field ei_mal_serv_find_next_object_count = EI_INIT;
655 static expert_field ei_mal_rpi_no_data = EI_INIT;
656 static expert_field ei_mal_fwd_close_missing_data = EI_INIT;
657 static expert_field ei_mal_opt_attr_list = EI_INIT;
658 static expert_field ei_mal_opt_service_list = EI_INIT;
659 static expert_field ei_mal_padded_epath_size = EI_INIT;
660 static expert_field ei_mal_missing_string_data = EI_INIT;
661
662 static dissector_table_t subdissector_class_table;
663 static dissector_table_t subdissector_symbol_table;
664
665 /* Translate function to string - CIP Service codes */
666 static const value_string cip_sc_vals[] = {
667 GENERIC_SC_LIST
668
669 { 0, NULL }
670 };
671
672 /* Translate function to string - CIP Service codes for CM */
673 static const value_string cip_sc_vals_cm[] = {
674 GENERIC_SC_LIST
675
676 /* Some class specific services */
677 { SC_CM_FWD_CLOSE, "Forward Close" },
678 { SC_CM_FWD_OPEN, "Forward Open" },
679 { SC_CM_UNCON_SEND, "Unconnected Send" },
680 { SC_CM_LARGE_FWD_OPEN, "Large Forward Open" },
681 { SC_CM_GET_CONN_DATA, "Get Connection Data" },
682 { SC_CM_SEARCH_CONN_DATA, "Search Connection Data" },
683 { SC_CM_GET_CONN_OWNER, "Get Connection Owner" },
684
685 { 0, NULL }
686 };
687
688 /* Translate function to string - CIP Service codes for PCCC */
689 static const value_string cip_sc_vals_pccc[] = {
690 GENERIC_SC_LIST
691
692 /* Some class specific services */
693 { SC_PCCC_EXECUTE_PCCC, "Execute PCCC" },
694
695 { 0, NULL }
696 };
697
698 /* Translate function to string - CIP Service codes for MB */
699 static const value_string cip_sc_vals_mb[] = {
700 GENERIC_SC_LIST
701
702 /* Some class specific services */
703 { SC_MB_READ_DISCRETE_INPUTS, "Read Discrete" },
704 { SC_MB_READ_COILS, "Read Coils" },
705 { SC_MB_READ_INPUT_REGISTERS, "Read Input Registers" },
706 { SC_MB_READ_HOLDING_REGISTERS, "Read Holding Registers" },
707 { SC_MB_WRITE_COILS, "Write Coils" },
708 { SC_MB_WRITE_HOLDING_REGISTERS, "Write Holding Registers" },
709 { SC_MB_PASSTHROUGH, "Modbus Passthrough" },
710
711 { 0, NULL }
712 };
713
714 /* Translate function to string - CIP Service codes for CCO */
715 static const value_string cip_sc_vals_cco[] = {
716 GENERIC_SC_LIST
717
718 /* Some class specific services */
719 { SC_CCO_KICK_TIMER, "Kick Timer" },
720 { SC_CCO_OPEN_CONN, "Open Connection" },
721 { SC_CCO_CLOSE_CONN, "Close Connection" },
722 { SC_CCO_STOP_CONN, "Stop Connection" },
723 { SC_CCO_CHANGE_START, "Change Start" },
724 { SC_CCO_GET_STATUS, "Get Status" },
725 { SC_CCO_CHANGE_COMPLETE, "Change Complete" },
726 { SC_CCO_AUDIT_CHANGE, "Audit Changes" },
727
728 { 0, NULL }
729 };
730
731 /* Translate function to string - CIP Request/Response */
732 const value_string cip_sc_rr[] = {
733 { 0, "Request" },
734 { 1, "Response" },
735
736 { 0, NULL }
737 };
738
739 /* Translate function to string - Compatibility */
740 static const value_string cip_com_bit_vals[] = {
741 { 0, "Bit Cleared" },
742 { 1, "Bit Set" },
743
744 { 0, NULL }
745 };
746
747 const value_string cip_reset_type_vals[] = {
748 { 0, "Cycle Power" },
749 { 1, "Factory Default" },
750 { 2, "Keep Communication Parameters" },
751
752 { 0, NULL }
753 };
754
755 /* Translate function to string - Connection priority */
756 static const value_string cip_con_prio_vals[] = {
757 { 0, "Low Priority" },
758 { 1, "High Priority" },
759 { 2, "Scheduled" },
760 { 3, "Urgent" },
761
762 { 0, NULL }
763 };
764
765 /* Translate function to string - Connection size fixed or variable */
766 static const value_string cip_con_fw_vals[] = {
767 { 0, "Fixed" },
768 { 1, "Variable" },
769
770 { 0, NULL }
771 };
772
773 /* Translate function to string - Connection owner */
774 static const value_string cip_con_owner_vals[] = {
775 { 0, "Non-Redundant" },
776 { 1, "Redundant" },
777
778 { 0, NULL }
779 };
780
781 /* Translate function to string - Connection direction */
782 static const value_string cip_con_dir_vals[] = {
783 { 0, "Client" },
784 { 1, "Server" },
785
786 { 0, NULL }
787 };
788
789 /* Translate function to string - Connection type*/
790 static const value_string cip_con_vals[] = {
791 { 0, "Originator" },
792 { 1, "Target" },
793
794 { 0, NULL }
795 };
796
797 /* Translate function to string - Production trigger */
798 static const value_string cip_con_trigg_vals[] = {
799 { 0, "Cyclic" },
800 { 1, "Change-Of-State" },
801 { 2, "Application Object" },
802
803 { 0, NULL }
804 };
805
806 /* Translate function to string - Transport class */
807 static const value_string cip_con_class_vals[] = {
808 { 0, "0" },
809 { 1, "1" },
810 { 2, "2" },
811 { 3, "3" },
812
813 { 0, NULL }
814 };
815
816 /* Translate function to string - Connection type */
817 static const value_string cip_con_type_vals[] = {
818 { CONN_TYPE_NULL, "Null" },
819 { CONN_TYPE_MULTICAST, "Multicast" },
820 { CONN_TYPE_P2P, "Point to Point" },
821 { CONN_TYPE_RESERVED, "Reserved" },
822
823 { 0, NULL }
824 };
825
826 /* Translate function to string - Timeout Multiplier */
827 static const value_string cip_con_time_mult_vals[] = {
828 { 0, "*4" },
829 { 1, "*8" },
830 { 2, "*16" },
831 { 3, "*32" },
832 { 4, "*64" },
833 { 5, "*128" },
834 { 6, "*256" },
835 { 7, "*512" },
836
837 { 0, NULL }
838 };
839
840 /* Translate function to string - Connection Last Action */
841 static const value_string cip_con_last_action_vals[] = {
842 { 0, "No Owner" },
843 { 1, "Owner Is Idle Mode" },
844 { 2, "Owner Is Run Mode" },
845 { 255, "Implementation not supported" },
846
847 { 0, NULL }
848 };
849
850 /* Translate function to string - real time transfer format type */
851 static const value_string cip_con_rtf_vals[] = {
852 { 0, "32-bit Header" },
853 { 1, "Zero data length idle mode"},
854 { 2, "Modeless" },
855 { 3, "Heartbeat" },
856 { 5, "Safety" },
857
858 { 0, NULL }
859 };
860
861 /* Translate function to string - CCO change type */
862 static const value_string cip_cco_change_type_vals[] = {
863 { 0, "Full" },
864 { 1, "Incremental" },
865
866 { 0, NULL }
867 };
868
869 static const value_string cip_time_sync_clock_class_vals[] = {
870 { 6, "Primary Reference" },
871 { 7, "Primary Reference (Hold)" },
872 { 52, "Degraded Reference A (Master only)" },
873 { 187, "Degraded Reference B (Master/Slave)" },
874 { 248, "Default" },
875 { 255, "Slave Only" },
876
877 { 0, NULL }
878 };
879
880 static const value_string cip_time_sync_time_accuracy_vals[] = {
881 { 0x20, "Accurate to within 25ns" },
882 { 0x21, "Accurate to within 100ns" },
883 { 0x22, "Accurate to within 250ns" },
884 { 0x23, "Accurate to within 1us" },
885 { 0x24, "Accurate to within 2.5us" },
886 { 0x25, "Accurate to within 10us" },
887 { 0x26, "Accurate to within 25us" },
888 { 0x27, "Accurate to within 100us" },
889 { 0x28, "Accurate to within 250us" },
890 { 0x29, "Accurate to within 1ms" },
891 { 0x2A, "Accurate to within 2.5ms" },
892 { 0x2B, "Accurate to within 10ms" },
893 { 0x2C, "Accurate to within 25ms" },
894 { 0x2D, "Accurate to within 100ms" },
895 { 0x2E, "Accurate to within 250ms" },
896 { 0x2F, "Accurate to within 1s" },
897 { 0x30, "Accurate to within 10s" },
898 { 0x31, "Accurate to >10s" },
899 { 0, NULL }
900 };
901
902 static const value_string cip_time_sync_time_source_vals[] = {
903 { 0x10, "Atomic Clock" },
904 { 0x20, "GPS" },
905 { 0x30, "Terrestrial Radio" },
906 { 0x40, "PTP" },
907 { 0x50, "NTP" },
908 { 0x60, "Hand Set" },
909 { 0x90, "Other" },
910 { 0xA0, "Internal Oscillator" },
911 { 0, NULL }
912 };
913
914 static const value_string cip_time_sync_port_state_vals[] = {
915 { 1, "INITIALIZING" },
916 { 2, "FAULTY" },
917 { 3, "DISABLED" },
918 { 4, "LISTENING" },
919 { 5, "PRE_MASTER" },
920 { 6, "MASTER" },
921 { 7, "PASSIVE" },
922 { 8, "UNCALIBRATED" },
923 { 9, "SLAVE" },
924 { 0, NULL }
925 };
926
927 static const value_string cip_time_sync_network_protocol_vals[] = {
928 { 1, "UDP/IPv4" },
929 { 2, "UDP/IPv6" },
930 { 3, "IEEE 802.3" },
931 { 4, "DeviceNet" },
932 { 5, "ControlNet" },
933 { 0xFFFF, "Local or Unknown protocol" },
934 { 0, NULL }
935 };
936
937 static const value_string cip_path_seg_vals[] = {
938 { ((CI_PORT_SEGMENT>>5)&7), "Port Segment" },
939 { ((CI_LOGICAL_SEGMENT>>5)&7), "Logical Segment" },
940 { ((CI_NETWORK_SEGMENT>>5)&7), "Network Segment" },
941 { ((CI_SYMBOLIC_SEGMENT>>5)&7), "Symbolic Segment" },
942 { ((CI_DATA_SEGMENT>>5)&7), "Data Segment" },
943 { 5, "Constructed Data Type" },
944 { 6, "Elementary Data Type" },
945 { 7, "Reserved" },
946
947 { 0, NULL }
948 };
949
950 static const value_string cip_logical_segment_type_vals[] = {
951 { ((CI_LOGICAL_SEG_CLASS_ID>>2)&7), "Class ID" },
952 { ((CI_LOGICAL_SEG_INST_ID>>2)&7), "Instance ID" },
953 { ((CI_LOGICAL_SEG_MBR_ID>>2)&7), "Member ID" },
954 { ((CI_LOGICAL_SEG_CON_POINT>>2)&7), "Connection Point" },
955 { ((CI_LOGICAL_SEG_ATTR_ID>>2)&7), "Attribute ID" },
956 { ((CI_LOGICAL_SEG_SPECIAL>>2)&7), "Special" },
957 { ((CI_LOGICAL_SEG_SERV_ID>>2)&7), "Service ID" },
958 { ((CI_LOGICAL_SEG_EXT_LOGICAL>>2)&7), "Extended Logical" },
959
960 { 0, NULL }
961 };
962
963 static const value_string cip_logical_segment_format_vals[] = {
964 { CI_LOGICAL_SEG_8_BIT, "8-bit Logical Segment" },
965 { CI_LOGICAL_SEG_16_BIT, "16-bit Logical Segment" },
966 { CI_LOGICAL_SEG_32_BIT, "32-bit Logical Segment" },
967 { CI_LOGICAL_SEG_RES_2, "Reserved" },
968
969 { 0, NULL }
970 };
971
972 static const value_string cip_logical_seg_vals[] = {
973 {((CI_LOGICAL_SEG_CLASS_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_8_BIT), "8-Bit Class Segment"},
974 {((CI_LOGICAL_SEG_CLASS_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_16_BIT), "16-Bit Class Segment"},
975 {((CI_LOGICAL_SEG_CLASS_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_32_BIT), "32-Bit Class Segment"},
976
977 {((CI_LOGICAL_SEG_INST_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_8_BIT), "8-Bit Instance Segment"},
978 {((CI_LOGICAL_SEG_INST_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_16_BIT), "16-Bit Instance Segment"},
979 {((CI_LOGICAL_SEG_INST_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_32_BIT), "32-Bit Instance Segment"},
980
981 {((CI_LOGICAL_SEG_MBR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_8_BIT), "8-Bit Member Segment"},
982 {((CI_LOGICAL_SEG_MBR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_16_BIT), "16-Bit Member Segment"},
983 {((CI_LOGICAL_SEG_MBR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_32_BIT), "32-Bit Member Segment"},
984
985 {((CI_LOGICAL_SEG_CON_POINT & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_8_BIT), "8-Bit Connection Point Segment"},
986 {((CI_LOGICAL_SEG_CON_POINT & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_16_BIT), "16-Bit Connection Point Segment"},
987 {((CI_LOGICAL_SEG_CON_POINT & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_32_BIT), "32-Bit Connection Point Segment"},
988
989 {((CI_LOGICAL_SEG_ATTR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_8_BIT), "8-Bit Attribute Segment"},
990 {((CI_LOGICAL_SEG_ATTR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_16_BIT), "16-Bit Attribute Segment"},
991 {((CI_LOGICAL_SEG_ATTR_ID & CI_LOGICAL_SEG_TYPE_MASK)|CI_LOGICAL_SEG_32_BIT), "32-Bit Attribute Segment"},
992
993 {((CI_LOGICAL_SEG_SERV_ID & CI_LOGICAL_SEG_TYPE_MASK) | CI_LOGICAL_SEG_8_BIT), "8-Bit Service ID Segment"},
994
995 {CI_LOGICAL_SEG_SPECIAL, "Electronic Key Segment"},
996
997 {((CI_LOGICAL_SEG_EXT_LOGICAL & CI_LOGICAL_SEG_TYPE_MASK) | CI_LOGICAL_SEG_8_BIT), "8-Bit Extended Logical Segment"},
998 {((CI_LOGICAL_SEG_EXT_LOGICAL & CI_LOGICAL_SEG_TYPE_MASK) | CI_LOGICAL_SEG_16_BIT), "16-Bit Extended Logical Segment"},
999 {((CI_LOGICAL_SEG_EXT_LOGICAL & CI_LOGICAL_SEG_TYPE_MASK) | CI_LOGICAL_SEG_32_BIT), "32-Bit Extended Logical Segment"},
1000
1001 { 0, NULL }
1002 };
1003
1004 static const value_string cip_ext_logical_segment_format_vals[] = {
1005 { 0, "Reserved" },
1006 { 1, "Array Index" },
1007 { 2, "Indirect Array Index" },
1008 { 3, "Bit Index" },
1009 { 4, "Indirect Bit Index" },
1010 { 5, "Structure Member Number" },
1011 { 6, "Structure Member Handle" },
1012
1013 { 0, NULL }
1014 };
1015
1016 static const value_string cip_data_segment_type_vals[] = {
1017 {CI_DATA_SEG_SIMPLE, "Simple Data Segment"},
1018 {CI_DATA_SEG_SYMBOL, "ANSI Extended Symbol Segment"},
1019
1020 { 0, NULL }
1021 };
1022
1023 static const value_string cip_network_segment_type_vals[] = {
1024 {CI_NETWORK_SEG_SCHEDULE, "Schedule Segment"},
1025 {CI_NETWORK_SEG_FIXED_TAG, "Fixed Tag Segment"},
1026 {CI_NETWORK_SEG_PROD_INHI, "Production Inhibit Time in Milliseconds"},
1027 {CI_NETWORK_SEG_SAFETY, "Safety Segment"},
1028 {CI_NETWORK_SEG_PROD_INHI_US, "Production Inhibit Time in Microseconds"},
1029 {CI_NETWORK_SEG_EXTENDED, "Extended Network Segment"},
1030
1031 { 0, NULL }
1032 };
1033
1034 static const value_string cip_symbolic_format_vals[] = {
1035 { 1, "Double Byte Segment" },
1036 { 2, "Triple Byte Segment" },
1037 { 6, "Numeric Segment" },
1038
1039 { 0, NULL }
1040 };
1041
1042 static const value_string cip_symbolic_numeric_format_vals[] = {
1043 { 6, "USINT" },
1044 { 7, "UINT" },
1045 { 8, "UDINT" },
1046
1047 { 0, NULL }
1048 };
1049
1050 static const value_string cip_safety_segment_format_type_vals[] = {
1051 {0, "Target Format"},
1052 {1, "Router Format"},
1053 {2, "Extended Format"},
1054
1055 { 0, NULL }
1056 };
1057
1058 static const value_string cip_cm_rpi_type_vals[] = {
1059 {0, "RPI acceptable"},
1060 {1, "Unspecified"},
1061 {2, "Minimum acceptable RPI"},
1062 {3, "Maximum acceptable RPI"},
1063 {4, "Required RPI to correct mismatch"},
1064
1065 { 0, NULL }
1066 };
1067
1068 /* Translate function to string - CIP General Status codes */
1069 static const value_string cip_gs_vals[] = {
1070 { CI_GRC_SUCCESS, "Success" },
1071 { CI_GRC_FAILURE, "Connection failure" },
1072 { CI_GRC_NO_RESOURCE, "Resource unavailable" },
1073 { CI_GRC_BAD_DATA, "Invalid parameter value" },
1074 { CI_GRC_BAD_PATH, "Path segment error" },
1075 { CI_GRC_BAD_CLASS_INSTANCE, "Path destination unknown" },
1076 { CI_GRC_PARTIAL_DATA, "Partial transfer" },
1077 { CI_GRC_CONN_LOST, "Connection lost" },
1078 { CI_GRC_BAD_SERVICE, "Service not supported" },
1079 { CI_GRC_BAD_ATTR_DATA, "Invalid attribute value" },
1080 { CI_GRC_ATTR_LIST_ERROR, "Attribute list error" },
1081 { CI_GRC_ALREADY_IN_MODE, "Already in requested mode/state" },
1082 { CI_GRC_BAD_OBJ_MODE, "Object state conflict" },
1083 { CI_GRC_OBJ_ALREADY_EXISTS, "Object already exists" },
1084 { CI_GRC_ATTR_NOT_SETTABLE, "Attribute not settable" },
1085 { CI_GRC_PERMISSION_DENIED, "Privilege violation" },
1086 { CI_GRC_DEV_IN_WRONG_STATE, "Device state conflict" },
1087 { CI_GRC_REPLY_DATA_TOO_LARGE,"Reply data too large" },
1088 { CI_GRC_FRAGMENT_PRIMITIVE, "Fragmentation of a primitive value" },
1089 { CI_GRC_CONFIG_TOO_SMALL, "Not enough data" },
1090 { CI_GRC_UNDEFINED_ATTR, "Attribute not supported" },
1091 { CI_GRC_CONFIG_TOO_BIG, "Too much data" },
1092 { CI_GRC_OBJ_DOES_NOT_EXIST, "Object does not exist" },
1093 { CI_GRC_NO_FRAGMENTATION, "Service fragmentation sequence not in progress" },
1094 { CI_GRC_DATA_NOT_SAVED, "No stored attribute data" },
1095 { CI_GRC_DATA_WRITE_FAILURE, "Store operation failure" },
1096 { CI_GRC_REQUEST_TOO_LARGE, "Routing failure, request packet too large" },
1097 { CI_GRC_RESPONSE_TOO_LARGE, "Routing failure, response packet too large" },
1098 { CI_GRC_MISSING_LIST_DATA, "Missing attribute list entry data" },
1099 { CI_GRC_INVALID_LIST_STATUS, "Invalid attribute value list" },
1100 { CI_GRC_SERVICE_ERROR, "Embedded service error" },
1101 { CI_GRC_CONN_RELATED_FAILURE,"Vendor specific error" },
1102 { CI_GRC_INVALID_PARAMETER, "Invalid parameter" },
1103 { CI_GRC_WRITE_ONCE_FAILURE, "Write-once value or medium already written" },
1104 { CI_GRC_INVALID_REPLY, "Invalid reply received" },
1105 { CI_GRC_BUFFER_OVERFLOW, "Buffer overflow" },
1106 { CI_GRC_MESSAGE_FORMAT, "Invalid message format" },
1107 { CI_GRC_BAD_KEY_IN_PATH, "Key failure in path" },
1108 { CI_GRC_BAD_PATH_SIZE, "Path size invalid" },
1109 { CI_GRC_UNEXPECTED_ATTR, "Unexpected attribute in list" },
1110 { CI_GRC_INVALID_MEMBER, "Invalid Member ID" },
1111 { CI_GRC_MEMBER_NOT_SETTABLE, "Member not settable" },
1112 { CI_GRC_G2_SERVER_FAILURE, "Group 2 only server general failure" },
1113 { CI_GRC_UNKNOWN_MB_ERROR, "Unknown Modbus error" },
1114 { CI_GRC_ATTRIBUTE_NOT_GET, "Attribute not gettable" },
1115
1116 { 0, NULL }
1117 };
1118
1119 value_string_ext cip_gs_vals_ext = VALUE_STRING_EXT_INIT(cip_gs_vals);
1120
1121 /* Connection Manager Extended Status codes */
1122 #define CM_ES_DUP_FWD_OPEN 0x100
1123 #define CM_ES_CLASS_AND_TRIGGER 0x103
1124 #define CM_ES_OWNERSHIP_CONFLICT 0x106
1125 #define CM_ES_TARGET_CONN_NOT_FOUND 0x107
1126 #define CM_ES_INVALID_NET_CONN_PARAM 0x108
1127 #define CM_ES_INVALID_CONNECTION_SIZE 0x109
1128 #define CM_ES_TARGET_CONNECTION_NOT_CONFIGURED 0x110
1129 #define CM_ES_RPI_NOT_SUPPORTED 0x111
1130 #define CM_ES_RPI_NOT_ACCEPTABLE 0x112
1131 #define CM_ES_OUT_OF_CONNECTIONS 0x113
1132 #define CM_ES_VENDOR_ID_OR_PRODUCT_CODE_MISMATCH 0x114
1133 #define CM_ES_DEVICE_TYPE_MISMATCH 0x115
1134 #define CM_ES_REVISION_MISMATCH 0x116
1135 #define CM_ES_INVALID_PROD_CONS_APP_PATH 0x117
1136 #define CM_ES_INVALID_OR_INCONSISTENT_CONF_APP_PATH 0x118
1137 #define CM_ES_NON_LISTEN_ONLY_CONN_NOT_OPENED 0x119
1138 #define CM_ES_TARGET_OBJECT_OUT_OF_CONNECTIONS 0x11A
1139 #define CM_ES_RPI_SMALLER_THAN_PROD_INHIBIT_TIME 0x11B
1140 #define CM_ES_TRANSPORT_CLASS_NOT_SUPPORTED 0x11C
1141 #define CM_ES_PRODUCTION_TRIGGER_NOT_SUPPORTED 0x11D
1142 #define CM_ES_DIRECTION_NOT_SUPPORTED 0x11E
1143 #define CM_ES_INVALID_OT_NET_CONN_FIX_VAR 0x11F
1144 #define CM_ES_INVALID_TO_NET_CONN_FIX_VAR 0x120
1145 #define CM_ES_INVALID_OT_NET_CONN_PRIORITY 0x121
1146 #define CM_ES_INVALID_TO_NET_CONN_PRIORITY 0x122
1147 #define CM_ES_INVALID_OT_NET_CONN_TYPE 0x123
1148 #define CM_ES_INVALID_TO_NET_CONN_TYPE 0x124
1149 #define CM_ES_INVALID_OT_NET_CONN_REDUNDANT_OWNER 0x125
1150 #define CM_ES_INVALID_CONFIGURATION_SIZE 0x126
1151 #define CM_ES_INVALID_OT_SIZE 0x127
1152 #define CM_ES_INVALID_TO_SIZE 0x128
1153 #define CM_ES_INVALID_CONFIGURATION_APP_PATH 0x129
1154 #define CM_ES_INVALID_CONSUMING_APP_PATH 0x12A
1155 #define CM_ES_INVALID_PRODUCING_APP_PATH 0x12B
1156 #define CM_ES_CONFIGURATION_SYMBOL_NOT_EXIST 0x12C
1157 #define CM_ES_CONSUMING_SYMBOL_NOT_EXIST 0x12D
1158 #define CM_ES_PRODUCING_SYMBOL_NOT_EXIST 0x12E
1159 #define CM_ES_INCONSISTENT_APP_PATH_COMBO 0x12F
1160 #define CM_ES_INCONSISTENT_CONSUME_DATA_FORMAT 0x130
1161 #define CM_ES_INCONSISTENT_PRODUCE_DATA_FORMAT 0x131
1162 #define CM_ES_NULL_FORWARD_OPEN_NOT_SUPPORTED 0x132
1163 #define CM_ES_CONNECTION_TIMED_OUT 0x203
1164 #define CM_ES_UNCONNECTED_REQUEST_TIMED_OUT 0x204
1165 #define CM_ES_PARAMETER_ERROR_IN_UNCONNECTED_REQUEST 0x205
1166 #define CM_ES_MESSAGE_TOO_LARGE_FOR_UNCONNECTED_SEND 0x206
1167 #define CM_ES_UNCONNECTED_ACK_WITHOUT_REPLY 0x207
1168 #define CM_ES_NO_BUFFER_MEMORY_AVAILABLE 0x301
1169 #define CM_ES_NETWORK_BANDWIDTH_NOT_AVAIL_FOR_DATA 0x302
1170 #define CM_ES_NO_CONSUMED_CONN_ID_FILTER_AVAILABLE 0x303
1171 #define CM_ES_NOT_CONFIGURED_TO_SEND_SCHEDULED_DATA 0x304
1172 #define CM_ES_SCHEDULE_SIGNATURE_MISMATCH 0x305
1173 #define CM_ES_SCHEDULE_SIGNATURE_VALIDATION_NOT_POSS 0x306
1174 #define CM_ES_PORT_NOT_AVAILABLE 0x311
1175 #define CM_ES_LINK_ADDRESS_NOT_VALID 0x312
1176 #define CM_ES_INVALID_SEGMENT_IN_CONN_PATH 0x315
1177 #define CM_ES_FWD_CLOSE_CONN_PATH_MISMATCH 0x316
1178 #define CM_ES_SCHEDULING_NOT_SPECIFIED 0x317
1179 #define CM_ES_LINK_ADDRESS_TO_SELF_INVALID 0x318
1180 #define CM_ES_SECONDARY_RESOURCES_UNAVAILABLE 0x319
1181 #define CM_ES_RACK_CONNECTION_ALREADY_ESTABLISHED 0x31A
1182 #define CM_ES_MODULE_CONNECTION_ALREADY_ESTABLISHED 0x31B
1183 #define CM_ES_MISCELLANEOUS 0x31C
1184 #define CM_ES_REDUNDANT_CONNECTION_MISMATCH 0x31D
1185 #define CM_ES_NO_CONSUMER_RES_AVAIL_IN_PROD_MODULE 0x31E
1186 #define CM_ES_NO_CONSUMER_RES_CONF_IN_PROD_MODULE 0x31F
1187 #define CM_ES_NETWORK_LINK_OFFLINE 0x800
1188 #define CM_ES_INCOMPATIBLE_MULTICAST_RPI 0x801
1189 #define CM_ES_INVALID_SAFETY_CONN_SIZE 0x802
1190 #define CM_ES_INVALID_SAFETY_CONN_FORMAT 0x803
1191 #define CM_ES_INVALID_TIME_CORRECTION_CONN_PARAM 0x804
1192 #define CM_ES_INVALID_PING_INTERVAL_EPI_MULTIPLIER 0x805
1193 #define CM_ES_TIME_COORDINATION_MSG_MIN_MULTIPLIER 0x806
1194 #define CM_ES_NETWORK_TIME_EXPECTATION_MULTIPLIER 0x807
1195 #define CM_ES_TIMEOUT_MULTIPLIER 0x808
1196 #define CM_ES_INVALID_MAX_CONSUMER_NUMBER 0x809
1197 #define CM_ES_INVALID_CPCRC 0x80A
1198 #define CM_ES_TIME_CORRECTION_CONN_ID_INVALID 0x80B
1199 #define CM_ES_SCID_MISMATCH 0x80C
1200 #define CM_ES_TUNID_NOT_SET 0x80D
1201 #define CM_ES_TUNID_MISMATCH 0x80E
1202 #define CM_ES_CONFIGURATION_OPERATION_NOT_ALLOWED 0x80F
1203 #define CM_ES_NO_TARGET_APP_DATA_AVAILABLE 0x810
1204 #define CM_ES_NO_ORIG_APP_DATA_AVAILABLE 0x811
1205 #define CM_ES_NODE_ADDRESS_CHANGED_AFTER_SCHEDULED 0x812
1206 #define CM_ES_NOT_CONFIGURED_MULTICAST 0x813
1207 #define CM_ES_INVALID_PROD_CONS_DATA_FORMAT 0x814
1208
1209 /* Translate function to string - CIP Extended Status codes */
1210 static const value_string cip_cm_ext_st_vals[] = {
1211 { CM_ES_DUP_FWD_OPEN, "Connection in use or duplicate Forward Open" },
1212 { CM_ES_CLASS_AND_TRIGGER, "Transport class and trigger combination not supported" },
1213 { CM_ES_OWNERSHIP_CONFLICT, "Ownership conflict" },
1214 { CM_ES_TARGET_CONN_NOT_FOUND, "Target connection not found" },
1215 { CM_ES_INVALID_NET_CONN_PARAM, "Invalid network connection parameter" },
1216 { CM_ES_INVALID_CONNECTION_SIZE, "Invalid connection size" },
1217 { CM_ES_TARGET_CONNECTION_NOT_CONFIGURED, "Target for connection not configured" },
1218 { CM_ES_RPI_NOT_SUPPORTED, "RPI not supported" },
1219 { CM_ES_RPI_NOT_ACCEPTABLE, "RPI value(s) not acceptable" },
1220 { CM_ES_OUT_OF_CONNECTIONS, "Out of connections" },
1221 { CM_ES_VENDOR_ID_OR_PRODUCT_CODE_MISMATCH, "Vendor ID or product code mismatch" },
1222 { CM_ES_DEVICE_TYPE_MISMATCH, "Device type mismatch" },
1223 { CM_ES_REVISION_MISMATCH, "Revision mismatch" },
1224 { CM_ES_INVALID_PROD_CONS_APP_PATH, "Invalid produced or consumed application path" },
1225 { CM_ES_INVALID_OR_INCONSISTENT_CONF_APP_PATH, "Invalid or inconsistent configuration application path" },
1226 { CM_ES_NON_LISTEN_ONLY_CONN_NOT_OPENED, "Non-listen only connection not opened" },
1227 { CM_ES_TARGET_OBJECT_OUT_OF_CONNECTIONS, "Target object out of connections" },
1228 { CM_ES_RPI_SMALLER_THAN_PROD_INHIBIT_TIME, "RPI is smaller than the production inhibit time" },
1229 { CM_ES_TRANSPORT_CLASS_NOT_SUPPORTED, "Transport class not supported" },
1230 { CM_ES_PRODUCTION_TRIGGER_NOT_SUPPORTED, "Production trigger not supported" },
1231 { CM_ES_DIRECTION_NOT_SUPPORTED, "Direction not supported" },
1232 { CM_ES_INVALID_OT_NET_CONN_FIX_VAR, "Invalid O->T Fixed/Variable" },
1233 { CM_ES_INVALID_TO_NET_CONN_FIX_VAR, "Invalid T->O Fixed/Variable" },
1234 { CM_ES_INVALID_OT_NET_CONN_PRIORITY, "Invalid O->T Priority" },
1235 { CM_ES_INVALID_TO_NET_CONN_PRIORITY, "Invalid T->O Priority" },
1236 { CM_ES_INVALID_OT_NET_CONN_TYPE, "Invalid O->T connection type" },
1237 { CM_ES_INVALID_TO_NET_CONN_TYPE, "Invalid T->O connection type" },
1238 { CM_ES_INVALID_OT_NET_CONN_REDUNDANT_OWNER, "Invalid O->T redundant owner" },
1239 { CM_ES_INVALID_CONFIGURATION_SIZE, "Invalid configuration size" },
1240 { CM_ES_INVALID_OT_SIZE, "Invalid O->T size" },
1241 { CM_ES_INVALID_TO_SIZE, "Invalid T->O size" },
1242 { CM_ES_INVALID_CONFIGURATION_APP_PATH, "Invalid configuration application path" },
1243 { CM_ES_INVALID_CONSUMING_APP_PATH, "Invalid consuming application path" },
1244 { CM_ES_INVALID_PRODUCING_APP_PATH, "Invalid producing application path" },
1245 { CM_ES_CONFIGURATION_SYMBOL_NOT_EXIST, "Configuration symbol does not exist" },
1246 { CM_ES_CONSUMING_SYMBOL_NOT_EXIST, "Consuming symbol does not exist" },
1247 { CM_ES_PRODUCING_SYMBOL_NOT_EXIST, "Producing symbol does not exist" },
1248 { CM_ES_INCONSISTENT_APP_PATH_COMBO, "Inconsistent application path combination" },
1249 { CM_ES_INCONSISTENT_CONSUME_DATA_FORMAT, "Inconsistent consume data format" },
1250 { CM_ES_INCONSISTENT_PRODUCE_DATA_FORMAT, "Inconsistent produce data format" },
1251 { CM_ES_NULL_FORWARD_OPEN_NOT_SUPPORTED, "NULL ForwardOpen not supported" },
1252 { CM_ES_CONNECTION_TIMED_OUT, "Connection timed out" },
1253 { CM_ES_UNCONNECTED_REQUEST_TIMED_OUT, "Unconnected request timed out" },
1254 { CM_ES_PARAMETER_ERROR_IN_UNCONNECTED_REQUEST, "Parameter error in unconnected request" },
1255 { CM_ES_MESSAGE_TOO_LARGE_FOR_UNCONNECTED_SEND, "Message too large for UnconnectedSend" },
1256 { CM_ES_UNCONNECTED_ACK_WITHOUT_REPLY, "Unconnected acknowledged without reply" },
1257 { CM_ES_NO_BUFFER_MEMORY_AVAILABLE, "No buffer memory available" },
1258 { CM_ES_NETWORK_BANDWIDTH_NOT_AVAIL_FOR_DATA, "Network bandwidth not available for data" },
1259 { CM_ES_NO_CONSUMED_CONN_ID_FILTER_AVAILABLE, "No consumed connection ID filter available" },
1260 { CM_ES_NOT_CONFIGURED_TO_SEND_SCHEDULED_DATA, "Not configured to send scheduled priority data" },
1261 { CM_ES_SCHEDULE_SIGNATURE_MISMATCH, "Schedule signature mismatch" },
1262 { CM_ES_SCHEDULE_SIGNATURE_VALIDATION_NOT_POSS, "Schedule signature validation not possible" },
1263 { CM_ES_PORT_NOT_AVAILABLE, "Port not available" },
1264 { CM_ES_LINK_ADDRESS_NOT_VALID, "Link address not valid" },
1265 { CM_ES_INVALID_SEGMENT_IN_CONN_PATH, "Invalid segment in connection path" },
1266 { CM_ES_FWD_CLOSE_CONN_PATH_MISMATCH, "ForwardClose connection path mismatch" },
1267 { CM_ES_SCHEDULING_NOT_SPECIFIED, "Scheduling not specified" },
1268 { CM_ES_LINK_ADDRESS_TO_SELF_INVALID, "Link address to self invalid" },
1269 { CM_ES_SECONDARY_RESOURCES_UNAVAILABLE, "Secondary resources unavailable" },
1270 { CM_ES_RACK_CONNECTION_ALREADY_ESTABLISHED, "Rack connection already established" },
1271 { CM_ES_MODULE_CONNECTION_ALREADY_ESTABLISHED, "Module connection already established" },
1272 { CM_ES_MISCELLANEOUS, "Miscellaneous" },
1273 { CM_ES_REDUNDANT_CONNECTION_MISMATCH, "Redundant connection mismatch" },
1274 { CM_ES_NO_CONSUMER_RES_AVAIL_IN_PROD_MODULE, "No more user configurable link consumer resources available in the producing module" },
1275 { CM_ES_NO_CONSUMER_RES_CONF_IN_PROD_MODULE, "No more user configurable link consumer resources configured in the producing module" },
1276 { CM_ES_NETWORK_LINK_OFFLINE, "Network link offline" },
1277 { CM_ES_INCOMPATIBLE_MULTICAST_RPI, "Incompatible Multicast RPI" },
1278 { CM_ES_INVALID_SAFETY_CONN_SIZE, "Invalid Safety Connection Size" },
1279 { CM_ES_INVALID_SAFETY_CONN_FORMAT, "Invalid Safety Connection Format" },
1280 { CM_ES_INVALID_TIME_CORRECTION_CONN_PARAM, "Invalid Time Correction Connection Parameters" },
1281 { CM_ES_INVALID_PING_INTERVAL_EPI_MULTIPLIER, "Invalid Ping Interval EPI Multiplier" },
1282 { CM_ES_TIME_COORDINATION_MSG_MIN_MULTIPLIER, "Time Coordination Msg Min Multiplier" },
1283 { CM_ES_NETWORK_TIME_EXPECTATION_MULTIPLIER, "Network Time Expectation Multiplier" },
1284 { CM_ES_TIMEOUT_MULTIPLIER, "Timeout Multiplier" },
1285 { CM_ES_INVALID_MAX_CONSUMER_NUMBER, "Invalid Max Consumer Number" },
1286 { CM_ES_INVALID_CPCRC, "Invalid CPCRC" },
1287 { CM_ES_TIME_CORRECTION_CONN_ID_INVALID, "Time Correction Connection ID Invalid" },
1288 { CM_ES_SCID_MISMATCH, "SCID Mismatch" },
1289 { CM_ES_TUNID_NOT_SET, "TUNID not set" },
1290 { CM_ES_TUNID_MISMATCH, "TUNID Mismatch" },
1291 { CM_ES_CONFIGURATION_OPERATION_NOT_ALLOWED, "Configuration operation not allowed" },
1292 { CM_ES_NO_TARGET_APP_DATA_AVAILABLE, "No target application data available" },
1293 { CM_ES_NO_ORIG_APP_DATA_AVAILABLE, "No originator application data available" },
1294 { CM_ES_NODE_ADDRESS_CHANGED_AFTER_SCHEDULED, "Node address has changed since the network was scheduled" },
1295 { CM_ES_NOT_CONFIGURED_MULTICAST, "Not configured for off-subnet multicast" },
1296 { CM_ES_INVALID_PROD_CONS_DATA_FORMAT, "Invalid produce/consume data format" },
1297
1298 { 0, NULL }
1299 };
1300
1301 value_string_ext cip_cm_ext_st_vals_ext = VALUE_STRING_EXT_INIT(cip_cm_ext_st_vals);
1302
1303 /* Translate function to string - PCCC Status codes */
1304 static const value_string cip_pccc_gs_st_vals[] = {
1305 { PCCC_GS_SUCCESS, "Success" },
1306 { PCCC_GS_ILLEGAL_CMD, "Illegal command or format" },
1307 { PCCC_GS_HOST_COMMS, "Host has a problem and will not communicate" },
1308 { PCCC_GS_MISSING_REMOTE_NODE, "Remote node host is missing, disconnected, or shut down" },
1309 { PCCC_GS_HARDWARE_FAULT, "Host could not complete function due to hardware fault" },
1310 { PCCC_GS_ADDRESSING_ERROR, "Addressing problem or memory protect rungs" },
1311 { PCCC_GS_CMD_PROTECTION, "Function not allowed due to command protection selection" },
1312 { PCCC_GS_PROGRAM_MODE, "Processor is in Program mode" },
1313 { PCCC_GS_MISSING_COMPATABILITY_FILE, "Compatibility mode file missing or communication zone problem" },
1314 { PCCC_GS_BUFFER_FULL_1, "Remote node cannot buffer command" },
1315 { PCCC_GS_WAIT_ACK, "Wait ACK (1775-KA buffer full)" },
1316 { PCCC_GS_REMOTE_DOWNLOAD_ERROR, "Remote node problem due to download" },
1317 { PCCC_GS_BUFFER_FULL_2, "Wait ACK (1775-KA buffer full)" },
1318 { PCCC_GS_NOT_USED_1, "Not used" },
1319 { PCCC_GS_NOT_USED_2, "Not used" },
1320 { PCCC_GS_USE_EXTSTS, "Error code in the EXT STS byte" },
1321
1322 { 0, NULL }
1323 };
1324
1325 static value_string_ext cip_pccc_gs_st_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_gs_st_vals);
1326
1327 /* Translate function to string - PCCC Extended Status codes */
1328 static const value_string cip_pccc_es_st_vals[] = {
1329 { PCCC_ES_ILLEGAL_VALUE, "A field has an illegal value" },
1330 { PCCC_ES_SHORT_ADDRESS, "Less levels specified in address than minimum for any address" },
1331 { PCCC_ES_LONG_ADDRESS, "More levels specified in address than system supports" },
1332 { PCCC_ES_NOT_FOUND, "Symbol not found" },
1333 { PCCC_ES_BAD_FORMAT, "Symbol is of improper format" },
1334 { PCCC_ES_BAD_POINTER, "Address doesn't point to something usable" },
1335 { PCCC_ES_BAD_SIZE, "File is wrong size" },
1336 { PCCC_ES_SITUATION_CHANGED, "Cannot complete request, situation has changed since the start of the command" },
1337 { PCCC_ES_DATA_TOO_LARGE, "Data or file is too large" },
1338 { PCCC_ES_TRANS_TOO_LARGE, "Transaction size plus word address is too large" },
1339 { PCCC_ES_ACCESS_DENIED, "Access denied, improper privilege" },
1340 { PCCC_ES_NOT_AVAILABLE, "Condition cannot be generated - resource is not available" },
1341 { PCCC_ES_ALREADY_EXISTS, "Condition already exists - resource is already available" },
1342 { PCCC_ES_NO_EXECUTION, "Command cannot be executed" },
1343 { PCCC_ES_HIST_OVERFLOW, "Histogram overflow" },
1344 { PCCC_ES_NO_ACCESS, "No access" },
1345 { PCCC_ES_ILLEGAL_DATA_TYPE, "Illegal data type" },
1346 { PCCC_ES_INVALID_DATA, "Invalid parameter or invalid data" },
1347 { PCCC_ES_BAD_REFERENCE, "Address reference exists to deleted area" },
1348 { PCCC_ES_EXECUTION_FAILURE, "Command execution failure for unknown reason; possible PLC-3 histogram overflow" },
1349 { PCCC_ES_CONVERSION_ERROR, "Data conversion error" },
1350 { PCCC_ES_NO_COMMS, "Scanner not able to communicate with 1771 rack adapter" },
1351 { PCCC_ES_TYPE_MISMATCH, "Type mismatch" },
1352 { PCCC_ES_BAD_RESPONSE, "1771 module response was not valid" },
1353 { PCCC_ES_DUP_LABEL, "Duplicated label" },
1354 { PCCC_ES_FILE_ALREADY_OPEN, "File is open; another node owns it" },
1355 { PCCC_ES_PROGRAM_ALREADY_OWNED, "Another node is the program owner" },
1356 { PCCC_ES_RESERVED_1, "Reserved" },
1357 { PCCC_ES_RESERVED_2, "Reserved" },
1358 { PCCC_ES_PROTECTION_VIOLATION, "Data table element protection violation" },
1359 { PCCC_ES_TMP_INTERNAL_ERROR, "Temporary internal problem" },
1360 { PCCC_ES_RACK_FAULT, "Remote rack fault" },
1361 { PCCC_ES_TIMEOUT, "Timeout" },
1362 { PCCC_ES_UNKNOWN, "Unknown error" },
1363
1364 { 0, NULL }
1365 };
1366
1367 static value_string_ext cip_pccc_es_st_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_es_st_vals);
1368
1369 /* Translate PCCC Function Codes */
1370 static const value_string cip_pccc_fnc_06_vals[] = {
1371 { PCCC_FNC_06_00, "Echo" },
1372 { PCCC_FNC_06_01, "Read diagnostic counters" },
1373 { PCCC_FNC_06_02, "Set variables" },
1374 { PCCC_FNC_06_03, "Diagnostic status" },
1375 { PCCC_FNC_06_04, "Set timeout" },
1376 { PCCC_FNC_06_05, "Set NAKs" },
1377 { PCCC_FNC_06_06, "Set ENQs" },
1378 { PCCC_FNC_06_07, "Reset diagnostic counters" },
1379 { PCCC_FNC_06_08, "Set data table size" },
1380 { PCCC_FNC_06_09, "Read link parameters" },
1381 { PCCC_FNC_06_0A, "Set link parameters" },
1382
1383 { 0, NULL }
1384 };
1385
1386 static value_string_ext cip_pccc_fnc_06_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_fnc_06_vals);
1387
1388 static const value_string cip_pccc_fnc_07_vals[] = {
1389 { PCCC_FNC_07_00, "Disable outputs" },
1390 { PCCC_FNC_07_01, "Enable outputs" },
1391 { PCCC_FNC_07_03, "Enable PLC scanning" },
1392 { PCCC_FNC_07_04, "Enter download mode" },
1393 { PCCC_FNC_07_05, "Exit download/upload mode" },
1394 { PCCC_FNC_07_06, "Enter upload mode" },
1395
1396 { 0, NULL }
1397 };
1398
1399 static value_string_ext cip_pccc_fnc_07_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_fnc_07_vals);
1400
1401 static const value_string cip_pccc_fnc_0f_vals[] = {
1402 { PCCC_FNC_0F_00, "Word range write" },
1403 { PCCC_FNC_0F_01, "Word range read" },
1404 { PCCC_FNC_0F_02, "Bit write" },
1405 { PCCC_FNC_0F_03, "File write" },
1406 { PCCC_FNC_0F_04, "File read" },
1407 { PCCC_FNC_0F_05, "Download request" },
1408 { PCCC_FNC_0F_06, "Upload" },
1409 { PCCC_FNC_0F_07, "Shutdown" },
1410 { PCCC_FNC_0F_08, "Physical write" },
1411 { PCCC_FNC_0F_09, "Physical read" },
1412 { PCCC_FNC_0F_0A, "Restart request" },
1413 { PCCC_FNC_0F_11, "Get edit resource" },
1414 { PCCC_FNC_0F_12, "Return edit resource" },
1415 { PCCC_FNC_0F_17, "Read bytes physical" },
1416 { PCCC_FNC_0F_18, "Write bytes physical" },
1417 { PCCC_FNC_0F_26, "Read-modify-write" },
1418 { PCCC_FNC_0F_29, "Read section size" },
1419 { PCCC_FNC_0F_3A, "Set CPU mode" },
1420 { PCCC_FNC_0F_41, "Disable forces" },
1421 { PCCC_FNC_0F_50, "Download all request" },
1422 { PCCC_FNC_0F_52, "Download completed" },
1423 { PCCC_FNC_0F_53, "Upload all request (upload)" },
1424 { PCCC_FNC_0F_55, "Upload completed" },
1425 { PCCC_FNC_0F_57, "Initialize memory" },
1426 { PCCC_FNC_0F_5E, "Modify PLC-2 compatibility file" },
1427 { PCCC_FNC_0F_67, "Typed write" },
1428 { PCCC_FNC_0F_68, "Typed read" },
1429 { PCCC_FNC_0F_79, "Read-modify-write N" },
1430 { PCCC_FNC_0F_80, "Change CPU mode" },
1431 { PCCC_FNC_0F_81, "Open file" },
1432 { PCCC_FNC_0F_82, "Close file" },
1433 { PCCC_FNC_0F_88, "Execute Multiple Commands" },
1434 { PCCC_FNC_0F_8F, "Apply port configuration" },
1435 { PCCC_FNC_0F_A1, "Protected typed logical read with two address fields" },
1436 { PCCC_FNC_0F_A2, "Protected typed logical read with three address fields" },
1437 { PCCC_FNC_0F_A7, "Protected typed file read" },
1438 { PCCC_FNC_0F_A9, "Protected typed logical write with two address fields" },
1439 { PCCC_FNC_0F_AA, "Protected typed logical write with three address fields" },
1440 { PCCC_FNC_0F_AB, "Protected typed logical masked-write with three address fields" },
1441 { PCCC_FNC_0F_AF, "Protected typed file write" },
1442
1443 { 0, NULL }
1444 };
1445
1446 static value_string_ext cip_pccc_fnc_0f_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_fnc_0f_vals);
1447
1448 /* Translate PCCC File Types */
1449 static const value_string cip_pccc_file_types_vals[] = {
1450 { PCCC_FILE_TYPE_LOGIC, "Ladder Logic File" },
1451 { PCCC_FILE_TYPE_CHANNEL_CONFIG, "Channel Configuration File" },
1452 { PCCC_FILE_TYPE_FUNCTION_ES1, "EtherNet/IP Function File" },
1453 { PCCC_FILE_TYPE_ONLINE_EDIT, "Online Editing File" },
1454 { PCCC_FILE_TYPE_FUNCTION_IOS, "IOS Function File" },
1455 { PCCC_FILE_TYPE_DATA_OUTPUT, "Output Data File" },
1456 { PCCC_FILE_TYPE_DATA_INPUT, "Input Data File" },
1457 { PCCC_FILE_TYPE_DATA_STATUS, "Status Data File" },
1458 { PCCC_FILE_TYPE_DATA_BINARY, "Binary Data File" },
1459 { PCCC_FILE_TYPE_DATA_TIMER, "Timer Data File" },
1460 { PCCC_FILE_TYPE_DATA_COUNTER, "Counter Data File" },
1461 { PCCC_FILE_TYPE_DATA_INTEGER, "Integer Data File" },
1462 { PCCC_FILE_TYPE_DATA_FLOAT, "Float Data File" },
1463 { PCCC_FILE_TYPE_FORCE_OUTPUT, "Output Force File" },
1464 { PCCC_FILE_TYPE_FORCE_INPUT, "Input Force File" },
1465 { PCCC_FILE_TYPE_FUNCTION_ES0, "ES0 Function File" },
1466 { PCCC_FILE_TYPE_FUNCTION_STI, "STI Function File" },
1467 { PCCC_FILE_TYPE_FUNCTION_EII, "EII Function File" },
1468 { PCCC_FILE_TYPE_FUNCTION_RTC, "RTC Function File" },
1469 { PCCC_FILE_TYPE_FUNCTION_BHI, "BHI Function File" },
1470 { PCCC_FILE_TYPE_FUNCTION_MMI, "Memory Module Function File" },
1471 { PCCC_FILE_TYPE_FUNCTION_LCD, "Built-in LCD Function File" },
1472 { PCCC_FILE_TYPE_FUNCTION_PTOX, "PTOX Function File" },
1473 { PCCC_FILE_TYPE_FUNCTION_PWMX, "PWMX Function File" },
1474
1475 { 0, NULL }
1476 };
1477
1478 static value_string_ext cip_pccc_file_type_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_file_types_vals);
1479
1480 /* Translate PCCC CPU Modes */
1481 #if 0
1482 static const value_string cip_pccc_cpu_mode_3a_vals[] = {
1483 { PCCC_CPU_3A_PROGRAM, "Remote Program" },
1484 { PCCC_CPU_3A_RUN, "Remote Run" },
1485
1486 { 0, NULL }
1487 };
1488
1489 value_string_ext cip_pccc_cpu_mode_3a_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_cpu_mode_3a_vals);
1490 #endif
1491
1492 static const value_string cip_pccc_cpu_mode_80_vals[] = {
1493 { PCCC_CPU_80_PROGRAM, "Remote Program" },
1494 { PCCC_CPU_80_RUN, "Remote Run" },
1495 { PCCC_CPU_80_TEST_CONT, "Remote Test Continuous" },
1496 { PCCC_CPU_80_TEST_SINGLE, "Remote Test Single" },
1497 { PCCC_CPU_80_TEST_DEBUG, "Remote Test Debug" },
1498
1499 { 0, NULL }
1500 };
1501
1502 static value_string_ext cip_pccc_cpu_mode_80_vals_ext = VALUE_STRING_EXT_INIT(cip_pccc_cpu_mode_80_vals);
1503
1504 /* Translate Vendor IDs */
1505 static const value_string cip_vendor_vals[] = {
1506 { 0, "Reserved" },
1507 { 1, "Rockwell Automation/Allen-Bradley" },
1508 { 2, "Namco Controls Corp." },
1509 { 3, "Honeywell Inc." },
1510 { 4, "Parker Hannifin Corp. (Veriflo Division)" },
1511 { 5, "Rockwell Automation/Reliance Elec." },
1512 { 6, "Reserved" },
1513 { 7, "SMC Corporation" },
1514 { 8, "Molex Incorporated" },
1515 { 9, "Western Reserve Controls Corp." },
1516 { 10, "Advanced Micro Controls Inc. (AMCI)" },
1517 { 11, "ASCO Pneumatic Controls" },
1518 { 12, "Banner Engineering Corp." },
1519 { 13, "Belden Wire & Cable Company" },
1520 { 14, "Cooper Interconnect" },
1521 { 15, "Reserved" },
1522 { 16, "Daniel Woodhead Co. (Woodhead Connectivity)" },
1523 { 17, "Dearborn Group Inc." },
1524 { 18, "Reserved" },
1525 { 19, "Helm Instrument Company" },
1526 { 20, "Huron Net Works" },
1527 { 21, "Lumberg, Inc." },
1528 { 22, "Online Development Inc.(Automation Value)" },
1529 { 23, "Vorne Industries, Inc." },
1530 { 24, "ODVA Special Reserve" },
1531 { 25, "Reserved" },
1532 { 26, "Festo Corporation" },
1533 { 27, "Reserved" },
1534 { 28, "Reserved" },
1535 { 29, "Reserved" },
1536 { 30, "Unico, Inc." },
1537 { 31, "Ross Controls" },
1538 { 32, "Reserved" },
1539 { 33, "Reserved" },
1540 { 34, "Hohner Corp." },
1541 { 35, "Micro Mo Electronics, Inc." },
1542 { 36, "MKS Instruments, Inc." },
1543 { 37, "Yaskawa Electric America formerly Magnetek Drives" },
1544 { 38, "Reserved" },
1545 { 39, "AVG Automation (Uticor)" },
1546 { 40, "Wago Corporation" },
1547 { 41, "Kinetics (Unit Instruments)" },
1548 { 42, "IMI Norgren Limited" },
1549 { 43, "BALLUFF, Inc." },
1550 { 44, "Yaskawa Electric America, Inc." },
1551 { 45, "Eurotherm Controls Inc" },
1552 { 46, "ABB Industrial Systems" },
1553 { 47, "Omron Corporation" },
1554 { 48, "TURCk, Inc." },
1555 { 49, "Grayhill Inc." },
1556 { 50, "Real Time Automation (C&ID)" },
1557 { 51, "Reserved" },
1558 { 52, "Numatics, Inc." },
1559 { 53, "Lutze, Inc." },
1560 { 54, "Reserved" },
1561 { 55, "Reserved" },
1562 { 56, "Softing GmbH" },
1563 { 57, "Pepperl + Fuchs" },
1564 { 58, "Spectrum Controls, Inc." },
1565 { 59, "D.I.P. Inc. MKS Inst." },
1566 { 60, "Applied Motion Products, Inc." },
1567 { 61, "Sencon Inc." },
1568 { 62, "High Country Tek" },
1569 { 63, "SWAC Automation Consult GmbH" },
1570 { 64, "Clippard Instrument Laboratory" },
1571 { 65, "Reserved" },
1572 { 66, "Reserved" },
1573 { 67, "Reserved" },
1574 { 68, "Eaton Electrical" },
1575 { 69, "Reserved" },
1576 { 70, "Reserved" },
1577 { 71, "Toshiba International Corp." },
1578 { 72, "Control Technology Incorporated" },
1579 { 73, "TCS (NZ) Ltd." },
1580 { 74, "Hitachi, Ltd." },
1581 { 75, "ABB Robotics Products AB" },
1582 { 76, "NKE Corporation" },
1583 { 77, "Rockwell Software, Inc." },
1584 { 78, "Escort Memory Systems (A Datalogic Group Co.)" },
1585 { 79, "Reserved" },
1586 { 80, "Industrial Devices Corporation" },
1587 { 81, "IXXAT Automation GmbH" },
1588 { 82, "Mitsubishi Electric Automation, Inc." },
1589 { 83, "OPTO-22" },
1590 { 84, "Reserved" },
1591 { 85, "Reserved" },
1592 { 86, "Horner Electric" },
1593 { 87, "Burkert Werke GmbH & Co. KG" },
1594 { 88, "Reserved" },
1595 { 89, "Industrial Indexing Systems, Inc." },
1596 { 90, "HMS Industrial Networks AB" },
1597 { 91, "Robicon" },
1598 { 92, "Helix Technology (Granville-Phillips)" },
1599 { 93, "Arlington Laboratory" },
1600 { 94, "Advantech Co. Ltd." },
1601 { 95, "Square D Company" },
1602 { 96, "Digital Electronics Corp." },
1603 { 97, "Danfoss" },
1604 { 98, "Reserved" },
1605 { 99, "Reserved" },
1606 { 100, "Bosch Rexroth Corporation, Pneumatics" },
1607 { 101, "Applied Materials, Inc." },
1608 { 102, "Showa Electric Wire & Cable Co." },
1609 { 103, "Pacific Scientific (API Controls Inc.)" },
1610 { 104, "Sharp Manufacturing Systems Corp." },
1611 { 105, "Olflex Wire & Cable, Inc." },
1612 { 106, "Reserved" },
1613 { 107, "Unitrode" },
1614 { 108, "Beckhoff Automation GmbH" },
1615 { 109, "National Instruments" },
1616 { 110, "Mykrolis Corporations (Millipore)" },
1617 { 111, "International Motion Controls Corp." },
1618 { 112, "Reserved" },
1619 { 113, "SEG Kempen GmbH" },
1620 { 114, "Reserved" },
1621 { 115, "Reserved" },
1622 { 116, "MTS Systems Corp." },
1623 { 117, "Krones, Inc" },
1624 { 118, "Reserved" },
1625 { 119, "EXOR Electronic R & D" },
1626 { 120, "SIEI S.p.A." },
1627 { 121, "KUKA Roboter GmbH" },
1628 { 122, "Reserved" },
1629 { 123, "SEC (Samsung Electronics Co., Ltd)" },
1630 { 124, "Binary Electronics Ltd" },
1631 { 125, "Flexible Machine Controls" },
1632 { 126, "Reserved" },
1633 { 127, "ABB Inc. (Entrelec)" },
1634 { 128, "MAC Valves, Inc." },
1635 { 129, "Auma Actuators Inc" },
1636 { 130, "Toyoda Machine Works, Ltd" },
1637 { 131, "Reserved" },
1638 { 132, "Reserved" },
1639 { 133, "Balogh T.A.G., Corporation" },
1640 { 134, "TR Systemtechnik GmbH" },
1641 { 135, "UNIPULSE Corporation" },
1642 { 136, "Reserved" },
1643 { 137, "Reserved" },
1644 { 138, "Conxall Corporation Inc." },
1645 { 139, "Reserved" },
1646 { 140, "Reserved" },
1647 { 141, "Kuramo Electric Co., Ltd." },
1648 { 142, "Creative Micro Designs" },
1649 { 143, "GE Industrial Systems" },
1650 { 144, "Leybold Vacuum GmbH" },
1651 { 145, "Siemens Energy & Automation/Drives" },
1652 { 146, "Kodensha Ltd" },
1653 { 147, "Motion Engineering, Inc." },
1654 { 148, "Honda Engineering Co., Ltd" },
1655 { 149, "EIM Valve Controls" },
1656 { 150, "Melec Inc." },
1657 { 151, "Sony Manufacturing Systems Corporation" },
1658 { 152, "North American Mfg." },
1659 { 153, "WATLOW" },
1660 { 154, "Japan Radio Co., Ltd" },
1661 { 155, "NADEX Co., Ltd" },
1662 { 156, "Ametek Automation & Process Technologies" },
1663 { 157, "Reserved" },
1664 { 158, "KVASER AB" },
1665 { 159, "IDEC IZUMI Corporation" },
1666 { 160, "Mitsubishi Heavy Industries Ltd" },
1667 { 161, "Mitsubishi Electric Corporation" },
1668 { 162, "Horiba-STEC Inc." },
1669 { 163, "esd electronic system design gmbh" },
1670 { 164, "DAIHEN Corporation" },
1671 { 165, "Tyco Valves & Controls/Keystone" },
1672 { 166, "EBARA Corporation" },
1673 { 167, "Reserved" },
1674 { 168, "Reserved" },
1675 { 169, "Hokuyo Electric Co. Ltd" },
1676 { 170, "Pyramid Solutions, Inc." },
1677 { 171, "Denso Wave Incorporated" },
1678 { 172, "HLS Hard-Line Solutions Inc" },
1679 { 173, "Caterpillar, Inc." },
1680 { 174, "PDL Electronics Ltd." },
1681 { 175, "Reserved" },
1682 { 176, "Red Lion Controls" },
1683 { 177, "ANELVA Corporation" },
1684 { 178, "Toyo Denki Seizo KK" },
1685 { 179, "Sanyo Denki Co., Ltd" },
1686 { 180, "Advanced Energy Japan K.K. (Aera Japan)" },
1687 { 181, "Pilz GmbH & Co" },
1688 { 182, "Marsh Bellofram-Bellofram PCD Division" },
1689 { 183, "Reserved" },
1690 { 184, "M-SYSTEM Co. Ltd" },
1691 { 185, "Nissin Electric Co., Ltd" },
1692 { 186, "Hitachi Metals Ltd." },
1693 { 187, "Oriental Motor Company" },
1694 { 188, "A&D Co., Ltd" },
1695 { 189, "Phasetronics, Inc." },
1696 { 190, "Cummins Engine Company" },
1697 { 191, "Deltron Inc." },
1698 { 192, "Geneer Corporation" },
1699 { 193, "Anatol Automation, Inc." },
1700 { 194, "Reserved" },
1701 { 195, "Reserved" },
1702 { 196, "Medar, Inc." },
1703 { 197, "Comdel Inc." },
1704 { 198, "Advanced Energy Industries, Inc" },
1705 { 199, "Reserved" },
1706 { 200, "DAIDEN Co., Ltd" },
1707 { 201, "CKD Corporation" },
1708 { 202, "Toyo Electric Corporation" },
1709 { 203, "Reserved" },
1710 { 204, "AuCom Electronics Ltd" },
1711 { 205, "Shinko Electric Co., Ltd" },
1712 { 206, "Vector Informatik GmbH" },
1713 { 207, "Reserved" },
1714 { 208, "Moog Inc." },
1715 { 209, "Contemporary Controls" },
1716 { 210, "Tokyo Sokki Kenkyujo Co., Ltd" },
1717 { 211, "Schenck-AccuRate, Inc." },
1718 { 212, "The Oilgear Company" },
1719 { 213, "Reserved" },
1720 { 214, "ASM Japan K.K." },
1721 { 215, "HIRATA Corp." },
1722 { 216, "SUNX Limited" },
1723 { 217, "Meidensha Corp." },
1724 { 218, "NIDEC SANKYO CORPORATION (Sankyo Seiki Mfg. Co., Ltd)" },
1725 { 219, "KAMRO Corp." },
1726 { 220, "Nippon System Development Co., Ltd" },
1727 { 221, "EBARA Technologies Inc." },
1728 { 222, "Reserved" },
1729 { 223, "Reserved" },
1730 { 224, "SG Co., Ltd" },
1731 { 225, "Vaasa Institute of Technology" },
1732 { 226, "MKS Instruments (ENI Technology)" },
1733 { 227, "Tateyama System Laboratory Co., Ltd." },
1734 { 228, "QLOG Corporation" },
1735 { 229, "Matric Limited Inc." },
1736 { 230, "NSD Corporation" },
1737 { 231, "Reserved" },
1738 { 232, "Sumitomo Wiring Systems, Ltd" },
1739 { 233, "Group 3 Technology Ltd" },
1740 { 234, "CTI Cryogenics" },
1741 { 235, "POLSYS CORP" },
1742 { 236, "Ampere Inc." },
1743 { 237, "Reserved" },
1744 { 238, "Simplatroll Ltd" },
1745 { 239, "Reserved" },
1746 { 240, "Reserved" },
1747 { 241, "Leading Edge Design" },
1748 { 242, "Humphrey Products" },
1749 { 243, "Schneider Automation, Inc." },
1750 { 244, "Westlock Controls Corp." },
1751 { 245, "Nihon Weidmuller Co., Ltd" },
1752 { 246, "Brooks Instrument (Div. of Emerson)" },
1753 { 247, "Reserved" },
1754 { 248, "Moeller GmbH" },
1755 { 249, "Varian Vacuum Products" },
1756 { 250, "Yokogawa Electric Corporation" },
1757 { 251, "Electrical Design Daiyu Co., Ltd" },
1758 { 252, "Omron Software Co., Ltd" },
1759 { 253, "BOC Edwards" },
1760 { 254, "Control Technology Corporation" },
1761 { 255, "Bosch Rexroth" },
1762 { 256, "Turck" },
1763 { 257, "Control Techniques PLC" },
1764 { 258, "Hardy Instruments, Inc." },
1765 { 259, "LS Industrial Systems" },
1766 { 260, "E.O.A. Systems Inc." },
1767 { 261, "Reserved" },
1768 { 262, "New Cosmos Electric Co., Ltd." },
1769 { 263, "Sense Eletronica LTDA" },
1770 { 264, "Xycom, Inc." },
1771 { 265, "Baldor Electric" },
1772 { 266, "Reserved" },
1773 { 267, "Patlite Corporation" },
1774 { 268, "Reserved" },
1775 { 269, "Mogami Wire & Cable Corporation" },
1776 { 270, "Welding Technology Corporation (WTC)" },
1777 { 271, "Reserved" },
1778 { 272, "Deutschmann Automation GmbH" },
1779 { 273, "ICP Panel-Tec Inc." },
1780 { 274, "Bray Controls USA" },
1781 { 275, "Reserved" },
1782 { 276, "Status Technologies" },
1783 { 277, "Trio Motion Technology Ltd" },
1784 { 278, "Sherrex Systems Ltd" },
1785 { 279, "Adept Technology, Inc." },
1786 { 280, "Spang Power Electronics" },
1787 { 281, "Reserved" },
1788 { 282, "Acrosser Technology Co., Ltd" },
1789 { 283, "Hilscher GmbH" },
1790 { 284, "IMAX Corporation" },
1791 { 285, "Electronic Innovation, Inc. (Falter Engineering)" },
1792 { 286, "Netlogic Inc." },
1793 { 287, "Bosch Rexroth Corporation, Indramat" },
1794 { 288, "Reserved" },
1795 { 289, "Reserved" },
1796 { 290, "Murata Machinery Ltd." },
1797 { 291, "MTT Company Ltd." },
1798 { 292, "Kanematsu Semiconductor Corp." },
1799 { 293, "Takebishi Electric Sales Co." },
1800 { 294, "Tokyo Electron Device Ltd" },
1801 { 295, "PFU Limited" },
1802 { 296, "Hakko Automation Co., Ltd." },
1803 { 297, "Advanet Inc." },
1804 { 298, "Tokyo Electron Software Technologies Ltd." },
1805 { 299, "Reserved" },
1806 { 300, "Shinagawa Electric Wire Co., Ltd." },
1807 { 301, "Yokogawa M&C Corporation" },
1808 { 302, "KONAN Electric Co., Ltd." },
1809 { 303, "Binar Elektronik AB" },
1810 { 304, "Furukawa Electric Co." },
1811 { 305, "Cooper Energy Services" },
1812 { 306, "Schleicher GmbH & Co." },
1813 { 307, "Hirose Electric Co., Ltd" },
1814 { 308, "Western Servo Design Inc." },
1815 { 309, "Prosoft Technology" },
1816 { 310, "Reserved" },
1817 { 311, "Towa Shoko Co., Ltd" },
1818 { 312, "Kyopal Co., Ltd" },
1819 { 313, "Extron Co." },
1820 { 314, "Wieland Electric GmbH" },
1821 { 315, "SEW Eurodrive GmbH" },
1822 { 316, "Aera Corporation" },
1823 { 317, "STA Reutlingen" },
1824 { 318, "Reserved" },
1825 { 319, "Fuji Electric Co., Ltd." },
1826 { 320, "Reserved" },
1827 { 321, "Reserved" },
1828 { 322, "ifm efector, inc." },
1829 { 323, "Reserved" },
1830 { 324, "IDEACOD-Hohner Automation S.A." },
1831 { 325, "CommScope Inc." },
1832 { 326, "GE Fanuc Automation North America, Inc." },
1833 { 327, "Matsushita Electric Industrial Co., Ltd" },
1834 { 328, "Okaya Electronics Corporation" },
1835 { 329, "KASHIYAMA Industries, Ltd" },
1836 { 330, "JVC" },
1837 { 331, "Interface Corporation" },
1838 { 332, "Grape Systems Inc." },
1839 { 333, "Reserved" },
1840 { 334, "Reserved" },
1841 { 335, "Toshiba IT & Control Systems Corporation" },
1842 { 336, "Sanyo Machine Works, Ltd." },
1843 { 337, "Vansco Electronics Ltd." },
1844 { 338, "Dart Container Corp." },
1845 { 339, "Livingston & Co., Inc." },
1846 { 340, "Alfa Laval LKM as" },
1847 { 341, "BF ENTRON Ltd. (British Federal)" },
1848 { 342, "Bekaert Engineering NV" },
1849 { 343, "Ferran Scientific Inc." },
1850 { 344, "KEBA AG" },
1851 { 345, "Endress + Hauser" },
1852 { 346, "Reserved" },
1853 { 347, "ABB ALSTOM Power UK Ltd. (EGT)" },
1854 { 348, "Berger Lahr GmbH" },
1855 { 349, "Reserved" },
1856 { 350, "Federal Signal Corp." },
1857 { 351, "Kawasaki Robotics (USA), Inc." },
1858 { 352, "Bently Nevada Corporation" },
1859 { 353, "Reserved" },
1860 { 354, "FRABA Posital GmbH" },
1861 { 355, "Elsag Bailey, Inc." },
1862 { 356, "Fanuc Robotics America" },
1863 { 357, "Reserved" },
1864 { 358, "Surface Combustion, Inc." },
1865 { 359, "Reserved" },
1866 { 360, "AILES Electronics Ind. Co., Ltd." },
1867 { 361, "Wonderware Corporation" },
1868 { 362, "Particle Measuring Systems, Inc." },
1869 { 363, "Reserved" },
1870 { 364, "Reserved" },
1871 { 365, "BITS Co., Ltd" },
1872 { 366, "Japan Aviation Electronics Industry Ltd" },
1873 { 367, "Keyence Corporation" },
1874 { 368, "Kuroda Precision Industries Ltd." },
1875 { 369, "Mitsubishi Electric Semiconductor Application" },
1876 { 370, "Nippon Seisen Cable, Ltd." },
1877 { 371, "Omron ASO Co., Ltd" },
1878 { 372, "Seiko Seiki Co., Ltd." },
1879 { 373, "Sumitomo Heavy Industries, Ltd." },
1880 { 374, "Tango Computer Service Corporation" },
1881 { 375, "Technology Service, Inc." },
1882 { 376, "Toshiba Information Systems (Japan) Corporation" },
1883 { 377, "TOSHIBA Schneider Inverter Corporation" },
1884 { 378, "Toyooki Kogyo Co., Ltd." },
1885 { 379, "XEBEC" },
1886 { 380, "Madison Cable Corporation" },
1887 { 381, "Hitati Engineering & Services Co., Ltd" },
1888 { 382, "TEM-TECH Lab Co., Ltd" },
1889 { 383, "International Laboratory Corporation" },
1890 { 384, "Dyadic Systems Co., Ltd." },
1891 { 385, "SETO Electronics Industry Co., Ltd" },
1892 { 386, "Tokyo Electron Kyushu Limited" },
1893 { 387, "KEI System Co., Ltd" },
1894 { 388, "Reserved" },
1895 { 389, "Asahi Engineering Co., Ltd" },
1896 { 390, "Contrex Inc." },
1897 { 391, "Paradigm Controls Ltd." },
1898 { 392, "Reserved" },
1899 { 393, "Ohm Electric Co., Ltd." },
1900 { 394, "RKC Instrument Inc." },
1901 { 395, "Suzuki Motor Corporation" },
1902 { 396, "Custom Servo Motors Inc." },
1903 { 397, "PACE Control Systems" },
1904 { 398, "Reserved" },
1905 { 399, "Reserved" },
1906 { 400, "LINTEC Co., Ltd." },
1907 { 401, "Hitachi Cable Ltd." },
1908 { 402, "BUSWARE Direct" },
1909 { 403, "Eaton Electric B.V. (former Holec Holland N.V.)" },
1910 { 404, "VAT Vakuumventile AG" },
1911 { 405, "Scientific Technologies Incorporated" },
1912 { 406, "Alfa Instrumentos Eletronicos Ltda" },
1913 { 407, "TWK Elektronik GmbH" },
1914 { 408, "ABB Welding Systems AB" },
1915 { 409, "BYSTRONIC Maschinen AG" },
1916 { 410, "Kimura Electric Co., Ltd" },
1917 { 411, "Nissei Plastic Industrial Co., Ltd" },
1918 { 412, "Reserved" },
1919 { 413, "Kistler-Morse Corporation" },
1920 { 414, "Proteous Industries Inc." },
1921 { 415, "IDC Corporation" },
1922 { 416, "Nordson Corporation" },
1923 { 417, "Rapistan Systems" },
1924 { 418, "LP-Elektronik GmbH" },
1925 { 419, "GERBI & FASE S.p.A.(Fase Saldatura)" },
1926 { 420, "Phoenix Digital Corporation" },
1927 { 421, "Z-World Engineering" },
1928 { 422, "Honda R&D Co., Ltd." },
1929 { 423, "Bionics Instrument Co., Ltd." },
1930 { 424, "Teknic, Inc." },
1931 { 425, "R.Stahl, Inc." },
1932 { 426, "Reserved" },
1933 { 427, "Ryco Graphic Manufacturing Inc." },
1934 { 428, "Giddings & Lewis, Inc." },
1935 { 429, "Koganei Corporation" },
1936 { 430, "Reserved" },
1937 { 431, "Nichigoh Communication Electric Wire Co., Ltd." },
1938 { 432, "Reserved" },
1939 { 433, "Fujikura Ltd." },
1940 { 434, "AD Link Technology Inc." },
1941 { 435, "StoneL Corporation" },
1942 { 436, "Computer Optical Products, Inc." },
1943 { 437, "CONOS Inc." },
1944 { 438, "Erhardt + Leimer GmbH" },
1945 { 439, "UNIQUE Co. Ltd" },
1946 { 440, "Roboticsware, Inc." },
1947 { 441, "Nachi Fujikoshi Corporation" },
1948 { 442, "Hengstler GmbH" },
1949 { 443, "Reserved" },
1950 { 444, "SUNNY GIKEN Inc." },
1951 { 445, "Lenze Drive Systems GmbH" },
1952 { 446, "CD Systems B.V." },
1953 { 447, "FMT/Aircraft Gate Support Systems AB" },
1954 { 448, "Axiomatic Technologies Corp" },
1955 { 449, "Embedded System Products, Inc." },
1956 { 450, "Reserved" },
1957 { 451, "Mencom Corporation" },
1958 { 452, "Reserved" },
1959 { 453, "Matsushita Welding Systems Co., Ltd." },
1960 { 454, "Dengensha Mfg. Co. Ltd." },
1961 { 455, "Quinn Systems Ltd." },
1962 { 456, "Tellima Technology Ltd" },
1963 { 457, "MDT, Software" },
1964 { 458, "Taiwan Keiso Co., Ltd" },
1965 { 459, "Pinnacle Systems" },
1966 { 460, "Ascom Hasler Mailing Sys" },
1967 { 461, "INSTRUMAR Limited" },
1968 { 462, "Reserved" },
1969 { 463, "Navistar International Transportation Corp" },
1970 { 464, "Huettinger Elektronik GmbH + Co. KG" },
1971 { 465, "OCM Technology Inc." },
1972 { 466, "Professional Supply Inc." },
1973 { 467, "Control Solutions" },
1974 { 468, "Baumer IVO GmbH & Co. KG" },
1975 { 469, "Worcester Controls Corporation" },
1976 { 470, "Pyramid Technical Consultants, Inc." },
1977 { 471, "Reserved" },
1978 { 472, "Apollo Fire Detectors Limited" },
1979 { 473, "Avtron Manufacturing, Inc." },
1980 { 474, "Reserved" },
1981 { 475, "Tokyo Keiso Co., Ltd." },
1982 { 476, "Daishowa Swiki Co., Ltd." },
1983 { 477, "Kojima Instruments Inc." },
1984 { 478, "Shimadzu Corporation" },
1985 { 479, "Tatsuta Electric Wire & Cable Co., Ltd." },
1986 { 480, "MECS Corporation" },
1987 { 481, "Tahara Electric" },
1988 { 482, "Koyo Electronics" },
1989 { 483, "Clever Devices" },
1990 { 484, "GCD Hardware & Software GmbH" },
1991 { 485, "Reserved" },
1992 { 486, "Miller Electric Mfg Co." },
1993 { 487, "GEA Tuchenhagen GmbH" },
1994 { 488, "Riken Keiki Co., LTD" },
1995 { 489, "Keisokugiken Corporation" },
1996 { 490, "Fuji Machine Mfg. Co., Ltd" },
1997 { 491, "Reserved" },
1998 { 492, "Nidec-Shimpo Corp." },
1999 { 493, "UTEC Corporation" },
2000 { 494, "Sanyo Electric Co. Ltd." },
2001 { 495, "Reserved" },
2002 { 496, "Reserved" },
2003 { 497, "Okano Electric Wire Co. Ltd" },
2004 { 498, "Shimaden Co. Ltd." },
2005 { 499, "Teddington Controls Ltd" },
2006 { 500, "Reserved" },
2007 { 501, "VIPA GmbH" },
2008 { 502, "Warwick Manufacturing Group" },
2009 { 503, "Danaher Controls" },
2010 { 504, "Reserved" },
2011 { 505, "Reserved" },
2012 { 506, "American Science & Engineering" },
2013 { 507, "Accutron Controls International Inc." },
2014 { 508, "Norcott Technologies Ltd" },
2015 { 509, "TB Woods, Inc" },
2016 { 510, "Proportion-Air, Inc." },
2017 { 511, "SICK Stegmann GmbH" },
2018 { 512, "Reserved" },
2019 { 513, "Edwards Signaling" },
2020 { 514, "Sumitomo Metal Industries, Ltd" },
2021 { 515, "Cosmo Instruments Co., Ltd." },
2022 { 516, "Denshosha Co., Ltd." },
2023 { 517, "Kaijo Corp." },
2024 { 518, "Michiproducts Co., Ltd." },
2025 { 519, "Miura Corporation" },
2026 { 520, "TG Information Network Co., Ltd." },
2027 { 521, "Fujikin , Inc." },
2028 { 522, "Estic Corp." },
2029 { 523, "GS Hydraulic Sales" },
2030 { 524, "Reserved" },
2031 { 525, "MTE Limited" },
2032 { 526, "Hyde Park Electronics, Inc." },
2033 { 527, "Pfeiffer Vacuum GmbH" },
2034 { 528, "Cyberlogic Technologies" },
2035 { 529, "OKUMA Corporation FA Systems Division" },
2036 { 530, "Reserved" },
2037 { 531, "Hitachi Kokusai Electric Co., Ltd." },
2038 { 532, "SHINKO TECHNOS Co., Ltd." },
2039 { 533, "Itoh Electric Co., Ltd." },
2040 { 534, "Colorado Flow Tech Inc." },
2041 { 535, "Love Controls Division/Dwyer Inst." },
2042 { 536, "Alstom Drives and Controls" },
2043 { 537, "The Foxboro Company" },
2044 { 538, "Tescom Corporation" },
2045 { 539, "Reserved" },
2046 { 540, "Atlas Copco Controls UK" },
2047 { 541, "Reserved" },
2048 { 542, "Autojet Technologies" },
2049 { 543, "Prima Electronics S.p.A." },
2050 { 544, "PMA GmbH" },
2051 { 545, "Shimafuji Electric Co., Ltd" },
2052 { 546, "Oki Electric Industry Co., Ltd" },
2053 { 547, "Kyushu Matsushita Electric Co., Ltd" },
2054 { 548, "Nihon Electric Wire & Cable Co., Ltd" },
2055 { 549, "Tsuken Electric Ind Co., Ltd" },
2056 { 550, "Tamadic Co." },
2057 { 551, "MAATEL SA" },
2058 { 552, "OKUMA America" },
2059 { 553, "Control Techniques PLC-NA" },
2060 { 554, "TPC Wire & Cable" },
2061 { 555, "ATI Industrial Automation" },
2062 { 556, "Microcontrol (Australia) Pty Ltd" },
2063 { 557, "Serra Soldadura, S.A." },
2064 { 558, "Southwest Research Institute" },
2065 { 559, "Cabinplant International" },
2066 { 560, "Sartorius Mechatronics T&H GmbH" },
2067 { 561, "Comau S.p.A. Robotics & Final Assembly Division" },
2068 { 562, "Phoenix Contact" },
2069 { 563, "Yokogawa MAT Corporation" },
2070 { 564, "asahi sangyo co., ltd." },
2071 { 565, "Reserved" },
2072 { 566, "Akita Myotoku Ltd." },
2073 { 567, "OBARA Corp." },
2074 { 568, "Suetron Electronic GmbH" },
2075 { 569, "Reserved" },
2076 { 570, "Serck Controls Limited" },
2077 { 571, "Fairchild Industrial Products Company" },
2078 { 572, "ARO S.A." },
2079 { 573, "M2C GmbH" },
2080 { 574, "Shin Caterpillar Mitsubishi Ltd." },
2081 { 575, "Santest Co., Ltd." },
2082 { 576, "Cosmotechs Co., Ltd." },
2083 { 577, "Hitachi Electric Systems" },
2084 { 578, "Smartscan Ltd" },
2085 { 579, "Woodhead Software & Electronics France" },
2086 { 580, "Athena Controls, Inc." },
2087 { 581, "Syron Engineering & Manufacturing, Inc." },
2088 { 582, "Asahi Optical Co., Ltd." },
2089 { 583, "Sansha Electric Mfg. Co., Ltd." },
2090 { 584, "Nikki Denso Co., Ltd." },
2091 { 585, "Star Micronics, Co., Ltd." },
2092 { 586, "Ecotecnia Socirtat Corp." },
2093 { 587, "AC Technology Corp." },
2094 { 588, "West Instruments Limited" },
2095 { 589, "NTI Limited" },
2096 { 590, "Delta Computer Systems, Inc." },
2097 { 591, "FANUC Ltd." },
2098 { 592, "Hearn-Gu Lee" },
2099 { 593, "ABB Automation Products" },
2100 { 594, "Orion Machinery Co., Ltd." },
2101 { 595, "Reserved" },
2102 { 596, "Wire-Pro, Inc." },
2103 { 597, "Beijing Huakong Technology Co. Ltd." },
2104 { 598, "Yokoyama Shokai Co., Ltd." },
2105 { 599, "Toyogiken Co., Ltd." },
2106 { 600, "Coester Equipamentos Eletronicos Ltda." },
2107 { 601, "Reserved" },
2108 { 602, "Electroplating Engineers of Japan Ltd." },
2109 { 603, "ROBOX S.p.A." },
2110 { 604, "Spraying Systems Company" },
2111 { 605, "Benshaw Inc." },
2112 { 606, "ZPA-DP A.S." },
2113 { 607, "Wired Rite Systems" },
2114 { 608, "Tandis Research, Inc." },
2115 { 609, "SSD Drives GmbH" },
2116 { 610, "ULVAC Japan Ltd." },
2117 { 611, "DYNAX Corporation" },
2118 { 612, "Nor-Cal Products, Inc." },
2119 { 613, "Aros Electronics AB" },
2120 { 614, "Jun-Tech Co., Ltd." },
2121 { 615, "HAN-MI Co. Ltd." },
2122 { 616, "uniNtech (formerly SungGi Internet)" },
2123 { 617, "Hae Pyung Electronics Reserch Institute" },
2124 { 618, "Milwaukee Electronics" },
2125 { 619, "OBERG Industries" },
2126 { 620, "Parker Hannifin/Compumotor Division" },
2127 { 621, "TECHNO DIGITAL CORPORATION" },
2128 { 622, "Network Supply Co., Ltd." },
2129 { 623, "Union Electronics Co., Ltd." },
2130 { 624, "Tritronics Services PM Ltd." },
2131 { 625, "Rockwell Automation-Sprecher+Schuh" },
2132 { 626, "Matsushita Electric Industrial Co., Ltd/Motor Co." },
2133 { 627, "Rolls-Royce Energy Systems, Inc." },
2134 { 628, "JEONGIL INTERCOM CO., LTD" },
2135 { 629, "Interroll Corp." },
2136 { 630, "Hubbell Wiring Device-Kellems (Delaware)" },
2137 { 631, "Intelligent Motion Systems" },
2138 { 632, "Reserved" },
2139 { 633, "INFICON AG" },
2140 { 634, "Hirschmann, Inc." },
2141 { 635, "The Siemon Company" },
2142 { 636, "YAMAHA Motor Co. Ltd." },
2143 { 637, "aska corporation" },
2144 { 638, "Woodhead Connectivity" },
2145 { 639, "Trimble AB" },
2146 { 640, "Murrelektronik GmbH" },
2147 { 641, "Creatrix Labs, Inc." },
2148 { 642, "TopWorx" },
2149 { 643, "Kumho Industrial Co., Ltd." },
2150 { 644, "Wind River Systems, Inc." },
2151 { 645, "Bihl & Wiedemann GmbH" },
2152 { 646, "Harmonic Drive Systems Inc." },
2153 { 647, "Rikei Corporation" },
2154 { 648, "BL Autotec, Ltd." },
2155 { 649, "Hana Information & Technology Co., Ltd." },
2156 { 650, "Seoil Electric Co., Ltd." },
2157 { 651, "Fife Corporation" },
2158 { 652, "Shanghai Electrical Apparatus Research Institute" },
2159 { 653, "Reserved" },
2160 { 654, "Parasense Development Centre" },
2161 { 655, "Reserved" },
2162 { 656, "Reserved" },
2163 { 657, "Six Tau S.p.A." },
2164 { 658, "Aucos GmbH" },
2165 { 659, "Rotork Controls" },
2166 { 660, "Automationdirect.com" },
2167 { 661, "Thermo BLH" },
2168 { 662, "System Controls, Ltd." },
2169 { 663, "Univer S.p.A." },
2170 { 664, "MKS-Tenta Technology" },
2171 { 665, "Lika Electronic SNC" },
2172 { 666, "Mettler-Toledo, Inc." },
2173 { 667, "DXL USA Inc." },
2174 { 668, "Rockwell Automation/Entek IRD Intl." },
2175 { 669, "Nippon Otis Elevator Company" },
2176 { 670, "Sinano Electric, Co., Ltd." },
2177 { 671, "Sony Manufacturing Systems" },
2178 { 672, "Reserved" },
2179 { 673, "Contec Co., Ltd." },
2180 { 674, "Automated Solutions" },
2181 { 675, "Controlweigh" },
2182 { 676, "Reserved" },
2183 { 677, "Fincor Electronics" },
2184 { 678, "Cognex Corporation" },
2185 { 679, "Qualiflow" },
2186 { 680, "Weidmuller, Inc." },
2187 { 681, "Morinaga Milk Industry Co., Ltd." },
2188 { 682, "Takagi Industrial Co., Ltd." },
2189 { 683, "Wittenstein AG" },
2190 { 684, "Sena Technologies, Inc." },
2191 { 685, "Reserved" },
2192 { 686, "APV Products Unna" },
2193 { 687, "Creator Teknisk Utvedkling AB" },
2194 { 688, "Reserved" },
2195 { 689, "Mibu Denki Industrial Co., Ltd." },
2196 { 690, "Takamastsu Machineer Section" },
2197 { 691, "Startco Engineering Ltd." },
2198 { 692, "Reserved" },
2199 { 693, "Holjeron" },
2200 { 694, "ALCATEL High Vacuum Technology" },
2201 { 695, "Taesan LCD Co., Ltd." },
2202 { 696, "POSCON" },
2203 { 697, "VMIC" },
2204 { 698, "Matsushita Electric Works, Ltd." },
2205 { 699, "IAI Corporation" },
2206 { 700, "Horst GmbH" },
2207 { 701, "MicroControl GmbH & Co." },
2208 { 702, "Leine & Linde AB" },
2209 { 703, "Reserved" },
2210 { 704, "EC Elettronica Srl" },
2211 { 705, "VIT Software HB" },
2212 { 706, "Bronkhorst High-Tech B.V." },
2213 { 707, "Optex Co., Ltd." },
2214 { 708, "Yosio Electronic Co." },
2215 { 709, "Terasaki Electric Co., Ltd." },
2216 { 710, "Sodick Co., Ltd." },
2217 { 711, "MTS Systems Corporation-Automation Division" },
2218 { 712, "Mesa Systemtechnik" },
2219 { 713, "SHIN HO SYSTEM Co., Ltd." },
2220 { 714, "Goyo Electronics Co, Ltd." },
2221 { 715, "Loreme" },
2222 { 716, "SAB Brockskes GmbH & Co. KG" },
2223 { 717, "Trumpf Laser GmbH + Co. KG" },
2224 { 718, "Niigata Electronic Instruments Co., Ltd." },
2225 { 719, "Yokogawa Digital Computer Corporation" },
2226 { 720, "O.N. Electronic Co., Ltd." },
2227 { 721, "Industrial Control Communication, Inc." },
2228 { 722, "ABB, Inc." },
2229 { 723, "ElectroWave USA, Inc." },
2230 { 724, "Industrial Network Controls, LLC" },
2231 { 725, "KDT Systems Co., Ltd." },
2232 { 726, "SEFA Technology Inc." },
2233 { 727, "Nippon POP Rivets and Fasteners Ltd." },
2234 { 728, "Yamato Scale Co., Ltd." },
2235 { 729, "Zener Electric" },
2236 { 730, "GSE Scale Systems" },
2237 { 731, "ISAS (Integrated Switchgear & Sys. Pty Ltd)" },
2238 { 732, "Beta LaserMike Limited" },
2239 { 733, "TOEI Electric Co., Ltd." },
2240 { 734, "Hakko Electronics Co., Ltd" },
2241 { 735, "Reserved" },
2242 { 736, "RFID, Inc." },
2243 { 737, "Adwin Corporation" },
2244 { 738, "Osaka Vacuum, Ltd." },
2245 { 739, "A-Kyung Motion, Inc." },
2246 { 740, "Camozzi S.P. A." },
2247 { 741, "Crevis Co., LTD" },
2248 { 742, "Rice Lake Weighing Systems" },
2249 { 743, "Linux Network Services" },
2250 { 744, "KEB Antriebstechnik GmbH" },
2251 { 745, "Hagiwara Electric Co., Ltd." },
2252 { 746, "Glass Inc. International" },
2253 { 747, "Reserved" },
2254 { 748, "DVT Corporation" },
2255 { 749, "Woodward Governor" },
2256 { 750, "Mosaic Systems, Inc." },
2257 { 751, "Laserline GmbH" },
2258 { 752, "COM-TEC, Inc." },
2259 { 753, "Weed Instrument" },
2260 { 754, "Prof-face European Technology Center" },
2261 { 755, "Fuji Automation Co., Ltd." },
2262 { 756, "Matsutame Co., Ltd." },
2263 { 757, "Hitachi Via Mechanics, Ltd." },
2264 { 758, "Dainippon Screen Mfg. Co. Ltd." },
2265 { 759, "FLS Automation A/S" },
2266 { 760, "ABB Stotz Kontakt GmbH" },
2267 { 761, "Technical Marine Service" },
2268 { 762, "Advanced Automation Associates, Inc." },
2269 { 763, "Baumer Ident GmbH" },
2270 { 764, "Tsubakimoto Chain Co." },
2271 { 765, "Reserved" },
2272 { 766, "Furukawa Co., Ltd." },
2273 { 767, "Active Power" },
2274 { 768, "CSIRO Mining Automation" },
2275 { 769, "Matrix Integrated Systems" },
2276 { 770, "Digitronic Automationsanlagen GmbH" },
2277 { 771, "SICK STEGMANN Inc." },
2278 { 772, "TAE-Antriebstechnik GmbH" },
2279 { 773, "Electronic Solutions" },
2280 { 774, "Rocon L.L.C." },
2281 { 775, "Dijitized Communications Inc." },
2282 { 776, "Asahi Organic Chemicals Industry Co., Ltd." },
2283 { 777, "Hodensha" },
2284 { 778, "Harting, Inc. NA" },
2285 { 779, "Kubler GmbH" },
2286 { 780, "Yamatake Corporation" },
2287 { 781, "JEOL" },
2288 { 782, "Yamatake Industrial Systems Co., Ltd." },
2289 { 783, "HAEHNE Elektronische Messgerate GmbH" },
2290 { 784, "Ci Technologies Pty Ltd (for Pelamos Industries)" },
2291 { 785, "N. SCHLUMBERGER & CIE" },
2292 { 786, "Teijin Seiki Co., Ltd." },
2293 { 787, "DAIKIN Industries, Ltd" },
2294 { 788, "RyuSyo Industrial Co., Ltd." },
2295 { 789, "SAGINOMIYA SEISAKUSHO, INC." },
2296 { 790, "Seishin Engineering Co., Ltd." },
2297 { 791, "Japan Support System Ltd." },
2298 { 792, "Decsys" },
2299 { 793, "Metronix Messgerate u. Elektronik GmbH" },
2300 { 794, "Reserved" },
2301 { 795, "Vaccon Company, Inc." },
2302 { 796, "Siemens Energy & Automation, Inc." },
2303 { 797, "Ten X Technology, Inc." },
2304 { 798, "Tyco Electronics" },
2305 { 799, "Delta Power Electronics Center" },
2306 { 800, "Denker" },
2307 { 801, "Autonics Corporation" },
2308 { 802, "JFE Electronic Engineering Pty. Ltd." },
2309 { 803, "Reserved" },
2310 { 804, "Electro-Sensors, Inc." },
2311 { 805, "Digi International, Inc." },
2312 { 806, "Texas Instruments" },
2313 { 807, "ADTEC Plasma Technology Co., Ltd" },
2314 { 808, "SICK AG" },
2315 { 809, "Ethernet Peripherals, Inc." },
2316 { 810, "Animatics Corporation" },
2317 { 811, "Reserved" },
2318 { 812, "Process Control Corporation" },
2319 { 813, "SystemV. Inc." },
2320 { 814, "Danaher Motion SRL" },
2321 { 815, "SHINKAWA Sensor Technology, Inc." },
2322 { 816, "Tesch GmbH & Co. KG" },
2323 { 817, "Reserved" },
2324 { 818, "Trend Controls Systems Ltd." },
2325 { 819, "Guangzhou ZHIYUAN Electronic Co., Ltd." },
2326 { 820, "Mykrolis Corporation" },
2327 { 821, "Bethlehem Steel Corporation" },
2328 { 822, "KK ICP" },
2329 { 823, "Takemoto Denki Corporation" },
2330 { 824, "The Montalvo Corporation" },
2331 { 825, "Reserved" },
2332 { 826, "LEONI Special Cables GmbH" },
2333 { 827, "Reserved" },
2334 { 828, "ONO SOKKI CO.,LTD." },
2335 { 829, "Rockwell Samsung Automation" },
2336 { 830, "SHINDENGEN ELECTRIC MFG. CO. LTD" },
2337 { 831, "Origin Electric Co. Ltd." },
2338 { 832, "Quest Technical Solutions, Inc." },
2339 { 833, "LS Cable, Ltd." },
2340 { 834, "Enercon-Nord Electronic GmbH" },
2341 { 835, "Northwire Inc." },
2342 { 836, "Engel Elektroantriebe GmbH" },
2343 { 837, "The Stanley Works" },
2344 { 838, "Celesco Transducer Products, Inc." },
2345 { 839, "Chugoku Electric Wire and Cable Co." },
2346 { 840, "Kongsberg Simrad AS" },
2347 { 841, "Panduit Corporation" },
2348 { 842, "Spellman High Voltage Electronics Corp." },
2349 { 843, "Kokusai Electric Alpha Co., Ltd." },
2350 { 844, "Brooks Automation, Inc." },
2351 { 845, "ANYWIRE CORPORATION" },
2352 { 846, "Honda Electronics Co. Ltd" },
2353 { 847, "REO Elektronik AG" },
2354 { 848, "Fusion UV Systems, Inc." },
2355 { 849, "ASI Advanced Semiconductor Instruments GmbH" },
2356 { 850, "Datalogic, Inc." },
2357 { 851, "SoftPLC Corporation" },
2358 { 852, "Dynisco Instruments LLC" },
2359 { 853, "WEG Industrias SA" },
2360 { 854, "Frontline Test Equipment, Inc." },
2361 { 855, "Tamagawa Seiki Co., Ltd." },
2362 { 856, "Multi Computing Co., Ltd." },
2363 { 857, "RVSI" },
2364 { 858, "Commercial Timesharing Inc." },
2365 { 859, "Tennessee Rand Automation LLC" },
2366 { 860, "Wacogiken Co., Ltd" },
2367 { 861, "Reflex Integration Inc." },
2368 { 862, "Siemens AG, A&D PI Flow Instruments" },
2369 { 863, "G. Bachmann Electronic GmbH" },
2370 { 864, "NT International" },
2371 { 865, "Schweitzer Engineering Laboratories" },
2372 { 866, "ATR Industrie-Elektronik GmbH Co." },
2373 { 867, "PLASMATECH Co., Ltd" },
2374 { 868, "Reserved" },
2375 { 869, "GEMU GmbH & Co. KG" },
2376 { 870, "Alcorn McBride Inc." },
2377 { 871, "MORI SEIKI CO., LTD" },
2378 { 872, "NodeTech Systems Ltd" },
2379 { 873, "Emhart Teknologies" },
2380 { 874, "Cervis, Inc." },
2381 { 875, "FieldServer Technologies (Div Sierra Monitor Corp)" },
2382 { 876, "NEDAP Power Supplies" },
2383 { 877, "Nippon Sanso Corporation" },
2384 { 878, "Mitomi Giken Co., Ltd." },
2385 { 879, "PULS GmbH" },
2386 { 880, "Reserved" },
2387 { 881, "Japan Control Engineering Ltd" },
2388 { 882, "Embedded Systems Korea (Former Zues Emtek Co Ltd.)" },
2389 { 883, "Automa SRL" },
2390 { 884, "Harms+Wende GmbH & Co KG" },
2391 { 885, "SAE-STAHL GmbH" },
2392 { 886, "Microwave Data Systems" },
2393 { 887, "B&R Industrial Automation GmbH" },
2394 { 888, "Hiprom Technologies" },
2395 { 889, "Reserved" },
2396 { 890, "Nitta Corporation" },
2397 { 891, "Kontron Modular Computers GmbH" },
2398 { 892, "Marlin Controls" },
2399 { 893, "ELCIS s.r.l." },
2400 { 894, "Acromag, Inc." },
2401 { 895, "Avery Weigh-Tronix" },
2402 { 896, "Reserved" },
2403 { 897, "Reserved" },
2404 { 898, "Reserved" },
2405 { 899, "Practicon Ltd" },
2406 { 900, "Schunk GmbH & Co. KG" },
2407 { 901, "MYNAH Technologies" },
2408 { 902, "Defontaine Groupe" },
2409 { 903, "Emerson Process Management Power & Water Solutions" },
2410 { 904, "F.A. Elec" },
2411 { 905, "Hottinger Baldwin Messtechnik GmbH" },
2412 { 906, "Coreco Imaging, Inc." },
2413 { 907, "London Electronics Ltd." },
2414 { 908, "HSD SpA" },
2415 { 909, "Comtrol Corporation" },
2416 { 910, "TEAM, S.A. (Tecnica Electronica de Automatismo Y Medida)" },
2417 { 911, "MAN B&W Diesel Ltd. Regulateurs Europa" },
2418 { 912, "Reserved" },
2419 { 913, "Reserved" },
2420 { 914, "Micro Motion, Inc." },
2421 { 915, "Eckelmann AG" },
2422 { 916, "Hanyoung Nux" },
2423 { 917, "Ransburg Industrial Finishing KK" },
2424 { 918, "Kun Hung Electric Co. Ltd." },
2425 { 919, "Brimos wegbebakening b.v." },
2426 { 920, "Nitto Seiki Co., Ltd" },
2427 { 921, "PPT Vision, Inc." },
2428 { 922, "Yamazaki Machinery Works" },
2429 { 923, "SCHMIDT Technology GmbH" },
2430 { 924, "Parker Hannifin SpA (SBC Division)" },
2431 { 925, "HIMA Paul Hildebrandt GmbH" },
2432 { 926, "RivaTek, Inc." },
2433 { 927, "Misumi Corporation" },
2434 { 928, "GE Multilin" },
2435 { 929, "Measurement Computing Corporation" },
2436 { 930, "Jetter AG" },
2437 { 931, "Tokyo Electronics Systems Corporation" },
2438 { 932, "Togami Electric Mfg. Co., Ltd." },
2439 { 933, "HK Systems" },
2440 { 934, "CDA Systems Ltd." },
2441 { 935, "Aerotech Inc." },
2442 { 936, "JVL Industrie Elektronik A/S" },
2443 { 937, "NovaTech Process Solutions LLC" },
2444 { 938, "Reserved" },
2445 { 939, "Cisco Systems" },
2446 { 940, "Grid Connect" },
2447 { 941, "ITW Automotive Finishing" },
2448 { 942, "HanYang System" },
2449 { 943, "ABB K.K. Technical Center" },
2450 { 944, "Taiyo Electric Wire & Cable Co., Ltd." },
2451 { 945, "Reserved" },
2452 { 946, "SEREN IPS INC" },
2453 { 947, "Belden CDT Electronics Division" },
2454 { 948, "ControlNet International" },
2455 { 949, "Gefran S.P.A." },
2456 { 950, "Jokab Safety AB" },
2457 { 951, "SUMITA OPTICAL GLASS, INC." },
2458 { 952, "Biffi Italia srl" },
2459 { 953, "Beck IPC GmbH" },
2460 { 954, "Copley Controls Corporation" },
2461 { 955, "Fagor Automation S. Coop." },
2462 { 956, "DARCOM" },
2463 { 957, "Frick Controls (div. of York International)" },
2464 { 958, "SymCom, Inc." },
2465 { 959, "Infranor" },
2466 { 960, "Kyosan Cable, Ltd." },
2467 { 961, "Varian Vacuum Technologies" },
2468 { 962, "Messung Systems" },
2469 { 963, "Xantrex Technology, Inc." },
2470 { 964, "StarThis Inc." },
2471 { 965, "Chiyoda Co., Ltd." },
2472 { 966, "Flowserve Corporation" },
2473 { 967, "Spyder Controls Corp." },
2474 { 968, "IBA AG" },
2475 { 969, "SHIMOHIRA ELECTRIC MFG.CO.,LTD" },
2476 { 970, "Reserved" },
2477 { 971, "Siemens L&A" },
2478 { 972, "Micro Innovations AG" },
2479 { 973, "Switchgear & Instrumentation" },
2480 { 974, "PRE-TECH CO., LTD." },
2481 { 975, "National Semiconductor" },
2482 { 976, "Invensys Process Systems" },
2483 { 977, "Ametek HDR Power Systems" },
2484 { 978, "Reserved" },
2485 { 979, "TETRA-K Corporation" },
2486 { 980, "C & M Corporation" },
2487 { 981, "Siempelkamp Maschinen" },
2488 { 982, "Reserved" },
2489 { 983, "Daifuku America Corporation" },
2490 { 984, "Electro-Matic Products Inc." },
2491 { 985, "BUSSAN MICROELECTRONICS CORP." },
2492 { 986, "ELAU AG" },
2493 { 987, "Hetronic USA" },
2494 { 988, "NIIGATA POWER SYSTEMS Co., Ltd." },
2495 { 989, "Software Horizons Inc." },
2496 { 990, "B3 Systems, Inc." },
2497 { 991, "Moxa Networking Co., Ltd." },
2498 { 992, "Reserved" },
2499 { 993, "S4 Integration" },
2500 { 994, "Elettro Stemi S.R.L." },
2501 { 995, "AquaSensors" },
2502 { 996, "Ifak System GmbH" },
2503 { 997, "SANKEI MANUFACTURING Co.,LTD." },
2504 { 998, "Emerson Network Power Co., Ltd." },
2505 { 999, "Fairmount Automation, Inc." },
2506 { 1000, "Bird Electronic Corporation" },
2507 { 1001, "Nabtesco Corporation" },
2508 { 1002, "AGM Electronics, Inc." },
2509 { 1003, "ARCX Inc." },
2510 { 1004, "DELTA I/O Co." },
2511 { 1005, "Chun IL Electric Ind. Co." },
2512 { 1006, "N-Tron" },
2513 { 1007, "Nippon Pneumatics/Fludics System CO.,LTD." },
2514 { 1008, "DDK Ltd." },
2515 { 1009, "Seiko Epson Corporation" },
2516 { 1010, "Halstrup-Walcher GmbH" },
2517 { 1011, "ITT" },
2518 { 1012, "Ground Fault Systems bv" },
2519 { 1013, "Scolari Engineering S.p.A." },
2520 { 1014, "Vialis Traffic bv" },
2521 { 1015, "Weidmueller Interface GmbH & Co. KG" },
2522 { 1016, "Shanghai Sibotech Automation Co. Ltd" },
2523 { 1017, "AEG Power Supply Systems GmbH" },
2524 { 1018, "Komatsu Electronics Inc." },
2525 { 1019, "Souriau" },
2526 { 1020, "Baumuller Chicago Corp." },
2527 { 1021, "J. Schmalz GmbH" },
2528 { 1022, "SEN Corporation" },
2529 { 1023, "Korenix Technology Co. Ltd" },
2530 { 1024, "Cooper Power Tools" },
2531 { 1025, "INNOBIS" },
2532 { 1026, "Shinho System" },
2533 { 1027, "Xm Services Ltd." },
2534 { 1028, "KVC Co., Ltd." },
2535 { 1029, "Sanyu Seiki Co., Ltd." },
2536 { 1030, "TuxPLC" },
2537 { 1031, "Northern Network Solutions" },
2538 { 1032, "Converteam GmbH" },
2539 { 1033, "Symbol Technologies" },
2540 { 1034, "S-TEAM Lab" },
2541 { 1035, "Maguire Products, Inc." },
2542 { 1036, "AC&T" },
2543 { 1037, "MITSUBISHI HEAVY INDUSTRIES, LTD. KOBE SHIPYARD & MACHINERY WORKS" },
2544 { 1038, "Hurletron Inc." },
2545 { 1039, "Chunichi Denshi Co., Ltd" },
2546 { 1040, "Cardinal Scale Mfg. Co." },
2547 { 1041, "BTR NETCOM via RIA Connect, Inc." },
2548 { 1042, "Base2" },
2549 { 1043, "ASRC Aerospace" },
2550 { 1044, "Beijing Stone Automation" },
2551 { 1045, "Changshu Switchgear Manufacture Ltd." },
2552 { 1046, "METRONIX Corp." },
2553 { 1047, "WIT" },
2554 { 1048, "ORMEC Systems Corp." },
2555 { 1049, "ASATech (China) Inc." },
2556 { 1050, "Controlled Systems Limited" },
2557 { 1051, "Mitsubishi Heavy Ind. Digital System Co., Ltd. (M.H.I.)" },
2558 { 1052, "Electrogrip" },
2559 { 1053, "TDS Automation" },
2560 { 1054, "T&C Power Conversion, Inc." },
2561 { 1055, "Robostar Co., Ltd" },
2562 { 1056, "Scancon A/S" },
2563 { 1057, "Haas Automation, Inc." },
2564 { 1058, "Eshed Technology" },
2565 { 1059, "Delta Electronic Inc." },
2566 { 1060, "Innovasic Semiconductor" },
2567 { 1061, "SoftDEL Systems Limited" },
2568 { 1062, "FiberFin, Inc." },
2569 { 1063, "Nicollet Technologies Corp." },
2570 { 1064, "B.F. Systems" },
2571 { 1065, "Empire Wire and Supply LLC" },
2572 { 1066, "Reserved" },
2573 { 1067, "Elmo Motion Control LTD" },
2574 { 1068, "Reserved" },
2575 { 1069, "Asahi Keiki Co., Ltd." },
2576 { 1070, "Joy Mining Machinery" },
2577 { 1071, "MPM Engineering Ltd" },
2578 { 1072, "Wolke Inks & Printers GmbH" },
2579 { 1073, "Mitsubishi Electric Engineering Co., Ltd." },
2580 { 1074, "COMET AG" },
2581 { 1075, "Real Time Objects & Systems, LLC" },
2582 { 1076, "MISCO Refractometer" },
2583 { 1077, "JT Engineering Inc." },
2584 { 1078, "Automated Packing Systems" },
2585 { 1079, "Niobrara R&D Corp." },
2586 { 1080, "Garmin Ltd." },
2587 { 1081, "Japan Mobile Platform Co., Ltd" },
2588 { 1082, "Advosol Inc." },
2589 { 1083, "ABB Global Services Limited" },
2590 { 1084, "Sciemetric Instruments Inc." },
2591 { 1085, "Tata Elxsi Ltd." },
2592 { 1086, "TPC Mechatronics, Co., Ltd." },
2593 { 1087, "Cooper Bussmann" },
2594 { 1088, "Trinite Automatisering B.V." },
2595 { 1089, "Peek Traffic B.V." },
2596 { 1090, "Acrison, Inc" },
2597 { 1091, "Applied Robotics, Inc." },
2598 { 1092, "FireBus Systems, Inc." },
2599 { 1093, "Beijing Sevenstar Huachuang Electronics" },
2600 { 1094, "Magnetek" },
2601 { 1095, "Microscan" },
2602 { 1096, "Air Water Inc." },
2603 { 1097, "Sensopart Industriesensorik GmbH" },
2604 { 1098, "Tiefenbach Control Systems GmbH" },
2605 { 1099, "INOXPA S.A" },
2606 { 1100, "Zurich University of Applied Sciences" },
2607 { 1101, "Ethernet Direct" },
2608 { 1102, "GSI-Micro-E Systems" },
2609 { 1103, "S-Net Automation Co., Ltd." },
2610 { 1104, "Power Electronics S.L." },
2611 { 1105, "Renesas Technology Corp." },
2612 { 1106, "NSWCCD-SSES" },
2613 { 1107, "Porter Engineering Ltd." },
2614 { 1108, "Meggitt Airdynamics, Inc." },
2615 { 1109, "Inductive Automation" },
2616 { 1110, "Neural ID" },
2617 { 1111, "EEPod LLC" },
2618 { 1112, "Hitachi Industrial Equipment Systems Co., Ltd." },
2619 { 1113, "Salem Automation" },
2620 { 1114, "port GmbH" },
2621 { 1115, "B & PLUS" },
2622 { 1116, "Graco Inc." },
2623 { 1117, "Altera Corporation" },
2624 { 1118, "Technology Brewing Corporation" },
2625 { 1121, "CSE Servelec" },
2626 { 1124, "Fluke Networks" },
2627 { 1125, "Tetra Pak Packaging Solutions SPA" },
2628 { 1126, "Racine Federated, Inc." },
2629 { 1127, "Pureron Japan Co., Ltd." },
2630 { 1130, "Brother Industries, Ltd." },
2631 { 1132, "Leroy Automation" },
2632 { 1134, "THK CO., LTD." },
2633 { 1137, "TR-Electronic GmbH" },
2634 { 1138, "ASCON S.p.A." },
2635 { 1139, "Toledo do Brasil Industria de Balancas Ltda." },
2636 { 1140, "Bucyrus DBT Europe GmbH" },
2637 { 1141, "Emerson Process Management Valve Automation" },
2638 { 1142, "Alstom Transport" },
2639 { 1144, "Matrox Electronic Systems" },
2640 { 1145, "Littelfuse" },
2641 { 1146, "PLASMART, Inc." },
2642 { 1147, "Miyachi Corporation" },
2643 { 1150, "Promess Incorporated" },
2644 { 1151, "COPA-DATA GmbH" },
2645 { 1152, "Precision Engine Controls Corporation" },
2646 { 1153, "Alga Automacao e controle LTDA" },
2647 { 1154, "U.I. Lapp GmbH" },
2648 { 1155, "ICES" },
2649 { 1156, "Philips Lighting bv" },
2650 { 1157, "Aseptomag AG" },
2651 { 1158, "ARC Informatique" },
2652 { 1159, "Hesmor GmbH" },
2653 { 1160, "Kobe Steel, Ltd." },
2654 { 1161, "FLIR Systems" },
2655 { 1162, "Simcon A/S" },
2656 { 1163, "COPALP" },
2657 { 1164, "Zypcom, Inc." },
2658 { 1165, "Swagelok" },
2659 { 1166, "Elspec" },
2660 { 1167, "ITT Water & Wastewater AB" },
2661 { 1168, "Kunbus GmbH Industrial Communication" },
2662 { 1170, "Performance Controls, Inc." },
2663 { 1171, "ACS Motion Control, Ltd." },
2664 { 1173, "IStar Technology Limited" },
2665 { 1174, "Alicat Scientific, Inc." },
2666 { 1176, "ADFweb.com SRL" },
2667 { 1177, "Tata Consultancy Services Limited" },
2668 { 1178, "CXR Ltd." },
2669 { 1179, "Vishay Nobel AB" },
2670 { 1181, "SolaHD" },
2671 { 1182, "Endress+Hauser" },
2672 { 1183, "Bartec GmbH" },
2673 { 1185, "AccuSentry, Inc." },
2674 { 1186, "Exlar Corporation" },
2675 { 1187, "ILS Technology" },
2676 { 1188, "Control Concepts Inc." },
2677 { 1190, "Procon Engineering Limited" },
2678 { 1191, "Hermary Opto Electronics Inc." },
2679 { 1192, "Q-Lambda" },
2680 { 1194, "VAMP Ltd" },
2681 { 1195, "FlexLink" },
2682 { 1196, "Office FA.com Co., Ltd." },
2683 { 1197, "SPMC (Changzhou) Co. Ltd." },
2684 { 1198, "Anton Paar GmbH" },
2685 { 1199, "Zhuzhou CSR Times Electric Co., Ltd." },
2686 { 1200, "DeStaCo" },
2687 { 1201, "Synrad, Inc" },
2688 { 1202, "Bonfiglioli Vectron GmbH" },
2689 { 1203, "Pivotal Systems" },
2690 { 1204, "TKSCT" },
2691 { 1205, "Randy Nuernberger" },
2692 { 1206, "CENTRALP" },
2693 { 1207, "Tengen Group" },
2694 { 1208, "OES, Inc." },
2695 { 1209, "Actel Corporation" },
2696 { 1210, "Monaghan Engineering, Inc." },
2697 { 1211, "wenglor sensoric gmbh" },
2698 { 1212, "HSA Systems" },
2699 { 1213, "MK Precision Co., Ltd." },
2700 { 1214, "Tappan Wire and Cable" },
2701 { 1215, "Heinzmann GmbH & Co. KG" },
2702 { 1216, "Process Automation International Ltd." },
2703 { 1217, "Secure Crossing" },
2704 { 1218, "SMA Railway Technology GmbH" },
2705 { 1219, "FMS Force Measuring Systems AG" },
2706 { 1220, "ABT Endustri Enerji Sistemleri Sanayi Tic. Ltd. Sti." },
2707 { 1221, "MagneMotion Inc." },
2708 { 1222, "STS Co., Ltd." },
2709 { 1223, "MERAK SIC, SA" },
2710 { 1224, "ABOUNDI, Inc." },
2711 { 1225, "Rosemount Inc." },
2712 { 1226, "GEA FES, Inc." },
2713 { 1227, "TMG Technologie und Engineering GmbH" },
2714 { 1228, "embeX GmbH" },
2715 { 1229, "GH Electrotermia, S.A." },
2716 { 1230, "Tolomatic" },
2717 { 1231, "Dukane" },
2718 { 1232, "Elco (Tian Jin) Electronics Co., Ltd." },
2719 { 1233, "Jacobs Automation" },
2720 { 1234, "Noda Radio Frequency Technologies Co., Ltd." },
2721 { 1235, "MSC Tuttlingen GmbH" },
2722 { 1236, "Hitachi Cable Manchester" },
2723 { 1237, "ACOREL SAS" },
2724 { 1238, "Global Engineering Solutions Co., Ltd." },
2725 { 1239, "ALTE Transportation, S.L." },
2726 { 1240, "Penko Engineering B.V." },
2727
2728 { 0, NULL }
2729 };
2730
2731 value_string_ext cip_vendor_vals_ext = VALUE_STRING_EXT_INIT(cip_vendor_vals);
2732
2733 /* Translate Device Profile's */
2734 static const value_string cip_devtype_vals[] = {
2735 { 0x00, "Generic Device (deprecated)" },
2736 { 0x02, "AC Drive" },
2737 { 0x03, "Motor Overload" },
2738 { 0x04, "Limit Switch" },
2739 { 0x05, "Inductive Proximity Switch" },
2740 { 0x06, "Photoelectric Sensor" },
2741 { 0x07, "General Purpose Discrete I/O" },
2742 { 0x09, "Resolver" },
2743 { 0x0C, "Communications Adapter" },
2744 { 0x0E, "Programmable Logic Controller" },
2745 { 0x10, "Position Controller", },
2746 { 0x13, "DC Drive" },
2747 { 0x15, "Contactor", },
2748 { 0x16, "Motor Starter", },
2749 { 0x17, "Soft Start", },
2750 { 0x18, "Human-Machine Interface" },
2751 { 0x1A, "Mass Flow Controller" },
2752 { 0x1B, "Pneumatic Valve" },
2753 { 0x1C, "Vacuum Pressure Gauge" },
2754 { 0x1D, "Process Control Value" },
2755 { 0x1E, "Residual Gas Analyzer" },
2756 { 0x1F, "DC Power Generator" },
2757 { 0x20, "RF Power Generator" },
2758 { 0x21, "Turbomolecular Vacuum Pump" },
2759 { 0x22, "Encoder" },
2760 { 0x23, "Safety Discrete I/O Device" },
2761 { 0x24, "Fluid Flow Controller" },
2762 { 0x25, "CIP Motion Drive" },
2763 { 0x26, "CompoNet Repeater" },
2764 { 0x27, "Mass Flow Controller, Enhanced" },
2765 { 0x28, "CIP Modbus Device" },
2766 { 0x29, "CIP Modbus Translator" },
2767 { 0x2A, "Safety Analog I/O Device" },
2768 { 0x2B, "Generic Device (keyable)" },
2769 { 0x2C, "Managed Ethernet Switch" },
2770 { 0x2D, "CIP Motion Safety Drive Device" },
2771 { 0x2E, "Safety Drive Device" },
2772 { 0x2F, "CIP Motion Encoder" },
2773 { 0x30, "CIP Motion Converter" },
2774 { 0x31, "CIP Motion I/O" },
2775 { 0x32, "ControlNet Physical Layer Component" },
2776 { 0x33, "Circuit Breaker" },
2777 { 0x34, "HART Device" },
2778 { 0x35, "CIP-HART Translator" },
2779 { 0xC8, "Embedded Component" },
2780
2781 { 0, NULL }
2782 };
2783
2784 value_string_ext cip_devtype_vals_ext = VALUE_STRING_EXT_INIT(cip_devtype_vals);
2785
2786 /* Translate class names */
2787 const value_string cip_class_names_vals[] = {
2788 { 0x01, "Identity" },
2789 { 0x02, "Message Router" },
2790 { 0x03, "DeviceNet" },
2791 { 0x04, "Assembly" },
2792 { 0x05, "Connection" },
2793 { 0x06, "Connection Manager" },
2794 { 0x07, "Register" },
2795 { 0x08, "Discrete Input Point" },
2796 { 0x09, "Discrete Output Point" },
2797 { 0x0A, "Analog Input Point" },
2798 { 0x0B, "Analog Output Point" },
2799 { 0x0E, "Presence Sensing" },
2800 { 0x0F, "Parameter" },
2801 { 0x10, "Parameter Group" },
2802 { 0x12, "Group" },
2803 { 0x1D, "Discrete Input Group" },
2804 { 0x1E, "Discrete Output Group" },
2805 { 0x1F, "Discrete Group" },
2806 { 0x20, "Analog Input Group" },
2807 { 0x21, "Analog Output Group" },
2808 { 0x22, "Analog Group" },
2809 { 0x23, "Position Sensor" },
2810 { 0x24, "Position Controller Supervisor" },
2811 { 0x25, "Position Controller" },
2812 { 0x26, "Block Sequencer" },
2813 { 0x27, "Command Block" },
2814 { 0x28, "Motor Data" },
2815 { 0x29, "Control Supervisor" },
2816 { 0x2A, "AC/DC Drive" },
2817 { 0x2B, "Acknowledge Handler" },
2818 { 0x2C, "Overload" },
2819 { 0x2D, "Softstart" },
2820 { 0x2E, "Selection" },
2821 { 0x30, "S-Device Supervisor" },
2822 { 0x31, "S-Analog Sensor" },
2823 { 0x32, "S-Analog Actuator" },
2824 { 0x33, "S-Single Stage Controller" },
2825 { 0x34, "S-Gas Calibration" },
2826 { 0x35, "Trip Point" },
2827 { 0x37, "File" },
2828 { 0x38, "S-Partial Pressure" },
2829 { 0x39, "Safety Supervisor" },
2830 { 0x3A, "Safety Validator" },
2831 { 0x3B, "Safety Discrete Output Point" },
2832 { 0x3C, "Safety Discrete Output Group" },
2833 { 0x3D, "Safety Discrete Input Point" },
2834 { 0x3E, "Safety Discrete Input Group" },
2835 { 0x3F, "Safety Dual Channel Output" },
2836 { 0x40, "S-Sensor Calibration" },
2837 { 0x41, "Event Log" },
2838 { 0x42, "Motion Device Axis" },
2839 { 0x43, "Time Sync" },
2840 { 0x44, "Modbus" },
2841 { 0x45, "Originator Connection List" },
2842 { 0x46, "Modbus Serial Link" },
2843 { 0x47, "Device Level Ring (DLR)" },
2844 { 0x48, "QoS" },
2845 { 0x49, "Safety Analog Input Point" },
2846 { 0x4A, "Safety Analog Input Group" },
2847 { 0x4B, "Safety Dual Channel Analog Input" },
2848 { 0x4C, "SERCOS III Link" },
2849 { 0x4D, "Target Connection List" },
2850 { 0x4E, "Base Energy" },
2851 { 0x4F, "Electrical Energy" },
2852 { 0x50, "Non-Electrical Energy" },
2853 { 0x51, "Base Switch" },
2854 { 0x52, "SNMP" },
2855 { 0x53, "Power Management" },
2856 { 0x54, "RSTP Bridge" },
2857 { 0x55, "RSTP Port" },
2858 { 0x56, "PRP/HSR Protocol" },
2859 { 0x57, "PRP/HSR Nodes Table" },
2860 { 0x58, "Safety Feedback" },
2861 { 0x59, "Safety Dual Channel Feedback" },
2862 { 0x5A, "Safety Stop Functions" },
2863 { 0x5B, "Safety Limit Functions" },
2864 { 0x5C, "Power Curtailment" },
2865 { 0x5D, "CIP Security" },
2866 { 0x5E, "EtherNet/IP Security" },
2867 { 0x5F, "Certificate Management" },
2868 { 0x60, "Authority" },
2869 { 0x61, "Password Authenticator" },
2870 { 0x62, "Certificate Authenticator" },
2871 { 0x67, "PCCC Class" },
2872 { 0xF0, "ControlNet" },
2873 { 0xF1, "ControlNet Keeper" },
2874 { 0xF2, "ControlNet Scheduling" },
2875 { 0xF3, "Connection Configuration" },
2876 { 0xF4, "Port" },
2877 { 0xF5, "TCP/IP Interface" },
2878 { 0xF6, "Ethernet Link" },
2879 { 0xF7, "CompoNet" },
2880 { 0xF8, "CompoNet Repeater" },
2881 { 0xF9, "HART Master Port" },
2882 { 0xFA, "I/O Aggregation" },
2883 { 0x100, "Protection Trip" },
2884 { 0x101, "Protection Alarm" },
2885 { 0x102, "Circuit Breaker Supervisor" },
2886 { 0x103, "Circuit Breaker Statistics" },
2887 { 0x104, "Electrical Demand" },
2888 { 0x105, "Electrical Statistics" },
2889 { 0x106, "Machine Base Data" },
2890 { 0x107, "HART Process Device" },
2891 { 0x108, "Process Device Diagnostics" },
2892 { 0x109, "LLDP Management" },
2893 { 0x10A, "LLDP Data Table" },
2894 { 0x10B, "IO-Link Service Parameter" },
2895 { 0x10C, "IO-Link Master PHY" },
2896 { 0x10D, "IO-Link Device PHY" },
2897 { 0x10E, "Pilot Light Supervisor" },
2898 { 0x10F, "Select Line Link" },
2899 { 0x110, "In-Cabinet Actual Topology" },
2900 { 0x111, "In-Cabinet Commissioning" },
2901
2902 { 0, NULL }
2903 };
2904
2905 static const value_string cip_id_state_vals[] = {
2906 { 0, "Nonexistent" },
2907 { 1, "Device Self Testing" },
2908 { 2, "Standby" },
2909 { 3, "Operational" },
2910 { 4, "Major Recoverable Fault" },
2911 { 5, "Major Unrecoverable Fault" },
2912
2913 { 0, NULL }
2914 };
2915
2916 static const range_string cip_port_type_vals[] = {
2917 { 0, 0, "Any - no routing" },
2918 { 1, 1, "Reserved for legacy use" },
2919 { 2, 2, "ControlNet" },
2920 { 3, 3, "ControlNet with redundancy" },
2921 { 4, 4, "EtherNet/IP" },
2922 { 5, 5, "DeviceNet" },
2923 { 6, 99, "Reserved for legacy use" },
2924 { 100, 199, "Vendor Specific" },
2925 { 200, 200, "CompoNet" },
2926 { 201, 201, "Modbus/TCP" },
2927 { 202, 202, "Modbus/SL" },
2928 { 203, 203, "SERCOS III" },
2929 { 204, 65534, "Reserved for future use" },
2930 { 65535, 65535, "Any - user configurable" },
2931
2932 { 0, 0, NULL }
2933 };
2934
2935 const value_string cip_port_number_vals[] = {
2936 { 0, "Reserved" },
2937 { 1, "Backplane" },
2938
2939 { 0, NULL }
2940 };
2941
2942 value_string_ext cip_class_names_vals_ext = VALUE_STRING_EXT_INIT(cip_class_names_vals);
2943
2944 /* Translate function to string - Run/Idle */
2945 static const value_string cip_run_idle_vals[] = {
2946 { 0, "Idle" },
2947 { 1, "Run" },
2948
2949 { 0, NULL }
2950 };
2951
cip_rpi_api_fmt(gchar * s,guint32 value)2952 void cip_rpi_api_fmt(gchar *s, guint32 value)
2953 {
2954 g_snprintf(s, ITEM_LABEL_LENGTH, "%.3fms", value / 1000.0);
2955 }
2956
add_cip_class_to_info_column(packet_info * pinfo,guint32 class_id,int display_type)2957 static void add_cip_class_to_info_column(packet_info *pinfo, guint32 class_id, int display_type)
2958 {
2959 cip_req_info_t *cip_req_info;
2960
2961 /* Skip printing the top level class for certain common messages because it gets
2962 too wordy in the Info column. */
2963 cip_req_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
2964 if (cip_req_info
2965 && ((cip_req_info->bService == SC_CM_UNCON_SEND && class_id == CI_CLS_CM)
2966 || (cip_req_info->bService == SC_MULT_SERV_PACK && class_id == CI_CLS_MR)))
2967 {
2968 return;
2969 }
2970
2971 if (display_type == DISPLAY_CONNECTION_PATH)
2972 {
2973 col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", val_to_str(class_id, cip_class_names_vals, "Class (0x%02x)"));
2974 }
2975 else if (display_type == DISPLAY_REQUEST_PATH)
2976 {
2977 col_append_fstr(pinfo->cinfo, COL_INFO, "%s - ", val_to_str(class_id, cip_class_names_vals, "Class (0x%02x)"));
2978 }
2979 }
2980
add_cip_symbol_to_info_column(packet_info * pinfo,gchar * symbol_name,int display_type)2981 static void add_cip_symbol_to_info_column(packet_info *pinfo, gchar *symbol_name, int display_type)
2982 {
2983 if (symbol_name == NULL)
2984 {
2985 return;
2986 }
2987
2988 if (display_type == DISPLAY_CONNECTION_PATH)
2989 {
2990 col_append_fstr(pinfo->cinfo, COL_INFO, " ('%s')", symbol_name);
2991 }
2992 else if (display_type == DISPLAY_REQUEST_PATH)
2993 {
2994 col_append_fstr(pinfo->cinfo, COL_INFO, "'%s' - ", symbol_name);
2995 }
2996 }
2997
add_cip_service_to_info_column(packet_info * pinfo,guint8 service,const value_string * service_vals)2998 void add_cip_service_to_info_column(packet_info *pinfo, guint8 service, const value_string* service_vals)
2999 {
3000 col_append_str( pinfo->cinfo, COL_INFO,
3001 val_to_str(service & CIP_SC_MASK, service_vals, "Service (0x%02x)"));
3002 col_set_fence(pinfo->cinfo, COL_INFO);
3003 }
3004
add_cip_pccc_function_to_info_column(packet_info * pinfo,guint8 fnc,const value_string * fnc_vals)3005 static void add_cip_pccc_function_to_info_column(packet_info *pinfo, guint8 fnc, const value_string* fnc_vals)
3006 {
3007 col_append_fstr( pinfo->cinfo, COL_INFO,
3008 " - %s", val_to_str(fnc, fnc_vals, "Function (0x%02x)"));
3009 col_set_fence(pinfo->cinfo, COL_INFO);
3010 }
3011
dissect_id_revision(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3012 static int dissect_id_revision(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3013 int offset, int total_len)
3014 {
3015 if (total_len < 2)
3016 {
3017 expert_add_info(pinfo, item, &ei_mal_identity_revision);
3018 return total_len;
3019 }
3020
3021 proto_tree_add_item( tree, hf_id_major_rev, tvb, offset, 1, ENC_LITTLE_ENDIAN);
3022 proto_tree_add_item( tree, hf_id_minor_rev, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
3023 return 2;
3024 }
3025
dissect_id_status(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3026 static int dissect_id_status(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3027 int offset, int total_len)
3028 {
3029 static int * const status[] = {
3030 &hf_id_status_owned,
3031 &hf_id_status_conf,
3032 &hf_id_status_extended1,
3033 &hf_id_status_minor_fault_rec,
3034 &hf_id_status_minor_fault_unrec,
3035 &hf_id_status_major_fault_rec,
3036 &hf_id_status_major_fault_unrec,
3037 &hf_id_status_extended2,
3038 NULL
3039 };
3040
3041 if (total_len < 2)
3042 {
3043 expert_add_info(pinfo, item, &ei_mal_identity_status);
3044 return total_len;
3045 }
3046
3047 proto_tree_add_bitmask(tree, tvb, offset, hf_id_status, ett_id_status, status, ENC_LITTLE_ENDIAN);
3048
3049 return 2;
3050 }
3051
dissect_msg_rout_num_classes(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3052 static int dissect_msg_rout_num_classes(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3053 int offset, int total_len)
3054 {
3055 guint16 i, num_classes;
3056
3057 num_classes = tvb_get_letohs( tvb, offset);
3058 proto_tree_add_item( tree, hf_msg_rout_num_classes, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3059
3060 if (total_len < (2+(num_classes*2)))
3061 {
3062 expert_add_info(pinfo, item, &ei_mal_msg_rout_num_classes);
3063 return total_len;
3064 }
3065
3066 for (i = 0; i < num_classes; i++)
3067 proto_tree_add_item( tree, hf_msg_rout_classes, tvb, offset+2+(i*2), 2, ENC_LITTLE_ENDIAN);
3068
3069 return (2+(num_classes*2));
3070 }
3071
dissect_cm_connection_entry_list(packet_info * pinfo _U_,proto_tree * tree,proto_item * item _U_,tvbuff_t * tvb,int offset,int total_len _U_)3072 static int dissect_cm_connection_entry_list(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
3073 int offset, int total_len _U_)
3074 {
3075 guint32 num_conn_entries = 0;
3076 guint32 num_conn_entries_bytes;
3077
3078 proto_tree_add_item_ret_uint(tree, hf_conn_mgr_num_conn_entries, tvb, offset, 2, ENC_LITTLE_ENDIAN, &num_conn_entries);
3079
3080 num_conn_entries_bytes = (num_conn_entries+7)/8;
3081 proto_tree_add_uint(tree, hf_conn_mgr_num_conn_entries_bytes, tvb, 0, 0, num_conn_entries_bytes);
3082
3083 for (guint32 i = 0; i < num_conn_entries_bytes; i++)
3084 {
3085 proto_tree_add_item(tree, hf_conn_mgr_conn_open_bits, tvb, offset + 2 + i, 1, ENC_LITTLE_ENDIAN);
3086 }
3087
3088 return 2 + num_conn_entries_bytes;
3089 }
3090
dissect_time_sync_grandmaster_clock(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3091 static int dissect_time_sync_grandmaster_clock(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3092 int offset, int total_len)
3093 {
3094 if (total_len < 24)
3095 {
3096 expert_add_info(pinfo, item, &ei_mal_time_sync_gm_clock);
3097 return total_len;
3098 }
3099
3100 proto_tree_add_item( tree, hf_time_sync_gm_clock_clock_id, tvb, offset, 8, ENC_NA);
3101 proto_tree_add_item( tree, hf_time_sync_gm_clock_clock_class, tvb, offset+8, 2, ENC_LITTLE_ENDIAN);
3102 proto_tree_add_item( tree, hf_time_sync_gm_clock_time_accuracy, tvb, offset+10, 2, ENC_LITTLE_ENDIAN);
3103 proto_tree_add_item( tree, hf_time_sync_gm_clock_offset_scaled_log_variance, tvb, offset+12, 2, ENC_LITTLE_ENDIAN);
3104 proto_tree_add_item( tree, hf_time_sync_gm_clock_current_utc_offset, tvb, offset+14, 2, ENC_LITTLE_ENDIAN);
3105
3106 static int* const bits[] = {
3107 &hf_time_sync_gm_clock_time_property_flags_leap61,
3108 &hf_time_sync_gm_clock_time_property_flags_leap59,
3109 &hf_time_sync_gm_clock_time_property_flags_current_utc_valid,
3110 &hf_time_sync_gm_clock_time_property_flags_ptp_timescale,
3111 &hf_time_sync_gm_clock_time_property_flags_time_traceable,
3112 &hf_time_sync_gm_clock_time_property_flags_freq_traceable,
3113 NULL
3114 };
3115 proto_tree_add_bitmask(tree, tvb, offset + 16, hf_time_sync_gm_clock_time_property_flags, ett_time_sync_gm_clock_flags, bits, ENC_LITTLE_ENDIAN);
3116
3117 proto_tree_add_item( tree, hf_time_sync_gm_clock_time_source, tvb, offset+18, 2, ENC_LITTLE_ENDIAN);
3118 proto_tree_add_item( tree, hf_time_sync_gm_clock_priority1, tvb, offset+20, 2, ENC_LITTLE_ENDIAN);
3119 proto_tree_add_item( tree, hf_time_sync_gm_clock_priority2, tvb, offset+22, 2, ENC_LITTLE_ENDIAN);
3120 return 24;
3121 }
3122
dissect_time_sync_parent_clock(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3123 static int dissect_time_sync_parent_clock(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3124 int offset, int total_len)
3125 {
3126 if (total_len < 16)
3127 {
3128 expert_add_info(pinfo, item, &ei_mal_time_sync_parent_clock);
3129 return total_len;
3130 }
3131
3132 proto_tree_add_item( tree, hf_time_sync_parent_clock_clock_id, tvb, offset, 8, ENC_NA);
3133 proto_tree_add_item( tree, hf_time_sync_parent_clock_port_number, tvb, offset+8, 2, ENC_LITTLE_ENDIAN);
3134 proto_tree_add_item( tree, hf_time_sync_parent_clock_observed_offset_scaled_log_variance, tvb, offset+10, 2, ENC_LITTLE_ENDIAN);
3135 proto_tree_add_item( tree, hf_time_sync_parent_clock_observed_phase_change_rate, tvb, offset+12, 4, ENC_LITTLE_ENDIAN);
3136 return 16;
3137 }
3138
dissect_time_sync_local_clock(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3139 static int dissect_time_sync_local_clock(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3140 int offset, int total_len)
3141 {
3142 if (total_len < 20)
3143 {
3144 expert_add_info(pinfo, item, &ei_mal_time_sync_local_clock);
3145 return total_len;
3146 }
3147
3148 proto_tree_add_item( tree, hf_time_sync_local_clock_clock_id, tvb, offset, 8, ENC_NA);
3149 proto_tree_add_item( tree, hf_time_sync_local_clock_clock_class, tvb, offset+8, 2, ENC_LITTLE_ENDIAN);
3150 proto_tree_add_item( tree, hf_time_sync_local_clock_time_accuracy, tvb, offset+10, 2, ENC_LITTLE_ENDIAN);
3151 proto_tree_add_item( tree, hf_time_sync_local_clock_offset_scaled_log_variance, tvb, offset+12, 2, ENC_LITTLE_ENDIAN);
3152 proto_tree_add_item( tree, hf_time_sync_local_clock_current_utc_offset, tvb, offset+14, 2, ENC_LITTLE_ENDIAN);
3153
3154 static int* const bits[] = {
3155 &hf_time_sync_local_clock_time_property_flags_leap61,
3156 &hf_time_sync_local_clock_time_property_flags_leap59,
3157 &hf_time_sync_local_clock_time_property_flags_current_utc_valid,
3158 &hf_time_sync_local_clock_time_property_flags_ptp_timescale,
3159 &hf_time_sync_local_clock_time_property_flags_time_traceable,
3160 &hf_time_sync_local_clock_time_property_flags_freq_traceable,
3161 NULL
3162 };
3163 proto_tree_add_bitmask(tree, tvb, offset + 16, hf_time_sync_local_clock_time_property_flags, ett_time_sync_local_clock_flags, bits, ENC_LITTLE_ENDIAN);
3164
3165 proto_tree_add_item( tree, hf_time_sync_local_clock_time_source, tvb, offset+18, 2, ENC_LITTLE_ENDIAN);
3166 return 20;
3167 }
3168
dissect_time_sync_port_state_info(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3169 static int dissect_time_sync_port_state_info(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3170 int offset, int total_len)
3171 {
3172 guint16 i, num_ports;
3173 proto_tree* port_tree;
3174
3175 if (total_len < 2)
3176 {
3177 expert_add_info(pinfo, item, &ei_mal_time_sync_port_state_info);
3178 return total_len;
3179 }
3180
3181 num_ports = tvb_get_letohs( tvb, offset);
3182 proto_tree_add_item( tree, hf_time_sync_port_state_info_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3183
3184 if (2+num_ports*4 > total_len)
3185 {
3186 expert_add_info(pinfo, item, &ei_mal_time_sync_port_state_info_ports);
3187 return total_len;
3188 }
3189
3190 for (i = 0; i < num_ports; i++)
3191 {
3192 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*4, 4, ett_time_sync_port_state_info, NULL, "Port #%d", i+1);
3193 proto_tree_add_item(port_tree, hf_time_sync_port_state_info_port_num, tvb, offset+2+i*4, 2, ENC_LITTLE_ENDIAN);
3194 proto_tree_add_item(port_tree, hf_time_sync_port_state_info_port_state, tvb, offset+4+i*4, 2, ENC_LITTLE_ENDIAN);
3195 }
3196
3197 return 2+num_ports*4;
3198 }
3199
dissect_time_sync_port_enable_cfg(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3200 static int dissect_time_sync_port_enable_cfg(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3201 int offset, int total_len)
3202 {
3203 guint16 i, num_ports;
3204 proto_tree* port_tree;
3205
3206 if (total_len < 2)
3207 {
3208 expert_add_info(pinfo, item, &ei_mal_time_sync_port_enable_cfg);
3209 return total_len;
3210 }
3211
3212 num_ports = tvb_get_letohs( tvb, offset);
3213 proto_tree_add_item( tree, hf_time_sync_port_enable_cfg_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3214
3215 if (2+num_ports*4 > total_len)
3216 {
3217 expert_add_info(pinfo, item, &ei_mal_time_sync_port_enable_cfg_ports);
3218 return total_len;
3219 }
3220
3221 for (i = 0; i < num_ports; i++)
3222 {
3223 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*4, 4, ett_time_sync_port_enable_cfg, NULL, "Port #%d", i+1);
3224 proto_tree_add_item(port_tree, hf_time_sync_port_enable_cfg_port_num, tvb, offset+2+i*4, 2, ENC_LITTLE_ENDIAN);
3225 proto_tree_add_item(port_tree, hf_time_sync_port_enable_cfg_port_enable, tvb, offset+4+i*4, 2, ENC_LITTLE_ENDIAN);
3226 }
3227
3228 return 2+num_ports*4;
3229 }
3230
dissect_time_sync_port_log_announce(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3231 static int dissect_time_sync_port_log_announce(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3232 int offset, int total_len)
3233 {
3234 guint16 i, num_ports;
3235 proto_tree* port_tree;
3236
3237 if (total_len < 2)
3238 {
3239 expert_add_info(pinfo, item, &ei_mal_time_sync_port_log_announce);
3240 return total_len;
3241 }
3242
3243 num_ports = tvb_get_letohs( tvb, offset);
3244 proto_tree_add_item( tree, hf_time_sync_port_log_announce_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3245
3246 if (2+num_ports*4 > total_len)
3247 {
3248 expert_add_info(pinfo, item, &ei_mal_time_sync_port_log_announce_ports);
3249 return total_len;
3250 }
3251
3252 for (i = 0; i < num_ports; i++)
3253 {
3254 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*4, 4, ett_time_sync_port_log_announce, NULL, "Port #%d", i+1);
3255 proto_tree_add_item(port_tree, hf_time_sync_port_log_announce_port_num, tvb, offset+2+i*4, 2, ENC_LITTLE_ENDIAN);
3256 proto_tree_add_item(port_tree, hf_time_sync_port_log_announce_interval, tvb, offset+4+i*4, 2, ENC_LITTLE_ENDIAN);
3257 }
3258
3259 return 2+num_ports*4;
3260 }
3261
dissect_time_sync_port_log_sync(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3262 static int dissect_time_sync_port_log_sync(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3263 int offset, int total_len)
3264 {
3265 guint16 i, num_ports;
3266 proto_tree* port_tree;
3267
3268 if (total_len < 2)
3269 {
3270 expert_add_info(pinfo, item, &ei_mal_time_sync_port_log_sync);
3271 return total_len;
3272 }
3273
3274 num_ports = tvb_get_letohs( tvb, offset);
3275 proto_tree_add_item( tree, hf_time_sync_port_log_sync_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3276
3277 if (2+num_ports*4 > total_len)
3278 {
3279 expert_add_info(pinfo, item, &ei_mal_time_sync_port_log_sync_ports);
3280 return total_len;
3281 }
3282
3283 for (i = 0; i < num_ports; i++)
3284 {
3285 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*4, 4, ett_time_sync_port_log_sync, NULL, "Port #%d", i+1);
3286 proto_tree_add_item(port_tree, hf_time_sync_port_log_sync_port_num, tvb, offset+2+i*4, 2, ENC_LITTLE_ENDIAN);
3287 proto_tree_add_item(port_tree, hf_time_sync_port_log_sync_port_log_sync_interval, tvb, offset+4+i*4, 2, ENC_LITTLE_ENDIAN);
3288 }
3289
3290 return 2+num_ports*4;
3291 }
3292
dissect_time_sync_clock_type(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3293 static int dissect_time_sync_clock_type(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3294 int offset, int total_len)
3295 {
3296 if (total_len < 2)
3297 {
3298 expert_add_info(pinfo, item, &ei_mal_time_sync_clock_type);
3299 return total_len;
3300 }
3301
3302 static int* const bits[] = {
3303 &hf_time_sync_clock_type_management,
3304 &hf_time_sync_clock_type_end_to_end,
3305 &hf_time_sync_clock_type_boundary,
3306 &hf_time_sync_clock_type_ordinary,
3307 &hf_time_sync_clock_type_slave_only,
3308 NULL
3309 };
3310 proto_tree_add_bitmask(tree, tvb, offset, hf_time_sync_clock_type, ett_time_sync_clock_type, bits, ENC_LITTLE_ENDIAN);
3311
3312 return 2;
3313 }
3314
dissect_time_sync_manufacture_id(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3315 static int dissect_time_sync_manufacture_id(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3316 int offset, int total_len)
3317 {
3318 if (total_len < 4)
3319 {
3320 expert_add_info(pinfo, item, &ei_mal_time_sync_manufacture_id);
3321 return total_len;
3322 }
3323
3324 proto_tree_add_item( tree, hf_time_sync_manufacture_id_oui, tvb, offset, 3, ENC_LITTLE_ENDIAN);
3325 proto_tree_add_item( tree, hf_time_sync_manufacture_id_reserved, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
3326 return 4;
3327 }
3328
dissect_time_sync_prod_desc(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3329 static int dissect_time_sync_prod_desc(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3330 int offset, int total_len)
3331 {
3332 guint32 size;
3333
3334 if (total_len < 4)
3335 {
3336 expert_add_info(pinfo, item, &ei_mal_time_sync_prod_desc);
3337 return total_len;
3338 }
3339
3340 proto_tree_add_item_ret_uint( tree, hf_time_sync_prod_desc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &size);
3341
3342 if (size > 64)
3343 {
3344 expert_add_info(pinfo, item, &ei_mal_time_sync_prod_desc_64);
3345 return total_len;
3346 }
3347
3348 if ((int)(size+4) > total_len)
3349 {
3350 expert_add_info(pinfo, item, &ei_mal_time_sync_prod_desc_size);
3351 return total_len;
3352 }
3353
3354 proto_tree_add_item( tree, hf_time_sync_prod_desc_str, tvb, offset+4, size, ENC_ASCII|ENC_NA);
3355 return size+4;
3356 }
3357
dissect_time_sync_revision_data(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3358 static int dissect_time_sync_revision_data(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3359 int offset, int total_len)
3360 {
3361 guint32 size;
3362
3363 if (total_len < 4)
3364 {
3365 expert_add_info(pinfo, item, &ei_mal_time_sync_revision_data);
3366 return total_len;
3367 }
3368
3369 proto_tree_add_item_ret_uint( tree, hf_time_sync_revision_data_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &size);
3370
3371 if (size > 32)
3372 {
3373 expert_add_info(pinfo, item, &ei_mal_time_sync_revision_data_32);
3374 return total_len;
3375 }
3376
3377 if ((int)(size+4) > total_len)
3378 {
3379 expert_add_info(pinfo, item, &ei_mal_time_sync_revision_data_size);
3380 return total_len;
3381 }
3382
3383 proto_tree_add_item( tree, hf_time_sync_revision_data_str, tvb, offset+4, size, ENC_ASCII|ENC_NA);
3384 return size+4;
3385 }
3386
dissect_time_sync_user_desc(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3387 static int dissect_time_sync_user_desc(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3388 int offset, int total_len)
3389 {
3390 guint32 size;
3391
3392 if (total_len < 4)
3393 {
3394 expert_add_info(pinfo, item, &ei_mal_time_sync_user_desc);
3395 return total_len;
3396 }
3397
3398 proto_tree_add_item_ret_uint( tree, hf_time_sync_user_desc_size, tvb, offset, 4, ENC_LITTLE_ENDIAN, &size);
3399
3400 if (size > 128)
3401 {
3402 expert_add_info(pinfo, item, &ei_mal_time_sync_user_desc_128);
3403 return total_len;
3404 }
3405
3406 if ((int)(size+4) > total_len)
3407 {
3408 expert_add_info(pinfo, item, &ei_mal_time_sync_user_desc_size);
3409 return total_len;
3410 }
3411
3412 proto_tree_add_item( tree, hf_time_sync_user_desc_str, tvb, offset+4, size, ENC_ASCII|ENC_NA);
3413 return size+4;
3414 }
3415
dissect_time_sync_port_profile_id_info(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3416 static int dissect_time_sync_port_profile_id_info(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3417 int offset, int total_len)
3418 {
3419 guint16 i, num_ports;
3420 proto_tree* port_tree;
3421
3422 if (total_len < 2)
3423 {
3424 expert_add_info(pinfo, item, &ei_mal_time_sync_port_profile_id_info);
3425 return total_len;
3426 }
3427
3428 num_ports = tvb_get_letohs( tvb, offset);
3429 proto_tree_add_item( tree, hf_time_sync_port_profile_id_info_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3430
3431 if (2+num_ports*10 > total_len)
3432 {
3433 expert_add_info(pinfo, item, &ei_mal_time_sync_port_profile_id_info_ports);
3434 return total_len;
3435 }
3436
3437 for (i = 0; i < num_ports; i++)
3438 {
3439 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*10, 10, ett_time_sync_port_profile_id_info, NULL, "Port #%d", i+1);
3440 proto_tree_add_item(port_tree, hf_time_sync_port_profile_id_info_port_num, tvb, offset+2+i*10, 2, ENC_LITTLE_ENDIAN);
3441 proto_tree_add_item(port_tree, hf_time_sync_port_profile_id_info_profile_id, tvb, offset+4+i*10, 8, ENC_NA);
3442 }
3443
3444 return 2+num_ports*10;
3445 }
3446
dissect_time_sync_port_phys_addr_info(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3447 static int dissect_time_sync_port_phys_addr_info(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3448 int offset, int total_len)
3449 {
3450 guint16 i, num_ports;
3451 proto_tree* port_tree;
3452
3453 if (total_len < 2)
3454 {
3455 expert_add_info(pinfo, item, &ei_mal_time_sync_port_phys_addr_info);
3456 return total_len;
3457 }
3458
3459 num_ports = tvb_get_letohs( tvb, offset);
3460 proto_tree_add_item( tree, hf_time_sync_port_phys_addr_info_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3461
3462 if (2+num_ports*36 > total_len)
3463 {
3464 expert_add_info(pinfo, item, &ei_mal_time_sync_port_phys_addr_info_ports);
3465 return total_len;
3466 }
3467
3468 for (i = 0; i < num_ports; i++)
3469 {
3470 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*36, 36, ett_time_sync_port_phys_addr_info, NULL, "Port #%d", i+1);
3471 proto_tree_add_item(port_tree, hf_time_sync_port_phys_addr_info_port_num, tvb, offset+2+i*36, 2, ENC_LITTLE_ENDIAN);
3472 proto_tree_add_item(port_tree, hf_time_sync_port_phys_addr_info_phys_proto, tvb, offset+4+i*36, 16, ENC_ASCII|ENC_NA);
3473
3474 guint32 addr_size;
3475 proto_tree_add_item_ret_uint(port_tree, hf_time_sync_port_phys_addr_info_addr_size, tvb, offset+20+i*36, 2, ENC_LITTLE_ENDIAN, &addr_size);
3476
3477 // Field is 16 bytes, but only highlight the actual size.
3478 proto_tree_add_item(port_tree, hf_time_sync_port_phys_addr_info_phys_addr, tvb, offset+22+i*36, addr_size, ENC_NA);
3479 }
3480
3481 return 2+num_ports*36;
3482 }
3483
dissect_time_sync_port_proto_addr_info(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3484 static int dissect_time_sync_port_proto_addr_info(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3485 int offset, int total_len)
3486 {
3487 guint16 i, num_ports;
3488 proto_tree* port_tree;
3489
3490 if (total_len < 2)
3491 {
3492 expert_add_info(pinfo, item, &ei_mal_time_sync_port_proto_addr_info);
3493 return total_len;
3494 }
3495
3496 num_ports = tvb_get_letohs( tvb, offset);
3497 proto_tree_add_item( tree, hf_time_sync_port_proto_addr_info_num_ports, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3498
3499 if (2+num_ports*22 > total_len)
3500 {
3501 expert_add_info(pinfo, item, &ei_mal_time_sync_port_proto_addr_info_ports);
3502 return total_len;
3503 }
3504
3505 for (i = 0; i < num_ports; i++)
3506 {
3507 port_tree = proto_tree_add_subtree_format(tree, tvb, offset+2+i*22, 22, ett_time_sync_port_proto_addr_info, NULL, "Port #%d", i+1);
3508 proto_tree_add_item(port_tree, hf_time_sync_port_proto_addr_info_port_num, tvb, offset+2+i*22, 2, ENC_LITTLE_ENDIAN);
3509 proto_tree_add_item(port_tree, hf_time_sync_port_proto_addr_info_network_proto, tvb, offset+4+i*22, 2, ENC_LITTLE_ENDIAN);
3510 proto_tree_add_item(port_tree, hf_time_sync_port_proto_addr_info_addr_size, tvb, offset+6+i*22, 2, ENC_LITTLE_ENDIAN);
3511 proto_tree_add_item(port_tree, hf_time_sync_port_proto_addr_info_port_proto_addr, tvb, offset+8+i*22, 16, ENC_NA);
3512 }
3513
3514 return 2+num_ports*22;
3515 }
3516
dissect_time_sync_sys_time_and_offset(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3517 static int dissect_time_sync_sys_time_and_offset(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3518 int offset, int total_len)
3519 {
3520 if (total_len < 16)
3521 {
3522 expert_add_info(pinfo, item, &ei_mal_time_sync_sys_time_and_offset);
3523 return total_len;
3524 }
3525
3526 dissect_cip_utime(tree, tvb, offset, hf_time_sync_sys_time_and_offset_time);
3527 proto_tree_add_item( tree, hf_time_sync_sys_time_and_offset_offset, tvb, offset+8, 8, ENC_LITTLE_ENDIAN);
3528
3529 return 16;
3530 }
3531
dissect_optional_attr_list(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3532 int dissect_optional_attr_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3533 int offset, int total_len)
3534 {
3535 guint32 i;
3536 guint32 num_attr = 0;
3537
3538 proto_tree_add_item_ret_uint(tree, hf_attr_class_opt_attr_num, tvb, offset, 2, ENC_LITTLE_ENDIAN, &num_attr);
3539
3540 if (total_len < (int)(2 + num_attr * 2))
3541 {
3542 expert_add_info(pinfo, item, &ei_mal_opt_attr_list);
3543 return total_len;
3544 }
3545
3546 // Look up the request data to get the CIP Class.
3547 cip_req_info_t *cip_req_info;
3548 cip_req_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
3549
3550 for (i = 0; i < num_attr; ++i)
3551 {
3552 proto_item* attr_item = proto_tree_add_item(tree, hf_attr_class_attr_num, tvb, offset + 2 + 2 * i, 2, ENC_LITTLE_ENDIAN);
3553
3554 // Display attribute name.
3555 if (cip_req_info && cip_req_info->ciaData)
3556 {
3557 attribute_info_t* attr;
3558 attr = cip_get_attribute(cip_req_info->ciaData->iClass, 1, i);
3559 if (attr)
3560 {
3561 proto_item_append_text(attr_item, " (%s)", attr->text);
3562 }
3563 }
3564 }
3565
3566 return 2 + num_attr * 2;
3567 }
3568
dissect_optional_service_list(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3569 int dissect_optional_service_list(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3570 int offset, int total_len)
3571 {
3572 guint32 i;
3573 guint32 num_services = 0;
3574
3575 proto_tree_add_item_ret_uint(tree, hf_attr_class_opt_service_num, tvb, offset, 2, ENC_LITTLE_ENDIAN, &num_services);
3576
3577 if (total_len < (int)(2 + num_services * 2))
3578 {
3579 expert_add_info(pinfo, item, &ei_mal_opt_service_list);
3580 return total_len;
3581 }
3582
3583 for (i = 0; i < num_services; ++i)
3584 {
3585 proto_tree_add_item(tree, hf_attr_class_service_code, tvb, offset + 2 + 2 * i, 2, ENC_LITTLE_ENDIAN);
3586 }
3587
3588 return 2 + num_services * 2;
3589 }
3590
dissect_port_instance_info(packet_info * pinfo _U_,proto_tree * tree,proto_item * item _U_,tvbuff_t * tvb,int offset,int total_len)3591 static int dissect_port_instance_info(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
3592 int offset, int total_len)
3593 {
3594 int i;
3595
3596 for (i = 0; i < total_len; i += 4)
3597 {
3598 proto_tree_add_item(tree, hf_port_type, tvb, offset + i, 2, ENC_LITTLE_ENDIAN);
3599 proto_tree_add_item(tree, hf_port_number, tvb, offset + i + 2, 2, ENC_LITTLE_ENDIAN);
3600 }
3601
3602 return total_len;
3603 }
3604
dissect_port_associated_comm_objects(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len _U_)3605 static int dissect_port_associated_comm_objects(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3606 int offset, int total_len _U_)
3607 {
3608 guint32 num_entries;
3609 proto_tree_add_item_ret_uint(tree, hf_port_num_comm_object_entries, tvb, offset, 1, ENC_LITTLE_ENDIAN, &num_entries);
3610
3611 int parsed_len = 1;
3612 for (guint32 i = 0; i < num_entries; ++i)
3613 {
3614 parsed_len += dissect_padded_epath_len_usint(pinfo, tree, item, tvb, offset + parsed_len,
3615 tvb_reported_length_remaining(tvb, offset + parsed_len));
3616 }
3617
3618 return parsed_len;
3619 }
3620
dissect_padded_epath_len(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len,gboolean one_byte_len)3621 static int dissect_padded_epath_len(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3622 int offset, int total_len, gboolean one_byte_len)
3623 {
3624 guint32 path_size;
3625 proto_tree *epath_tree;
3626 proto_item *path_item;
3627
3628 guint32 path_size_len;
3629 int hf_path_len;
3630 if (one_byte_len == TRUE)
3631 {
3632 path_size_len = 1;
3633 hf_path_len = hf_path_len_usint;
3634 }
3635 else
3636 {
3637 path_size_len = 2;
3638 hf_path_len = hf_path_len_uint;
3639 }
3640
3641 path_item = proto_tree_add_item_ret_uint(tree, hf_path_len, tvb, offset, path_size_len, ENC_LITTLE_ENDIAN, &path_size);
3642
3643 if (total_len < (int)(path_size * 2 + path_size_len))
3644 {
3645 expert_add_info(pinfo, item, &ei_mal_padded_epath_size);
3646 return total_len;
3647 }
3648
3649 epath_tree = proto_tree_add_subtree(tree, tvb, offset + path_size_len, path_size * 2, ett_path, &path_item, "Path: ");
3650 dissect_epath(tvb, pinfo, epath_tree, path_item, offset + path_size_len, path_size * 2, FALSE, FALSE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
3651
3652 return path_size * 2 + path_size_len;
3653 }
3654
3655 /* Format: USINT (Length of EPATH in 16-bit words) + Padded EPATH */
dissect_padded_epath_len_usint(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3656 int dissect_padded_epath_len_usint(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3657 int offset, int total_len)
3658 {
3659 return dissect_padded_epath_len(pinfo, tree, item, tvb, offset, total_len, TRUE);
3660 }
3661
3662 /* Format: UINT (Length of EPATH in 16-bit words) + Padded EPATH */
dissect_padded_epath_len_uint(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3663 int dissect_padded_epath_len_uint(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3664 int offset, int total_len)
3665 {
3666 return dissect_padded_epath_len(pinfo, tree, item, tvb, offset, total_len, FALSE);
3667 }
3668
dissect_single_segment_packed_attr(packet_info * pinfo,proto_tree * tree,proto_item * item _U_,tvbuff_t * tvb,int offset,int total_len _U_)3669 static int dissect_single_segment_packed_attr(packet_info *pinfo, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
3670 int offset, int total_len _U_)
3671 {
3672 proto_tree *subtree;
3673 proto_item *subitem;
3674 subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_port_path, &subitem, "Path: ");
3675
3676 int parsed_len = dissect_cip_segment_single(pinfo, tvb, offset, subtree, subitem, FALSE, TRUE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
3677 proto_item_set_len(subitem, parsed_len);
3678
3679 return parsed_len;
3680 }
3681
dissect_single_segment_padded_attr(packet_info * pinfo,proto_tree * tree,proto_item * item _U_,tvbuff_t * tvb,int offset,int total_len _U_)3682 static int dissect_single_segment_padded_attr(packet_info *pinfo, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
3683 int offset, int total_len _U_)
3684 {
3685 proto_tree *subtree;
3686 proto_item *subitem;
3687 subtree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_port_path, &subitem, "Path: ");
3688
3689 int parsed_len = dissect_cip_segment_single(pinfo, tvb, offset, subtree, subitem, FALSE, FALSE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
3690 proto_item_set_len(subitem, parsed_len);
3691
3692 return parsed_len;
3693 }
3694
dissect_port_link_object(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int total_len)3695 static int dissect_port_link_object(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
3696 int offset, int total_len)
3697 {
3698 return dissect_padded_epath_len_uint(pinfo, tree, item, tvb, offset, total_len);
3699 }
3700
dissect_port_node_range(packet_info * pinfo _U_,proto_tree * tree,proto_item * item _U_,tvbuff_t * tvb,int offset,int total_len _U_)3701 static int dissect_port_node_range(packet_info *pinfo _U_, proto_tree *tree, proto_item *item _U_, tvbuff_t *tvb,
3702 int offset, int total_len _U_)
3703 {
3704 proto_tree_add_item(tree, hf_port_min_node_num, tvb, offset, 2, ENC_LITTLE_ENDIAN);
3705 proto_tree_add_item(tree, hf_port_max_node_num, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
3706
3707 return 4;
3708 }
3709
3710 static attribute_info_t cip_attribute_vals[] = {
3711 /* Identity Object (class attributes) */
3712 {0x01, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3713 {0x01, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3714 {0x01, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3715 {0x01, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3716 {0x01, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3717 {0x01, TRUE, 6, 2, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3718 {0x01, TRUE, 7, 3, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3719
3720 /* Identity Object (instance attributes) */
3721 {0x01, FALSE, 1, 0, "Vendor ID", cip_uint, &hf_id_vendor_id, NULL},
3722 {0x01, FALSE, 2, 1, "Device Type", cip_uint, &hf_id_device_type, NULL},
3723 {0x01, FALSE, 3, 2, "Product Code", cip_uint, &hf_id_product_code, NULL},
3724 {0x01, FALSE, 4, 3, "Revision", cip_dissector_func, NULL, dissect_id_revision},
3725 {0x01, FALSE, 5, 4, "Status", cip_dissector_func, NULL, dissect_id_status},
3726 {0x01, FALSE, 6, 5, "Serial Number", cip_udint, &hf_id_serial_number, NULL},
3727 {0x01, FALSE, 7, 6, "Product Name", cip_short_string, &hf_id_product_name, NULL},
3728 {0x01, FALSE, 8, 7, "State", cip_usint, &hf_id_state, NULL},
3729 {0x01, FALSE, 9, 8, "Configuration Consistency Value", cip_uint, &hf_id_config_value, NULL},
3730 {0x01, FALSE, 10, 9, "Heartbeat Interval", cip_usint, &hf_id_heartbeat, NULL},
3731
3732 /* Message Router Object (class attributes) */
3733 {0x02, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3734 {0x02, TRUE, 2, -1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3735 {0x02, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3736 {0x02, TRUE, 4, 1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3737 {0x02, TRUE, 5, 2, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3738 {0x02, TRUE, 6, 3, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3739 {0x02, TRUE, 7, 4, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3740
3741 /* Message Router Object (instance attributes) */
3742 {0x02, FALSE, 1, 0, "Object List", cip_dissector_func, NULL, dissect_msg_rout_num_classes},
3743 {0x02, FALSE, 2, 1, "Number Available", cip_uint, &hf_msg_rout_num_available, NULL},
3744 {0x02, FALSE, 3, 2, "Number Active", cip_uint, &hf_msg_rout_num_active, NULL},
3745 {0x02, FALSE, 4, 3, "Active Connections", cip_uint_array, &hf_msg_rout_active_connections, NULL},
3746
3747 /* Connection Manager Object (class attributes) */
3748 {0x06, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3749 {0x06, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3750 {0x06, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3751 {0x06, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3752 {0x06, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3753 {0x06, TRUE, 6, 2, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3754 {0x06, TRUE, 7, 3, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3755
3756 /* Connection Manager Object (instance attributes) */
3757 {0x06, FALSE, 1, 0, "Open Requests", cip_uint, &hf_conn_mgr_open_requests, NULL},
3758 {0x06, FALSE, 2, 1, "Open Format Rejects", cip_uint, &hf_conn_mgr_open_format_rejects, NULL},
3759 {0x06, FALSE, 3, 2, "Open Resource Rejects", cip_uint, &hf_conn_mgr_open_resource_rejects, NULL},
3760 {0x06, FALSE, 4, 3, "Other Open Rejects", cip_uint, &hf_conn_mgr_other_open_rejects, NULL},
3761 {0x06, FALSE, 5, 4, "Close Requests", cip_uint, &hf_conn_mgr_close_requests, NULL},
3762 {0x06, FALSE, 6, 5, "Close Format Requests", cip_uint, &hf_conn_close_format_requests, NULL},
3763 {0x06, FALSE, 7, 6, "Close Other Requests", cip_uint, &hf_conn_mgr_close_other_requests, NULL},
3764 {0x06, FALSE, 8, 7, "Connection Timeouts", cip_uint, &hf_conn_mgr_conn_timouts, NULL},
3765 {0x06, FALSE, 9, 8, "Connection Entry List", cip_dissector_func, NULL, dissect_cm_connection_entry_list },
3766 {0x06, FALSE, 11, 9, "CPU Utilization", cip_uint, &hf_conn_mgr_cpu_utilization, NULL },
3767 {0x06, FALSE, 12, 10, "Max Buff Size", cip_udint, &hf_conn_mgr_max_buff_size, NULL },
3768 {0x06, FALSE, 13, 11, "Buff Size Remaining", cip_udint, &hf_conn_mgr_buff_size_remaining, NULL },
3769
3770 /* File Object (instance attributes) */
3771 {0x37, FALSE, 4, -1, "File Name", cip_stringi, &hf_file_filename, NULL },
3772
3773 /* Time Sync Object (class attributes) */
3774 {0x43, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3775 {0x43, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3776 {0x43, TRUE, 3, 2, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3777 {0x43, TRUE, 4, 3, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3778 {0x43, TRUE, 5, 4, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3779 {0x43, TRUE, 6, 5, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3780 {0x43, TRUE, 7, 6, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3781
3782 /* Time Sync Object (instance attributes) */
3783 {0x43, FALSE, 1, -1, "PTP Enable", cip_bool, &hf_time_sync_ptp_enable, NULL},
3784 {0x43, FALSE, 2, -1, "Is Synchronized", cip_bool, &hf_time_sync_is_synchronized, NULL},
3785 {0x43, FALSE, 3, -1, "System Time (Microseconds)", cip_utime, &hf_time_sync_sys_time_micro, NULL},
3786 {0x43, FALSE, 4, -1, "System Time (Nanoseconds)", cip_stime, &hf_time_sync_sys_time_nano, NULL},
3787 {0x43, FALSE, 5, -1, "Offset from Master", cip_ntime, &hf_time_sync_offset_from_master, NULL},
3788 {0x43, FALSE, 6, -1, "Max Offset from Master", cip_ulint, &hf_time_sync_max_offset_from_master, NULL},
3789 {0x43, FALSE, 7, -1, "Mean Path Delay To Master", cip_ntime, &hf_time_sync_mean_path_delay_to_master, NULL},
3790 {0x43, FALSE, 8, -1, "Grand Master Clock Info", cip_dissector_func, NULL, dissect_time_sync_grandmaster_clock},
3791 {0x43, FALSE, 9, -1, "Parent Clock Info", cip_dissector_func, NULL, dissect_time_sync_parent_clock},
3792 {0x43, FALSE, 10, -1, "Local Clock Info", cip_dissector_func, NULL, dissect_time_sync_local_clock},
3793 {0x43, FALSE, 11, -1, "Number of Ports", cip_uint, &hf_time_sync_num_ports, NULL},
3794 {0x43, FALSE, 12, -1, "Port State Info", cip_dissector_func, NULL, dissect_time_sync_port_state_info},
3795 {0x43, FALSE, 13, -1, "Port Enable Cfg", cip_dissector_func, NULL, dissect_time_sync_port_enable_cfg},
3796 {0x43, FALSE, 14, -1, "Port Log Announcement Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_announce},
3797 {0x43, FALSE, 15, -1, "Port Log Sync Interval Cfg", cip_dissector_func, NULL, dissect_time_sync_port_log_sync},
3798 {0x43, FALSE, 16, -1, "Priority1", cip_usint, &hf_time_sync_priority1, NULL},
3799 {0x43, FALSE, 17, -1, "Priority2", cip_usint, &hf_time_sync_priority2, NULL},
3800 {0x43, FALSE, 18, -1, "Domain number", cip_usint, &hf_time_sync_domain_number, NULL},
3801 {0x43, FALSE, 19, -1, "Clock Type", cip_dissector_func, NULL, dissect_time_sync_clock_type},
3802 {0x43, FALSE, 20, -1, "Manufacture Identity", cip_dissector_func, NULL, dissect_time_sync_manufacture_id},
3803 {0x43, FALSE, 21, -1, "Product Description", cip_dissector_func, NULL, dissect_time_sync_prod_desc},
3804 {0x43, FALSE, 22, -1, "Revision Data", cip_dissector_func, NULL, dissect_time_sync_revision_data},
3805 {0x43, FALSE, 23, -1, "User Description", cip_dissector_func, NULL, dissect_time_sync_user_desc},
3806 {0x43, FALSE, 24, -1, "Port Profile Identity Info", cip_dissector_func, NULL, dissect_time_sync_port_profile_id_info},
3807 {0x43, FALSE, 25, -1, "Port Physical Address Info", cip_dissector_func, NULL, dissect_time_sync_port_phys_addr_info},
3808 {0x43, FALSE, 26, -1, "Port Protocol Address Info", cip_dissector_func, NULL, dissect_time_sync_port_proto_addr_info},
3809 {0x43, FALSE, 27, -1, "Steps Removed", cip_uint, &hf_time_sync_steps_removed, NULL},
3810 {0x43, FALSE, 28, -1, "System Time and Offset", cip_dissector_func, NULL, dissect_time_sync_sys_time_and_offset},
3811
3812
3813 /* Connection Configuration Object (class attributes) */
3814 /* Data sizes are different than common class attributes for some items. */
3815 { 0xF3, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3816 { 0xF3, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_udint, &hf_cip_class_max_inst32, NULL },
3817 { 0xF3, TRUE, 3, 2, CLASS_ATTRIBUTE_3_NAME, cip_udint, &hf_cip_class_num_inst32, NULL },
3818 { 0xF3, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3819 { 0xF3, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3820 { 0xF3, TRUE, 6, -1, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3821 { 0xF3, TRUE, 7, -1, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3822 { 0xF3, TRUE, 8, 3, "Format Number", cip_uint, &hf_cip_cco_format_number, NULL },
3823 { 0xF3, TRUE, 9, 4, "Edit Signature", cip_udint, &hf_cip_cco_edit_signature, NULL },
3824
3825 /* Port Object (class attributes) */
3826 { 0xF4, TRUE, 1, 0, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3827 { 0xF4, TRUE, 2, 1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3828 { 0xF4, TRUE, 3, 2, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3829 { 0xF4, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3830 { 0xF4, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3831 { 0xF4, TRUE, 6, -1, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3832 { 0xF4, TRUE, 7, -1, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3833 { 0xF4, TRUE, 8, 3, "Entry Port", cip_uint, &hf_port_entry_port, NULL },
3834 { 0xF4, TRUE, 9, 4, "Port Instance Info", cip_dissector_func, NULL, dissect_port_instance_info },
3835
3836 /* Port Object (instance attributes) */
3837 { 0xF4, FALSE, 1, 0, "Port Type", cip_uint, &hf_port_type, NULL },
3838 { 0xF4, FALSE, 2, 1, "Port Number", cip_uint, &hf_port_number, NULL },
3839 { 0xF4, FALSE, 3, 2, "Link Object", cip_dissector_func, NULL, dissect_port_link_object },
3840 { 0xF4, FALSE, 4, 3, "Port Name", cip_short_string, &hf_port_name, NULL },
3841 { 0xF4, FALSE, 7, 4, "Port Number and Node Address", cip_dissector_func, NULL, dissect_single_segment_padded_attr },
3842 { 0xF4, FALSE, 8, -1, "Port Node Range", cip_dissector_func, NULL, dissect_port_node_range },
3843 { 0xF4, FALSE, 9, -1, "Chassis Identity", cip_dissector_func, NULL, dissect_single_segment_packed_attr },
3844 { 0xF4, FALSE, 11, -1, "Associated Communication Objects", cip_dissector_func, NULL, dissect_port_associated_comm_objects },
3845 };
3846
3847 typedef struct attribute_val_array {
3848 size_t size;
3849 attribute_info_t* attrs;
3850 } attribute_val_array_t;
3851
3852 /* Each entry in this table (eg: cip_attribute_vals) is a list of:
3853 Attribute information (class_id/class_instance/attribute) to attribute property
3854
3855 Note: If more items are added to the individual tables, it may make sense
3856 to switch to a more efficient implementation (eg: hash table).
3857 */
3858
3859 static attribute_val_array_t all_attribute_vals[] = {
3860 {sizeof(cip_attribute_vals)/sizeof(attribute_info_t), cip_attribute_vals},
3861 {sizeof(enip_attribute_vals)/sizeof(attribute_info_t), enip_attribute_vals},
3862 {sizeof(cip_safety_attribute_vals)/sizeof(attribute_info_t), cip_safety_attribute_vals},
3863 {sizeof(cip_motion_attribute_vals)/sizeof(attribute_info_t), cip_motion_attribute_vals},
3864 };
3865
cip_get_attribute(guint class_id,guint instance,guint attribute)3866 attribute_info_t* cip_get_attribute(guint class_id, guint instance, guint attribute)
3867 {
3868 size_t i, j;
3869 attribute_val_array_t* att_array;
3870 attribute_info_t* pattr;
3871
3872 static attribute_info_t class_attribute_vals[] = {
3873 { 0, TRUE, 1, -1, CLASS_ATTRIBUTE_1_NAME, cip_uint, &hf_attr_class_revision, NULL },
3874 { 0, TRUE, 2, -1, CLASS_ATTRIBUTE_2_NAME, cip_uint, &hf_attr_class_max_instance, NULL },
3875 { 0, TRUE, 3, -1, CLASS_ATTRIBUTE_3_NAME, cip_uint, &hf_attr_class_num_instance, NULL },
3876 { 0, TRUE, 4, -1, CLASS_ATTRIBUTE_4_NAME, cip_dissector_func, NULL, dissect_optional_attr_list },
3877 { 0, TRUE, 5, -1, CLASS_ATTRIBUTE_5_NAME, cip_dissector_func, NULL, dissect_optional_service_list },
3878 { 0, TRUE, 6, -1, CLASS_ATTRIBUTE_6_NAME, cip_uint, &hf_attr_class_num_class_attr, NULL },
3879 { 0, TRUE, 7, -1, CLASS_ATTRIBUTE_7_NAME, cip_uint, &hf_attr_class_num_inst_attr, NULL },
3880 };
3881
3882 for (i = 0; i < sizeof(all_attribute_vals)/sizeof(attribute_val_array_t); i++)
3883 {
3884 att_array = &all_attribute_vals[i];
3885 for (j = 0; j < att_array->size; j++)
3886 {
3887 pattr = &att_array->attrs[j];
3888 if ((pattr->class_id == class_id) &&
3889 (instance != SEGMENT_VALUE_NOT_SET) &&
3890 (((instance == 0) && (pattr->class_instance == TRUE)) || ((instance != 0) && (pattr->class_instance == FALSE))) &&
3891 (pattr->attribute == attribute))
3892 {
3893 return pattr;
3894 }
3895 }
3896 }
3897
3898 /* Check against common class attributes. */
3899 if (instance == 0)
3900 {
3901 for (i = 0; i < sizeof(class_attribute_vals) / sizeof(attribute_info_t); i++)
3902 {
3903 pattr = &class_attribute_vals[i];
3904 if (pattr->attribute == attribute)
3905 {
3906 return pattr;
3907 }
3908 }
3909 }
3910
3911 return NULL;
3912 }
3913
3914 static const char *
3915 segment_name_format(const char *segment_name, const char *fmt)
3916 G_GNUC_FORMAT(2);
3917
3918 static const char *
segment_name_format(const char * segment_name,const char * fmt)3919 segment_name_format(const char *segment_name, const char *fmt)
3920 {
3921 wmem_strbuf_t *strbuf;
3922
3923 strbuf = wmem_strbuf_new(wmem_packet_scope(), segment_name);
3924 wmem_strbuf_append(strbuf, fmt);
3925 return wmem_strbuf_get_str(strbuf);
3926 }
3927
3928 static int
dissect_cia(tvbuff_t * tvb,int offset,unsigned char segment_type,gboolean generate,gboolean packed,packet_info * pinfo,proto_item * epath_item,proto_tree * path_tree,proto_item * path_item,proto_item ** ret_item,const char * segment_name,const value_string * vals,int * value,int hf8,int hf16,int hf32)3929 dissect_cia(tvbuff_t *tvb, int offset, unsigned char segment_type,
3930 gboolean generate, gboolean packed, packet_info *pinfo, proto_item *epath_item,
3931 proto_tree *path_tree, proto_item *path_item, proto_item ** ret_item,
3932 const char* segment_name, const value_string* vals, int* value,
3933 int hf8, int hf16, int hf32)
3934 {
3935 unsigned char logical_format;
3936 int segment_len;
3937 int temp_data;
3938 int value_offset;
3939 wmem_strbuf_t *strbuf;
3940 gboolean extended_logical = FALSE;
3941
3942 /* Extended Logical Format is slightly different than other logical formats. An extra byte is
3943 inserted after the segment type. */
3944 if ((segment_type & CI_LOGICAL_SEG_TYPE_MASK) == CI_LOGICAL_SEG_EXT_LOGICAL)
3945 {
3946 extended_logical = TRUE;
3947
3948 if (generate)
3949 {
3950 temp_data = tvb_get_guint8(tvb, offset + 1);
3951 *ret_item = proto_tree_add_uint(path_tree, hf_cip_ext_logical_type, tvb, 0, 0, temp_data);
3952 proto_item_set_generated(*ret_item);
3953 }
3954 else
3955 {
3956 *ret_item = proto_tree_add_item(path_tree, hf_cip_ext_logical_type, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
3957 }
3958 }
3959
3960 logical_format = segment_type & CI_LOGICAL_SEG_FORMAT_MASK;
3961 switch (logical_format)
3962 {
3963 case CI_LOGICAL_SEG_8_BIT:
3964 value_offset = offset + 1;
3965
3966 if (extended_logical == TRUE)
3967 {
3968 value_offset += 1;
3969 }
3970
3971 temp_data = tvb_get_guint8(tvb, value_offset);
3972
3973 if ( generate )
3974 {
3975 *ret_item = proto_tree_add_uint(path_tree, hf8, tvb, 0, 0, temp_data );
3976 proto_item_set_generated(*ret_item);
3977 }
3978 else
3979 {
3980 *ret_item = proto_tree_add_item(path_tree, hf8, tvb, value_offset, 1, ENC_LITTLE_ENDIAN);
3981 }
3982
3983 if (vals == NULL)
3984 {
3985 proto_item_append_text( epath_item, "%s: 0x%02X", segment_name, temp_data);
3986 }
3987 else
3988 {
3989 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, vals, segment_name_format( segment_name, ": 0x%02X" ) ) );
3990 }
3991
3992 if (value != NULL)
3993 *value = temp_data;
3994
3995 segment_len = 2;
3996 if (extended_logical == TRUE)
3997 {
3998 if (packed)
3999 {
4000 segment_len += 1;
4001 }
4002 else
4003 {
4004 segment_len += 2;
4005 }
4006 }
4007 break;
4008 case CI_LOGICAL_SEG_16_BIT:
4009 if (packed && extended_logical == FALSE)
4010 {
4011 value_offset = offset + 1;
4012 segment_len = 3;
4013 }
4014 else
4015 {
4016 value_offset = offset + 2;
4017 segment_len = 4;
4018 }
4019
4020 temp_data = tvb_get_letohs(tvb, value_offset);
4021
4022 if ( generate )
4023 {
4024 *ret_item = proto_tree_add_uint(path_tree, hf16, tvb, 0, 0, temp_data );
4025 proto_item_set_generated(*ret_item);
4026 }
4027 else
4028 {
4029 *ret_item = proto_tree_add_item(path_tree, hf16, tvb, value_offset, 2, ENC_LITTLE_ENDIAN);
4030 }
4031
4032 if (vals == NULL)
4033 {
4034 proto_item_append_text( epath_item, "%s: 0x%04X", segment_name, temp_data);
4035 }
4036 else
4037 {
4038 strbuf = wmem_strbuf_new(wmem_packet_scope(), segment_name);
4039 wmem_strbuf_append(strbuf, ": 0x%04X");
4040
4041 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, vals, segment_name_format( segment_name, ": 0x%04X" ) ) );
4042 }
4043
4044 if (value != NULL)
4045 *value = temp_data;
4046
4047 break;
4048 case CI_LOGICAL_SEG_32_BIT:
4049 if (packed && extended_logical == FALSE)
4050 {
4051 value_offset = offset + 1;
4052 segment_len = 5;
4053 }
4054 else
4055 {
4056 value_offset = offset + 2;
4057 segment_len = 6;
4058 }
4059 temp_data = tvb_get_letohl(tvb, value_offset);
4060
4061 if ( generate )
4062 {
4063 *ret_item = proto_tree_add_uint(path_tree, hf32, tvb, 0, 0, temp_data );
4064 proto_item_set_generated(*ret_item);
4065 }
4066 else
4067 {
4068 *ret_item = proto_tree_add_item(path_tree, hf32, tvb, value_offset, 4, ENC_LITTLE_ENDIAN);
4069 }
4070
4071 if (vals == NULL)
4072 {
4073 proto_item_append_text( epath_item, "%s: 0x%08X", segment_name, temp_data);
4074 }
4075 else
4076 {
4077 strbuf = wmem_strbuf_new(wmem_packet_scope(), segment_name);
4078 wmem_strbuf_append(strbuf, ": 0x%08X");
4079
4080 proto_item_append_text( epath_item, "%s", val_to_str( temp_data, vals, segment_name_format( segment_name, ": 0x%08X" ) ) );
4081 }
4082
4083 if (value != NULL)
4084 *value = temp_data;
4085
4086 break;
4087 default:
4088 expert_add_info(pinfo, epath_item, &ei_proto_log_seg_format);
4089 return 0;
4090 }
4091
4092 if (generate == FALSE)
4093 {
4094 proto_item_set_len(path_item, segment_len);
4095 }
4096
4097 return segment_len;
4098 }
4099
4100 /* Dissect Device ID structure */
4101 void
dissect_deviceid(tvbuff_t * tvb,int offset,proto_tree * tree,int hf_vendor,int hf_devtype,int hf_prodcode,int hf_compatibility,int hf_comp_bit,int hf_majrev,int hf_minrev,gboolean generate)4102 dissect_deviceid(tvbuff_t *tvb, int offset, proto_tree *tree,
4103 int hf_vendor, int hf_devtype, int hf_prodcode,
4104 int hf_compatibility, int hf_comp_bit, int hf_majrev, int hf_minrev,
4105 gboolean generate)
4106 {
4107 proto_item* vendor_id_item = proto_tree_add_item(tree, hf_vendor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
4108 proto_item* device_type_item = proto_tree_add_item(tree, hf_devtype, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
4109 proto_item* product_code_item = proto_tree_add_item(tree, hf_prodcode, tvb, offset + 4, 2, ENC_LITTLE_ENDIAN);
4110
4111 /* Major revision/Compatibility */
4112 guint8 compatibility = tvb_get_guint8(tvb, offset + 6);
4113
4114 /* Add Major revision/Compatibility tree */
4115 proto_item* compatibility_item = proto_tree_add_uint_format_value(tree, hf_compatibility,
4116 tvb, offset + 6, 1, compatibility, "%s, Major Revision: %d",
4117 val_to_str_const((compatibility & 0x80) >> 7, cip_com_bit_vals, ""),
4118 compatibility & 0x7F);
4119 proto_tree* compatibility_tree = proto_item_add_subtree(compatibility_item, ett_mcsc);
4120
4121 proto_item* comp_bit_item = proto_tree_add_item(compatibility_tree, hf_comp_bit, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
4122 proto_item* major_rev_item = proto_tree_add_item(compatibility_tree, hf_majrev, tvb, offset + 6, 1, ENC_LITTLE_ENDIAN);
4123 proto_item* minor_rev_item = proto_tree_add_item(tree, hf_minrev, tvb, offset + 7, 1, ENC_LITTLE_ENDIAN);
4124
4125 if (generate)
4126 {
4127 proto_item_set_generated(vendor_id_item);
4128 proto_item_set_generated(device_type_item);
4129 proto_item_set_generated(product_code_item);
4130 proto_item_set_generated(compatibility_item);
4131 proto_item_set_generated(comp_bit_item);
4132 proto_item_set_generated(major_rev_item);
4133 proto_item_set_generated(minor_rev_item);
4134 }
4135 }
4136
4137 static void
dissect_net_param16(tvbuff_t * tvb,int offset,proto_tree * tree,int hf_net_param16,int hf_owner,int hf_type,int hf_priority,int hf_fixed_var,int hf_con_size,gint ncp_ett,cip_connID_info_t * conn_info)4138 dissect_net_param16(tvbuff_t *tvb, int offset, proto_tree *tree,
4139 int hf_net_param16, int hf_owner, int hf_type,
4140 int hf_priority, int hf_fixed_var, int hf_con_size, gint ncp_ett, cip_connID_info_t* conn_info)
4141 {
4142 proto_item *net_param_item;
4143 proto_tree *net_param_tree;
4144
4145 net_param_item = proto_tree_add_item(tree, hf_net_param16, tvb, offset, 2, ENC_LITTLE_ENDIAN );
4146 net_param_tree = proto_item_add_subtree(net_param_item, ncp_ett);
4147
4148 /* Add the data to the tree */
4149 proto_tree_add_item(net_param_tree, hf_owner, tvb, offset, 2, ENC_LITTLE_ENDIAN );
4150 proto_tree_add_item_ret_uint(net_param_tree, hf_type, tvb, offset, 2, ENC_LITTLE_ENDIAN, &conn_info->type);
4151 proto_tree_add_item(net_param_tree, hf_priority, tvb, offset, 2, ENC_LITTLE_ENDIAN );
4152 proto_tree_add_item(net_param_tree, hf_fixed_var, tvb, offset, 2, ENC_LITTLE_ENDIAN );
4153 proto_tree_add_item(net_param_tree, hf_con_size, tvb, offset, 2, ENC_LITTLE_ENDIAN );
4154 }
4155
4156 static void
dissect_net_param32(tvbuff_t * tvb,int offset,proto_tree * tree,int hf_net_param16,int hf_owner,int hf_type,int hf_priority,int hf_fixed_var,int hf_con_size,gint ncp_ett,cip_connID_info_t * conn_info)4157 dissect_net_param32(tvbuff_t *tvb, int offset, proto_tree *tree,
4158 int hf_net_param16, int hf_owner, int hf_type,
4159 int hf_priority, int hf_fixed_var, int hf_con_size, gint ncp_ett, cip_connID_info_t* conn_info)
4160 {
4161 proto_item *net_param_item;
4162 proto_tree *net_param_tree;
4163
4164 net_param_item = proto_tree_add_item(tree, hf_net_param16, tvb, offset, 4, ENC_LITTLE_ENDIAN );
4165 net_param_tree = proto_item_add_subtree(net_param_item, ncp_ett);
4166
4167 /* Add the data to the tree */
4168 proto_tree_add_item(net_param_tree, hf_owner, tvb, offset, 4, ENC_LITTLE_ENDIAN );
4169 proto_tree_add_item_ret_uint(net_param_tree, hf_type, tvb, offset, 4, ENC_LITTLE_ENDIAN, &conn_info->type);
4170 proto_tree_add_item(net_param_tree, hf_priority, tvb, offset, 4, ENC_LITTLE_ENDIAN );
4171 proto_tree_add_item(net_param_tree, hf_fixed_var, tvb, offset, 4, ENC_LITTLE_ENDIAN );
4172 proto_tree_add_item(net_param_tree, hf_con_size, tvb, offset, 4, ENC_LITTLE_ENDIAN );
4173 }
4174
4175 static void
dissect_transport_type_trigger(tvbuff_t * tvb,int offset,proto_tree * tree,int hf_ttt,int hf_direction,int hf_trigger,int hf_class,gint ett)4176 dissect_transport_type_trigger(tvbuff_t *tvb, int offset, proto_tree *tree,
4177 int hf_ttt, int hf_direction, int hf_trigger, int hf_class, gint ett)
4178 {
4179 int* const bits[] = {
4180 &hf_direction,
4181 &hf_trigger,
4182 &hf_class,
4183 NULL
4184 };
4185
4186 proto_tree_add_bitmask(tree, tvb, offset, hf_ttt, ett, bits, ENC_LITTLE_ENDIAN);
4187 }
4188
dissect_segment_network_extended(packet_info * pinfo,proto_item * epath_item,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * net_tree)4189 static int dissect_segment_network_extended(packet_info *pinfo, proto_item *epath_item, tvbuff_t *tvb, int offset, gboolean generate, proto_tree *net_tree)
4190 {
4191 int data_words;
4192 data_words = tvb_get_guint8(tvb, offset + 1);
4193
4194 if (generate)
4195 {
4196 proto_item *it;
4197 guint16 temp_data;
4198
4199 it = proto_tree_add_uint(net_tree, hf_cip_seg_network_size, tvb, 0, 0, data_words);
4200 proto_item_set_generated(it);
4201
4202 temp_data = tvb_get_letohs(tvb, offset + 2);
4203 it = proto_tree_add_uint(net_tree, hf_cip_seg_network_subtype, tvb, 0, 0, temp_data);
4204 proto_item_set_generated(it);
4205 }
4206 else
4207 {
4208 proto_tree_add_item(net_tree, hf_cip_seg_network_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4209 proto_tree_add_item(net_tree, hf_cip_seg_network_subtype, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
4210 }
4211
4212 // Extended Network Subtype is included in the Number of Data words, so we must have at least 1.
4213 if (data_words < 1)
4214 {
4215 expert_add_info(pinfo, epath_item, &ei_proto_ext_network);
4216 return 0;
4217 }
4218
4219 if (generate == FALSE)
4220 {
4221 /* The first word of the data is the extended segment subtype, so
4222 don't include that in the displayed data block. */
4223 int net_seg_data_offset;
4224 int net_seg_data_len;
4225 net_seg_data_offset = offset + 4;
4226 net_seg_data_len = (data_words - 1) * 2;
4227
4228 if (tvb_reported_length_remaining(tvb, net_seg_data_offset) < net_seg_data_len)
4229 {
4230 expert_add_info(pinfo, epath_item, &ei_proto_ext_network);
4231 return 0;
4232 }
4233
4234 if (net_seg_data_len > 0)
4235 {
4236 proto_tree_add_item(net_tree, hf_cip_data, tvb, net_seg_data_offset, net_seg_data_len, ENC_NA);
4237 }
4238 }
4239
4240 return data_words * 2 + 2;
4241 }
4242
dissect_segment_network_production_inhibit_us(tvbuff_t * tvb,int offset,gboolean generate,proto_tree * net_tree)4243 static int dissect_segment_network_production_inhibit_us(tvbuff_t *tvb, int offset, gboolean generate, proto_tree *net_tree)
4244 {
4245 int data_words;
4246 guint32 inhibit_time;
4247
4248 data_words = tvb_get_guint8(tvb, offset + 1);
4249 inhibit_time = tvb_get_letohl(tvb, offset + 2);
4250
4251 if (generate == TRUE)
4252 {
4253 proto_item *it;
4254 it = proto_tree_add_uint(net_tree, hf_cip_seg_network_size, tvb, 0, 0, data_words);
4255 proto_item_set_generated(it);
4256
4257 it = proto_tree_add_uint(net_tree, hf_cip_seg_prod_inhibit_time_us, tvb, 0, 0, inhibit_time);
4258 proto_item_set_generated(it);
4259 }
4260 else
4261 {
4262 proto_tree_add_item(net_tree, hf_cip_seg_network_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4263 proto_tree_add_item(net_tree, hf_cip_seg_prod_inhibit_time_us,
4264 tvb, offset + 2, 4, ENC_LITTLE_ENDIAN);
4265 }
4266
4267 return (data_words * 2) + 2;
4268 }
4269
dissect_segment_symbolic(tvbuff_t * tvb,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item,int offset,gboolean generate)4270 static int dissect_segment_symbolic(tvbuff_t *tvb, proto_tree *path_seg_tree,
4271 proto_item *path_seg_item, proto_item *epath_item,
4272 int offset, gboolean generate)
4273 {
4274 int seg_size;
4275 proto_item *it;
4276 guint8 symbol_size;
4277
4278 symbol_size = tvb_get_guint8(tvb, offset) & 0x1F;
4279 if (generate)
4280 {
4281 it = proto_tree_add_uint(path_seg_tree, hf_cip_symbol_size, tvb, 0, 0, symbol_size);
4282 proto_item_set_generated(it);
4283 }
4284 else
4285 {
4286 proto_tree_add_item(path_seg_tree, hf_cip_symbol_size, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4287 }
4288
4289 if (symbol_size != 0)
4290 {
4291 gchar *symbol_name;
4292 symbol_name = tvb_format_text(wmem_packet_scope(), tvb, offset + 1, symbol_size);
4293
4294 proto_item_append_text(path_seg_item, " (Symbolic Segment)");
4295
4296 if (generate)
4297 {
4298 it = proto_tree_add_string(path_seg_tree, hf_cip_symbol_ascii, tvb, 0, 0, symbol_name);
4299 proto_item_set_generated(it);
4300 }
4301 else
4302 {
4303 proto_tree_add_item(path_seg_tree, hf_cip_symbol_ascii, tvb, offset + 1, symbol_size, ENC_ASCII | ENC_NA);
4304 }
4305
4306 proto_item_append_text(epath_item, "%s", symbol_name);
4307
4308 seg_size = symbol_size + 1;
4309 }
4310 else
4311 {
4312 /* Extended String */
4313 guint8 string_format;
4314 guint8 string_size;
4315 int data_size = 0;
4316
4317 proto_item_append_text(path_seg_item, " (Extended String Symbolic Segment)");
4318
4319 string_format = tvb_get_guint8(tvb, offset + 1) & CI_SYMBOL_SEG_FORMAT_MASK;
4320 string_size = tvb_get_guint8(tvb, offset + 1) & CI_SYMBOL_SEG_SIZE_MASK;
4321
4322 if (generate)
4323 {
4324 it = proto_tree_add_uint(path_seg_tree, hf_cip_symbol_extended_format, tvb, 0, 0, string_format);
4325 proto_item_set_generated(it);
4326 }
4327 else
4328 {
4329 proto_tree_add_item(path_seg_tree, hf_cip_symbol_extended_format, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4330 }
4331
4332 switch (string_format)
4333 {
4334 case CI_SYMBOL_SEG_DOUBLE:
4335 data_size = string_size * 2;
4336
4337 if (generate)
4338 {
4339 it = proto_tree_add_uint(path_seg_tree, hf_cip_symbol_double_size, tvb, 0, 0, string_size);
4340 proto_item_set_generated(it);
4341 }
4342 else
4343 {
4344 proto_tree_add_item(path_seg_tree, hf_cip_symbol_double_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4345 proto_tree_add_item(path_seg_tree, hf_cip_data, tvb, offset + 2, data_size, ENC_NA);
4346 }
4347
4348 proto_item_append_text(epath_item, "[Data]");
4349
4350 break;
4351 case CI_SYMBOL_SEG_TRIPLE:
4352 data_size = string_size * 3;
4353
4354 if (generate)
4355 {
4356 it = proto_tree_add_uint(path_seg_tree, hf_cip_symbol_triple_size, tvb, 0, 0, string_size);
4357 proto_item_set_generated(it);
4358 }
4359 else
4360 {
4361 proto_tree_add_item(path_seg_tree, hf_cip_symbol_triple_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4362 proto_tree_add_item(path_seg_tree, hf_cip_data, tvb, offset + 2, data_size, ENC_NA);
4363 }
4364
4365 proto_item_append_text(epath_item, "[Data]");
4366
4367 break;
4368 case CI_SYMBOL_SEG_NUMERIC:
4369 {
4370 guint32 numeric_data;
4371
4372 if (generate)
4373 {
4374 it = proto_tree_add_uint(path_seg_tree, hf_cip_symbol_numeric_format, tvb, 0, 0, string_size);
4375 proto_item_set_generated(it);
4376 }
4377 else
4378 {
4379 proto_tree_add_item(path_seg_tree, hf_cip_symbol_numeric_format, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4380 }
4381
4382 if (string_size == CI_SYMBOL_NUMERIC_USINT)
4383 {
4384 data_size = 1;
4385 numeric_data = tvb_get_guint8(tvb, offset + 2);
4386
4387 if (generate)
4388 {
4389 it = proto_tree_add_uint(path_seg_tree, hf_cip_numeric_usint, tvb, 0, 0, numeric_data);
4390 proto_item_set_generated(it);
4391 }
4392 else
4393 {
4394 proto_tree_add_item(path_seg_tree, hf_cip_numeric_usint, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN);
4395 }
4396 }
4397 else if (string_size == CI_SYMBOL_NUMERIC_UINT)
4398 {
4399 data_size = 2;
4400 numeric_data = tvb_get_letohs(tvb, offset + 2);
4401
4402 if (generate)
4403 {
4404 it = proto_tree_add_uint(path_seg_tree, hf_cip_numeric_uint, tvb, 0, 0, numeric_data);
4405 proto_item_set_generated(it);
4406 }
4407 else
4408 {
4409 proto_tree_add_item(path_seg_tree, hf_cip_numeric_uint, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
4410 }
4411 }
4412 else if (string_size == CI_SYMBOL_NUMERIC_UDINT)
4413 {
4414 data_size = 4;
4415 numeric_data = tvb_get_letohl(tvb, offset + 2);
4416
4417 if (generate)
4418 {
4419 it = proto_tree_add_uint(path_seg_tree, hf_cip_numeric_udint, tvb, 0, 0, numeric_data);
4420 proto_item_set_generated(it);
4421 }
4422 else
4423 {
4424 proto_tree_add_item(path_seg_tree, hf_cip_numeric_udint, tvb, offset + 2, 4, ENC_LITTLE_ENDIAN);
4425 }
4426 }
4427 else
4428 {
4429 /* Unknown Extended String Format. */
4430 return 0;
4431 }
4432
4433 proto_item_append_text(epath_item, "0x%x", numeric_data);
4434
4435 break;
4436 }
4437 default:
4438 /* Unknown Extended String Format. */
4439 return 0;
4440 }
4441
4442 seg_size = 2 + data_size;
4443 }
4444
4445 /* Add padding. */
4446 seg_size += seg_size % 2;
4447
4448 return seg_size;
4449 }
4450
dissect_segment_port(tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item)4451 static int dissect_segment_port(tvbuff_t* tvb, int offset, gboolean generate,
4452 proto_tree* path_seg_tree, proto_item* path_seg_item, proto_item* epath_item)
4453 {
4454 int segment_len = 0;
4455 gboolean extended_port = FALSE;
4456 int extended_port_offset = 0;
4457 guint8 segment_type = tvb_get_guint8(tvb, offset);
4458
4459 /* Add Extended Link Address flag & Port Identifier*/
4460 if (generate)
4461 {
4462 proto_item* it = proto_tree_add_boolean(path_seg_tree, hf_cip_port_ex_link_addr, tvb, 0, 0, segment_type & CI_PORT_SEG_EX_LINK_ADDRESS);
4463 proto_item_set_generated(it);
4464 it = proto_tree_add_uint(path_seg_tree, hf_cip_port, tvb, 0, 0, (segment_type & CI_PORT_SEG_PORT_ID_MASK));
4465 proto_item_set_generated(it);
4466 }
4467 else
4468 {
4469 proto_tree_add_item(path_seg_tree, hf_cip_port_ex_link_addr, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4470 proto_tree_add_item(path_seg_tree, hf_cip_port, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4471 }
4472
4473 guint8 port_id = segment_type & CI_PORT_SEG_PORT_ID_MASK;
4474 if (port_id == 0xF)
4475 {
4476 extended_port = TRUE;
4477 }
4478
4479 proto_item_append_text(path_seg_item, " (Port Segment)");
4480
4481 const gchar *port_name = try_val_to_str(port_id, cip_port_number_vals);
4482 if (port_name)
4483 {
4484 proto_item_append_text(epath_item, "Port: %s", port_name);
4485 }
4486 else
4487 {
4488 proto_item_append_text(epath_item, "Port: %d", port_id);
4489 }
4490
4491 if (segment_type & CI_PORT_SEG_EX_LINK_ADDRESS)
4492 {
4493 int offset_link_address = 2;
4494
4495 if (extended_port == TRUE)
4496 {
4497 offset_link_address += 2;
4498 extended_port_offset = offset + 2;
4499 }
4500
4501 guint8 opt_link_size = tvb_get_guint8(tvb, offset + 1);
4502
4503 if (generate)
4504 {
4505 /* Add size of extended link address */
4506 proto_item* it = proto_tree_add_uint(path_seg_item, hf_cip_link_address_size, tvb, 0, 0, opt_link_size);
4507 proto_item_set_generated(it);
4508 /* Add extended link address */
4509 it = proto_tree_add_string(path_seg_item, hf_cip_link_address_string, tvb, 0, 0, tvb_format_text(wmem_packet_scope(), tvb, offset + offset_link_address, opt_link_size));
4510 proto_item_set_generated(it);
4511 }
4512 else
4513 {
4514 proto_tree_add_item(path_seg_item, hf_cip_link_address_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4515 proto_tree_add_item(path_seg_item, hf_cip_link_address_string, tvb, offset + offset_link_address, opt_link_size, ENC_ASCII | ENC_NA);
4516 }
4517
4518 proto_item_append_text(epath_item, ", Address: %s", tvb_format_text(wmem_packet_scope(), tvb, offset + offset_link_address, opt_link_size));
4519
4520 /* Pad byte */
4521 if (opt_link_size % 2)
4522 {
4523 segment_len = 1 + offset_link_address + opt_link_size;
4524 }
4525 else
4526 {
4527 segment_len = offset_link_address + opt_link_size;
4528 }
4529 }
4530 else
4531 {
4532 int offset_link_address = 1;
4533
4534 segment_len = 2;
4535
4536 if (extended_port == TRUE)
4537 {
4538 segment_len += 2;
4539 offset_link_address += 2;
4540 extended_port_offset = offset + 1;
4541 }
4542
4543 /* Add Link Address */
4544 if (generate)
4545 {
4546 guint8 link_address_byte = tvb_get_guint8(tvb, offset + offset_link_address);
4547 proto_item* it = proto_tree_add_uint(path_seg_item, hf_cip_link_address_byte, tvb, 0, 0, link_address_byte);
4548 proto_item_set_generated(it);
4549 }
4550 else
4551 {
4552 proto_tree_add_item(path_seg_item, hf_cip_link_address_byte, tvb, offset + offset_link_address, 1, ENC_LITTLE_ENDIAN);
4553 }
4554
4555 proto_item_append_text(epath_item, ", Address: %d", tvb_get_guint8(tvb, offset + offset_link_address));
4556 }
4557
4558 if (extended_port == TRUE)
4559 {
4560 if (generate)
4561 {
4562 guint16 port_extended = tvb_get_letohs(tvb, extended_port_offset);
4563 proto_item* it = proto_tree_add_uint(path_seg_item, hf_cip_port_extended, tvb, 0, 0, port_extended);
4564 proto_item_set_generated(it);
4565 }
4566 else
4567 {
4568 proto_tree_add_item(path_seg_item, hf_cip_port_extended, tvb, extended_port_offset, 2, ENC_LITTLE_ENDIAN);
4569 }
4570 }
4571
4572 if (generate == FALSE)
4573 {
4574 proto_item_set_len(path_seg_item, segment_len);
4575 }
4576
4577 return segment_len;
4578 }
4579
dissect_segment_safety(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * net_tree,cip_safety_epath_info_t * safety)4580 static int dissect_segment_safety(packet_info* pinfo, tvbuff_t* tvb, int offset, gboolean generate,
4581 proto_tree* net_tree, cip_safety_epath_info_t* safety)
4582 {
4583 guint16 seg_size = tvb_get_guint8(tvb, offset + 1) * 2;
4584 int segment_len = seg_size + 2;
4585
4586 if (generate)
4587 {
4588 /* TODO: Skip printing information in response packets for now. Think of a better way to handle
4589 generated data that doesn't require a lot of copy-paste. */
4590 return segment_len;
4591 }
4592
4593 /* Segment size */
4594 proto_tree_add_item(net_tree, hf_cip_seg_network_size, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4595
4596 guint32 safety_format;
4597 proto_tree_add_item_ret_uint(net_tree, hf_cip_seg_safety_format, tvb, offset + 2, 1, ENC_LITTLE_ENDIAN, &safety_format);
4598
4599 /* Safety Network Segment Format */
4600 if (safety_format < 3)
4601 {
4602 cip_connID_info_t ignore;
4603 proto_tree* safety_tree = proto_tree_add_subtree(net_tree, tvb, offset + 3, seg_size - 1,
4604 ett_network_seg_safety, NULL, val_to_str_const(safety_format, cip_safety_segment_format_type_vals, "Reserved"));
4605 switch (safety_format)
4606 {
4607 case 0:
4608 {
4609 /* Target Format */
4610 if (safety != NULL)
4611 safety->format = CIP_SAFETY_BASE_FORMAT;
4612
4613 proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
4614 proto_tree_add_item(safety_tree, hf_cip_seg_safety_configuration_crc, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
4615 dissect_cipsafety_snn(safety_tree, tvb, pinfo, offset + 8,
4616 hf_cip_seg_safety_configuration_timestamp, hf_cip_seg_safety_configuration_date, hf_cip_seg_safety_configuration_time);
4617 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_epi, tvb, offset + 14, 4, ENC_LITTLE_ENDIAN);
4618 dissect_net_param16(tvb, offset + 18, safety_tree,
4619 hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
4620 hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
4621 hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
4622 ett_network_seg_safety_time_correction_net_params, &ignore);
4623 proto_item* it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_tunid, tvb, offset + 20, 10, ENC_NA);
4624 dissect_unid(tvb, pinfo, offset + 20, it, "Target UNID SNN", hf_cip_seg_safety_tunid_snn_timestamp,
4625 hf_cip_seg_safety_tunid_snn_date, hf_cip_seg_safety_tunid_snn_time, hf_cip_seg_safety_tunid_nodeid,
4626 ett_cip_seg_safety_tunid, ett_cip_seg_safety_tunid_snn);
4627 it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_ounid, tvb, offset + 30, 10, ENC_NA);
4628 dissect_unid(tvb, pinfo, offset + 30, it, "Originator UNID SNN", hf_cip_seg_safety_ounid_snn_timestamp,
4629 hf_cip_seg_safety_ounid_snn_date, hf_cip_seg_safety_ounid_snn_time, hf_cip_seg_safety_ounid_nodeid,
4630 ett_cip_seg_safety_ounid, ett_cip_seg_safety_ounid_snn);
4631 proto_tree_add_item(safety_tree, hf_cip_seg_safety_ping_eri_multiplier, tvb, offset + 40, 2, ENC_LITTLE_ENDIAN);
4632 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_coord_msg_min_multiplier, tvb, offset + 42, 2, ENC_LITTLE_ENDIAN);
4633 proto_tree_add_item(safety_tree, hf_cip_seg_safety_network_time_expected_multiplier, tvb, offset + 44, 2, ENC_LITTLE_ENDIAN);
4634 proto_tree_add_item(safety_tree, hf_cip_seg_safety_timeout_multiplier, tvb, offset + 46, 1, ENC_LITTLE_ENDIAN);
4635 proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_consumer_number, tvb, offset + 47, 1, ENC_LITTLE_ENDIAN);
4636 proto_tree_add_item(safety_tree, hf_cip_seg_safety_conn_param_crc, tvb, offset + 48, 4, ENC_LITTLE_ENDIAN);
4637 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset + 52, 4, ENC_LITTLE_ENDIAN);
4638 break;
4639 }
4640 case 1:
4641 /* Router Format */
4642 if (safety != NULL)
4643 safety->format = CIP_SAFETY_BASE_FORMAT;
4644
4645 proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
4646 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
4647 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_epi, tvb, offset + 8, 4, ENC_LITTLE_ENDIAN);
4648 dissect_net_param16(tvb, offset + 12, safety_tree,
4649 hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
4650 hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
4651 hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
4652 ett_network_seg_safety_time_correction_net_params, &ignore);
4653 break;
4654 case 2:
4655 {
4656 /* Extended Format */
4657 if (safety != NULL)
4658 safety->format = CIP_SAFETY_EXTENDED_FORMAT;
4659
4660 proto_tree_add_item(safety_tree, hf_cip_seg_safety_reserved, tvb, offset + 3, 1, ENC_LITTLE_ENDIAN);
4661 proto_tree_add_item(safety_tree, hf_cip_seg_safety_configuration_crc, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
4662 dissect_cipsafety_snn(safety_tree, tvb, pinfo, offset + 8,
4663 hf_cip_seg_safety_configuration_timestamp, hf_cip_seg_safety_configuration_date, hf_cip_seg_safety_configuration_time);
4664 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_epi, tvb, offset + 14, 4, ENC_LITTLE_ENDIAN);
4665 dissect_net_param16(tvb, offset + 18, safety_tree,
4666 hf_cip_seg_safety_time_correction_net_params, hf_cip_seg_safety_time_correction_own,
4667 hf_cip_seg_safety_time_correction_typ, hf_cip_seg_safety_time_correction_prio,
4668 hf_cip_seg_safety_time_correction_fixed_var, hf_cip_seg_safety_time_correction_con_size,
4669 ett_network_seg_safety_time_correction_net_params, &ignore);
4670 proto_item* it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_tunid, tvb, offset + 20, 10, ENC_NA);
4671 dissect_unid(tvb, pinfo, offset + 20, it, "Target UNID SNN", hf_cip_seg_safety_tunid_snn_timestamp,
4672 hf_cip_seg_safety_tunid_snn_date, hf_cip_seg_safety_tunid_snn_time, hf_cip_seg_safety_tunid_nodeid,
4673 ett_cip_seg_safety_tunid, ett_cip_seg_safety_tunid_snn);
4674 it = proto_tree_add_item(safety_tree, hf_cip_seg_safety_ounid, tvb, offset + 30, 10, ENC_NA);
4675 dissect_unid(tvb, pinfo, offset + 30, it, "Originator UNID SNN", hf_cip_seg_safety_ounid_snn_timestamp,
4676 hf_cip_seg_safety_ounid_snn_date, hf_cip_seg_safety_ounid_snn_time, hf_cip_seg_safety_ounid_nodeid,
4677 ett_cip_seg_safety_ounid, ett_cip_seg_safety_ounid_snn);
4678 proto_tree_add_item(safety_tree, hf_cip_seg_safety_ping_eri_multiplier, tvb, offset + 40, 2, ENC_LITTLE_ENDIAN);
4679 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_coord_msg_min_multiplier, tvb, offset + 42, 2, ENC_LITTLE_ENDIAN);
4680 proto_tree_add_item(safety_tree, hf_cip_seg_safety_network_time_expected_multiplier, tvb, offset + 44, 2, ENC_LITTLE_ENDIAN);
4681 proto_tree_add_item(safety_tree, hf_cip_seg_safety_timeout_multiplier, tvb, offset + 46, 1, ENC_LITTLE_ENDIAN);
4682 proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_consumer_number, tvb, offset + 47, 1, ENC_LITTLE_ENDIAN);
4683 proto_tree_add_item(safety_tree, hf_cip_seg_safety_max_fault_number, tvb, offset + 48, 2, ENC_LITTLE_ENDIAN);
4684 proto_tree_add_item(safety_tree, hf_cip_seg_safety_conn_param_crc, tvb, offset + 50, 4, ENC_LITTLE_ENDIAN);
4685 proto_tree_add_item(safety_tree, hf_cip_seg_safety_time_correction_conn_id, tvb, offset + 54, 4, ENC_LITTLE_ENDIAN);
4686 proto_tree_add_item(safety_tree, hf_cip_seg_safety_init_timestamp, tvb, offset + 58, 2, ENC_LITTLE_ENDIAN);
4687 proto_tree_add_item(safety_tree, hf_cip_seg_safety_init_rollover, tvb, offset + 60, 2, ENC_LITTLE_ENDIAN);
4688 break;
4689 }
4690 } // END switch
4691 }
4692 else
4693 {
4694 proto_tree_add_item(net_tree, hf_cip_seg_safety_data, tvb, offset + 3, seg_size - 1, ENC_NA);
4695 }
4696
4697 if (safety != NULL)
4698 {
4699 safety->safety_seg = TRUE;
4700 }
4701
4702 return segment_len;
4703 }
4704
dissect_segment_data_simple(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,cip_simple_request_info_t * req_data)4705 static int dissect_segment_data_simple(packet_info* pinfo, tvbuff_t* tvb, int offset, gboolean generate,
4706 proto_tree* path_seg_tree, proto_item* path_seg_item, cip_simple_request_info_t* req_data)
4707 {
4708 guint16 seg_size = tvb_get_guint8(tvb, offset + 1) * 2;
4709 int segment_len = seg_size + 2;
4710
4711 if (generate)
4712 {
4713 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_data_seg_size_simple, tvb, 0, 0, seg_size / 2);
4714 proto_item_set_generated(it);
4715 }
4716 else
4717 {
4718 proto_tree_add_item(path_seg_tree, hf_cip_data_seg_size_simple, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4719 }
4720
4721 if (generate)
4722 {
4723 return segment_len;
4724 }
4725
4726 /* Segment data */
4727 if (seg_size != 0)
4728 {
4729 int parsed_data_len = 0;
4730 if (req_data && req_data->iClass == CI_CLS_MOTION
4731 && req_data->iConnPointA != SEGMENT_VALUE_NOT_SET
4732 && req_data->iConnPoint != SEGMENT_VALUE_NOT_SET)
4733 {
4734 parsed_data_len += dissect_motion_configuration_block(tvb, pinfo, path_seg_tree, path_seg_item, offset + 2);
4735 }
4736
4737 int remaining_data_len = seg_size - parsed_data_len;
4738 if (remaining_data_len > 0)
4739 {
4740 proto_tree_add_item(path_seg_tree, hf_cip_data_seg_item, tvb, offset + 2 + parsed_data_len, remaining_data_len, ENC_NA);
4741 }
4742 }
4743
4744 proto_item_set_len(path_seg_item, segment_len);
4745
4746 return segment_len;
4747 }
4748
dissect_segment_ansi_extended_symbol(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item,int display_type,gboolean is_msp_item,proto_item * msp_item)4749 static int dissect_segment_ansi_extended_symbol(packet_info* pinfo, tvbuff_t* tvb, int offset,
4750 gboolean generate, proto_tree* path_seg_tree, proto_item* path_seg_item,
4751 proto_item* epath_item, int display_type,
4752 gboolean is_msp_item, proto_item* msp_item)
4753 {
4754 /* Segment size */
4755 guint16 seg_size = tvb_get_guint8(tvb, offset + 1);
4756 if (generate)
4757 {
4758 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_data_seg_size_extended, tvb, 0, 0, seg_size);
4759 proto_item_set_generated(it);
4760 }
4761 else
4762 proto_tree_add_item(path_seg_tree, hf_cip_data_seg_size_extended, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4763
4764 /* Segment data */
4765 if (seg_size != 0)
4766 {
4767 gchar* symbol_name = tvb_format_text(pinfo->pool, tvb, offset + 2, seg_size);
4768
4769 if (generate)
4770 {
4771 proto_item* it = proto_tree_add_string(path_seg_tree, hf_cip_symbol, tvb, 0, 0, symbol_name);
4772 proto_item_set_generated(it);
4773 }
4774 else
4775 proto_tree_add_item(path_seg_tree, hf_cip_symbol, tvb, offset + 2, seg_size, ENC_ASCII | ENC_NA);
4776
4777 proto_item_append_text(epath_item, "%s", symbol_name);
4778
4779 if (cip_enhanced_info_column == TRUE && is_msp_item == FALSE)
4780 {
4781 add_cip_symbol_to_info_column(pinfo, symbol_name, display_type);
4782 }
4783
4784 if (msp_item != NULL)
4785 {
4786 proto_item_append_text(msp_item, "'%s' - ", symbol_name);
4787 }
4788 }
4789
4790 /* Check for pad byte */
4791 if (seg_size % 2)
4792 seg_size++;
4793
4794 if (!generate)
4795 {
4796 proto_item_set_len(path_seg_item, 2 + seg_size);
4797 }
4798
4799 return 2 + seg_size;
4800 }
4801
dissect_segment_logical_special(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item)4802 static int dissect_segment_logical_special(packet_info* pinfo, tvbuff_t* tvb, int offset,
4803 gboolean generate, proto_tree* path_seg_tree,
4804 proto_item* path_seg_item, proto_item* epath_item)
4805 {
4806 int segment_len = 0;
4807
4808 guint8 segment_type = tvb_get_guint8(tvb, offset);
4809
4810 /* Logical Special ID, the only logical format specified is electronic key */
4811 if ((segment_type & CI_LOGICAL_SEG_FORMAT_MASK) == CI_LOGICAL_SEG_E_KEY)
4812 {
4813 guint8 key_format = tvb_get_guint8(tvb, offset + 1);
4814 if (key_format == CI_E_KEY_FORMAT_VAL || key_format == CI_E_SERIAL_NUMBER_KEY_FORMAT_VAL)
4815 {
4816 if (key_format == CI_E_KEY_FORMAT_VAL)
4817 {
4818 segment_len = 10;
4819 }
4820 else // CI_E_SERIAL_NUMBER_KEY_FORMAT_VAL
4821 {
4822 segment_len = 14;
4823 }
4824
4825 if (generate)
4826 {
4827 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_ekey_format, tvb, 0, 0, key_format);
4828 proto_item_set_generated(it);
4829
4830 dissect_deviceid(tvb, offset + 2, path_seg_tree,
4831 hf_cip_ekey_vendor, hf_cip_ekey_devtype, hf_cip_ekey_prodcode,
4832 hf_cip_ekey_compatibility, hf_cip_ekey_comp_bit, hf_cip_ekey_majorrev, hf_cip_ekey_minorrev, TRUE);
4833 }
4834 else
4835 {
4836 proto_tree_add_item(path_seg_tree, hf_cip_ekey_format, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4837
4838 /* dissect the device ID */
4839 dissect_deviceid(tvb, offset + 2, path_seg_tree,
4840 hf_cip_ekey_vendor, hf_cip_ekey_devtype, hf_cip_ekey_prodcode,
4841 hf_cip_ekey_compatibility, hf_cip_ekey_comp_bit, hf_cip_ekey_majorrev, hf_cip_ekey_minorrev, FALSE);
4842
4843 if (key_format == CI_E_SERIAL_NUMBER_KEY_FORMAT_VAL)
4844 {
4845 proto_tree_add_item(path_seg_tree, hf_cip_ekey_serial_number, tvb, offset + 12, 4, ENC_LITTLE_ENDIAN);
4846 }
4847
4848 proto_item_set_len(path_seg_item, segment_len);
4849 }
4850
4851 /* Add "summary" information to parent item */
4852 guint16 vendor_id = tvb_get_letohs(tvb, offset + 2);
4853 proto_item_append_text(path_seg_tree, " (VendorID: 0x%04X", vendor_id);
4854
4855 guint16 device_type = tvb_get_letohs(tvb, offset + 4);
4856 proto_item_append_text(path_seg_tree, ", DevTyp: 0x%04X", device_type);
4857
4858 guint8 major_rev = tvb_get_guint8(tvb, offset + 8);
4859 guint8 minor_rev = tvb_get_guint8(tvb, offset + 9);
4860
4861 proto_item_append_text(path_seg_tree, ", %d.%d)", (major_rev & 0x7F), minor_rev);
4862 proto_item_append_text(epath_item, "[Key]");
4863 }
4864 else
4865 {
4866 expert_add_info(pinfo, epath_item, &ei_proto_electronic_key_format);
4867 }
4868 }
4869 else
4870 {
4871 expert_add_info(pinfo, epath_item, &ei_proto_special_segment_format);
4872 }
4873
4874 return segment_len;
4875 }
4876
dissect_segment_network(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item,int display_type,cip_safety_epath_info_t * safety)4877 static int dissect_segment_network(packet_info* pinfo, tvbuff_t* tvb, int offset,
4878 gboolean generate, proto_tree* path_seg_tree, proto_item* path_seg_item,
4879 proto_item* epath_item, int display_type, cip_safety_epath_info_t* safety)
4880 {
4881 int segment_len = 0;
4882
4883 guint8 segment_type = tvb_get_guint8(tvb, offset);
4884
4885 /* Network segment -Determine the segment sub-type */
4886 if (generate)
4887 {
4888 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_network_seg_type, tvb, 0, 0, segment_type & CI_NETWORK_SEG_TYPE_MASK);
4889 proto_item_set_generated(it);
4890 }
4891 else
4892 {
4893 proto_tree_add_item(path_seg_tree, hf_cip_network_seg_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
4894 }
4895
4896 proto_item_append_text(path_seg_item, " (%s)", val_to_str_const((segment_type & CI_NETWORK_SEG_TYPE_MASK), cip_network_segment_type_vals, "Reserved"));
4897
4898 switch (segment_type & CI_NETWORK_SEG_TYPE_MASK)
4899 {
4900 case CI_NETWORK_SEG_SCHEDULE:
4901 if (generate)
4902 {
4903 guint8 schedule = tvb_get_guint8(tvb, offset + 1);
4904 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_seg_schedule, tvb, 0, 0, schedule);
4905 proto_item_set_generated(it);
4906 }
4907 else
4908 {
4909 proto_tree_add_item(path_seg_tree, hf_cip_seg_schedule, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4910 }
4911
4912 segment_len = 2;
4913 break;
4914
4915 case CI_NETWORK_SEG_FIXED_TAG:
4916 if (generate)
4917 {
4918 guint8 fixed_tag = tvb_get_guint8(tvb, offset + 1);
4919 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_seg_fixed_tag, tvb, 0, 0, fixed_tag);
4920 proto_item_set_generated(it);
4921 }
4922 else
4923 {
4924 proto_tree_add_item(path_seg_tree, hf_cip_seg_fixed_tag, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4925 }
4926
4927 segment_len = 2;
4928 break;
4929
4930 case CI_NETWORK_SEG_PROD_INHI:
4931 if (generate)
4932 {
4933 guint8 inhibit_time = tvb_get_guint8(tvb, offset + 1);
4934 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_seg_prod_inhibit_time, tvb, 0, 0, inhibit_time);
4935 proto_item_set_generated(it);
4936 }
4937 else
4938 {
4939 proto_tree_add_item(path_seg_tree, hf_cip_seg_prod_inhibit_time, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4940 }
4941
4942 segment_len = 2;
4943 break;
4944
4945 case CI_NETWORK_SEG_PROD_INHI_US:
4946 segment_len = dissect_segment_network_production_inhibit_us(tvb, offset, generate, path_seg_tree);
4947 break;
4948
4949 case CI_NETWORK_SEG_EXTENDED:
4950 segment_len = dissect_segment_network_extended(pinfo, epath_item, tvb, offset, generate, path_seg_tree);
4951 proto_item_append_text(epath_item, "[Network]");
4952 break;
4953
4954 case CI_NETWORK_SEG_SAFETY:
4955 proto_item_append_text(epath_item, "[Safety]");
4956
4957 if (display_type == DISPLAY_CONNECTION_PATH)
4958 {
4959 col_append_str(pinfo->cinfo, COL_INFO, " [Safety]");
4960 }
4961
4962 segment_len = dissect_segment_safety(pinfo, tvb, offset, generate, path_seg_tree, safety);
4963 break;
4964
4965 default:
4966 expert_add_info(pinfo, epath_item, &ei_proto_log_sub_seg_type);
4967 segment_len = 0;
4968 break;
4969 } /* End of switch sub-type */
4970
4971 if (generate == FALSE)
4972 {
4973 proto_item_set_len(path_seg_item, segment_len);
4974 }
4975
4976 return segment_len;
4977 }
4978
dissect_segment_logical_service_id(packet_info * pinfo,tvbuff_t * tvb,int offset,gboolean generate,proto_tree * path_seg_tree,proto_item * path_seg_item,proto_item * epath_item)4979 static int dissect_segment_logical_service_id(packet_info* pinfo, tvbuff_t* tvb, int offset,
4980 gboolean generate, proto_tree* path_seg_tree, proto_item* path_seg_item, proto_item* epath_item)
4981 {
4982 int segment_len = 0;
4983
4984 guint8 segment_type = tvb_get_guint8(tvb, offset);
4985
4986 /* Logical Service ID - the only logical format specified is 8-bit Service ID */
4987 if ((segment_type & CI_LOGICAL_SEG_FORMAT_MASK) == CI_LOGICAL_SEG_8_BIT)
4988 {
4989 guint8 service_id = tvb_get_guint8(tvb, offset + 1);
4990
4991 if (generate)
4992 {
4993 proto_item* it = proto_tree_add_uint(path_seg_tree, hf_cip_serviceid8, tvb, 0, 0, service_id);
4994 proto_item_set_generated(it);
4995 }
4996 else
4997 {
4998 proto_tree_add_item(path_seg_tree, hf_cip_serviceid8, tvb, offset + 1, 1, ENC_LITTLE_ENDIAN);
4999
5000 proto_item_set_len(path_seg_item, 2);
5001 }
5002
5003 proto_item_append_text(epath_item, "Service ID: 0x%x", service_id);
5004
5005 segment_len = 2;
5006 }
5007 else
5008 {
5009 expert_add_info(pinfo, epath_item, &ei_proto_log_seg_type);
5010 }
5011
5012 return segment_len;
5013 }
5014
dissect_cip_segment_single(packet_info * pinfo,tvbuff_t * tvb,int offset,proto_tree * path_tree,proto_item * epath_item,gboolean generate,gboolean packed,cip_simple_request_info_t * req_data,cip_safety_epath_info_t * safety,int display_type,proto_item * msp_item,gboolean is_msp_item)5015 int dissect_cip_segment_single(packet_info *pinfo, tvbuff_t *tvb, int offset, proto_tree *path_tree, proto_item *epath_item,
5016 gboolean generate, gboolean packed, cip_simple_request_info_t* req_data, cip_safety_epath_info_t* safety,
5017 int display_type, proto_item *msp_item,
5018 gboolean is_msp_item)
5019 {
5020 int segment_len = 0;
5021 unsigned char segment_type;
5022 proto_tree *path_seg_tree;
5023 proto_item *it, *cia_ret_item;
5024 proto_item *path_seg_item;
5025
5026 {
5027 if (tvb_reported_length_remaining(tvb, offset) <= 0)
5028 {
5029 expert_add_info(pinfo, epath_item, &ei_mal_incomplete_epath);
5030 return 0;
5031 }
5032
5033 /* Get segment type */
5034 segment_type = tvb_get_guint8( tvb, offset );
5035
5036 if ( generate )
5037 {
5038 path_seg_item = proto_tree_add_uint(path_tree, hf_cip_path_segment, tvb, 0, 0, segment_type );
5039 proto_item_set_generated(path_seg_item);
5040 path_seg_tree = proto_item_add_subtree( path_seg_item, ett_path_seg );
5041 it = proto_tree_add_uint(path_seg_tree, hf_cip_path_segment_type, tvb, 0, 0, segment_type&CI_SEGMENT_TYPE_MASK);
5042 proto_item_set_generated(it);
5043 }
5044 else
5045 {
5046 path_seg_item = proto_tree_add_item(path_tree, hf_cip_path_segment, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5047 path_seg_tree = proto_item_add_subtree( path_seg_item, ett_path_seg );
5048 proto_tree_add_item(path_seg_tree, hf_cip_path_segment_type, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5049 }
5050
5051 /* Determine the segment type */
5052
5053 switch( segment_type & CI_SEGMENT_TYPE_MASK )
5054 {
5055 case CI_PORT_SEGMENT:
5056 {
5057 segment_len = dissect_segment_port(tvb, offset, generate, path_seg_tree, path_seg_item, epath_item);
5058 break;
5059 }
5060
5061 case CI_LOGICAL_SEGMENT:
5062 {
5063 guint8 logical_seg_type;
5064 logical_seg_type = segment_type & CI_LOGICAL_SEG_TYPE_MASK;
5065
5066 /* Logical segment, determine the logical type */
5067 if ( generate )
5068 {
5069 it = proto_tree_add_uint(path_seg_tree, hf_cip_logical_seg_type, tvb, 0, 0, logical_seg_type);
5070 proto_item_set_generated(it);
5071 if (logical_seg_type != CI_LOGICAL_SEG_SPECIAL && logical_seg_type != CI_LOGICAL_SEG_SERV_ID)
5072 {
5073 it = proto_tree_add_uint(path_seg_tree, hf_cip_logical_seg_format, tvb, 0, 0, segment_type & CI_LOGICAL_SEG_FORMAT_MASK);
5074 proto_item_set_generated(it);
5075 }
5076 }
5077 else
5078 {
5079 proto_tree_add_item(path_seg_tree, hf_cip_logical_seg_type, tvb, offset, 1, ENC_LITTLE_ENDIAN );
5080 if (logical_seg_type != CI_LOGICAL_SEG_SPECIAL && logical_seg_type != CI_LOGICAL_SEG_SERV_ID)
5081 proto_tree_add_item(path_seg_tree, hf_cip_logical_seg_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5082 }
5083
5084 proto_item_append_text( path_seg_item, " (%s)", val_to_str_const( ((segment_type & (CI_LOGICAL_SEG_TYPE_MASK|CI_LOGICAL_SEG_FORMAT_MASK))), cip_logical_seg_vals, "Reserved"));
5085
5086 switch (logical_seg_type)
5087 {
5088 case CI_LOGICAL_SEG_CLASS_ID:
5089 {
5090 guint32 ClassID;
5091 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5092 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5093 "Class", cip_class_names_vals, &ClassID,
5094 hf_cip_class8, hf_cip_class16, hf_cip_class32);
5095 if (segment_len == 0)
5096 {
5097 return 0;
5098 }
5099
5100 if (req_data)
5101 {
5102 req_data->iClass = ClassID;
5103
5104 // Save the first ClassID separately.
5105 if (req_data->iClassA == SEGMENT_VALUE_NOT_SET)
5106 {
5107 req_data->iClassA = ClassID;
5108 }
5109 }
5110
5111 if (req_data != NULL)
5112 {
5113 if (cip_enhanced_info_column == TRUE && is_msp_item == FALSE)
5114 {
5115 add_cip_class_to_info_column(pinfo, req_data->iClass, display_type);
5116 }
5117
5118 if (msp_item != NULL)
5119 {
5120 proto_item_append_text(msp_item, "%s - ", val_to_str(req_data->iClass, cip_class_names_vals, "Class (0x%02x)"));
5121 }
5122 }
5123
5124 break;
5125 }
5126
5127 case CI_LOGICAL_SEG_INST_ID:
5128 {
5129 guint32 InstanceID;
5130 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5131 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5132 "Instance", NULL, &InstanceID,
5133 hf_cip_instance8, hf_cip_instance16, hf_cip_instance32);
5134 if (segment_len == 0)
5135 {
5136 return 0;
5137 }
5138
5139 if (req_data)
5140 {
5141 req_data->iInstance = InstanceID;
5142
5143 // Save the first InstanceID separately.
5144 if (req_data->iInstanceA == SEGMENT_VALUE_NOT_SET)
5145 {
5146 req_data->iInstanceA = InstanceID;
5147 }
5148 }
5149
5150 break;
5151 }
5152
5153 case CI_LOGICAL_SEG_MBR_ID:
5154 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5155 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5156 "Member", NULL, (req_data == NULL) ? NULL : &req_data->iMember,
5157 hf_cip_member8, hf_cip_member16, hf_cip_member32);
5158 break;
5159
5160 case CI_LOGICAL_SEG_ATTR_ID:
5161 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5162 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5163 "Attribute", NULL, (req_data == NULL) ? NULL : &req_data->iAttribute,
5164 hf_cip_attribute8, hf_cip_attribute16, hf_cip_attribute32);
5165 if (segment_len == 0)
5166 {
5167 return 0;
5168 }
5169
5170 if (req_data != NULL)
5171 {
5172 attribute_info_t* att_info = cip_get_attribute(req_data->iClass, req_data->iInstance,
5173 req_data->iAttribute);
5174 if (att_info != NULL)
5175 {
5176 proto_item_append_text(cia_ret_item, " (%s)", att_info->text);
5177 proto_item_append_text(epath_item, " (%s)", att_info->text);
5178 }
5179 }
5180 break;
5181
5182 case CI_LOGICAL_SEG_CON_POINT:
5183 {
5184 guint32 ConnPoint;
5185 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5186 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5187 "Connection Point", NULL, &ConnPoint,
5188 hf_cip_conpoint8, hf_cip_conpoint16, hf_cip_conpoint32);
5189 if (segment_len == 0)
5190 {
5191 return 0;
5192 }
5193
5194 if (req_data)
5195 {
5196 req_data->iConnPoint = ConnPoint;
5197
5198 // Save the first ConnPoint separately.
5199 if (req_data->iConnPointA == SEGMENT_VALUE_NOT_SET)
5200 {
5201 req_data->iConnPointA = ConnPoint;
5202 }
5203 }
5204
5205 break;
5206 }
5207
5208 case CI_LOGICAL_SEG_SPECIAL:
5209 segment_len = dissect_segment_logical_special(pinfo, tvb, offset, generate,
5210 path_seg_tree, path_seg_item, epath_item);
5211 break;
5212
5213 case CI_LOGICAL_SEG_SERV_ID:
5214 segment_len = dissect_segment_logical_service_id(pinfo, tvb, offset, generate,
5215 path_seg_tree, path_seg_item, epath_item);
5216 break;
5217
5218 case CI_LOGICAL_SEG_EXT_LOGICAL:
5219 segment_len = dissect_cia(tvb, offset, segment_type, generate, packed, pinfo,
5220 epath_item, path_seg_tree, path_seg_item, &cia_ret_item,
5221 "Extended Logical", NULL, NULL,
5222 hf_cip_ext_logical8, hf_cip_ext_logical16, hf_cip_ext_logical32);
5223 break;
5224
5225 default:
5226 expert_add_info(pinfo, epath_item, &ei_proto_log_seg_type);
5227 return 0;
5228
5229 } /* end of switch( logical_seg_type ) */
5230 break;
5231 }
5232
5233 case CI_DATA_SEGMENT:
5234 {
5235 /* Data segment, determine the logical type */
5236 if ( generate )
5237 {
5238 it = proto_tree_add_uint(path_seg_tree, hf_cip_data_seg_type, tvb, 0, 0, segment_type & CI_DATA_SEG_TYPE_MASK);
5239 proto_item_set_generated(it);
5240 }
5241 else
5242 {
5243 proto_tree_add_item(path_seg_tree, hf_cip_data_seg_type, tvb, offset, 1, ENC_LITTLE_ENDIAN );
5244 }
5245
5246 proto_item_append_text( path_seg_item, " (%s)", val_to_str_const( (segment_type & CI_DATA_SEG_TYPE_MASK), cip_data_segment_type_vals, "Reserved"));
5247
5248 switch( segment_type & CI_DATA_SEG_TYPE_MASK)
5249 {
5250 case CI_DATA_SEG_SIMPLE:
5251 segment_len = dissect_segment_data_simple(pinfo, tvb, offset, generate, path_seg_tree, path_seg_item, req_data);
5252 proto_item_append_text(epath_item, "[Data]" );
5253 break;
5254
5255 case CI_DATA_SEG_SYMBOL:
5256 segment_len = dissect_segment_ansi_extended_symbol(pinfo, tvb, offset, generate,
5257 path_seg_tree, path_seg_item, epath_item, display_type, is_msp_item, msp_item);
5258 break;
5259
5260 default:
5261 expert_add_info(pinfo, epath_item, &ei_proto_log_sub_seg_type);
5262 return 0;
5263
5264 } /* End of switch sub-type */
5265
5266 break;
5267 }
5268
5269 case CI_NETWORK_SEGMENT:
5270 segment_len = dissect_segment_network(pinfo, tvb, offset, generate, path_seg_tree, path_seg_item, epath_item, display_type, safety);
5271 break;
5272
5273 case CI_SYMBOLIC_SEGMENT:
5274 {
5275 segment_len = dissect_segment_symbolic(tvb, path_seg_tree,
5276 path_seg_item, epath_item,
5277 offset, generate);
5278
5279 if (segment_len == 0)
5280 {
5281 expert_add_info(pinfo, epath_item, &ei_proto_ext_string_format);
5282 return 0;
5283 }
5284
5285 if (generate == FALSE)
5286 {
5287 proto_item_set_len(path_seg_item, segment_len);
5288 }
5289
5290 break;
5291 }
5292
5293 default:
5294 expert_add_info(pinfo, epath_item, &ei_proto_seg_type);
5295 return 0;
5296
5297 } /* end of switch( segment_type & CI_SEGMENT_TYPE_MASK ) */
5298 }
5299
5300 return segment_len;
5301 }
5302
reset_cip_request_info(cip_simple_request_info_t * req_data)5303 void reset_cip_request_info(cip_simple_request_info_t* req_data)
5304 {
5305 req_data->iClass = SEGMENT_VALUE_NOT_SET;
5306 req_data->iClassA = SEGMENT_VALUE_NOT_SET;
5307
5308 req_data->iInstance = SEGMENT_VALUE_NOT_SET;
5309 req_data->iInstanceA = SEGMENT_VALUE_NOT_SET;
5310
5311 req_data->iAttribute = SEGMENT_VALUE_NOT_SET;
5312 req_data->iMember = SEGMENT_VALUE_NOT_SET;
5313
5314 req_data->iConnPoint = SEGMENT_VALUE_NOT_SET;
5315 req_data->iConnPointA = SEGMENT_VALUE_NOT_SET;
5316 }
5317
dissect_epath(tvbuff_t * tvb,packet_info * pinfo,proto_tree * path_tree,proto_item * epath_item,int offset,int path_length,gboolean generate,gboolean packed,cip_simple_request_info_t * req_data,cip_safety_epath_info_t * safety,int display_type,proto_item * msp_item,gboolean is_msp_item)5318 void dissect_epath(tvbuff_t *tvb, packet_info *pinfo, proto_tree *path_tree, proto_item *epath_item, int offset, int path_length,
5319 gboolean generate, gboolean packed, cip_simple_request_info_t* req_data, cip_safety_epath_info_t* safety,
5320 int display_type, proto_item *msp_item,
5321 gboolean is_msp_item)
5322 {
5323 int pathpos = 0;
5324 proto_item *hidden_item;
5325
5326 if (req_data != NULL)
5327 {
5328 reset_cip_request_info(req_data);
5329 }
5330
5331 if (safety != NULL)
5332 safety->safety_seg = FALSE;
5333
5334 if ( !generate )
5335 {
5336 hidden_item = proto_tree_add_item(path_tree, hf_cip_epath,
5337 tvb, offset, path_length, ENC_NA );
5338 proto_item_set_hidden(hidden_item);
5339 }
5340
5341 while( pathpos < path_length )
5342 {
5343 int segment_len;
5344 segment_len = dissect_cip_segment_single(pinfo, tvb, offset + pathpos, path_tree, epath_item, generate, packed, req_data, safety, display_type, msp_item, is_msp_item);
5345 if (segment_len == 0)
5346 {
5347 break;
5348 }
5349
5350 pathpos += segment_len;
5351
5352 /* Next path segment */
5353 if( pathpos < path_length )
5354 proto_item_append_text( epath_item, ", " );
5355
5356 } /* end of while( pathpos < path_length ) */
5357
5358 } /* end of dissect_epath() */
5359
5360 /* Number of seconds between Jan 1, 1970 00:00:00 epoch and CIP's epoch time of Jan 1, 1972 00:00:00 */
5361 #define CIP_TIMEBASE 63003600
5362
dissect_cip_date_and_time(proto_tree * tree,tvbuff_t * tvb,int offset,int hf_datetime)5363 void dissect_cip_date_and_time(proto_tree *tree, tvbuff_t *tvb, int offset, int hf_datetime)
5364 {
5365 nstime_t computed_time;
5366 guint16 num_days_since_1972;
5367 guint32 num_ms_today;
5368
5369 num_days_since_1972 = tvb_get_letohs(tvb, offset+4);
5370 num_ms_today = tvb_get_letohl(tvb, offset);
5371
5372 if ((num_days_since_1972 != 0) || (num_ms_today != 0))
5373 {
5374 computed_time.secs = CIP_TIMEBASE+(num_days_since_1972*60*60*24);
5375 computed_time.secs += num_ms_today/1000;
5376 computed_time.nsecs = (num_ms_today%1000)*1000000;
5377 }
5378 else
5379 {
5380 computed_time.secs = 0;
5381 computed_time.nsecs = 0;
5382 }
5383
5384 proto_tree_add_time(tree, hf_datetime, tvb, offset, 6, &computed_time);
5385 }
5386
5387 // CIP Type - STIME (nanoseconds)
dissect_cip_stime(proto_tree * tree,tvbuff_t * tvb,int offset,int hf_datetime)5388 static int dissect_cip_stime(proto_tree* tree, tvbuff_t* tvb, int offset, int hf_datetime)
5389 {
5390 nstime_t ts_nstime = { 0 };
5391 guint64 timestamp = tvb_get_letoh64(tvb, offset);
5392 ts_nstime.secs = timestamp / 1000000000;
5393 ts_nstime.nsecs = timestamp % 1000000000;
5394
5395 proto_tree_add_time(tree, hf_datetime, tvb, offset, 8, &ts_nstime);
5396
5397 return 8;
5398 }
5399
5400 // CIP Type - UTIME (microseconds)
dissect_cip_utime(proto_tree * tree,tvbuff_t * tvb,int offset,int hf_datetime)5401 int dissect_cip_utime(proto_tree* tree, tvbuff_t* tvb, int offset, int hf_datetime)
5402 {
5403 nstime_t ts_nstime = { 0 };
5404 guint64 timestamp = tvb_get_letoh64(tvb, offset);
5405 ts_nstime.secs = timestamp / 1000000;
5406 ts_nstime.nsecs = timestamp % 1000000;
5407
5408 proto_tree_add_time(tree, hf_datetime, tvb, offset, 8, &ts_nstime);
5409
5410 return 8;
5411 }
5412
dissect_cip_string_type(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset,int hf_type,int string_type)5413 int dissect_cip_string_type(packet_info *pinfo, proto_tree *tree, proto_item *item,
5414 tvbuff_t *tvb, int offset, int hf_type, int string_type)
5415 {
5416 guint32 string_size_field_len;
5417 guint32 string_size;
5418 guint string_encoding;
5419 int parsed_len;
5420 int total_len;
5421
5422 total_len = tvb_reported_length_remaining(tvb, offset);
5423
5424 switch (string_type)
5425 {
5426 case CIP_SHORT_STRING_TYPE:
5427 string_size = tvb_get_guint8(tvb, offset);
5428 string_encoding = ENC_ASCII | ENC_NA;
5429 string_size_field_len = 1;
5430 break;
5431
5432 case CIP_STRING_TYPE:
5433 string_size = tvb_get_letohs(tvb, offset);
5434 string_encoding = ENC_ASCII | ENC_NA;
5435 string_size_field_len = 2;
5436 break;
5437
5438 case CIP_STRING2_TYPE:
5439 string_size = tvb_get_letohs(tvb, offset) * 2;
5440 string_encoding = ENC_UCS_2 | ENC_LITTLE_ENDIAN;
5441 string_size_field_len = 2;
5442 break;
5443
5444 default:
5445 // Unsupported.
5446 return total_len;
5447 break;
5448 }
5449
5450 if (total_len < (int)(string_size + string_size_field_len))
5451 {
5452 expert_add_info(pinfo, item, &ei_mal_missing_string_data);
5453 parsed_len = total_len;
5454 }
5455 else
5456 {
5457 proto_tree_add_item(tree, hf_type, tvb, offset + string_size_field_len, string_size, string_encoding);
5458 parsed_len = string_size + string_size_field_len;
5459 }
5460
5461 return parsed_len;
5462 }
5463
dissect_cip_stringi(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,int offset)5464 static int dissect_cip_stringi(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb, int offset)
5465 {
5466 int parsed_len = 1;
5467 guint32 num_char = 0;
5468 proto_tree_add_item_ret_uint(tree, hf_stringi_number_char, tvb, offset, 1, ENC_LITTLE_ENDIAN, &num_char);
5469
5470 for (guint32 i = 0; i < num_char; ++i)
5471 {
5472 proto_tree_add_item(tree, hf_stringi_language_char, tvb, offset + 1, 3, ENC_ASCII | ENC_NA);
5473
5474 guint32 char_string_type = 0;
5475 proto_tree_add_item_ret_uint(tree, hf_stringi_char_string_struct, tvb, offset + 4, 1, ENC_LITTLE_ENDIAN, &char_string_type);
5476 proto_tree_add_item(tree, hf_stringi_char_set, tvb, offset + 5, 2, ENC_LITTLE_ENDIAN);
5477 parsed_len += 6;
5478
5479 if (char_string_type != CIP_STRING_TYPE
5480 && char_string_type != CIP_SHORT_STRING_TYPE
5481 && char_string_type != CIP_STRING2_TYPE)
5482 {
5483 // Unsupported type.
5484 break;
5485 }
5486
5487 parsed_len += dissect_cip_string_type(pinfo, tree, item, tvb, offset + parsed_len, hf_stringi_international_string, char_string_type);
5488 }
5489
5490 return parsed_len;
5491 }
5492
dissect_cip_attribute(packet_info * pinfo,proto_tree * tree,proto_item * item,tvbuff_t * tvb,attribute_info_t * attr,int offset,int total_len)5493 int dissect_cip_attribute(packet_info *pinfo, proto_tree *tree, proto_item *item, tvbuff_t *tvb,
5494 attribute_info_t* attr, int offset, int total_len)
5495 {
5496 int i, temp_data, temp_time, hour, min, sec, ms,
5497 consumed = 0;
5498 time_t computed_time;
5499 struct tm* date;
5500 char date_str[20];
5501
5502 /* sanity check */
5503 if (((attr->datatype == cip_dissector_func) && (attr->pdissect == NULL)) ||
5504 ((attr->datatype != cip_dissector_func) && (attr->phf == NULL)))
5505 {
5506 DISSECTOR_ASSERT(0);
5507 return total_len;
5508 }
5509
5510 switch (attr->datatype)
5511 {
5512 case cip_bool:
5513 case cip_usint:
5514 case cip_sint:
5515 case cip_byte:
5516 proto_tree_add_item(tree, *(attr->phf), tvb, offset, 1, ENC_LITTLE_ENDIAN);
5517 consumed = 1;
5518 break;
5519 case cip_uint:
5520 case cip_int:
5521 case cip_word:
5522 case cip_itime:
5523 proto_tree_add_item(tree, *(attr->phf), tvb, offset, 2, ENC_LITTLE_ENDIAN);
5524 consumed = 2;
5525 break;
5526 case cip_usint_array:
5527 for (i = 0; i < total_len; i++)
5528 proto_tree_add_item(tree, *(attr->phf), tvb, offset, total_len, ENC_NA);
5529 consumed = total_len;
5530 break;
5531 case cip_uint_array:
5532 for (i = 0; i < total_len; i+=2)
5533 proto_tree_add_item(tree, *(attr->phf), tvb, offset+i, 2, ENC_LITTLE_ENDIAN);
5534 consumed = i;
5535 break;
5536 case cip_udint:
5537 case cip_dint:
5538 case cip_dword:
5539 case cip_real:
5540 case cip_time:
5541 case cip_ftime:
5542 proto_tree_add_item(tree, *(attr->phf), tvb, offset, 4, ENC_LITTLE_ENDIAN);
5543 consumed = 4;
5544 break;
5545 case cip_ulint:
5546 case cip_lint:
5547 case cip_lword:
5548 case cip_lreal:
5549 case cip_ltime:
5550 case cip_ntime:
5551 proto_tree_add_item(tree, *(attr->phf), tvb, offset, 8, ENC_LITTLE_ENDIAN);
5552 consumed = 8;
5553 break;
5554 case cip_short_string:
5555 consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_SHORT_STRING_TYPE);
5556 break;
5557 case cip_string:
5558 consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_STRING_TYPE);
5559 break;
5560 case cip_dissector_func:
5561 consumed = attr->pdissect(pinfo, tree, item, tvb, offset, total_len);
5562 if (consumed == 0)
5563 {
5564 consumed = total_len;
5565 }
5566
5567 break;
5568 case cip_date_and_time:
5569 dissect_cip_date_and_time(tree, tvb, offset, *(attr->phf));
5570 consumed = 6;
5571 break;
5572 case cip_stime:
5573 consumed = dissect_cip_stime(tree, tvb, offset, *(attr->phf));
5574 break;
5575 case cip_utime:
5576 consumed = dissect_cip_utime(tree, tvb, offset, *(attr->phf));
5577 break;
5578 case cip_date:
5579 temp_data = tvb_get_letohs( tvb, offset);
5580 /* Convert to nstime epoch */
5581 computed_time = CIP_TIMEBASE+(temp_data*60*60*24);
5582 date = gmtime(&computed_time);
5583 if (date != NULL)
5584 strftime(date_str, 20, "%b %d, %Y", date);
5585 else
5586 (void) g_strlcpy(date_str, "Not representable", sizeof date_str);
5587 proto_tree_add_uint_format_value(tree, *(attr->phf), tvb, offset, 2, temp_data, "%s", date_str);
5588 consumed = 2;
5589 break;
5590 case cip_time_of_day:
5591 temp_time = temp_data = tvb_get_letohl( tvb, offset);
5592 hour = temp_time/(60*60*1000);
5593 temp_time %= (60*60*1000);
5594 min = temp_time/(60*1000);
5595 temp_time %= (60*1000);
5596 sec = temp_time/1000;
5597 ms = temp_time%1000;
5598 proto_tree_add_uint_format_value(tree, *(attr->phf), tvb, offset, 4, temp_data, "%02d:%02d:%02d.%03d", hour, min, sec, ms);
5599 consumed = 4;
5600 break;
5601 case cip_string2:
5602 consumed = dissect_cip_string_type(pinfo, tree, item, tvb, offset, *(attr->phf), CIP_STRING2_TYPE);
5603 break;
5604 case cip_stringi:
5605 consumed = dissect_cip_stringi(pinfo, tree, item, tvb, offset);
5606 break;
5607 case cip_stringN:
5608 /* CURRENTLY NOT SUPPORTED */
5609 expert_add_info(pinfo, item, &ei_proto_unsupported_datatype);
5610 consumed = total_len;
5611 break;
5612 }
5613
5614 return consumed;
5615 }
5616
5617 /************************************************
5618 *
5619 * Dissector for generic CIP object
5620 *
5621 ************************************************/
5622
5623 static void
dissect_cip_generic_data(proto_tree * item_tree,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo,proto_item * ti)5624 dissect_cip_generic_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo, proto_item *ti )
5625 {
5626 proto_tree *cmd_data_tree;
5627 int req_path_size;
5628 unsigned char add_stat_size;
5629 int cmd_data_len;
5630 int cmd_data_offset;
5631 guint8 service = tvb_get_guint8( tvb, offset );
5632
5633 if (service & CIP_SC_RESPONSE_MASK)
5634 {
5635 /* Response message */
5636 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
5637 cmd_data_len = item_length - 4 - add_stat_size;
5638 cmd_data_offset = offset + 4 + add_stat_size;
5639 }
5640 else
5641 {
5642 /* Request message */
5643 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
5644 cmd_data_len = item_length - req_path_size - 2;
5645 cmd_data_offset = offset + 2 + req_path_size;
5646 }
5647
5648 /* If there is any command specific data create a sub-tree for it */
5649 if (cmd_data_len > 0)
5650 {
5651 cmd_data_tree = proto_tree_add_subtree(item_tree, tvb, cmd_data_offset, cmd_data_len,
5652 ett_cmd_data, NULL, "Command Specific Data");
5653 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, cmd_data_offset, cmd_data_len, ENC_NA);
5654 }
5655 else
5656 {
5657 proto_item_set_hidden(ti);
5658 }
5659
5660 add_cip_service_to_info_column(pinfo, service, cip_sc_vals);
5661 } /* End of dissect_cip_generic_data() */
5662
5663 static int
dissect_cip_class_generic(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)5664 dissect_cip_class_generic(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
5665 {
5666 proto_item *ti;
5667 proto_tree *class_tree;
5668
5669 /* Create display subtree for the protocol */
5670 ti = proto_tree_add_item(tree, proto_cip_class_generic, tvb, 0, -1, ENC_NA);
5671 class_tree = proto_item_add_subtree( ti, ett_cip_class_generic );
5672
5673 dissect_cip_generic_data( class_tree, tvb, 0, tvb_reported_length(tvb), pinfo, ti );
5674
5675 return tvb_reported_length(tvb);
5676 }
5677
5678 static int
dissect_cip_set_attribute_single_req(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,cip_simple_request_info_t * req_data)5679 dissect_cip_set_attribute_single_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
5680 int offset, cip_simple_request_info_t* req_data)
5681 {
5682 int parsed_len = 0;
5683 attribute_info_t* attr;
5684
5685 attr = cip_get_attribute(req_data->iClass, req_data->iInstance, req_data->iAttribute);
5686 if (attr != NULL)
5687 {
5688 parsed_len = dissect_cip_attribute(pinfo, tree, item, tvb, attr, offset, tvb_reported_length_remaining(tvb, offset));
5689 }
5690
5691 return parsed_len;
5692 }
5693
dissect_cip_get_attribute_list_req(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,cip_simple_request_info_t * req_data)5694 int dissect_cip_get_attribute_list_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
5695 int offset, cip_simple_request_info_t* req_data)
5696 {
5697 int i, att_count, att_value;
5698 attribute_info_t* pattribute;
5699 proto_item *att_list, *att_item;
5700 proto_tree* att_tree;
5701
5702 /* Get attribute list request */
5703 if (tvb_reported_length_remaining(tvb, offset) < 2)
5704 {
5705 expert_add_info(pinfo, item, &ei_mal_serv_gal);
5706 return 0;
5707 }
5708
5709 /* Add number of attributes */
5710 att_count = tvb_get_letohs( tvb, offset);
5711 proto_tree_add_item(tree, hf_cip_sc_get_attr_list_attr_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5712 offset += 2;
5713
5714 /* Add Attribute List */
5715 att_tree = proto_tree_add_subtree(tree, tvb, offset, att_count*2, ett_cip_get_attribute_list, &att_list, "Attribute List" );
5716
5717 for( i=0; i < att_count; i++ )
5718 {
5719 att_value = tvb_get_letohs( tvb, offset);
5720 att_item = proto_tree_add_item(att_tree, hf_cip_attribute16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5721 pattribute = cip_get_attribute(req_data->iClass, req_data->iInstance, att_value);
5722 if (pattribute != NULL)
5723 proto_item_append_text(att_item, " (%s)", pattribute->text);
5724
5725 offset += 2;
5726 if ((tvb_reported_length_remaining(tvb, offset) < 2) && (i < att_count-1))
5727 {
5728 expert_add_info(pinfo, att_list, &ei_mal_serv_gal_count);
5729 break;
5730 }
5731 }
5732
5733 return 2 + att_count * 2;
5734 }
5735
5736 int
dissect_cip_set_attribute_list_req(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,cip_simple_request_info_t * req_data)5737 dissect_cip_set_attribute_list_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
5738 int offset, cip_simple_request_info_t* req_data)
5739 {
5740 int i, start_offset, att_count,
5741 att_value, att_size;
5742 attribute_info_t* attr;
5743 proto_item *att_list, *att_item;
5744 proto_tree *att_tree, *att_list_tree;
5745
5746 /* Get attribute list request */
5747 if (tvb_reported_length_remaining(tvb, offset) < 2)
5748 {
5749 expert_add_info(pinfo, item, &ei_mal_serv_sal);
5750 return 0;
5751 }
5752
5753 /* Add number of attributes */
5754 att_count = tvb_get_letohs( tvb, offset);
5755 proto_tree_add_item(tree, hf_cip_sc_set_attr_list_attr_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5756
5757 /* Add Attribute List */
5758 att_list_tree = proto_tree_add_subtree(tree, tvb, offset+2, att_count*2, ett_cip_set_attribute_list, &att_list, "Attribute List" );
5759 offset += 2;
5760 start_offset = offset;
5761
5762 for( i=0; i < att_count; i++ )
5763 {
5764 att_value = tvb_get_letohs( tvb, offset);
5765 att_item = proto_tree_add_item(att_list_tree, hf_cip_attribute16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5766 att_tree = proto_item_add_subtree( att_item, ett_cip_set_attribute_list_item);
5767 offset += 2;
5768
5769 attr = cip_get_attribute(req_data->iClass, req_data->iInstance, att_value);
5770 if (attr != NULL)
5771 {
5772 proto_item_append_text(att_item, " (%s)", attr->text);
5773 /* provide attribute data */
5774 att_size = dissect_cip_attribute(pinfo, att_tree, att_item, tvb, attr, offset, tvb_reported_length_remaining(tvb, offset));
5775 offset += att_size;
5776 proto_item_set_len(att_item, att_size+2);
5777 }
5778 else
5779 {
5780 /* Can't find the attribute. */
5781 break;
5782 }
5783
5784 if ((tvb_reported_length_remaining(tvb, offset) < 2) && (i < att_count-1))
5785 {
5786 expert_add_info(pinfo, att_list, &ei_mal_serv_sal_count);
5787 break;
5788 }
5789 }
5790
5791 proto_item_set_len(att_list, offset-start_offset );
5792
5793 return 2 + (offset - start_offset);
5794 }
5795
dissect_cip_multiple_service_packet(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,gboolean request)5796 int dissect_cip_multiple_service_packet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item, int offset, gboolean request)
5797 {
5798 proto_tree *mult_serv_tree, *offset_tree;
5799 int i, num_services, serv_offset, prev_offset = 0;
5800 int parsed_len;
5801 cip_req_info_t *cip_req_info, *mr_single_req_info;
5802 mr_mult_req_info_t *mr_mult_req_info = NULL;
5803
5804 if (tvb_reported_length_remaining(tvb, offset) < 2)
5805 {
5806 expert_add_info(pinfo, item, &ei_mal_msp_missing_services);
5807 return 0;
5808 }
5809
5810 num_services = tvb_get_letohs( tvb, offset);
5811 proto_tree_add_item(tree, hf_cip_sc_mult_serv_pack_num_services, tvb, offset, 2, ENC_LITTLE_ENDIAN);
5812
5813 /* Ensure a rough sanity check */
5814 if (num_services*2 > tvb_reported_length_remaining(tvb, offset+2))
5815 {
5816 expert_add_info(pinfo, item, &ei_mal_msp_services);
5817 }
5818
5819 offset_tree = proto_tree_add_subtree(tree, tvb, offset + 2, num_services * 2, ett_cip_msp_offset, NULL, "Offset List");
5820 for (i = 0; i < num_services; i++)
5821 {
5822 proto_tree_add_item(offset_tree, hf_cip_sc_mult_serv_pack_offset, tvb, offset + 2 + i * 2, 2, ENC_LITTLE_ENDIAN);
5823 }
5824
5825 cip_req_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0 );
5826 if ( cip_req_info )
5827 {
5828 /* Only allocate memory for requests. */
5829 if (cip_req_info->pData == NULL && request == TRUE)
5830 {
5831 mr_mult_req_info = wmem_new(wmem_file_scope(), mr_mult_req_info_t);
5832 mr_mult_req_info->service = SC_MULT_SERV_PACK;
5833 mr_mult_req_info->num_services = num_services;
5834 mr_mult_req_info->requests = (cip_req_info_t *)wmem_alloc0(wmem_file_scope(), sizeof(cip_req_info_t)*num_services);
5835 cip_req_info->pData = mr_mult_req_info;
5836 }
5837
5838 mr_mult_req_info = (mr_mult_req_info_t*)cip_req_info->pData;
5839
5840 if (mr_mult_req_info
5841 && (mr_mult_req_info->service != SC_MULT_SERV_PACK
5842 || mr_mult_req_info->num_services != num_services))
5843 {
5844 mr_mult_req_info = NULL;
5845 }
5846 }
5847
5848 col_append_str(pinfo->cinfo, COL_INFO, ": ");
5849
5850 parsed_len = 2 + num_services * 2;
5851 for( i=0; i < num_services; i++ )
5852 {
5853 proto_item *mult_serv_item;
5854 int serv_length;
5855 tvbuff_t *next_tvb;
5856
5857 serv_offset = tvb_get_letohs( tvb, offset+2+(i*2) );
5858
5859 if (tvb_reported_length_remaining(tvb, serv_offset) <= 0)
5860 {
5861 expert_add_info(pinfo, item, &ei_mal_msp_inv_offset);
5862 continue;
5863 }
5864
5865 if( i == (num_services-1) )
5866 {
5867 /* Last service to add */
5868 serv_length = tvb_reported_length_remaining(tvb, offset)-serv_offset;
5869 }
5870 else
5871 {
5872 serv_length = tvb_get_letohs( tvb, offset+2+((i+1)*2) ) - serv_offset;
5873 }
5874
5875 mult_serv_tree = proto_tree_add_subtree_format(tree, tvb, offset+serv_offset, serv_length,
5876 ett_cip_mult_service_packet, &mult_serv_item, "Service Packet #%d: ", i+1 );
5877 proto_tree_add_item(mult_serv_tree, hf_cip_sc_mult_serv_pack_offset, tvb, offset+2+(i*2) , 2, ENC_LITTLE_ENDIAN);
5878
5879 /* Make sure the offset is valid */
5880 if ((tvb_reported_length_remaining(tvb, serv_offset) <= 0) ||
5881 (tvb_reported_length_remaining(tvb, serv_offset+serv_length) <= 0) ||
5882 (serv_length <= 0) ||
5883 (prev_offset >= serv_offset))
5884 {
5885 expert_add_info(pinfo, mult_serv_item, &ei_mal_msp_inv_offset);
5886 prev_offset = serv_offset;
5887 continue;
5888 }
5889 prev_offset = serv_offset;
5890
5891 /*
5892 ** We call ourselves again to dissect embedded packet
5893 */
5894
5895 next_tvb = tvb_new_subset_length(tvb, offset+serv_offset, serv_length);
5896
5897 if ( mr_mult_req_info )
5898 {
5899 mr_single_req_info = mr_mult_req_info->requests + i;
5900 dissect_cip_data(mult_serv_tree, next_tvb, 0, pinfo, mr_single_req_info, mult_serv_item, TRUE);
5901 }
5902 else
5903 {
5904 dissect_cip_data(mult_serv_tree, next_tvb, 0, pinfo, NULL, mult_serv_item, TRUE);
5905 }
5906
5907 /* Add the embedded CIP service to the item. */
5908 if (mult_serv_item != NULL)
5909 {
5910 guint8 service = tvb_get_guint8(next_tvb, 0);
5911 proto_item_append_text(mult_serv_item, "%s", val_to_str(service & CIP_SC_MASK, cip_sc_vals, "Service (0x%02x)"));
5912 }
5913
5914 if (i != num_services - 1)
5915 {
5916 col_append_str(pinfo->cinfo, COL_INFO, ", ");
5917 }
5918
5919 parsed_len += serv_length;
5920 }
5921
5922 return parsed_len;
5923 }
5924
5925 static int
dissect_cip_generic_service_req(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,cip_simple_request_info_t * req_data)5926 dissect_cip_generic_service_req(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, cip_simple_request_info_t* req_data)
5927 {
5928 proto_item *cmd_data_item;
5929 int req_path_size,
5930 offset = 0;
5931 proto_tree *cmd_data_tree;
5932 guint8 service = tvb_get_guint8( tvb, offset ) & CIP_SC_MASK;
5933
5934 add_cip_service_to_info_column(pinfo, service, cip_sc_vals);
5935
5936 req_path_size = tvb_get_guint8(tvb, offset + 1);
5937 offset += ((req_path_size * 2) + 2);
5938
5939 /* Create service tree */
5940 cmd_data_tree = proto_tree_add_subtree(tree, tvb, offset, 0, ett_cmd_data, &cmd_data_item,
5941 val_to_str(service, cip_sc_vals , "Unknown Service (0x%02x)"));
5942 proto_item_append_text(cmd_data_item, " (Request)");
5943
5944 int parsed_len = 0;
5945
5946 switch(service)
5947 {
5948 case SC_GET_ATT_LIST:
5949 parsed_len = dissect_cip_get_attribute_list_req(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, req_data);
5950 break;
5951 case SC_SET_ATT_LIST:
5952 parsed_len = dissect_cip_set_attribute_list_req(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, req_data);
5953 break;
5954 case SC_RESET:
5955 // Parameter to reset is optional.
5956 if (tvb_reported_length_remaining(tvb, offset) > 0)
5957 {
5958 proto_tree_add_item(cmd_data_tree, hf_cip_sc_reset_param, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5959 parsed_len = 1;
5960 }
5961 break;
5962 case SC_MULT_SERV_PACK:
5963 parsed_len = dissect_cip_multiple_service_packet(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, TRUE);
5964 break;
5965 case SC_SET_ATT_SINGLE:
5966 parsed_len = dissect_cip_set_attribute_single_req(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, req_data);
5967 break;
5968 case SC_FIND_NEXT_OBJ_INST:
5969 proto_tree_add_item(cmd_data_tree, hf_cip_find_next_object_max_instance, tvb, offset, 1, ENC_LITTLE_ENDIAN);
5970 parsed_len = 1;
5971 break;
5972 default:
5973 // No specific handling for other services.
5974 break;
5975 }
5976
5977 // Display any remaining unparsed data.
5978 int remain_len = tvb_reported_length_remaining(tvb, offset + parsed_len);
5979 if (remain_len > 0)
5980 {
5981 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset + parsed_len, remain_len, ENC_NA);
5982 }
5983
5984 proto_item_set_len(cmd_data_item, parsed_len + remain_len);
5985
5986 return tvb_reported_length(tvb);
5987 }
5988
5989 typedef struct cip_gaa_key {
5990 guint32 cip_class;
5991 gboolean class_instance;
5992 } cip_gaa_key_t;
5993
5994 typedef struct cip_gaa_val {
5995 wmem_list_t *attributes;
5996 } cip_gaa_val_t;
5997
5998 static wmem_map_t *cip_gaa_hashtable = NULL;
5999
6000 static guint
cip_gaa_hash(gconstpointer v)6001 cip_gaa_hash (gconstpointer v)
6002 {
6003 const cip_gaa_key_t *key = (const cip_gaa_key_t *)v;
6004 guint val;
6005
6006 val = (guint)((key->cip_class << 1) & 0xFFFFFFFE);
6007 val |= (key->class_instance & 1);
6008
6009 return val;
6010 }
6011
6012 static gint
cip_gaa_equal(gconstpointer v,gconstpointer w)6013 cip_gaa_equal(gconstpointer v, gconstpointer w)
6014 {
6015 const cip_gaa_key_t *v1 = (const cip_gaa_key_t *)v;
6016 const cip_gaa_key_t *v2 = (const cip_gaa_key_t *)w;
6017
6018 if ((v1->cip_class == v2->cip_class) &&
6019 (v1->class_instance == v2->class_instance))
6020 return 1;
6021
6022 return 0;
6023 }
6024
build_get_attr_all_table(void)6025 static void build_get_attr_all_table(void)
6026 {
6027 size_t i, j;
6028 attribute_val_array_t* att_array;
6029 attribute_info_t* pattr;
6030 cip_gaa_key_t key;
6031 cip_gaa_key_t* new_key;
6032 cip_gaa_val_t *gaa_val;
6033 int last_attribute_index = -1;
6034
6035 cip_gaa_hashtable = wmem_map_new(wmem_epan_scope(), cip_gaa_hash, cip_gaa_equal);
6036
6037 for (i = 0; i < sizeof(all_attribute_vals)/sizeof(attribute_val_array_t); i++)
6038 {
6039 att_array = &all_attribute_vals[i];
6040 for (j = 0; j < att_array->size; j++)
6041 {
6042 pattr = &att_array->attrs[j];
6043 key.cip_class = pattr->class_id;
6044 key.class_instance = pattr->class_instance;
6045
6046 gaa_val = (cip_gaa_val_t *)wmem_map_lookup( cip_gaa_hashtable, &key );
6047 if (gaa_val == NULL)
6048 {
6049 new_key = (cip_gaa_key_t*)wmem_memdup(wmem_epan_scope(), &key, sizeof(cip_gaa_key_t));
6050 gaa_val = wmem_new0(wmem_epan_scope(), cip_gaa_val_t);
6051 gaa_val->attributes = wmem_list_new(wmem_epan_scope());
6052
6053 wmem_map_insert(cip_gaa_hashtable, new_key, gaa_val );
6054 last_attribute_index = -1;
6055 }
6056
6057 if ((pattr->gaa_index >= 0) && (pattr->gaa_index > last_attribute_index))
6058 {
6059 wmem_list_append(gaa_val->attributes, pattr);
6060 last_attribute_index = pattr->gaa_index;
6061 }
6062 }
6063 }
6064 }
6065
dissect_cip_get_attribute_all_rsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,int offset,cip_simple_request_info_t * req_data)6066 int dissect_cip_get_attribute_all_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
6067 int offset, cip_simple_request_info_t* req_data)
6068 {
6069 int att_size;
6070 gint len_remain;
6071 attribute_info_t* attr;
6072 proto_item *att_item;
6073 proto_tree *att_tree;
6074 cip_gaa_key_t key;
6075 cip_gaa_val_t *gaa_val;
6076 wmem_list_frame_t* attribute_list;
6077 int parsed_len = 0;
6078
6079 key.cip_class = req_data->iClass;
6080 key.class_instance = (req_data->iInstance == 0);
6081
6082 gaa_val = (cip_gaa_val_t *)wmem_map_lookup( cip_gaa_hashtable, &key );
6083 if (gaa_val == NULL)
6084 {
6085 return 0;
6086 }
6087
6088 for (attribute_list = wmem_list_head(gaa_val->attributes);
6089 (attribute_list != NULL);
6090 attribute_list = wmem_list_frame_next(attribute_list))
6091 {
6092 attr = (attribute_info_t *)wmem_list_frame_data(attribute_list);
6093 len_remain = tvb_reported_length_remaining(tvb, offset);
6094
6095 /* If there are no more attributes defined or there is no data left. */
6096 if (attr == NULL || len_remain <= 0)
6097 break;
6098
6099 att_item = proto_tree_add_uint_format_value(tree, hf_cip_attribute16, tvb, offset, 0, attr->attribute, "%d (%s)", attr->attribute, attr->text);
6100 att_tree = proto_item_add_subtree(att_item, ett_cip_get_attributes_all_item);
6101
6102 att_size = dissect_cip_attribute(pinfo, att_tree, att_item, tvb, attr, offset, len_remain);
6103 proto_item_set_len(att_item, att_size);
6104
6105 offset += att_size;
6106 parsed_len += att_size;
6107 }
6108
6109 return parsed_len;
6110 }
6111
6112 static int
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)6113 dissect_cip_get_attribute_list_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
6114 int offset, cip_simple_request_info_t* req_data)
6115 {
6116 int i, start_offset, att_count,
6117 att_value, att_status;
6118 guint att_size;
6119 attribute_info_t* attr;
6120 proto_item *att_list, *att_item;
6121 proto_tree *att_tree, *att_list_tree;
6122
6123 /* Get attribute list response */
6124 if (tvb_reported_length_remaining(tvb, offset) < 2)
6125 {
6126 expert_add_info(pinfo, item, &ei_mal_serv_gal);
6127 return 0;
6128 }
6129
6130 /* Add number of attributes */
6131 att_count = tvb_get_letohs( tvb, offset);
6132 proto_tree_add_item(tree, hf_cip_sc_get_attr_list_attr_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
6133
6134 /* Add Attribute List */
6135 att_list_tree = proto_tree_add_subtree(tree, tvb, offset+2, att_count*4, ett_cip_get_attribute_list, &att_list, "Attribute List" );
6136 offset += 2;
6137 start_offset = offset;
6138
6139 for( i=0; i < att_count; i++ )
6140 {
6141 att_value = tvb_get_letohs( tvb, offset);
6142 att_item = proto_tree_add_item(att_list_tree, hf_cip_attribute16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
6143 att_tree = proto_item_add_subtree( att_item, ett_cip_get_attribute_list_item);
6144
6145 att_status = tvb_get_letohs( tvb, offset+2);
6146 proto_tree_add_item(att_tree, hf_cip_sc_get_attr_list_attr_status, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
6147
6148 attr = cip_get_attribute(req_data->iClass, req_data->iInstance, att_value);
6149 if (attr != NULL)
6150 proto_item_append_text(att_item, " (%s)", attr->text);
6151
6152 offset += 4;
6153 if (att_status == 0)
6154 {
6155 if (attr != NULL)
6156 {
6157 /* provide attribute data */
6158 att_size = dissect_cip_attribute(pinfo, att_tree, att_item, tvb, attr, offset, tvb_reported_length_remaining(tvb, offset));
6159 offset += att_size;
6160 proto_item_set_len(att_item, att_size+4);
6161 }
6162 else
6163 {
6164 /* Can't find the attribute */
6165 break;
6166 }
6167 }
6168
6169 if ((tvb_reported_length_remaining(tvb, offset) < 4) && (i < att_count-1))
6170 {
6171 expert_add_info(pinfo, att_list, &ei_mal_serv_gal_count);
6172 break;
6173 }
6174 }
6175
6176 proto_item_set_len(att_list, offset-start_offset );
6177 return 2 + (offset - start_offset);
6178 }
6179
6180 int
dissect_cip_set_attribute_list_rsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,cip_simple_request_info_t * req_data)6181 dissect_cip_set_attribute_list_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
6182 int offset, cip_simple_request_info_t* req_data)
6183 {
6184 int i, start_offset, att_count, att_value;
6185 attribute_info_t* attr;
6186 proto_item *att_list, *att_item;
6187 proto_tree *att_tree, *att_list_tree;
6188
6189 /* Get attribute list request */
6190 if (tvb_reported_length_remaining(tvb, offset) < 2)
6191 {
6192 expert_add_info(pinfo, item, &ei_mal_serv_sal);
6193 return 0;
6194 }
6195
6196 /* Add number of attributes */
6197 att_count = tvb_get_letohs( tvb, offset);
6198 proto_tree_add_item(tree, hf_cip_sc_set_attr_list_attr_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
6199
6200 /* Add Attribute List */
6201 att_list_tree = proto_tree_add_subtree(tree, tvb, offset+2, att_count*4, ett_cip_get_attribute_list, &att_list, "Attribute List" );
6202 offset += 2;
6203 start_offset = offset;
6204
6205 for( i=0; i < att_count; i++ )
6206 {
6207 att_value = tvb_get_letohs( tvb, offset);
6208 att_item = proto_tree_add_item(att_list_tree, hf_cip_attribute16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
6209 att_tree = proto_item_add_subtree( att_item, ett_cip_set_attribute_list_item);
6210
6211 proto_tree_add_item(att_tree, hf_cip_sc_set_attr_list_attr_status, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
6212
6213 attr = cip_get_attribute(req_data->iClass, req_data->iInstance, att_value);
6214 if (attr != NULL)
6215 proto_item_append_text(att_item, " (%s)", attr->text);
6216
6217 offset += 4;
6218 if ((tvb_reported_length_remaining(tvb, offset) < 4) && (i < att_count-1))
6219 {
6220 expert_add_info(pinfo, att_list, &ei_mal_serv_sal_count);
6221 break;
6222 }
6223 }
6224
6225 proto_item_set_len(att_list, offset-start_offset );
6226 return 2 + (offset - start_offset);
6227 }
6228
6229 static int
dissect_cip_get_attribute_single_rsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset,cip_simple_request_info_t * req_data)6230 dissect_cip_get_attribute_single_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item,
6231 int offset, cip_simple_request_info_t* req_data)
6232 {
6233 int parsed_len = 0;
6234 int total_len;
6235 attribute_info_t* attr;
6236
6237 total_len = tvb_reported_length_remaining(tvb, offset);
6238 attr = cip_get_attribute(req_data->iClass, req_data->iInstance, req_data->iAttribute);
6239 if (attr != NULL)
6240 {
6241 proto_item_append_text(item, " (%s)", attr->text);
6242 parsed_len = dissect_cip_attribute(pinfo, tree, item, tvb, attr, offset, total_len);
6243 }
6244
6245 return parsed_len;
6246 }
6247
6248 static int
dissect_cip_find_next_object_rsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,proto_item * item,int offset)6249 dissect_cip_find_next_object_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_item * item, int offset)
6250 {
6251 guint32 i, num_instances;
6252
6253 if (tvb_reported_length_remaining(tvb, offset) < 1)
6254 {
6255 expert_add_info(pinfo, item, &ei_mal_serv_find_next_object);
6256 return 0;
6257 }
6258
6259 proto_tree_add_item_ret_uint(tree, hf_cip_find_next_object_num_instances, tvb, offset, 1, ENC_LITTLE_ENDIAN, &num_instances);
6260 offset += 1;
6261
6262 for (i = 0; i < num_instances; i++)
6263 {
6264 proto_tree_add_item(tree, hf_cip_find_next_object_instance_item, tvb, offset, 1, ENC_LITTLE_ENDIAN);
6265 offset += 1;
6266
6267 if ((tvb_reported_length_remaining(tvb, offset) < 2) && (i < num_instances-1))
6268 {
6269 expert_add_info(pinfo, item, &ei_mal_serv_find_next_object_count);
6270 break;
6271 }
6272 }
6273
6274 return 1 + num_instances * 2;
6275 }
6276
load_cip_request_data(packet_info * pinfo,cip_simple_request_info_t * req_data)6277 void load_cip_request_data(packet_info *pinfo, cip_simple_request_info_t *req_data)
6278 {
6279 cip_req_info_t* preq_info;
6280 preq_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6281
6282 if ((preq_info != NULL) &&
6283 (preq_info->ciaData != NULL))
6284 {
6285 memcpy(req_data, preq_info->ciaData, sizeof(cip_simple_request_info_t));
6286 }
6287 else
6288 {
6289 reset_cip_request_info(req_data);
6290 }
6291 }
6292
should_dissect_cip_response(tvbuff_t * tvb,int offset,guint8 gen_status)6293 gboolean should_dissect_cip_response(tvbuff_t *tvb, int offset, guint8 gen_status)
6294 {
6295 // Only parse the response if there is data left or it has a response status that allows additional data
6296 // to be returned.
6297 if ((tvb_reported_length_remaining(tvb, offset) == 0)
6298 && gen_status != CI_GRC_SUCCESS
6299 && gen_status != CI_GRC_ATTR_LIST_ERROR
6300 && gen_status != CI_GRC_SERVICE_ERROR
6301 && gen_status != CI_GRC_INVALID_LIST_STATUS)
6302 {
6303 return FALSE;
6304 }
6305
6306 return TRUE;
6307 }
6308
6309 static int
dissect_cip_generic_service_rsp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree)6310 dissect_cip_generic_service_rsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
6311 {
6312 proto_item *cmd_data_item;
6313 proto_tree *cmd_data_tree;
6314 cip_simple_request_info_t req_data;
6315 int offset = 0;
6316 guint8 gen_status = tvb_get_guint8(tvb, offset + 2);
6317 guint8 service = tvb_get_guint8(tvb, offset) & CIP_SC_MASK;
6318 guint16 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
6319
6320 offset = 4 + add_stat_size;
6321
6322 add_cip_service_to_info_column(pinfo, service, cip_sc_vals);
6323
6324 cmd_data_tree = proto_tree_add_subtree(tree, tvb, offset, 0,
6325 ett_cmd_data, &cmd_data_item, val_to_str(service, cip_sc_vals, "Unknown Service (0x%02x)"));
6326 proto_item_append_text(cmd_data_item, " (Response)");
6327
6328 load_cip_request_data(pinfo, &req_data);
6329
6330 if (should_dissect_cip_response(tvb, offset, gen_status) == FALSE)
6331 {
6332 return 0;
6333 }
6334
6335 int parsed_len = 0;
6336
6337 switch(service)
6338 {
6339 case SC_GET_ATT_ALL:
6340 parsed_len = dissect_cip_get_attribute_all_rsp(tvb, pinfo, cmd_data_tree, offset, &req_data);
6341 break;
6342 case SC_GET_ATT_LIST:
6343 parsed_len = dissect_cip_get_attribute_list_rsp(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, &req_data);
6344 break;
6345 case SC_SET_ATT_LIST:
6346 parsed_len = dissect_cip_set_attribute_list_rsp(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, &req_data);
6347 break;
6348 case SC_CREATE:
6349 proto_tree_add_item(cmd_data_tree, hf_cip_sc_create_instance, tvb, offset, 2, ENC_LITTLE_ENDIAN);
6350 parsed_len = 2;
6351 break;
6352 case SC_MULT_SERV_PACK:
6353 parsed_len = dissect_cip_multiple_service_packet(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, FALSE);
6354 break;
6355 case SC_GET_ATT_SINGLE:
6356 parsed_len = dissect_cip_get_attribute_single_rsp(tvb, pinfo, cmd_data_tree, cmd_data_item, offset, &req_data);
6357 break;
6358 case SC_FIND_NEXT_OBJ_INST:
6359 parsed_len = dissect_cip_find_next_object_rsp(tvb, pinfo, cmd_data_tree, cmd_data_item, offset);
6360 break;
6361 case SC_GROUP_SYNC:
6362 proto_tree_add_item(cmd_data_tree, hf_cip_sc_group_sync_is_sync, tvb, offset, 1, ENC_LITTLE_ENDIAN);
6363 parsed_len = 1;
6364 break;
6365 default:
6366 // No specific handling for other services.
6367 break;
6368 }
6369
6370 // Display any remaining unparsed data.
6371 int remain_len = tvb_reported_length_remaining(tvb, offset + parsed_len);
6372 if (remain_len > 0)
6373 {
6374 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset + parsed_len, remain_len, ENC_NA);
6375 }
6376
6377 proto_item_set_len(cmd_data_item, parsed_len + remain_len);
6378
6379 return tvb_reported_length(tvb);
6380 }
6381
6382 /************************************************
6383 *
6384 * Dissector for CIP Connection Manager
6385 *
6386 ************************************************/
6387
6388 static void
dissect_cip_cm_timeout(proto_tree * cmd_tree,tvbuff_t * tvb,int offset)6389 dissect_cip_cm_timeout(proto_tree *cmd_tree, tvbuff_t *tvb, int offset)
6390 {
6391 guint8 tick, timeout_tick;
6392 int timeout;
6393
6394 /* Display the priority/tick timer */
6395 tick = tvb_get_guint8( tvb, offset) & 0x0F;
6396 proto_tree_add_item( cmd_tree, hf_cip_cm_priority, tvb, offset, 1, ENC_LITTLE_ENDIAN);
6397 proto_tree_add_item( cmd_tree, hf_cip_cm_tick_time, tvb, offset, 1, ENC_LITTLE_ENDIAN);
6398
6399 /* Display the time-out ticks */
6400 timeout_tick = tvb_get_guint8( tvb, offset+1 );
6401 proto_tree_add_item( cmd_tree, hf_cip_cm_timeout_tick, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
6402
6403 /* Display the actual time out */
6404 timeout = ( 1 << tick ) * timeout_tick;
6405 proto_tree_add_uint(cmd_tree, hf_cip_cm_timeout, tvb, offset, 2, timeout);
6406 }
6407
dissect_connection_triad(tvbuff_t * tvb,int offset,proto_tree * tree,int hf_conn_serial,int hf_vendor,int hf_orig_serial,cip_connection_triad_t * triad)6408 static void dissect_connection_triad(tvbuff_t *tvb, int offset, proto_tree *tree,
6409 int hf_conn_serial, int hf_vendor, int hf_orig_serial,
6410 cip_connection_triad_t *triad)
6411 {
6412 guint32 ConnSerialNumber;
6413 guint32 VendorID;
6414 guint32 DeviceSerialNumber;
6415
6416 proto_tree_add_item_ret_uint(tree, hf_conn_serial, tvb, offset, 2, ENC_LITTLE_ENDIAN, &ConnSerialNumber);
6417 proto_tree_add_item_ret_uint(tree, hf_vendor, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN, &VendorID);
6418 proto_tree_add_item_ret_uint(tree, hf_orig_serial, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN, &DeviceSerialNumber);
6419
6420 if (triad)
6421 {
6422 triad->ConnSerialNumber = ConnSerialNumber;
6423 triad->VendorID = VendorID;
6424 triad->DeviceSerialNumber = DeviceSerialNumber;
6425 }
6426 }
6427
6428 // Mark this message as belonging to a specific CIP connection index.
mark_cip_connection(packet_info * pinfo,tvbuff_t * tvb,proto_tree * tree)6429 static void mark_cip_connection(packet_info* pinfo, tvbuff_t* tvb, proto_tree* tree)
6430 {
6431 cip_conn_info_t* conn_val = (cip_conn_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_CONNECTION_INFO);
6432 if (conn_val)
6433 {
6434 proto_item* pi = proto_tree_add_uint(tree, hf_cip_connection, tvb, 0, 0, conn_val->connid);
6435 proto_item_set_generated(pi);
6436 }
6437 }
6438
6439 // Save the Route or Connection Path for use in the response packet.
save_route_connection_path(packet_info * pinfo,tvbuff_t * tvb,int offset,guint path_size_bytes)6440 static void save_route_connection_path(packet_info* pinfo, tvbuff_t* tvb, int offset, guint path_size_bytes)
6441 {
6442 if (pinfo->fd->visited)
6443 {
6444 return;
6445 }
6446
6447 cip_req_info_t* preq_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6448 if (preq_info)
6449 {
6450 preq_info->pRouteConnectionPath = wmem_alloc(wmem_file_scope(), path_size_bytes);
6451 preq_info->RouteConnectionPathLen = path_size_bytes / 2;
6452 tvb_memcpy(tvb, preq_info->pRouteConnectionPath, offset, path_size_bytes);
6453 }
6454 }
6455
6456 static void
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)6457 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)
6458 {
6459 proto_item *pi;
6460 proto_tree *epath_tree;
6461 int conn_path_size, net_param_offset = 0;
6462 guint8 TransportClass_trigger;
6463 cip_simple_request_info_t connection_path;
6464 cip_safety_epath_info_t safety_fwdopen = {0};
6465
6466 cip_connID_info_t O2T_info = {0};
6467 cip_connID_info_t T2O_info = {0};
6468
6469 dissect_cip_cm_timeout(cmd_tree, tvb, offset);
6470 proto_tree_add_item_ret_uint( cmd_tree, hf_cip_cm_ot_connid, tvb, offset+2, 4, ENC_LITTLE_ENDIAN, &O2T_info.connID);
6471 proto_tree_add_item_ret_uint( cmd_tree, hf_cip_cm_to_connid, tvb, offset+6, 4, ENC_LITTLE_ENDIAN, &T2O_info.connID);
6472
6473 // Add Connection IDs as hidden items so that it's easy to find all Connection IDs in different fields.
6474 pi = proto_tree_add_item(cmd_tree, hf_cip_connid, tvb, offset + 2, 4, ENC_LITTLE_ENDIAN);
6475 proto_item_set_hidden(pi);
6476 pi = proto_tree_add_item(cmd_tree, hf_cip_connid, tvb, offset + 6, 4, ENC_LITTLE_ENDIAN);
6477 proto_item_set_hidden(pi);
6478
6479 cip_connection_triad_t conn_triad;
6480 dissect_connection_triad(tvb, offset + 10, cmd_tree,
6481 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
6482 &conn_triad);
6483
6484 proto_tree_add_item(cmd_tree, hf_cip_cm_timeout_multiplier, tvb, offset+18, 1, ENC_LITTLE_ENDIAN);
6485 proto_tree_add_item(cmd_tree, hf_cip_reserved24, tvb, offset+19, 3, ENC_LITTLE_ENDIAN);
6486
6487 // O->T parameters
6488 proto_tree_add_item(cmd_tree, hf_cip_cm_ot_rpi, tvb, offset + 22, 4, ENC_LITTLE_ENDIAN);
6489 if (large_fwd_open)
6490 {
6491 dissect_net_param32(tvb, offset+26, cmd_tree,
6492 hf_cip_cm_ot_net_params32, hf_cip_cm_lfwo_own, hf_cip_cm_lfwo_typ,
6493 hf_cip_cm_lfwo_prio, hf_cip_cm_lfwo_fixed_var, hf_cip_cm_lfwo_con_size, ett_cm_ncp, &O2T_info);
6494 net_param_offset = 4;
6495 }
6496 else
6497 {
6498 dissect_net_param16(tvb, offset+26, cmd_tree,
6499 hf_cip_cm_ot_net_params16, hf_cip_cm_fwo_own, hf_cip_cm_fwo_typ,
6500 hf_cip_cm_fwo_prio, hf_cip_cm_fwo_fixed_var, hf_cip_cm_fwo_con_size, ett_cm_ncp, &O2T_info);
6501 net_param_offset = 2;
6502 }
6503
6504 // T->O parameters
6505 proto_tree_add_item(cmd_tree, hf_cip_cm_to_rpi, tvb, offset + 26 + net_param_offset, 4, ENC_LITTLE_ENDIAN);
6506 if (large_fwd_open)
6507 {
6508 dissect_net_param32(tvb, offset+26+net_param_offset+4, cmd_tree,
6509 hf_cip_cm_to_net_params32, hf_cip_cm_lfwo_own, hf_cip_cm_lfwo_typ,
6510 hf_cip_cm_lfwo_prio, hf_cip_cm_lfwo_fixed_var, hf_cip_cm_lfwo_con_size, ett_cm_ncp, &T2O_info);
6511 net_param_offset += 4;
6512 }
6513 else
6514 {
6515 dissect_net_param16(tvb, offset+26+net_param_offset+4, cmd_tree,
6516 hf_cip_cm_to_net_params16, hf_cip_cm_fwo_own, hf_cip_cm_fwo_typ,
6517 hf_cip_cm_fwo_prio, hf_cip_cm_fwo_fixed_var, hf_cip_cm_fwo_con_size, ett_cm_ncp, &T2O_info);
6518 net_param_offset += 2;
6519 }
6520
6521 TransportClass_trigger = tvb_get_guint8( tvb, offset+26+net_param_offset+4);
6522 dissect_transport_type_trigger(tvb, offset+26+net_param_offset+4, cmd_tree, hf_cip_cm_transport_type_trigger,
6523 hf_cip_cm_fwo_dir, hf_cip_cm_fwo_trigg, hf_cip_cm_fwo_class, ett_cm_ttt);
6524
6525 /* Add path size */
6526 conn_path_size = tvb_get_guint8( tvb, offset+26+net_param_offset+5 )*2;
6527 proto_tree_add_item(cmd_tree, hf_cip_cm_conn_path_size, tvb, offset+26+net_param_offset+5, 1, ENC_LITTLE_ENDIAN);
6528
6529 /* Add the epath */
6530 epath_tree = proto_tree_add_subtree(cmd_tree, tvb, offset+26+net_param_offset+6, conn_path_size, ett_path, &pi, "Connection Path: ");
6531 dissect_epath( tvb, pinfo, epath_tree, pi, offset+26+net_param_offset+6, conn_path_size, FALSE, FALSE, &connection_path, &safety_fwdopen, DISPLAY_CONNECTION_PATH, NULL, FALSE);
6532 save_route_connection_path(pinfo, tvb, offset + 26 + net_param_offset + 6, conn_path_size);
6533
6534 if (pinfo->fd->visited)
6535 {
6536 /* "Connection" is created during ForwardOpen reply (which will be after ForwardOpen request),
6537 so ForwardOpen request can only be marked after the first pass */
6538 enip_mark_connection_triad(pinfo, &conn_triad);
6539 }
6540 else
6541 {
6542 if (preq_info != NULL)
6543 {
6544 DISSECTOR_ASSERT(preq_info->connInfo == NULL);
6545 preq_info->connInfo = wmem_new0(wmem_file_scope(), cip_conn_info_t);
6546
6547 preq_info->connInfo->triad = conn_triad;
6548 preq_info->connInfo->open_req_frame = pinfo->num;
6549
6550 preq_info->connInfo->O2T = O2T_info;
6551 preq_info->connInfo->T2O = T2O_info;
6552
6553 preq_info->connInfo->TransportClass_trigger = TransportClass_trigger;
6554 preq_info->connInfo->safety = safety_fwdopen;
6555 preq_info->connInfo->ClassID = connection_path.iClass;
6556 preq_info->connInfo->ConnPoint = connection_path.iConnPoint;
6557
6558 preq_info->connInfo->FwdOpenPathLenBytes = conn_path_size;
6559 preq_info->connInfo->pFwdOpenPathData = wmem_alloc(wmem_file_scope(), conn_path_size);
6560 tvb_memcpy(tvb, preq_info->connInfo->pFwdOpenPathData, offset + 26 + net_param_offset + 6, conn_path_size);
6561 }
6562 }
6563
6564 mark_cip_connection(pinfo, tvb, cmd_tree);
6565 }
6566
display_previous_route_connection_path(cip_req_info_t * preq_info,proto_tree * item_tree,tvbuff_t * tvb,packet_info * pinfo,int hf_path,int display_type)6567 static void display_previous_route_connection_path(cip_req_info_t *preq_info, proto_tree *item_tree, tvbuff_t *tvb, packet_info *pinfo, int hf_path, int display_type)
6568 {
6569 if (preq_info && preq_info->RouteConnectionPathLen && preq_info->pRouteConnectionPath)
6570 {
6571 tvbuff_t* tvbIOI = tvb_new_real_data((const guint8 *)preq_info->pRouteConnectionPath, preq_info->RouteConnectionPathLen * 2, preq_info->RouteConnectionPathLen * 2);
6572 if (!tvbIOI)
6573 {
6574 return;
6575 }
6576
6577 proto_item* pi = proto_tree_add_uint(item_tree, hf_path, tvb, 0, 0, preq_info->RouteConnectionPathLen);
6578 proto_item_set_generated(pi);
6579
6580 proto_tree* epath_tree = proto_tree_add_subtree(item_tree, tvb, 0, 0, ett_path, &pi, "Route/Connection Path: ");
6581 proto_item_set_generated(pi);
6582
6583 cip_simple_request_info_t route_conn_path;
6584 dissect_epath(tvbIOI, pinfo, epath_tree, pi, 0, preq_info->RouteConnectionPathLen * 2, TRUE, FALSE, &route_conn_path, NULL, display_type, NULL, FALSE);
6585 tvb_free(tvbIOI);
6586 }
6587 }
6588
6589 static int
dissect_cip_cm_fwd_open_rsp_success(cip_req_info_t * preq_info,proto_tree * tree,tvbuff_t * tvb,int offset,packet_info * pinfo)6590 dissect_cip_cm_fwd_open_rsp_success(cip_req_info_t *preq_info, proto_tree *tree, tvbuff_t *tvb, int offset, packet_info *pinfo)
6591 {
6592 int parsed_len = 26;
6593
6594 unsigned char app_rep_size;
6595 guint32 O2TConnID, T2OConnID;
6596 guint16 init_rollover_value = 0, init_timestamp_value = 0;
6597 proto_tree *pid_tree, *safety_tree;
6598 cip_connection_triad_t target_triad = {0};
6599
6600 /* Display originator to target connection ID */
6601 O2TConnID = tvb_get_letohl( tvb, offset );
6602 proto_tree_add_item( tree, hf_cip_cm_ot_connid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
6603
6604 /* Display target to originator connection ID */
6605 T2OConnID = tvb_get_letohl( tvb, offset+4 );
6606 proto_tree_add_item( tree, hf_cip_cm_to_connid, tvb, offset+4, 4, ENC_LITTLE_ENDIAN);
6607
6608 // Add Connection IDs as hidden items so that it's easy to find all Connection IDs in different fields.
6609 proto_item* pi = proto_tree_add_item(tree, hf_cip_connid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
6610 proto_item_set_hidden(pi);
6611 pi = proto_tree_add_item(tree, hf_cip_connid, tvb, offset + 4, 4, ENC_LITTLE_ENDIAN);
6612 proto_item_set_hidden(pi);
6613
6614 cip_connection_triad_t conn_triad;
6615 dissect_connection_triad(tvb, offset + 8, tree,
6616 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
6617 &conn_triad);
6618
6619 /* Display originator to target actual packet interval */
6620 guint32 O2TAPI = tvb_get_letohl( tvb, offset+16 );
6621 proto_tree_add_item(tree, hf_cip_cm_ot_api, tvb, offset + 16, 4, ENC_LITTLE_ENDIAN);
6622
6623 /* Display originator to target actual packet interval */
6624 guint32 T2OAPI = tvb_get_letohl( tvb, offset+20 );
6625 proto_tree_add_item(tree, hf_cip_cm_to_api, tvb, offset + 20, 4, ENC_LITTLE_ENDIAN);
6626
6627 /* Display the application reply size */
6628 app_rep_size = tvb_get_guint8( tvb, offset+24 ) * 2;
6629 proto_tree_add_item(tree, hf_cip_cm_app_reply_size, tvb, offset+24, 1, ENC_LITTLE_ENDIAN);
6630
6631 /* Display the Reserved byte */
6632 proto_tree_add_item(tree, hf_cip_reserved8, tvb, offset+25, 1, ENC_LITTLE_ENDIAN );
6633 if (app_rep_size > 0)
6634 {
6635 if ((preq_info == NULL) || (preq_info->connInfo == NULL) ||
6636 (preq_info->connInfo->safety.safety_seg == FALSE))
6637 {
6638 proto_tree_add_item(tree, hf_cip_cm_app_reply_data, tvb, offset+26, app_rep_size, ENC_NA );
6639 }
6640 else if (preq_info->connInfo->safety.format == CIP_SAFETY_BASE_FORMAT)
6641 {
6642 safety_tree = proto_tree_add_subtree( tree, tvb, offset+26, 10, ett_cip_cm_safety, NULL, "Safety Application Reply Data");
6643 proto_tree_add_item( safety_tree, hf_cip_cm_consumer_number, tvb, offset+26, 2, ENC_LITTLE_ENDIAN);
6644 pid_tree = proto_tree_add_subtree( safety_tree, tvb, offset+28, 8, ett_cip_cm_pid, NULL, "PID/CID");
6645 proto_tree_add_item( pid_tree, hf_cip_cm_targ_vendor_id, tvb, offset+28, 2, ENC_LITTLE_ENDIAN);
6646 target_triad.VendorID = tvb_get_letohs(tvb, offset+28);
6647
6648 proto_tree_add_item_ret_uint( pid_tree, hf_cip_cm_targ_dev_serial_num, tvb, offset+30, 4, ENC_LITTLE_ENDIAN, &target_triad.DeviceSerialNumber);
6649
6650 proto_tree_add_item( pid_tree, hf_cip_cm_targ_conn_serial_num, tvb, offset+34, 2, ENC_LITTLE_ENDIAN);
6651 target_triad.ConnSerialNumber = tvb_get_letohs(tvb, offset+34);
6652
6653 if (app_rep_size > 10)
6654 proto_tree_add_item(tree, hf_cip_cm_app_reply_data, tvb, offset+36, app_rep_size-10, ENC_NA );
6655 }
6656 else if (preq_info->connInfo->safety.format == CIP_SAFETY_EXTENDED_FORMAT)
6657 {
6658 safety_tree = proto_tree_add_subtree( tree, tvb, offset+26, 14, ett_cip_cm_safety, NULL, "Safety Application Reply Data");
6659 proto_tree_add_item( safety_tree, hf_cip_cm_consumer_number, tvb, offset+26, 2, ENC_LITTLE_ENDIAN);
6660 pid_tree = proto_tree_add_subtree( safety_tree, tvb, offset+28, 12, ett_cip_cm_pid, NULL, "PID/CID");
6661 proto_tree_add_item( pid_tree, hf_cip_cm_targ_vendor_id, tvb, offset+28, 2, ENC_LITTLE_ENDIAN);
6662 target_triad.VendorID = tvb_get_letohs(tvb, offset+28);
6663
6664 proto_tree_add_item_ret_uint( pid_tree, hf_cip_cm_targ_dev_serial_num, tvb, offset+30, 4, ENC_LITTLE_ENDIAN, &target_triad.DeviceSerialNumber);
6665
6666 proto_tree_add_item( pid_tree, hf_cip_cm_targ_conn_serial_num, tvb, offset+34, 2, ENC_LITTLE_ENDIAN);
6667 target_triad.ConnSerialNumber = tvb_get_letohs(tvb, offset+34);
6668
6669 proto_tree_add_item( pid_tree, hf_cip_cm_initial_timestamp, tvb, offset+36, 2, ENC_LITTLE_ENDIAN);
6670 init_timestamp_value = tvb_get_letohs(tvb, offset+36);
6671 proto_tree_add_item( pid_tree, hf_cip_cm_initial_rollover, tvb, offset+38, 2, ENC_LITTLE_ENDIAN);
6672 init_rollover_value = tvb_get_letohs(tvb, offset+38);
6673
6674 if (app_rep_size > 14)
6675 proto_tree_add_item(tree, hf_cip_cm_app_reply_data, tvb, offset+40, app_rep_size-14, ENC_NA );
6676 }
6677 }
6678
6679 proto_item* conn_info_item = NULL;
6680 proto_tree* conn_info_tree = proto_tree_add_subtree(tree, tvb, 0, 0, ett_connection_info, &conn_info_item, "Connection Information");
6681 proto_item_set_generated(conn_info_item);
6682
6683 mark_cip_connection(pinfo, tvb, conn_info_tree);
6684 display_previous_route_connection_path(preq_info, conn_info_tree, tvb, pinfo, hf_cip_cm_conn_path_size, DISPLAY_CONNECTION_PATH);
6685
6686 /* See if we've captured the ForwardOpen request. If so some of the conversation data has already been
6687 populated and we just need to update it. */
6688 if (pinfo->fd->visited)
6689 return parsed_len + app_rep_size;
6690
6691 if ((preq_info != NULL) && (preq_info->connInfo != NULL))
6692 {
6693 /* Ensure the connection triad matches before updating the connection IDs */
6694 if ((preq_info->connInfo->triad.ConnSerialNumber == conn_triad.ConnSerialNumber) &&
6695 (preq_info->connInfo->triad.VendorID == conn_triad.VendorID) &&
6696 (preq_info->connInfo->triad.DeviceSerialNumber == conn_triad.DeviceSerialNumber))
6697 {
6698 /* Update the connection IDs as ForwardOpen reply is allowed to update them from
6699 the ForwardOpen request */
6700 preq_info->connInfo->O2T.connID = O2TConnID;
6701 preq_info->connInfo->T2O.connID = T2OConnID;
6702
6703 preq_info->connInfo->O2T.api = O2TAPI;
6704 preq_info->connInfo->T2O.api = T2OAPI;
6705 if (preq_info->connInfo->safety.safety_seg == TRUE)
6706 {
6707 preq_info->connInfo->safety.running_rollover_value = init_rollover_value;
6708 preq_info->connInfo->safety.running_timestamp_value = init_timestamp_value;
6709 preq_info->connInfo->safety.target_triad = target_triad;
6710 }
6711 }
6712 }
6713
6714 return parsed_len + app_rep_size;
6715 }
6716
dissect_cip_cm_unconnected_send_req(proto_tree * cmd_data_tree,tvbuff_t * tvb,int offset,packet_info * pinfo)6717 static void dissect_cip_cm_unconnected_send_req(proto_tree* cmd_data_tree, tvbuff_t* tvb, int offset, packet_info* pinfo)
6718 {
6719 /* Display timeout fields */
6720 dissect_cip_cm_timeout(cmd_data_tree, tvb, offset);
6721
6722 /* Message request size */
6723 guint16 msg_req_siz = tvb_get_letohs(tvb, offset + 2);
6724 proto_tree_add_item(cmd_data_tree, hf_cip_cm_msg_req_size, tvb, offset + 2, 2, ENC_LITTLE_ENDIAN);
6725
6726 /* Message Request */
6727 proto_tree* temp_tree = proto_tree_add_subtree(cmd_data_tree, tvb, offset + 4, msg_req_siz, ett_cm_mes_req, NULL, "CIP Embedded Message Request");
6728
6729 /*
6730 ** We call ourselves again to dissect embedded packet
6731 */
6732
6733 col_append_str(pinfo->cinfo, COL_INFO, ": ");
6734
6735 tvbuff_t* next_tvb = tvb_new_subset_length(tvb, offset + 4, msg_req_siz);
6736 cip_req_info_t* preq_info = (cip_req_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6737 cip_req_info_t* pembedded_req_info = NULL;
6738 if (preq_info)
6739 {
6740 if (preq_info->pData == NULL)
6741 {
6742 pembedded_req_info = wmem_new0(wmem_file_scope(), cip_req_info_t);
6743 preq_info->pData = pembedded_req_info;
6744 }
6745 else
6746 {
6747 pembedded_req_info = (cip_req_info_t*)preq_info->pData;
6748 }
6749 }
6750
6751 dissect_cip_data(temp_tree, next_tvb, 0, pinfo, pembedded_req_info, NULL, FALSE);
6752
6753 if (msg_req_siz % 2)
6754 {
6755 /* Pad byte */
6756 proto_tree_add_item(cmd_data_tree, hf_cip_pad8, tvb, offset + 4 + msg_req_siz, 1, ENC_LITTLE_ENDIAN);
6757 msg_req_siz++; /* include the padding */
6758 }
6759
6760 /* Route Path Size */
6761 guint16 route_path_size = tvb_get_guint8(tvb, offset + 4 + msg_req_siz) * 2;
6762 proto_tree_add_item(cmd_data_tree, hf_cip_cm_route_path_size, tvb, offset + 4 + msg_req_siz, 1, ENC_LITTLE_ENDIAN);
6763
6764 /* Display the Reserved byte */
6765 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset + 5 + msg_req_siz, 1, ENC_LITTLE_ENDIAN);
6766
6767 /* Route Path */
6768 proto_item* epath_item;
6769 proto_tree* epath_tree = proto_tree_add_subtree(cmd_data_tree, tvb, offset + 6 + msg_req_siz, route_path_size, ett_path, &epath_item, "Route Path: ");
6770 dissect_epath(tvb, pinfo, epath_tree, epath_item, offset + 6 + msg_req_siz, route_path_size, FALSE, FALSE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
6771
6772 save_route_connection_path(pinfo, tvb, offset + 6 + msg_req_siz, route_path_size);
6773 }
6774
dissect_cip_cm_fwd_close_req(proto_tree * cmd_data_tree,tvbuff_t * tvb,int offset,packet_info * pinfo)6775 static void dissect_cip_cm_fwd_close_req(proto_tree* cmd_data_tree, tvbuff_t* tvb, int offset, packet_info* pinfo)
6776 {
6777 cip_simple_request_info_t conn_path;
6778
6779 dissect_cip_cm_timeout(cmd_data_tree, tvb, offset);
6780
6781 cip_connection_triad_t conn_triad;
6782 dissect_connection_triad(tvb, offset + 2, cmd_data_tree,
6783 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
6784 &conn_triad);
6785
6786 if (!pinfo->fd->visited)
6787 enip_mark_connection_triad(pinfo, &conn_triad);
6788
6789 /* Add the path size */
6790 guint16 conn_path_size = tvb_get_guint8(tvb, offset + 10) * 2;
6791 proto_tree_add_item(cmd_data_tree, hf_cip_cm_conn_path_size, tvb, offset + 10, 1, ENC_LITTLE_ENDIAN);
6792
6793 /* Display the Reserved byte */
6794 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset + 11, 1, ENC_LITTLE_ENDIAN);
6795
6796 /* Add the EPATH */
6797 proto_item *pi;
6798 proto_tree* epath_tree = proto_tree_add_subtree(cmd_data_tree, tvb, offset + 12, conn_path_size, ett_path, &pi, "Connection Path: ");
6799 dissect_epath(tvb, pinfo, epath_tree, pi, offset + 12, conn_path_size, FALSE, FALSE, &conn_path, NULL, DISPLAY_CONNECTION_PATH, NULL, FALSE);
6800 save_route_connection_path(pinfo, tvb, offset + 12, conn_path_size);
6801
6802 mark_cip_connection(pinfo, tvb, cmd_data_tree);
6803 }
6804
dissect_cip_cm_fwd_close_rsp_success(proto_tree * cmd_data_tree,tvbuff_t * tvb,int offset,packet_info * pinfo,proto_item * cmd_item)6805 static int dissect_cip_cm_fwd_close_rsp_success(proto_tree* cmd_data_tree, tvbuff_t* tvb, int offset, packet_info* pinfo, proto_item* cmd_item)
6806 {
6807 cip_connection_triad_t conn_triad;
6808 dissect_connection_triad(tvb, offset, cmd_data_tree,
6809 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
6810 &conn_triad);
6811
6812 /* Display the application reply size */
6813 guint16 app_rep_size = tvb_get_guint8(tvb, offset + 8) * 2;
6814 proto_tree_add_item(cmd_data_tree, hf_cip_cm_app_reply_size, tvb, offset + 8, 1, ENC_LITTLE_ENDIAN);
6815
6816 /* Display the Reserved byte */
6817 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset + 9, 1, ENC_LITTLE_ENDIAN);
6818 if (app_rep_size > 0)
6819 {
6820 if (tvb_reported_length_remaining(tvb, offset + 10) < app_rep_size)
6821 {
6822 expert_add_info(pinfo, cmd_item, &ei_mal_fwd_close_missing_data);
6823 return 0;
6824 }
6825 proto_tree_add_item(cmd_data_tree, hf_cip_cm_app_reply_data, tvb, offset + 10, app_rep_size, ENC_NA);
6826 }
6827
6828 enip_close_cip_connection(pinfo, &conn_triad);
6829
6830 proto_item* conn_info_item = NULL;
6831 proto_tree* conn_info_tree = proto_tree_add_subtree(cmd_data_tree, tvb, 0, 0, ett_connection_info, &conn_info_item, "Connection Information");
6832 proto_item_set_generated(conn_info_item);
6833
6834 mark_cip_connection(pinfo, tvb, conn_info_tree);
6835
6836 cip_req_info_t* preq_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6837 display_previous_route_connection_path(preq_info, conn_info_tree, tvb, pinfo, hf_cip_cm_conn_path_size, DISPLAY_CONNECTION_PATH);
6838
6839 return 10 + app_rep_size;
6840 }
6841
display_previous_request_path(cip_req_info_t * preq_info,proto_tree * item_tree,tvbuff_t * tvb,packet_info * pinfo,proto_item * msp_item,gboolean is_msp_item)6842 static void display_previous_request_path(cip_req_info_t *preq_info, proto_tree *item_tree, tvbuff_t *tvb, packet_info *pinfo, proto_item* msp_item, gboolean is_msp_item)
6843 {
6844 if (preq_info && preq_info->IOILen && preq_info->pIOI)
6845 {
6846 proto_item *pi;
6847 proto_tree *epath_tree;
6848 tvbuff_t* tvbIOI;
6849
6850 tvbIOI = tvb_new_real_data((const guint8 *)preq_info->pIOI, preq_info->IOILen * 2, preq_info->IOILen * 2);
6851 if (tvbIOI)
6852 {
6853 pi = proto_tree_add_uint(item_tree, hf_cip_request_path_size, tvb, 0, 0, preq_info->IOILen);
6854 proto_item_set_generated(pi);
6855
6856 /* Add the epath */
6857 epath_tree = proto_tree_add_subtree(item_tree, tvb, 0, 0, ett_path, &pi, "Request Path: ");
6858 proto_item_set_generated(pi);
6859
6860 if (preq_info->ciaData == NULL)
6861 {
6862 preq_info->ciaData = wmem_new(wmem_file_scope(), cip_simple_request_info_t);
6863 }
6864
6865 dissect_epath(tvbIOI, pinfo, epath_tree, pi, 0, preq_info->IOILen * 2, TRUE, FALSE, preq_info->ciaData, NULL, DISPLAY_REQUEST_PATH, msp_item, is_msp_item);
6866 tvb_free(tvbIOI);
6867 }
6868 }
6869 }
6870
6871 static void
dissect_cip_cm_data(proto_tree * item_tree,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo)6872 dissect_cip_cm_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
6873 {
6874 proto_item *rrsc_item, *status_item;
6875 proto_tree *rrsc_tree, *cmd_data_tree;
6876 int req_path_size;
6877 unsigned char service, gen_status, add_stat_size;
6878 unsigned short add_status;
6879 int i;
6880 cip_req_info_t *preq_info;
6881
6882 service = tvb_get_guint8( tvb, offset );
6883
6884 /* Special handling for Unconnected send response. If successful, embedded service code is sent.
6885 * If failed, it can be either an Unconnected send response or the embedded service code response. */
6886 preq_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0 );
6887 if ( preq_info != NULL && ( service & CIP_SC_RESPONSE_MASK )
6888 && preq_info->bService == SC_CM_UNCON_SEND
6889 )
6890 {
6891 gen_status = tvb_get_guint8( tvb, offset+2 );
6892 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
6893 if ( add_stat_size == 2 )
6894 add_status = tvb_get_letohs( tvb, offset + 4 );
6895 else
6896 add_status = 0;
6897
6898 if( gen_status == CI_GRC_SUCCESS
6899 || ( ( service & CIP_SC_MASK ) != SC_CM_UNCON_SEND )
6900 || !( ( gen_status == CI_GRC_FAILURE && (add_status == CM_ES_UNCONNECTED_REQUEST_TIMED_OUT ||
6901 add_status == CM_ES_PORT_NOT_AVAILABLE ||
6902 add_status == CM_ES_LINK_ADDRESS_NOT_VALID ||
6903 add_status == CM_ES_INVALID_SEGMENT_IN_CONN_PATH ||
6904 add_status == CM_ES_LINK_ADDRESS_TO_SELF_INVALID))
6905 || gen_status == CI_GRC_NO_RESOURCE
6906 || gen_status == CI_GRC_BAD_PATH
6907 )
6908 )
6909 {
6910 cip_req_info_t* pembedded_req_info = (cip_req_info_t*)preq_info->pData;
6911
6912 if ( pembedded_req_info )
6913 {
6914 tvbuff_t *next_tvb;
6915 void *p_save_proto_data;
6916 gint service_index;
6917 heur_dtbl_entry_t *hdtbl_entry;
6918
6919 p_save_proto_data = p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0 );
6920 p_remove_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6921 p_add_proto_data(wmem_file_scope(), pinfo, proto_cip, 0, pembedded_req_info );
6922
6923 proto_item_set_generated(proto_tree_add_uint_format( item_tree, hf_cip_cm_sc, tvb, 0, 0, SC_CM_UNCON_SEND|CIP_SC_RESPONSE_MASK, "Service: Unconnected Send (Response)" ));
6924 next_tvb = tvb_new_subset_length(tvb, offset, item_length);
6925
6926 display_previous_request_path(pembedded_req_info, item_tree, tvb, pinfo, NULL, FALSE);
6927 display_previous_route_connection_path(preq_info, item_tree, tvb, pinfo, hf_cip_cm_route_path_size, NO_DISPLAY);
6928
6929 /* Check to see if service is 'generic' */
6930 try_val_to_str_idx((service & CIP_SC_MASK), cip_sc_vals, &service_index);
6931
6932 if ( pembedded_req_info && pembedded_req_info->dissector )
6933 {
6934 call_dissector(pembedded_req_info->dissector, next_tvb, pinfo, item_tree );
6935 }
6936 else if (service_index >= 0)
6937 {
6938 /* See if object dissector wants to override generic service handling */
6939 if (!dissector_try_heuristic(heur_subdissector_service, tvb, pinfo, item_tree, &hdtbl_entry, NULL))
6940 {
6941 dissect_cip_generic_service_rsp(tvb, pinfo, item_tree);
6942 }
6943 }
6944 else
6945 {
6946 call_dissector( cip_class_generic_handle, next_tvb, pinfo, item_tree );
6947 }
6948
6949 p_remove_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
6950 p_add_proto_data(wmem_file_scope(), pinfo, proto_cip, 0, p_save_proto_data);
6951
6952 /* Return early because the response was only the embedded message response. */
6953 return;
6954 }
6955 }
6956 }
6957
6958 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CM");
6959
6960 /* Add Service code & Request/Response tree */
6961 rrsc_tree = proto_tree_add_subtree( item_tree, tvb, offset, 1, ett_cm_rrsc, &rrsc_item, "Service: " );
6962
6963 /* Add Request/Response */
6964 proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN );
6965
6966 /* watch for service collisions */
6967 proto_item_append_text( rrsc_item, "%s (%s)",
6968 val_to_str( ( service & CIP_SC_MASK ),
6969 cip_sc_vals_cm , "Unknown Service (0x%02x)"),
6970 val_to_str_const( ( service & CIP_SC_RESPONSE_MASK )>>7,
6971 cip_sc_rr, "") );
6972
6973 /* Add Service code */
6974 proto_tree_add_item(rrsc_tree, hf_cip_cm_sc, tvb, offset, 1, ENC_LITTLE_ENDIAN );
6975 add_cip_service_to_info_column(pinfo, service, cip_sc_vals_cm);
6976
6977 if( service & CIP_SC_RESPONSE_MASK )
6978 {
6979 /* Response message */
6980 gen_status = tvb_get_guint8( tvb, offset+2 );
6981 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
6982
6983 if (gen_status == CI_GRC_FAILURE)
6984 {
6985 /* Dissect object specific error codes */
6986 proto_tree* status_tree = proto_tree_add_subtree(item_tree, tvb, offset+2, 1, ett_status_item, &status_item, "Status: " );
6987
6988 /* Add general status */
6989 proto_tree_add_item(status_tree, hf_cip_cm_genstat, tvb, offset+2, 1, ENC_LITTLE_ENDIAN );
6990 proto_item_append_text( status_item, "%s", val_to_str_ext( gen_status,
6991 &cip_gs_vals_ext , "Unknown Response (%x)") );
6992
6993 /* Add additional status size */
6994 proto_tree_add_item(status_tree, hf_cip_cm_addstat_size, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
6995
6996 if( add_stat_size )
6997 {
6998 add_status = tvb_get_letohs( tvb, offset + 4 );
6999 proto_tree_add_item(status_tree, hf_cip_cm_ext_status, tvb, offset+4, 2, ENC_LITTLE_ENDIAN );
7000 proto_item_append_text(status_item, ", Extended: %s", val_to_str_ext(add_status, &cip_cm_ext_st_vals_ext, "Reserved (0x%04x)"));
7001
7002 switch(add_status)
7003 {
7004 case CM_ES_RPI_NOT_ACCEPTABLE:
7005 if (add_stat_size < 3)
7006 {
7007 expert_add_info(pinfo, status_item, &ei_mal_rpi_no_data);
7008 }
7009 else
7010 {
7011 proto_tree_add_item(status_tree, hf_cip_cm_ext112_ot_rpi_type, tvb, offset+6, 1, ENC_LITTLE_ENDIAN );
7012 proto_tree_add_item(status_tree, hf_cip_cm_ext112_to_rpi_type, tvb, offset+7, 1, ENC_LITTLE_ENDIAN );
7013 proto_tree_add_item(status_tree, hf_cip_cm_ext112_ot_rpi, tvb, offset + 8, 4, ENC_LITTLE_ENDIAN);
7014 proto_tree_add_item(status_tree, hf_cip_cm_ext112_to_rpi, tvb, offset + 12, 4, ENC_LITTLE_ENDIAN);
7015 }
7016 break;
7017 case CM_ES_INVALID_CONFIGURATION_SIZE:
7018 proto_tree_add_item(status_tree, hf_cip_cm_ext126_size, tvb, offset+6, 2, ENC_LITTLE_ENDIAN );
7019 break;
7020 case CM_ES_INVALID_OT_SIZE:
7021 proto_tree_add_item(status_tree, hf_cip_cm_ext127_size, tvb, offset+6, 2, ENC_LITTLE_ENDIAN );
7022 break;
7023 case CM_ES_INVALID_TO_SIZE:
7024 proto_tree_add_item(status_tree, hf_cip_cm_ext128_size, tvb, offset+6, 2, ENC_LITTLE_ENDIAN );
7025 break;
7026 default:
7027 /* Add additional status */
7028 if (add_stat_size > 1)
7029 {
7030 proto_tree* add_status_tree = proto_tree_add_subtree( status_tree, tvb, offset+4, add_stat_size, ett_cm_add_status_item, NULL, "Additional Status" );
7031
7032 for( i=0; i < add_stat_size-2; i += 2 )
7033 proto_tree_add_item(add_status_tree, hf_cip_cm_add_status, tvb, offset+4+i, 2, ENC_LITTLE_ENDIAN );
7034 }
7035 }
7036 }
7037 }
7038
7039 /* If there is any command specific data create a sub-tree for it */
7040 int data_len = item_length - 4 - add_stat_size;
7041 if (data_len > 0)
7042 {
7043 int parsed_len = 0;
7044 offset += (4 + add_stat_size);
7045
7046 proto_item *cmd_item;
7047 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset, data_len,
7048 ett_cm_cmd_data, &cmd_item, "Command Specific Data" );
7049
7050 if( gen_status == CI_GRC_SUCCESS )
7051 {
7052 /* Success responses */
7053 switch (service & CIP_SC_MASK)
7054 {
7055 case SC_CM_FWD_OPEN:
7056 case SC_CM_LARGE_FWD_OPEN:
7057 parsed_len = dissect_cip_cm_fwd_open_rsp_success(preq_info, cmd_data_tree, tvb, offset, pinfo);
7058 break;
7059 case SC_CM_FWD_CLOSE:
7060 parsed_len = dissect_cip_cm_fwd_close_rsp_success(cmd_data_tree, tvb, offset, pinfo, cmd_item);
7061 break;
7062 case SC_CM_GET_CONN_OWNER:
7063 {
7064 /* Get Connection owner response (Success) */
7065 proto_tree_add_item( cmd_data_tree, hf_cip_cm_gco_conn, tvb, offset, 1, ENC_LITTLE_ENDIAN);
7066 proto_tree_add_item( cmd_data_tree, hf_cip_cm_gco_coo_conn, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
7067 proto_tree_add_item( cmd_data_tree, hf_cip_cm_gco_roo_conn, tvb, offset+2, 1, ENC_LITTLE_ENDIAN);
7068 proto_tree_add_item( cmd_data_tree, hf_cip_cm_gco_last_action, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
7069
7070 dissect_connection_triad(tvb, offset + 4, cmd_data_tree,
7071 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
7072 NULL);
7073
7074 parsed_len = 12;
7075 }
7076 break;
7077 case SC_CM_UNCON_SEND: // Unconnected send response (Success)
7078 default:
7079 parsed_len = 0;
7080 break;
7081 }
7082 }
7083 else
7084 {
7085 /* Error responses */
7086 switch (service & CIP_SC_MASK)
7087 {
7088 case SC_CM_FWD_OPEN:
7089 case SC_CM_LARGE_FWD_OPEN:
7090 case SC_CM_FWD_CLOSE:
7091 {
7092 /* Forward open and forward close error response look the same */
7093 cip_connection_triad_t conn_triad;
7094 dissect_connection_triad(tvb, offset, cmd_data_tree,
7095 hf_cip_cm_conn_serial_num, hf_cip_cm_vendor, hf_cip_cm_orig_serial_num,
7096 &conn_triad);
7097
7098 proto_tree_add_item(cmd_data_tree, hf_cip_cm_remain_path_size, tvb, offset+8, 1, ENC_LITTLE_ENDIAN);
7099 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset+9, 1, ENC_LITTLE_ENDIAN);
7100
7101 /* With an error reply the connection will either never be established or it has since already closed
7102 That means the conversation should end too */
7103 enip_close_cip_connection(pinfo, &conn_triad);
7104 if (preq_info != NULL)
7105 {
7106 /* Remove any connection information */
7107 preq_info->connInfo = NULL;
7108 }
7109
7110
7111 display_previous_route_connection_path(preq_info, cmd_data_tree, tvb, pinfo, hf_cip_cm_conn_path_size, DISPLAY_CONNECTION_PATH);
7112
7113 parsed_len = 10;
7114 break;
7115 }
7116 case SC_CM_UNCON_SEND:
7117 /* Unconnected send response (Unsuccess) */
7118 proto_tree_add_item(cmd_data_tree, hf_cip_cm_remain_path_size, tvb, offset, 1, ENC_LITTLE_ENDIAN);
7119 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
7120 display_previous_route_connection_path(preq_info, item_tree, tvb, pinfo, hf_cip_cm_route_path_size, NO_DISPLAY);
7121 parsed_len = 2;
7122 break;
7123 default:
7124 parsed_len = 0;
7125 break;
7126 }
7127 } /* end of if-else( CI_CRC_SUCCESS ) */
7128
7129 int remain_len = tvb_reported_length_remaining(tvb, offset + parsed_len);
7130 if (remain_len > 0)
7131 {
7132 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset + parsed_len, remain_len, ENC_NA);
7133 }
7134 } /* End of if command-specific data present */
7135
7136 } /* End of if reply */
7137 else
7138 {
7139 /* Request message */
7140
7141 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
7142
7143 /* If there is any command specific data creat a sub-tree for it */
7144 if( (item_length-req_path_size-2) != 0 )
7145 {
7146
7147 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2,
7148 ett_cm_cmd_data, NULL, "Command Specific Data" );
7149
7150 /* Check what service code that received */
7151 switch (service)
7152 {
7153 case SC_CM_FWD_OPEN:
7154 /* Forward open Request*/
7155 dissect_cip_cm_fwd_open_req(preq_info, cmd_data_tree, tvb, offset+2+req_path_size, FALSE, pinfo);
7156 break;
7157 case SC_CM_LARGE_FWD_OPEN:
7158 /* Large Forward open Request*/
7159 dissect_cip_cm_fwd_open_req(preq_info, cmd_data_tree, tvb, offset+2+req_path_size, TRUE, pinfo);
7160 break;
7161 case SC_CM_FWD_CLOSE:
7162 dissect_cip_cm_fwd_close_req(cmd_data_tree, tvb, offset + 2 + req_path_size, pinfo);
7163 break;
7164 case SC_CM_UNCON_SEND:
7165 dissect_cip_cm_unconnected_send_req(cmd_data_tree, tvb, offset + 2 + req_path_size, pinfo);
7166 break;
7167 case SC_CM_GET_CONN_OWNER:
7168 {
7169 /* Get Connection Owner Request */
7170
7171 /* Display the Reserved byte */
7172 proto_tree_add_item(cmd_data_tree, hf_cip_reserved8, tvb, offset+2+req_path_size, 1, ENC_LITTLE_ENDIAN);
7173
7174 /* Add path size */
7175 guint16 conn_path_size = tvb_get_guint8( tvb, offset+2+req_path_size+1 )*2;
7176 proto_tree_add_item(cmd_data_tree, hf_cip_cm_conn_path_size, tvb, offset+2+req_path_size+1, 1, ENC_LITTLE_ENDIAN);
7177
7178 /* Add the epath */
7179 proto_item* pi;
7180 proto_tree* epath_tree = proto_tree_add_subtree(cmd_data_tree, tvb, offset+2+req_path_size+2, conn_path_size, ett_path, &pi, "Connection Path: ");
7181 dissect_epath(tvb, pinfo, epath_tree, pi, offset+2+req_path_size+2, conn_path_size, FALSE, FALSE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
7182 break;
7183 }
7184 default:
7185 /* Add data */
7186 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+2+req_path_size, item_length-req_path_size-2, ENC_NA);
7187 }
7188
7189 } /* End of if command-specific data present */
7190
7191 } /* End of if-else( request ) */
7192
7193 } /* End of dissect_cip_cm_data() */
7194
7195 static int
dissect_cip_class_cm(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)7196 dissect_cip_class_cm(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7197 {
7198 proto_item *ti;
7199 proto_tree *class_tree;
7200
7201 /* Create display subtree for the protocol */
7202 ti = proto_tree_add_item(tree, proto_cip_class_cm, tvb, 0, -1, ENC_NA);
7203 class_tree = proto_item_add_subtree( ti, ett_cip_class_cm );
7204
7205 dissect_cip_cm_data( class_tree, tvb, 0, tvb_reported_length(tvb), pinfo );
7206
7207 return tvb_reported_length(tvb);
7208 }
7209
7210 /************************************************
7211 *
7212 * Dissector for CIP PCCC Object
7213 *
7214 ************************************************/
7215 static void
dissect_cip_pccc_data(proto_tree * item_tree,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo)7216 dissect_cip_pccc_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
7217 {
7218 proto_item *rrsc_item;
7219 proto_tree *rrsc_tree, *req_id_tree, *pccc_cmd_tree, *cmd_data_tree;
7220 int req_path_size;
7221 unsigned char service;
7222 int add_status;
7223
7224 service = tvb_get_guint8( tvb, offset );
7225
7226 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP PCCC");
7227
7228 /* Add Service code & Request/Response tree */
7229 rrsc_tree = proto_tree_add_subtree( item_tree, tvb, offset, 1, ett_pccc_rrsc, &rrsc_item, "Service: " );
7230
7231 /* Add Request/Response */
7232 proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7233
7234 /* watch for service collisions */
7235 proto_item_append_text( rrsc_item, "%s (%s)",
7236 val_to_str( ( service & CIP_SC_MASK ),
7237 cip_sc_vals_pccc , "Unknown Service (0x%02x)"),
7238 val_to_str_const( ( service & CIP_SC_RESPONSE_MASK )>>7,
7239 cip_sc_rr, "") );
7240
7241 /* Add Service code */
7242 proto_tree_add_item(rrsc_tree, hf_cip_pccc_sc, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7243 add_cip_service_to_info_column (pinfo, service, cip_sc_vals_pccc);
7244
7245 /* There is a minimum of two bytes different between the request and response request path */
7246 /* Response message */
7247 if ( service & CIP_SC_RESPONSE_MASK )
7248 {
7249 req_path_size = 2 + tvb_get_guint8( tvb, offset+2 )*2;
7250 }
7251 /* Request message */
7252 else
7253 {
7254 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
7255 }
7256
7257 int req_id_offset = offset+req_path_size+2;
7258 int req_id_size = tvb_get_guint8( tvb, req_id_offset );
7259 int pccc_cmd_offset = req_id_offset+req_id_size;
7260
7261 /* Add Requestor ID tree */
7262 req_id_tree = proto_tree_add_subtree( item_tree, tvb, req_id_offset, req_id_size, ett_pccc_req_id, NULL, "Requestor ID" );
7263 /* Add Length of Requestor ID code */
7264 proto_tree_add_item(req_id_tree, hf_cip_pccc_req_id_len, tvb, req_id_offset, 1, ENC_LITTLE_ENDIAN );
7265 /* Add CIP Vendor ID */
7266 proto_tree_add_item(req_id_tree, hf_cip_pccc_cip_vend_id, tvb, req_id_offset+1, 2, ENC_LITTLE_ENDIAN );
7267 /* Add CIP Serial Number */
7268 proto_tree_add_item(req_id_tree, hf_cip_pccc_cip_serial_num, tvb, req_id_offset+3, 4, ENC_LITTLE_ENDIAN );
7269
7270 if( service & CIP_SC_RESPONSE_MASK )
7271 {
7272 /* Add PCCC Response Data tree */
7273 pccc_cmd_tree = proto_tree_add_subtree( item_tree, tvb, pccc_cmd_offset, item_length-req_path_size-2-req_id_size, ett_pccc_req_id, NULL, "PCCC Response Data" );
7274
7275 /* Add Command Code */
7276 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_resp_code, tvb, pccc_cmd_offset, 1, ENC_LITTLE_ENDIAN );
7277 /* Add Status Code */
7278 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_sts_code, tvb, pccc_cmd_offset+1, 1, ENC_LITTLE_ENDIAN );
7279 /* Add Transaction Code */
7280 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_tns_code, tvb, pccc_cmd_offset+2, 2, ENC_LITTLE_ENDIAN );
7281
7282 /* Check the status byte for the EXT_STS signifier - 0xF0 */
7283 add_status = tvb_get_guint8( tvb, pccc_cmd_offset+1 );
7284 // TODO: still need to test this
7285 if ( add_status == PCCC_GS_USE_EXTSTS )
7286 {
7287 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_ext_sts_code, tvb, pccc_cmd_offset+4, 1, ENC_LITTLE_ENDIAN );
7288 }
7289 // handle cases where data is returned in the response
7290 else if (item_length-req_path_size-2-req_id_size-4 != 0)
7291 {
7292 /* Add the data tree */
7293 cmd_data_tree = proto_tree_add_subtree( pccc_cmd_tree, tvb, pccc_cmd_offset+4, item_length-req_path_size-2-req_id_size-4, ett_pccc_cmd_data, NULL, "Function Specific Response Data" );
7294 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_data, tvb, pccc_cmd_offset+4, item_length-req_path_size-2-req_id_size-4, ENC_NA);
7295 }
7296
7297 } /* end of if reply */
7298
7299 /* Request message */
7300 else
7301 {
7302 /* If there is any command specific data create a sub-tree for it */
7303 if( (item_length-req_path_size-2) != 0 )
7304 {
7305 guint32 cmd_code, fnc_code;
7306
7307 /* Add PCCC CMD Data tree */
7308 pccc_cmd_tree = proto_tree_add_subtree( item_tree, tvb, pccc_cmd_offset, item_length-req_path_size-2-req_id_size, ett_pccc_req_id, NULL, "PCCC Command Data" );
7309
7310 /* Add Command Code */
7311 proto_tree_add_item_ret_uint(pccc_cmd_tree, hf_cip_pccc_cmd_code, tvb, pccc_cmd_offset, 1, ENC_LITTLE_ENDIAN, &cmd_code);
7312 /* Add Status Code */
7313 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_sts_code, tvb, pccc_cmd_offset+1, 1, ENC_LITTLE_ENDIAN );
7314 /* Add Transaction Code */
7315 proto_tree_add_item(pccc_cmd_tree, hf_cip_pccc_tns_code, tvb, pccc_cmd_offset+2, 2, ENC_LITTLE_ENDIAN );
7316 /* Add Function Code */
7317 switch(cmd_code)
7318 {
7319 case PCCC_CMD_06:
7320 proto_tree_add_item_ret_uint(pccc_cmd_tree, hf_cip_pccc_fnc_code_06, tvb, pccc_cmd_offset+4, 1, ENC_LITTLE_ENDIAN, &fnc_code);
7321 add_cip_pccc_function_to_info_column(pinfo, fnc_code, cip_pccc_fnc_06_vals);
7322 break;
7323
7324 case PCCC_CMD_07:
7325 proto_tree_add_item_ret_uint(pccc_cmd_tree, hf_cip_pccc_fnc_code_07, tvb, pccc_cmd_offset+4, 1, ENC_LITTLE_ENDIAN, &fnc_code);
7326 add_cip_pccc_function_to_info_column(pinfo, fnc_code, cip_pccc_fnc_07_vals);
7327 break;
7328
7329 case PCCC_CMD_0F:
7330 proto_tree_add_item_ret_uint(pccc_cmd_tree, hf_cip_pccc_fnc_code_0f, tvb, pccc_cmd_offset+4, 1, ENC_LITTLE_ENDIAN, &fnc_code);
7331 add_cip_pccc_function_to_info_column(pinfo, fnc_code, cip_pccc_fnc_0f_vals);
7332 break;
7333
7334 default:
7335 fnc_code = 0;
7336 break;
7337 }
7338
7339 if (item_length-req_path_size-2-req_id_size-5 != 0 )
7340 {
7341 /* Add the data tree */
7342 cmd_data_tree = proto_tree_add_subtree( pccc_cmd_tree, tvb, pccc_cmd_offset+5, item_length-req_path_size-req_id_size-7,
7343 ett_pccc_cmd_data, NULL, "Function Specific Data" );
7344
7345 int running_offset = pccc_cmd_offset+6;
7346 int num_cmds;
7347 int sub_fnc_len;
7348 proto_tree *sub_fnc_tree;
7349
7350 /* Add in parsing of instructions that contain data beyond the FNC code */
7351 /* Instructions that end at the FNC codes are already processed */
7352 switch(cmd_code)
7353 {
7354 case PCCC_CMD_0F:
7355 switch(fnc_code){
7356 /* Change CPU Mode */
7357 case PCCC_FNC_0F_80:
7358 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_cpu_mode_80, tvb, pccc_cmd_offset+5, 1, ENC_NA);
7359 break;
7360 /* Execute Multiple Commands */
7361 case PCCC_FNC_0F_88:
7362 num_cmds = tvb_get_guint8( tvb, pccc_cmd_offset+5 );
7363 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_execute_multi_count, tvb, pccc_cmd_offset+5, 1, ENC_NA);
7364
7365 /* iterate over each of the commands and break them out */
7366 for( int i=0; i < num_cmds; i++ ){
7367 sub_fnc_len = tvb_get_guint8( tvb, running_offset);
7368 sub_fnc_tree = proto_tree_add_subtree_format(cmd_data_tree, tvb, running_offset, sub_fnc_len+1, ett_pccc_req_id, NULL, "Sub Function #%d", i+1);
7369
7370 proto_tree_add_item(sub_fnc_tree, hf_cip_pccc_execute_multi_len, tvb, running_offset, 1, ENC_NA);
7371 proto_tree_add_item(sub_fnc_tree, hf_cip_pccc_execute_multi_fnc, tvb, running_offset+1, 1, ENC_NA);
7372 if( sub_fnc_len > 2 ){
7373 proto_tree_add_item(sub_fnc_tree, hf_cip_pccc_data, tvb, running_offset+2, sub_fnc_len-1, ENC_NA);
7374 }
7375 running_offset = running_offset+sub_fnc_len+1;
7376 }
7377 break;
7378 /* Protected Typed Logical Read with Three Address Fields */
7379 case PCCC_FNC_0F_A2:
7380 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_byte_size, tvb, pccc_cmd_offset+5, 1, ENC_NA);
7381 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_file_num, tvb, pccc_cmd_offset+6, 1, ENC_NA);
7382 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_file_type, tvb, pccc_cmd_offset+7, 1, ENC_NA);
7383 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_element_num, tvb, pccc_cmd_offset+8, 1, ENC_NA);
7384 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_subelement_num, tvb, pccc_cmd_offset+9, 1, ENC_NA);
7385 break;
7386 /* Protected Typed Logical Write with Three Address Fields */
7387 case PCCC_FNC_0F_AA:
7388 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_byte_size, tvb, pccc_cmd_offset+5, 1, ENC_NA);
7389 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_file_num, tvb, pccc_cmd_offset+6, 1, ENC_NA);
7390 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_file_type, tvb, pccc_cmd_offset+7, 1, ENC_NA);
7391 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_element_num, tvb, pccc_cmd_offset+8, 1, ENC_NA);
7392 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_subelement_num, tvb, pccc_cmd_offset+9, 1, ENC_NA);
7393 int byte_size;
7394 byte_size = tvb_get_guint8( tvb, pccc_cmd_offset+5 );
7395
7396 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_data, tvb, pccc_cmd_offset+10, byte_size, ENC_NA);
7397 break;
7398 default: /* just print the command data if no known command code is passed */
7399 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_data, tvb, pccc_cmd_offset+5, item_length-pccc_cmd_offset-5, ENC_NA);
7400 }
7401 break;
7402 default: /* just print the command data if no known command code is passed */
7403 proto_tree_add_item(cmd_data_tree, hf_cip_pccc_data, tvb, pccc_cmd_offset+5, 1, ENC_NA);
7404 }
7405 }
7406 } /* End of if-else( request ) */
7407 }
7408
7409 } /* End of dissect_cip_pccc_data() */
7410
7411 static int
dissect_cip_class_pccc(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)7412 dissect_cip_class_pccc(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7413 {
7414 proto_item *ti;
7415 proto_tree *class_tree;
7416
7417 /* Create display subtree for the protocol */
7418 ti = proto_tree_add_item(tree, proto_cip_class_pccc, tvb, 0, -1, ENC_NA);
7419 class_tree = proto_item_add_subtree( ti, ett_cip_class_pccc );
7420
7421 dissect_cip_pccc_data( class_tree, tvb, 0, tvb_reported_length(tvb), pinfo );
7422
7423 return tvb_reported_length(tvb);
7424 }
7425
7426 /************************************************
7427 *
7428 * Dissector for CIP Modbus Object
7429 *
7430 ************************************************/
7431 static void
dissect_cip_mb_data(proto_tree * item_tree,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo)7432 dissect_cip_mb_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
7433 {
7434 proto_item *rrsc_item;
7435 proto_tree *rrsc_tree, *cmd_data_tree;
7436 tvbuff_t *next_tvb;
7437 int req_path_size;
7438 guint8 gen_status, add_stat_size, service;
7439
7440 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP MB");
7441
7442 /* Add Service code & Request/Response tree */
7443 service = tvb_get_guint8( tvb, offset );
7444 rrsc_tree = proto_tree_add_subtree( item_tree, tvb, offset, 1, ett_mb_rrsc, &rrsc_item, "Service: " );
7445
7446 /* Add Request/Response */
7447 proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7448
7449 proto_item_append_text( rrsc_item, "%s (%s)",
7450 val_to_str( ( service & CIP_SC_MASK ),
7451 cip_sc_vals_mb , "Unknown Service (0x%02x)"),
7452 val_to_str_const( ( service & CIP_SC_RESPONSE_MASK )>>7,
7453 cip_sc_rr, "") );
7454
7455 /* Add Service code */
7456 proto_tree_add_item(rrsc_tree, hf_cip_mb_sc, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7457
7458 if( service & CIP_SC_RESPONSE_MASK )
7459 {
7460 /* Response message */
7461 gen_status = tvb_get_guint8( tvb, offset+2 );
7462 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
7463
7464 /* If there is any command specific data create a sub-tree for it */
7465 if( ( item_length-4-add_stat_size ) != 0 )
7466 {
7467 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size,
7468 ett_mb_cmd_data, NULL, "Command Specific Data" );
7469
7470 if( gen_status == CI_GRC_SUCCESS || gen_status == CI_GRC_SERVICE_ERROR )
7471 {
7472 /* Success responses */
7473 switch (service & CIP_SC_MASK)
7474 {
7475 case SC_MB_READ_DISCRETE_INPUTS:
7476 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);
7477 break;
7478
7479 case SC_MB_READ_COILS:
7480 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);
7481 break;
7482
7483 case SC_MB_READ_INPUT_REGISTERS:
7484 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);
7485 break;
7486
7487 case SC_MB_READ_HOLDING_REGISTERS:
7488 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);
7489 break;
7490
7491 case SC_MB_WRITE_COILS:
7492 proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_start_addr, tvb, offset+4+add_stat_size, 2, ENC_LITTLE_ENDIAN);
7493 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);
7494 break;
7495
7496 case SC_MB_WRITE_HOLDING_REGISTERS:
7497 proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_start_addr, tvb, offset+4+add_stat_size, 2, ENC_LITTLE_ENDIAN);
7498 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);
7499 break;
7500
7501 case SC_MB_PASSTHROUGH:
7502 /* Passthrough response (Success) */
7503 if( tvb_reported_length_remaining(tvb, offset) > 0 )
7504 {
7505 modbus_data_t modbus_data;
7506 modbus_data.packet_type = RESPONSE_PACKET;
7507 modbus_data.mbtcp_transid = 0;
7508 modbus_data.unit_id = 0;
7509
7510 /* dissect the Modbus PDU */
7511 next_tvb = tvb_new_subset_length( tvb, offset+4+add_stat_size, item_length-4-add_stat_size);
7512
7513 /* Call Modbus Dissector */
7514 call_dissector_with_data(modbus_handle, next_tvb, pinfo, cmd_data_tree, &modbus_data);
7515
7516 }
7517 break;
7518
7519 default:
7520 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);
7521 }
7522 }
7523 else
7524 {
7525 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);
7526 }
7527
7528 } /* End of if command-specific data present */
7529
7530 } /* End of if reply */
7531 else
7532 {
7533 /* Request message */
7534 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
7535
7536 /* If there is any command specific data creat a sub-tree for it */
7537 if( (item_length-req_path_size-2) != 0 )
7538 {
7539 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2,
7540 ett_mb_cmd_data, NULL, "Command Specific Data" );
7541
7542 /* Check what service code that received */
7543 switch (service)
7544 {
7545 case SC_MB_READ_DISCRETE_INPUTS:
7546 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);
7547 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);
7548 break;
7549
7550 case SC_MB_READ_COILS:
7551 proto_tree_add_item(cmd_data_tree, hf_cip_mb_read_coils_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
7552 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);
7553 break;
7554
7555 case SC_MB_READ_INPUT_REGISTERS:
7556 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);
7557 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);
7558 break;
7559
7560 case SC_MB_READ_HOLDING_REGISTERS:
7561 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);
7562 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);
7563 break;
7564
7565 case SC_MB_WRITE_COILS:
7566 {
7567 guint16 NumCoils;
7568
7569 proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_coils_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
7570 NumCoils = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
7571 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);
7572 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);
7573 }
7574 break;
7575
7576 case SC_MB_WRITE_HOLDING_REGISTERS:
7577 {
7578 guint16 NumRegisters;
7579
7580 proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_start_addr, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN);
7581 NumRegisters = tvb_get_letohs( tvb, offset+2+req_path_size+2 );
7582 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);
7583 proto_tree_add_item(cmd_data_tree, hf_cip_mb_write_registers_data, tvb, offset+2+req_path_size+4, NumRegisters*2, ENC_NA);
7584 }
7585 break;
7586
7587 case SC_MB_PASSTHROUGH:
7588 /* Passthrough Request */
7589 if( tvb_reported_length_remaining(tvb, offset) > 0 )
7590 {
7591 modbus_data_t modbus_data;
7592 modbus_data.packet_type = QUERY_PACKET;
7593 modbus_data.mbtcp_transid = 0;
7594 modbus_data.unit_id = 0;
7595
7596 /* dissect the Modbus PDU */
7597 next_tvb = tvb_new_subset_length( tvb, offset+2+req_path_size, item_length-req_path_size-2);
7598
7599 /* Call Modbus Dissector */
7600 call_dissector_with_data(modbus_handle, next_tvb, pinfo, cmd_data_tree, &modbus_data);
7601 }
7602 break;
7603
7604 default:
7605 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);
7606 }
7607
7608 } /* End of if command-specific data present */
7609
7610 } /* End of if-else( request ) */
7611
7612 add_cip_service_to_info_column(pinfo, service, cip_sc_vals_mb);
7613 } /* End of dissect_cip_mb_data() */
7614
7615 static int
dissect_cip_class_mb(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)7616 dissect_cip_class_mb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7617 {
7618 proto_item *ti;
7619 proto_tree *class_tree;
7620
7621 /* Create display subtree for the protocol */
7622 ti = proto_tree_add_item(tree, proto_cip_class_mb, tvb, 0, -1, ENC_NA);
7623 class_tree = proto_item_add_subtree( ti, ett_cip_class_mb );
7624
7625 dissect_cip_mb_data( class_tree, tvb, 0, tvb_reported_length(tvb), pinfo );
7626
7627 return tvb_reported_length(tvb);
7628 }
7629
7630 /************************************************
7631 *
7632 * Dissector for CIP Connection Configuration Object
7633 *
7634 ************************************************/
7635 static int
dissect_cip_cco_all_attribute_common(proto_tree * cmd_tree,proto_item * ti,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo)7636 dissect_cip_cco_all_attribute_common( proto_tree *cmd_tree, proto_item *ti,
7637 tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo)
7638 {
7639 proto_item *pi;
7640 proto_tree *tdi_tree, *iomap_tree, *epath_tree;
7641 proto_tree *ncp_tree;
7642 int conn_path_size, variable_data_size = 0, config_data_size;
7643 int iomap_size, ot_rtf, to_rtf;
7644 int temp_data;
7645
7646 /* Connection flags */
7647 temp_data = tvb_get_letohs( tvb, offset);
7648 ot_rtf = (temp_data >> 1) & 7;
7649 to_rtf = (temp_data >> 4) & 7;
7650
7651 static int *const connection_flags[] = {
7652 &hf_cip_cco_con_type,
7653 &hf_cip_cco_ot_rtf,
7654 &hf_cip_cco_to_rtf,
7655 NULL
7656 };
7657 proto_tree_add_bitmask(cmd_tree, tvb, offset, hf_cip_cco_con_flags, ett_cco_con_flag, connection_flags, ENC_LITTLE_ENDIAN);
7658
7659 /* Target device id */
7660 tdi_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+2, 10, ett_cco_tdi, NULL, "Target Device ID");
7661
7662 dissect_deviceid(tvb, offset+2, tdi_tree,
7663 hf_cip_cco_tdi_vendor, hf_cip_cco_tdi_devtype, hf_cip_cco_tdi_prodcode,
7664 hf_cip_cco_tdi_compatibility, hf_cip_cco_tdi_comp_bit, hf_cip_cco_tdi_majorrev, hf_cip_cco_tdi_minorrev, FALSE);
7665
7666 /* CS Data Index Number */
7667 proto_tree_add_item(cmd_tree, hf_cip_cco_cs_data_index, tvb, offset+10, 4, ENC_LITTLE_ENDIAN );
7668
7669 /* Net Connection Parameters */
7670 ncp_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+14, 14, ett_cco_ncp, NULL, "Net Connection Parameters");
7671
7672 /* Timeout multiplier */
7673 proto_tree_add_item(ncp_tree, hf_cip_cco_timeout_multiplier, tvb, offset+14, 1, ENC_LITTLE_ENDIAN );
7674
7675 dissect_transport_type_trigger(tvb, offset+15, ncp_tree, hf_cip_cco_transport_type_trigger,
7676 hf_cip_cco_fwo_dir, hf_cip_cco_fwo_trigger, hf_cip_cco_fwo_class, ett_cco_ttt);
7677
7678 proto_tree_add_item(ncp_tree, hf_cip_cco_ot_rpi, tvb, offset + 16, 4, ENC_LITTLE_ENDIAN);
7679
7680 /* Display O->T network connection parameters */
7681 cip_connID_info_t ignore;
7682 dissect_net_param16(tvb, offset+20, ncp_tree,
7683 hf_cip_cco_ot_net_param16, hf_cip_cco_fwo_own, hf_cip_cco_fwo_typ,
7684 hf_cip_cco_fwo_prio, hf_cip_cco_fwo_fixed_var, hf_cip_cco_fwo_con_size, ett_cco_ncp, &ignore);
7685
7686 proto_tree_add_item(ncp_tree, hf_cip_cco_to_rpi, tvb, offset + 22, 4, ENC_LITTLE_ENDIAN);
7687
7688 /* Display T->O network connection parameters */
7689 dissect_net_param16(tvb, offset+26, ncp_tree,
7690 hf_cip_cco_to_net_param16, hf_cip_cco_fwo_own, hf_cip_cco_fwo_typ,
7691 hf_cip_cco_fwo_prio, hf_cip_cco_fwo_fixed_var, hf_cip_cco_fwo_con_size, ett_cco_ncp, &ignore);
7692
7693 /* Connection Path */
7694 conn_path_size = tvb_get_guint8( tvb, offset+28 )*2;
7695 proto_tree_add_item(cmd_tree, hf_cip_cco_conn_path_size, tvb, offset+28, 1, ENC_LITTLE_ENDIAN);
7696
7697 /* Display the Reserved byte */
7698 proto_tree_add_item(cmd_tree, hf_cip_reserved8, tvb, offset+29, 1, ENC_LITTLE_ENDIAN );
7699
7700 /* Add the epath */
7701 epath_tree = proto_tree_add_subtree(cmd_tree, tvb, offset+30, conn_path_size, ett_path, &pi, "Connection Path: ");
7702 dissect_epath(tvb, pinfo, epath_tree, pi, offset+30, conn_path_size, FALSE, FALSE, NULL, NULL, NO_DISPLAY, NULL, FALSE);
7703
7704 variable_data_size += (conn_path_size+30);
7705
7706 /* Config #1 Data */
7707 config_data_size = tvb_get_letohs( tvb, offset+variable_data_size);
7708 proto_tree_add_item(cmd_tree, hf_cip_cco_proxy_config_size, tvb, offset+variable_data_size, 2, ENC_LITTLE_ENDIAN );
7709 if (config_data_size > 0)
7710 proto_tree_add_item(cmd_tree, hf_cip_cco_proxy_config_data, tvb, offset+variable_data_size+2, config_data_size, ENC_NA);
7711
7712 variable_data_size += (config_data_size+2);
7713
7714 /* Config #2 Data */
7715 config_data_size = tvb_get_letohs( tvb, offset+variable_data_size);
7716 proto_tree_add_item(cmd_tree, hf_cip_cco_target_config_size, tvb, offset+variable_data_size, 2, ENC_LITTLE_ENDIAN );
7717 if (config_data_size > 0)
7718 proto_tree_add_item(cmd_tree, hf_cip_cco_target_config_data, tvb, offset+variable_data_size+2, config_data_size, ENC_NA);
7719
7720 variable_data_size += (config_data_size+2);
7721
7722 /* Connection Name */
7723 variable_data_size += dissect_cip_string_type(pinfo, cmd_tree, ti, tvb, offset + variable_data_size, hf_cip_cco_connection_name, CIP_STRING2_TYPE);
7724
7725 /* I/O Mapping */
7726 iomap_size = tvb_get_letohs( tvb, offset+variable_data_size+2);
7727
7728 iomap_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+variable_data_size, iomap_size+4, ett_cco_iomap, NULL, "I/O Mapping");
7729
7730 proto_tree_add_item(iomap_tree, hf_cip_cco_iomap_format_number, tvb, offset+variable_data_size, 2, ENC_LITTLE_ENDIAN );
7731 proto_tree_add_item(iomap_tree, hf_cip_cco_iomap_size, tvb, offset+variable_data_size+2, 2, ENC_LITTLE_ENDIAN);
7732
7733 /* Attribute data */
7734 if (iomap_size > 0)
7735 proto_tree_add_item(iomap_tree, hf_cip_cco_iomap_attribute, tvb, offset+variable_data_size+4, iomap_size, ENC_NA);
7736
7737 variable_data_size += (iomap_size+4);
7738
7739 /* Proxy device id */
7740 tdi_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+variable_data_size, 8, ett_cco_pdi, NULL, "Proxy Device ID");
7741
7742 dissect_deviceid(tvb, offset+variable_data_size, tdi_tree,
7743 hf_cip_cco_pdi_vendor, hf_cip_cco_pdi_devtype, hf_cip_cco_pdi_prodcode,
7744 hf_cip_cco_pdi_compatibility, hf_cip_cco_pdi_comp_bit, hf_cip_cco_pdi_majorrev, hf_cip_cco_pdi_minorrev, FALSE);
7745
7746 /* Add in proxy device id size */
7747 variable_data_size += 8;
7748
7749 if ((offset+variable_data_size < item_length) &&
7750 ((ot_rtf == 5) || (to_rtf == 5)))
7751 {
7752 /* Safety parameters */
7753 proto_tree_add_item(cmd_tree, hf_cip_cco_safety, tvb, offset+variable_data_size, 55, ENC_NA);
7754 variable_data_size += 55;
7755 }
7756
7757 if (offset+variable_data_size < item_length)
7758 {
7759 proto_tree_add_item(cmd_tree, hf_cip_cco_connection_disable, tvb, offset+variable_data_size, 1, ENC_LITTLE_ENDIAN );
7760 variable_data_size++;
7761 }
7762
7763 if (offset+variable_data_size < item_length)
7764 {
7765 proto_tree_add_item(cmd_tree, hf_cip_cco_net_conn_param_attr, tvb, offset+variable_data_size, 1, ENC_LITTLE_ENDIAN );
7766 variable_data_size++;
7767 }
7768
7769 if (offset+variable_data_size < item_length)
7770 {
7771 /* Large Net Connection Parameter */
7772 ncp_tree = proto_tree_add_subtree( cmd_tree, tvb, offset+variable_data_size, 18, ett_cco_ncp, NULL, "Large Net Connection Parameters");
7773
7774 proto_tree_add_item(ncp_tree, hf_cip_cco_timeout_multiplier, tvb, offset+variable_data_size, 1, ENC_LITTLE_ENDIAN );
7775 dissect_transport_type_trigger(tvb, offset+variable_data_size+1, ncp_tree, hf_cip_cco_transport_type_trigger,
7776 hf_cip_cco_fwo_dir, hf_cip_cco_fwo_trigger, hf_cip_cco_fwo_class, ett_cco_ttt);
7777
7778 proto_tree_add_item(ncp_tree, hf_cip_cco_ot_rpi, tvb, offset + variable_data_size + 2, 4, ENC_LITTLE_ENDIAN);
7779
7780 /* Display O->T network connection parameters */
7781 dissect_net_param32(tvb, offset+variable_data_size+6, ncp_tree,
7782 hf_cip_cco_ot_net_param32, hf_cip_cco_lfwo_own, hf_cip_cco_lfwo_typ,
7783 hf_cip_cco_lfwo_prio, hf_cip_cco_lfwo_fixed_var, hf_cip_cco_lfwo_con_size, ett_cco_ncp, &ignore);
7784
7785 proto_tree_add_item(ncp_tree, hf_cip_cco_to_rpi, tvb, offset + variable_data_size + 10, 4, ENC_LITTLE_ENDIAN);
7786
7787 /* Display T->O network connection parameters */
7788 dissect_net_param32(tvb, offset+variable_data_size+14, ncp_tree,
7789 hf_cip_cco_to_net_param32, hf_cip_cco_lfwo_own, hf_cip_cco_lfwo_typ,
7790 hf_cip_cco_lfwo_prio, hf_cip_cco_lfwo_fixed_var, hf_cip_cco_lfwo_con_size, ett_cco_ncp, &ignore);
7791
7792 variable_data_size += 18;
7793 }
7794
7795 return variable_data_size;
7796 }
7797
7798 static void
dissect_cip_cco_data(proto_tree * item_tree,proto_item * ti,tvbuff_t * tvb,int offset,int item_length,packet_info * pinfo)7799 dissect_cip_cco_data( proto_tree *item_tree, proto_item *ti, tvbuff_t *tvb, int offset, int item_length, packet_info *pinfo )
7800 {
7801 proto_item *rrsc_item;
7802 proto_tree *rrsc_tree, *cmd_data_tree, *con_st_tree;
7803 int req_path_size;
7804 guint8 service, gen_status, add_stat_size;
7805 cip_simple_request_info_t req_data;
7806
7807 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP CCO");
7808
7809 /* Add Service code & Request/Response tree */
7810 service = tvb_get_guint8( tvb, offset );
7811 rrsc_tree = proto_tree_add_subtree( item_tree, tvb, offset, 1, ett_cco_rrsc, &rrsc_item, "Service: " );
7812
7813 /* Add Request/Response */
7814 proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7815
7816 proto_item_append_text( rrsc_item, "%s (%s)",
7817 val_to_str( ( service & CIP_SC_MASK ),
7818 cip_sc_vals_cco , "Unknown Service (0x%02x)"),
7819 val_to_str_const( ( service & CIP_SC_RESPONSE_MASK )>>7,
7820 cip_sc_rr, "") );
7821
7822 /* Add Service code */
7823 proto_tree_add_item(rrsc_tree, hf_cip_cco_sc, tvb, offset, 1, ENC_LITTLE_ENDIAN );
7824
7825 load_cip_request_data(pinfo, &req_data);
7826
7827 if(service & CIP_SC_RESPONSE_MASK )
7828 {
7829 /* Response message */
7830
7831 /* Add additional status size */
7832 gen_status = tvb_get_guint8( tvb, offset+2 );
7833 add_stat_size = tvb_get_guint8( tvb, offset+3 ) * 2;
7834
7835 /* If there is any command specific data create a sub-tree for it */
7836 if( ( item_length-4-add_stat_size ) != 0 )
7837 {
7838 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset+4+add_stat_size, item_length-4-add_stat_size,
7839 ett_cco_cmd_data, NULL, "Command Specific Data" );
7840
7841 if( gen_status == CI_GRC_SUCCESS )
7842 {
7843 /* Success responses */
7844 if (((service & CIP_SC_MASK) == SC_GET_ATT_ALL) &&
7845 (req_data.iInstance != SEGMENT_VALUE_NOT_SET))
7846 {
7847 if (req_data.iInstance == 0)
7848 {
7849 /* Get Attribute All (class) request */
7850 dissect_cip_get_attribute_all_rsp(tvb, pinfo, cmd_data_tree, offset + 4 + add_stat_size, &req_data);
7851 }
7852 else
7853 {
7854 /* Get Attribute All (instance) request */
7855
7856 /* Connection status */
7857 con_st_tree = proto_tree_add_subtree( cmd_data_tree, tvb, offset+4+add_stat_size, 4, ett_cco_con_status, NULL, "Connection Status");
7858
7859 proto_tree_add_item(con_st_tree, hf_cip_genstat, tvb, offset+4+add_stat_size, 1, ENC_LITTLE_ENDIAN );
7860 proto_tree_add_item(con_st_tree, hf_cip_pad8, tvb, offset+4+add_stat_size+1, 1, ENC_LITTLE_ENDIAN);
7861
7862 /* Extended Status */
7863 proto_tree_add_item(con_st_tree, hf_cip_cco_ext_status, tvb, offset+4+add_stat_size+2, 2, ENC_LITTLE_ENDIAN);
7864
7865 dissect_cip_cco_all_attribute_common(cmd_data_tree, ti, tvb, offset+4+add_stat_size+4, item_length, pinfo);
7866 }
7867 }
7868 else
7869 {
7870 /* Add data */
7871 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
7872 }
7873 }
7874 else
7875 {
7876 /* Error responses */
7877
7878 /* Add data */
7879 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+4+add_stat_size, item_length-4-add_stat_size, ENC_NA);
7880 } /* end of if-else( CI_CRC_SUCCESS ) */
7881
7882 } /* End of if command-specific data present */
7883
7884 } /* End of if reply */
7885 else
7886 {
7887 /* Request message */
7888 req_path_size = tvb_get_guint8( tvb, offset+1 )*2;
7889
7890 /* If there is any command specific data create a sub-tree for it */
7891 if( (item_length-req_path_size-2) != 0 )
7892 {
7893
7894 cmd_data_tree = proto_tree_add_subtree( item_tree, tvb, offset+2+req_path_size, item_length-req_path_size-2,
7895 ett_cco_cmd_data, NULL, "Command Specific Data" );
7896
7897 /* Check what service code that received */
7898
7899 switch (service)
7900 {
7901 case SC_CCO_AUDIT_CHANGE:
7902 proto_tree_add_item(cmd_data_tree, hf_cip_cco_change_type, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN );
7903 break;
7904 case SC_CCO_CHANGE_COMPLETE:
7905 proto_tree_add_item(cmd_data_tree, hf_cip_cco_change_type, tvb, offset+2+req_path_size, 2, ENC_LITTLE_ENDIAN );
7906 break;
7907 case SC_SET_ATT_ALL:
7908 if ((req_data.iInstance == 0) ||
7909 (req_data.iInstance == SEGMENT_VALUE_NOT_SET))
7910 {
7911 /* Just add raw data */
7912 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+2+req_path_size, item_length-req_path_size-2, ENC_NA);
7913 break;
7914 }
7915
7916 /* Set Attribute All (instance) request */
7917 dissect_cip_cco_all_attribute_common(cmd_data_tree, ti, tvb, offset+2+req_path_size, item_length, pinfo);
7918 break;
7919 default:
7920
7921 /* Add data */
7922 proto_tree_add_item(cmd_data_tree, hf_cip_data, tvb, offset+2+req_path_size, item_length-req_path_size-2, ENC_NA);
7923 } /* End of check service code */
7924
7925 } /* End of if command-specific data present */
7926
7927 } /* End of if-else( request ) */
7928
7929 add_cip_service_to_info_column(pinfo, service, cip_sc_vals_cco);
7930 } /* End of dissect_cip_cco_data() */
7931
7932 static int
dissect_cip_class_cco(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)7933 dissect_cip_class_cco(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7934 {
7935 proto_item *ti;
7936 proto_tree *class_tree;
7937
7938 /* Create display subtree for the protocol */
7939 ti = proto_tree_add_item(tree, proto_cip_class_cco, tvb, 0, -1, ENC_NA);
7940 class_tree = proto_item_add_subtree( ti, ett_cip_class_cco );
7941
7942 dissect_cip_cco_data( class_tree, ti, tvb, 0, tvb_reported_length(tvb), pinfo );
7943
7944 return tvb_reported_length(tvb);
7945 }
7946
7947 static gboolean
dissect_class_cco_heur(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)7948 dissect_class_cco_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
7949 {
7950 unsigned char service, service_code, ioilen, segment;
7951 cip_req_info_t* preq_info;
7952 guint32 classid = 0;
7953 int offset = 0;
7954
7955 service = tvb_get_guint8( tvb, offset );
7956 service_code = service & CIP_SC_MASK;
7957
7958 /* Handle GetAttributeAll and SetAttributeAll in CCO class */
7959 if ((service_code == SC_GET_ATT_ALL) ||
7960 (service_code == SC_SET_ATT_ALL))
7961 {
7962 if (service & CIP_SC_RESPONSE_MASK)
7963 {
7964 /* Service response */
7965 preq_info = (cip_req_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
7966 if ((preq_info != NULL) &&
7967 (preq_info->dissector == dissector_get_uint_handle( subdissector_class_table, CI_CLS_CCO)))
7968 {
7969 call_dissector(preq_info->dissector, tvb, pinfo, tree);
7970 return TRUE;
7971 }
7972 }
7973 else
7974 {
7975 /* Service request */
7976 ioilen = tvb_get_guint8( tvb, offset + 1 );
7977 if (ioilen > 1)
7978 {
7979 segment = tvb_get_guint8( tvb, offset + 2 );
7980 if (((segment & CI_SEGMENT_TYPE_MASK) == CI_LOGICAL_SEGMENT) &&
7981 ((segment & CI_LOGICAL_SEG_TYPE_MASK) == CI_LOGICAL_SEG_CLASS_ID))
7982 {
7983 /* Logical Class ID, do a format check */
7984 switch ( segment & CI_LOGICAL_SEG_FORMAT_MASK )
7985 {
7986 case CI_LOGICAL_SEG_8_BIT:
7987 classid = tvb_get_guint8( tvb, offset + 3 );
7988 break;
7989 case CI_LOGICAL_SEG_16_BIT:
7990 if ( ioilen >= 2 )
7991 classid = tvb_get_letohs( tvb, offset + 4 );
7992 break;
7993 case CI_LOGICAL_SEG_32_BIT:
7994 if ( ioilen >= 3 )
7995 classid = tvb_get_letohl( tvb, offset + 4 );
7996 break;
7997 }
7998 }
7999 }
8000
8001 if (classid == CI_CLS_CCO)
8002 {
8003 call_dissector(cip_class_cco_handle, tvb, pinfo, tree );
8004 return TRUE;
8005 }
8006
8007 }
8008 }
8009
8010 return FALSE;
8011 }
8012
8013 /************************************************
8014 *
8015 * Dissector for CIP Request/Response
8016 * - matches requests/responses
8017 * - calls class specific dissector
8018 *
8019 ************************************************/
8020
dissect_cip_data(proto_tree * item_tree,tvbuff_t * tvb,int offset,packet_info * pinfo,cip_req_info_t * preq_info,proto_item * msp_item,gboolean is_msp_item)8021 void dissect_cip_data( proto_tree *item_tree, tvbuff_t *tvb, int offset, packet_info *pinfo, cip_req_info_t* preq_info, proto_item* msp_item, gboolean is_msp_item )
8022 {
8023 proto_item *ti;
8024 proto_tree *cip_tree, *epath_tree;
8025 proto_item *pi, *rrsc_item, *status_item;
8026 proto_tree *rrsc_tree, *status_tree, *add_status_tree;
8027 int req_path_size;
8028 unsigned char i, gen_status;
8029 unsigned char service,ioilen,segment;
8030 void *p_save_proto_data;
8031 cip_simple_request_info_t path_info;
8032 dissector_handle_t dissector;
8033 gint service_index;
8034 heur_dtbl_entry_t *hdtbl_entry;
8035
8036 p_save_proto_data = p_get_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
8037 p_remove_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
8038 p_add_proto_data(wmem_file_scope(), pinfo, proto_cip, 0, preq_info);
8039
8040 /* Create display subtree for the protocol */
8041 ti = proto_tree_add_item(item_tree, proto_cip, tvb, 0, -1, ENC_NA);
8042 cip_tree = proto_item_add_subtree( ti, ett_cip );
8043
8044 service = tvb_get_guint8( tvb, offset );
8045
8046 /* Add Service code & Request/Response tree */
8047 rrsc_item = proto_tree_add_uint_format_value(cip_tree, hf_cip_service,
8048 tvb, offset, 1, service, "%s (%s)",
8049 val_to_str( ( service & CIP_SC_MASK ), cip_sc_vals , "Unknown Service (0x%02x)"),
8050 val_to_str_const( ( service & CIP_SC_RESPONSE_MASK )>>7, cip_sc_rr, ""));
8051
8052 rrsc_tree = proto_item_add_subtree( rrsc_item, ett_rrsc );
8053
8054 proto_tree_add_item( rrsc_tree, hf_cip_reqrsp, tvb, offset, 1, ENC_LITTLE_ENDIAN);
8055 proto_tree_add_item(rrsc_tree, hf_cip_service_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
8056
8057 if( service & CIP_SC_RESPONSE_MASK )
8058 {
8059 /* Response message */
8060 status_tree = proto_tree_add_subtree( cip_tree, tvb, offset+2, 1, ett_status_item, &status_item, "Status: " );
8061
8062 /* Add general status */
8063 gen_status = tvb_get_guint8( tvb, offset+2 );
8064 proto_tree_add_item(status_tree, hf_cip_genstat, tvb, offset+2, 1, ENC_LITTLE_ENDIAN );
8065 proto_item_append_text( status_item, "%s: ", val_to_str_ext( gen_status,
8066 &cip_gs_vals_ext , "Unknown Response (%x)") );
8067
8068 if (is_msp_item == FALSE)
8069 {
8070 /* Add reply status to info column */
8071 col_append_fstr(pinfo->cinfo, COL_INFO, "%s: ",
8072 val_to_str_ext(gen_status, &cip_gs_vals_ext, "Unknown Response (%x)"));
8073 }
8074 else
8075 {
8076 proto_item_append_text(msp_item, "%s: ",
8077 val_to_str_ext(gen_status, &cip_gs_vals_ext, "Unknown Response (%x)"));
8078 }
8079
8080 /* Add additional status size */
8081 guint8 add_stat_size = tvb_get_guint8( tvb, offset+3 );
8082 proto_tree_add_item(status_tree, hf_cip_addstat_size, tvb, offset+3, 1, ENC_LITTLE_ENDIAN);
8083
8084 if( add_stat_size )
8085 {
8086 /* Add additional status */
8087 add_status_tree = proto_tree_add_subtree( status_tree, tvb, offset+4, add_stat_size*2, ett_add_status_item, NULL, "Additional Status" );
8088
8089 for( i=0; i < add_stat_size; i ++ )
8090 proto_tree_add_item(add_status_tree, hf_cip_add_stat, tvb, offset+4+(i*2), 2, ENC_LITTLE_ENDIAN );
8091 }
8092
8093 proto_item_set_len( status_item, 2 + add_stat_size*2);
8094
8095 /* The previous packet service must be Unconnected Send, or match the current
8096 service to be a valid match. If they don't, ignore the previous data.*/
8097 if( preq_info
8098 && !( preq_info->bService == ( service & CIP_SC_MASK )
8099 || ( preq_info->bService == SC_CM_UNCON_SEND && preq_info->dissector == cip_class_cm_handle )
8100 )
8101 )
8102 preq_info = NULL;
8103
8104 display_previous_request_path(preq_info, cip_tree, tvb, pinfo, msp_item, is_msp_item);
8105
8106 /* Check to see if service is 'generic' */
8107 try_val_to_str_idx((service & CIP_SC_MASK), cip_sc_vals, &service_index);
8108
8109 /* If the request set a dissector, then check that first. This ensures
8110 that Unconnected Send responses are properly parsed based on the
8111 embedded request. */
8112 if (preq_info && preq_info->dissector)
8113 {
8114 call_dissector(preq_info->dissector, tvb, pinfo, item_tree);
8115 }
8116 else if (service_index >= 0)
8117 {
8118 /* See if object dissector wants to override generic service handling */
8119 if(!dissector_try_heuristic(heur_subdissector_service, tvb, pinfo, item_tree, &hdtbl_entry, NULL))
8120 {
8121 dissect_cip_generic_service_rsp(tvb, pinfo, cip_tree);
8122 }
8123 }
8124 else
8125 {
8126 call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
8127 }
8128 } /* End of if reply */
8129 else
8130 {
8131 /* Request message */
8132
8133 /* Add path size to tree */
8134 req_path_size = tvb_get_guint8( tvb, offset+1);
8135 proto_tree_add_item(cip_tree, hf_cip_request_path_size, tvb, offset+1, 1, ENC_LITTLE_ENDIAN);
8136
8137 /* Add the epath */
8138 epath_tree = proto_tree_add_subtree(cip_tree, tvb, offset+2, req_path_size*2, ett_path, &pi, "Request Path: ");
8139 if (preq_info)
8140 {
8141 preq_info->ciaData = wmem_new(wmem_file_scope(), cip_simple_request_info_t);
8142 dissect_epath(tvb, pinfo, epath_tree, pi, offset+2, req_path_size*2, FALSE, FALSE, preq_info->ciaData, NULL, DISPLAY_REQUEST_PATH, msp_item, is_msp_item);
8143 memcpy(&path_info, preq_info->ciaData, sizeof(cip_simple_request_info_t));
8144 }
8145 else
8146 {
8147 dissect_epath(tvb, pinfo, epath_tree, pi, offset+2, req_path_size*2, FALSE, FALSE, &path_info, NULL, DISPLAY_REQUEST_PATH, msp_item, is_msp_item);
8148 }
8149
8150 ioilen = tvb_get_guint8( tvb, offset + 1 );
8151
8152 if ( preq_info )
8153 preq_info->dissector = NULL;
8154 dissector = NULL;
8155
8156 /* The class ID should already be extracted if it's available */
8157 if (path_info.iClass != 0xFFFFFFFF)
8158 {
8159 dissector = dissector_get_uint_handle( subdissector_class_table, path_info.iClass);
8160 }
8161 else
8162 {
8163 if ( ioilen >= 1 )
8164 {
8165 segment = tvb_get_guint8( tvb, offset + 2 );
8166 if ((segment & CI_SEGMENT_TYPE_MASK) == CI_DATA_SEGMENT)
8167 {
8168 dissector = dissector_get_uint_handle( subdissector_symbol_table, segment );
8169 }
8170 }
8171 }
8172
8173 if ( preq_info )
8174 {
8175 preq_info->dissector = dissector;
8176
8177 /* copy IOI for access by response packet */
8178 preq_info->pIOI = wmem_alloc(wmem_file_scope(), ioilen*2);
8179 preq_info->IOILen = ioilen;
8180 tvb_memcpy(tvb, preq_info->pIOI, offset+2, ioilen*2);
8181
8182 preq_info->bService = service;
8183 }
8184
8185 /* Check to see if service is 'generic' */
8186 try_val_to_str_idx(service, cip_sc_vals, &service_index);
8187 if (service_index >= 0)
8188 {
8189 /* See if object dissector wants to override generic service handling */
8190 if(!dissector_try_heuristic(heur_subdissector_service, tvb, pinfo, item_tree, &hdtbl_entry, NULL))
8191 {
8192 /* No need to set a custom dissector if this is just a generic service. */
8193 if (preq_info)
8194 {
8195 preq_info->dissector = NULL;
8196 }
8197
8198 dissect_cip_generic_service_req(tvb, pinfo, cip_tree, &path_info);
8199 }
8200 }
8201 else if ( dissector )
8202 {
8203 call_dissector( dissector, tvb, pinfo, item_tree );
8204 }
8205 else
8206 {
8207 call_dissector( cip_class_generic_handle, tvb, pinfo, item_tree );
8208 }
8209 } /* End of if-else( request ) */
8210
8211 p_remove_proto_data(wmem_file_scope(), pinfo, proto_cip, 0);
8212 p_add_proto_data(wmem_file_scope(), pinfo, proto_cip, 0, p_save_proto_data);
8213
8214 } /* End of dissect_cip_data() */
8215
dissect_cip_run_idle(tvbuff_t * tvb,int offset,proto_tree * item_tree)8216 void dissect_cip_run_idle(tvbuff_t* tvb, int offset, proto_tree* item_tree)
8217 {
8218 static int * const run_idle_header[] = {
8219 &hf_32bitheader_roo,
8220 &hf_32bitheader_coo,
8221 &hf_32bitheader_run_idle,
8222 NULL
8223 };
8224
8225 proto_tree_add_bitmask(item_tree, tvb, offset, hf_32bitheader, ett_32bitheader_tree, run_idle_header, ENC_LITTLE_ENDIAN);
8226 }
8227
8228 static int
dissect_cip(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data _U_)8229 dissect_cip(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
8230 {
8231 enip_request_info_t *enip_info;
8232 cip_req_info_t *preq_info;
8233
8234 /* Make entries in Protocol column and Info column on summary display */
8235 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP");
8236
8237 col_clear(pinfo->cinfo, COL_INFO);
8238 col_append_sep_str(pinfo->cinfo, COL_INFO, " | ", "");
8239
8240 /* Each CIP request received by ENIP gets a unique ID */
8241 enip_info = (enip_request_info_t*)p_get_proto_data(wmem_file_scope(), pinfo, proto_enip, ENIP_REQUEST_INFO);
8242
8243 if ( enip_info )
8244 {
8245 preq_info = enip_info->cip_info;
8246 if ( preq_info == NULL )
8247 {
8248 preq_info = wmem_new0(wmem_file_scope(), cip_req_info_t);
8249 enip_info->cip_info = preq_info;
8250 }
8251 dissect_cip_data( tree, tvb, 0, pinfo, enip_info->cip_info, NULL, FALSE );
8252 }
8253 else
8254 {
8255 dissect_cip_data( tree, tvb, 0, pinfo, NULL, NULL, FALSE );
8256 }
8257
8258 return tvb_reported_length(tvb);
8259 }
8260
8261 static int
dissect_cip_implicit(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)8262 dissect_cip_implicit(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
8263 {
8264 proto_item *ti;
8265 proto_tree *cip_tree;
8266
8267 guint32 ClassID = GPOINTER_TO_UINT(data);
8268 int length = tvb_reported_length_remaining(tvb, 0);
8269
8270 /* Make entries in Protocol column and Info column on summary display */
8271 col_set_str(pinfo->cinfo, COL_PROTOCOL, "CIP");
8272 col_clear(pinfo->cinfo, COL_INFO);
8273
8274 /* Create display subtree for the protocol */
8275 ti = proto_tree_add_item(tree, proto_cip, tvb, 0, length, ENC_NA);
8276 cip_tree = proto_item_add_subtree(ti, ett_cip);
8277
8278 proto_tree_add_item(cip_tree, hf_cip_data, tvb, 0, length, ENC_NA);
8279
8280 col_append_fstr(pinfo->cinfo, COL_INFO, "Implicit Data - %s",
8281 val_to_str(ClassID, cip_class_names_vals, "Class (0x%02x)"));
8282
8283 return tvb_reported_length(tvb);
8284 }
8285
8286 /*
8287 * Protocol initialization
8288 */
8289
8290 void
proto_register_cip(void)8291 proto_register_cip(void)
8292 {
8293 /* Setup list of header fields */
8294 static hf_register_info hf[] = {
8295 { &hf_attr_class_revision, { "Revision", "cip.class_revision", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8296 { &hf_attr_class_max_instance, { "Max Instance", "cip.max_instance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8297 { &hf_attr_class_num_instance, { "Number of Instances", "cip.num_instance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8298 { &hf_attr_class_opt_attr_num, { "Number of Attributes", "cip.num_attr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8299 { &hf_attr_class_attr_num, { "Attribute Number", "cip.attr_num", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8300 { &hf_attr_class_opt_service_num, { "Number of Services", "cip.num_service", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8301 { &hf_attr_class_service_code, { "Service Code", "cip.service_code", FT_UINT16, BASE_HEX, VALS(cip_sc_vals), 0, NULL, HFILL } },
8302 { &hf_attr_class_num_class_attr, { "Maximum ID Number Class Attributes", "cip.num_class_attr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8303 { &hf_attr_class_num_inst_attr, { "Maximum ID Number Instance Attributes", "cip.num_inst_attr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8304
8305 { &hf_cip_service, { "Service", "cip.service", FT_UINT8, BASE_HEX, NULL, 0, "Service Code + Request/Response", HFILL }},
8306 { &hf_cip_reqrsp, { "Request/Response", "cip.rr", FT_UINT8, BASE_HEX, VALS(cip_sc_rr), CIP_SC_RESPONSE_MASK, "Request or Response message", HFILL }},
8307 { &hf_cip_service_code, { "Service", "cip.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals), CIP_SC_MASK, "Service Code", HFILL }},
8308 { &hf_cip_epath, { "EPath", "cip.epath", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8309 { &hf_cip_genstat, { "General Status", "cip.genstat", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_gs_vals_ext, 0, NULL, HFILL }},
8310 { &hf_cip_addstat_size, { "Additional Status Size", "cip.addstat_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8311 { &hf_cip_add_stat, { "Additional Status", "cip.addstat", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8312 { &hf_cip_request_path_size, { "Request Path Size", "cip.request_path_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8313
8314 { &hf_cip_path_segment, { "Path Segment", "cip.path_segment", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8315 { &hf_cip_path_segment_type, { "Path Segment Type", "cip.path_segment.type", FT_UINT8, BASE_DEC, VALS(cip_path_seg_vals), CI_SEGMENT_TYPE_MASK, NULL, HFILL }},
8316 { &hf_cip_port_ex_link_addr, { "Extended Link Address", "cip.ex_linkaddress", FT_BOOLEAN, 8, TFS(&tfs_true_false), CI_PORT_SEG_EX_LINK_ADDRESS, NULL, HFILL }},
8317 { &hf_cip_port, { "Port", "cip.port", FT_UINT8, BASE_DEC, VALS(cip_port_number_vals), CI_PORT_SEG_PORT_ID_MASK, "Port Identifier", HFILL } },
8318 { &hf_cip_port_extended,{ "Port Extended", "cip.port", FT_UINT16, BASE_HEX, NULL, 0, "Port Identifier Extended", HFILL } },
8319 { &hf_cip_link_address_byte, { "Link Address", "cip.linkaddress.byte", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8320 { &hf_cip_link_address_size, { "Link Address Size", "cip.linkaddress_size", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8321 { &hf_cip_link_address_string, { "Link Address", "cip.linkaddress.string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8322 { &hf_cip_logical_seg_type, { "Logical Segment Type", "cip.logical_segment.type", FT_UINT8, BASE_DEC, VALS(cip_logical_segment_type_vals), CI_LOGICAL_SEG_TYPE_MASK, NULL, HFILL }},
8323 { &hf_cip_logical_seg_format, { "Logical Segment Format", "cip.logical_segment.format", FT_UINT8, BASE_DEC, VALS(cip_logical_segment_format_vals), CI_LOGICAL_SEG_FORMAT_MASK, NULL, HFILL }},
8324 { &hf_cip_class8, { "Class", "cip.class", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0, NULL, HFILL }},
8325 { &hf_cip_class16, { "Class", "cip.class", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0, NULL, HFILL }},
8326 { &hf_cip_class32, { "Class", "cip.class", FT_UINT32, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0, NULL, HFILL }},
8327 { &hf_cip_instance8, { "Instance", "cip.instance", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8328 { &hf_cip_instance16, { "Instance", "cip.instance", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8329 { &hf_cip_instance32, { "Instance", "cip.instance", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8330 { &hf_cip_member8, { "Member", "cip.member", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8331 { &hf_cip_member16, { "Member", "cip.member", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8332 { &hf_cip_member32, { "Member", "cip.member", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8333 { &hf_cip_attribute8, { "Attribute", "cip.attribute", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8334 { &hf_cip_attribute16, { "Attribute", "cip.attribute", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8335 { &hf_cip_attribute32, { "Attribute", "cip.attribute", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8336 { &hf_cip_conpoint8, { "Connection Point", "cip.connpoint", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8337 { &hf_cip_conpoint16, { "Connection Point", "cip.connpoint", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8338 { &hf_cip_conpoint32, { "Connection Point", "cip.connpoint", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8339 { &hf_cip_serviceid8,{ "Service ID", "cip.serviceid", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
8340 { &hf_cip_ekey_format, { "Key Format", "cip.ekey.format", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8341 { &hf_cip_ekey_vendor, { "Vendor ID", "cip.ekey.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
8342 { &hf_cip_ekey_devtype, { "Device Type", "cip.ekey.devtype", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, NULL, HFILL }},
8343 { &hf_cip_ekey_prodcode, { "Product Code", "cip.ekey.product_code", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8344 { &hf_cip_ekey_compatibility, { "Compatibility", "cip.ekey.compatibility", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8345 { &hf_cip_ekey_comp_bit, { "Compatibility", "cip.ekey.comp_bit", FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80, "EKey: Compatibility bit", HFILL }},
8346 { &hf_cip_ekey_majorrev, { "Major Revision", "cip.ekey.major_rev", FT_UINT8, BASE_DEC, NULL, 0x7F, "EKey: Major Revision", HFILL }},
8347 { &hf_cip_ekey_minorrev, { "Minor Revision", "cip.ekey.minor_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8348 { &hf_cip_ekey_serial_number, { "Serial Number", "cip.ekey.serial_number", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8349 { &hf_cip_ext_logical8,{ "Extended Logical", "cip.extlogical", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
8350 { &hf_cip_ext_logical16,{ "Extended Logical", "cip.extlogical", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
8351 { &hf_cip_ext_logical32,{ "Extended Logical", "cip.extlogical", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } },
8352 { &hf_cip_ext_logical_type,{ "Extended Logical Type", "cip.extlogical.type", FT_UINT8, BASE_HEX, VALS(cip_ext_logical_segment_format_vals), 0, NULL, HFILL } },
8353 { &hf_cip_data_seg_type, { "Data Segment Type", "cip.data_segment.type", FT_UINT8, BASE_DEC, VALS(cip_data_segment_type_vals), CI_DATA_SEG_TYPE_MASK, NULL, HFILL }},
8354 { &hf_cip_data_seg_size_simple, { "Data Size", "cip.data_segment.size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8355 { &hf_cip_data_seg_size_extended, { "Data Size", "cip.data_segment.size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0, NULL, HFILL } },
8356 { &hf_cip_data_seg_item, { "Data", "cip.data_segment.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8357 { &hf_cip_symbol, { "ANSI Symbol", "cip.symbol", FT_STRING, BASE_NONE, NULL, 0, "ANSI Extended Symbol Segment", HFILL }},
8358 { &hf_cip_symbol_size, { "Symbolic Symbol Size", "cip.symbol.size", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } },
8359 { &hf_cip_symbol_ascii, { "ASCII Symbol", "cip.ascii_symbol", FT_STRING, BASE_NONE, NULL, 0, "ASCII Symbol Segment", HFILL } },
8360 { &hf_cip_symbol_extended_format,{ "Extended String Format", "cip.symbol.format", FT_UINT8, BASE_DEC, VALS(cip_symbolic_format_vals), CI_SYMBOL_SEG_FORMAT_MASK, NULL, HFILL } },
8361 { &hf_cip_symbol_numeric_format,{ "Extended String Numeric Format", "cip.symbol.numformat", FT_UINT8, BASE_DEC, VALS(cip_symbolic_numeric_format_vals), 0x1F, NULL, HFILL } },
8362 { &hf_cip_symbol_double_size, { "Double Byte Chars", "cip.symbol.size", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } },
8363 { &hf_cip_symbol_triple_size, { "Triple Byte Chars", "cip.symbol.size", FT_UINT8, BASE_DEC, NULL, 0x1F, NULL, HFILL } },
8364 { &hf_cip_numeric_usint,{ "Numeric Symbol", "cip.numeric_symbol", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
8365 { &hf_cip_numeric_uint,{ "Numeric Symbol", "cip.numeric_symbol", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
8366 { &hf_cip_numeric_udint,{ "Numeric Symbol", "cip.numeric_symbol", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } },
8367 { &hf_cip_network_seg_type, { "Network Segment Type", "cip.network_segment.type", FT_UINT8, BASE_DEC, VALS(cip_network_segment_type_vals), CI_NETWORK_SEG_TYPE_MASK, NULL, HFILL }},
8368 { &hf_cip_seg_schedule, { "Multiplier/Phase", "cip.network_segment.schedule", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8369 { &hf_cip_seg_fixed_tag, { "Fixed Tag", "cip.network_segment.fixed_tag", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8370 { &hf_cip_seg_prod_inhibit_time, { "Production Inhibit Time (ms)", "cip.network_segment.prod_inhibit", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8371 { &hf_cip_seg_prod_inhibit_time_us, { "Production Inhibit Time (us)", "cip.network_segment.prod_inhibit", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
8372 { &hf_cip_seg_network_size, { "Network Segment Length", "cip.network_segment.length", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8373 { &hf_cip_seg_network_subtype, { "Extended Segment Subtype", "cip.network_segment.subtype", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
8374 { &hf_cip_seg_safety_format, { "Safety Format", "cip.safety_segment.format", FT_UINT8, BASE_DEC, VALS(cip_safety_segment_format_type_vals), 0, NULL, HFILL }},
8375 { &hf_cip_seg_safety_reserved, { "Reserved", "cip.safety_segment.reserved", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8376 { &hf_cip_seg_safety_configuration_crc, { "Configuration CRC (SCCRC)", "cip.safety_segment.configuration_crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8377 { &hf_cip_seg_safety_configuration_timestamp, { "Configuration Timestamp (SCTS)", "cip.safety_segment.configuration_timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
8378 { &hf_cip_seg_safety_configuration_date, { "Configuration (Manual) Date", "cip.safety_segment.configuration_date", FT_UINT16, BASE_HEX, VALS(cipsafety_snn_date_vals), 0, NULL, HFILL }},
8379 { &hf_cip_seg_safety_configuration_time, { "Configuration (Manual) Time", "cip.safety_segment.configuration_time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8380 { &hf_cip_seg_safety_time_correction_epi, { "Time Correction EPI", "cip.safety_segment.time_correction_eri", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8381 { &hf_cip_seg_safety_time_correction_net_params, { "Time Correction Network Connection Parameters", "cip.safety_segment.time_correction.net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8382 { &hf_cip_seg_safety_time_correction_own, { "Redundant Owner", "cip.safety_segment.time_correction.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, "Time Correction: Redundant owner bit", HFILL }},
8383 { &hf_cip_seg_safety_time_correction_typ, { "Connection Type", "cip.safety_segment.time_correction.type", FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000, "Time Correction: Connection type", HFILL }},
8384 { &hf_cip_seg_safety_time_correction_prio, { "Priority", "cip.safety_segment.time_correction.prio", FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00, "Time Correction: Connection priority", HFILL }},
8385 { &hf_cip_seg_safety_time_correction_fixed_var, { "Connection Size Type", "cip.safety_segment.time_correction.f_v", FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200, "Time Correction: Fixed or variable connection size", HFILL }},
8386 { &hf_cip_seg_safety_time_correction_con_size, { "Connection Size", "cip.safety_segment.time_correction.consize", FT_UINT16, BASE_DEC, NULL, 0x01FF, "Time Correction: Connection size", HFILL }},
8387 { &hf_cip_seg_safety_tunid, { "Target UNID", "cip.safety_segment.tunid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8388 { &hf_cip_seg_safety_tunid_snn_timestamp, { "SNN Timestamp", "cip.safety_segment.tunid.snn.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
8389 { &hf_cip_seg_safety_tunid_snn_date, { "SNN (Manual) Date", "cip.safety_segment.tunid.snn.date", FT_UINT16, BASE_HEX, VALS(cipsafety_snn_date_vals), 0, NULL, HFILL }},
8390 { &hf_cip_seg_safety_tunid_snn_time, { "SNN (Manual) Time", "cip.safety_segment.tunid.snn.time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8391 { &hf_cip_seg_safety_tunid_nodeid, { "Node ID", "cip.safety_segment.tunid.nodeid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8392 { &hf_cip_seg_safety_ounid, { "Originator UNID", "cip.safety_segment.ounid", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8393 { &hf_cip_seg_safety_ounid_snn_timestamp, { "SNN Timestamp", "cip.safety_segment.tunid.snn.timestamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_UTC, NULL, 0, NULL, HFILL }},
8394 { &hf_cip_seg_safety_ounid_snn_date, { "SNN (Manual) Date", "cip.safety_segment.tunid.snn.date", FT_UINT16, BASE_HEX, VALS(cipsafety_snn_date_vals), 0, NULL, HFILL }},
8395 { &hf_cip_seg_safety_ounid_snn_time, { "SNN (Manual) Time", "cip.safety_segment.tunid.snn.time", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8396 { &hf_cip_seg_safety_ounid_nodeid, { "Node ID", "cip.safety_segment.ounid.nodeid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8397 { &hf_cip_seg_safety_ping_eri_multiplier, { "Ping Interval EPI Multiplier", "cip.safety_segment.ping_eri_multiplier", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8398 { &hf_cip_seg_safety_time_coord_msg_min_multiplier, { "Time Coord Msg Min Multiplier", "cip.safety_segment.time_coord_msg_min_multiplier", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8399 { &hf_cip_seg_safety_network_time_expected_multiplier, { "Network Time Expectation Multiplier", "cip.safety_segment.network_time_expected_multiplier", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_safety_128us, 0, NULL, HFILL }},
8400 { &hf_cip_seg_safety_timeout_multiplier, { "Timeout Multiplier", "cip.safety_segment.timeout_multiplier", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8401 { &hf_cip_seg_safety_max_consumer_number, { "Max Consumer Number", "cip.safety_segment.max_consumer_number", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8402 { &hf_cip_seg_safety_conn_param_crc, { "Connection Param CRC (CPCRC)", "cip.safety_segment.conn_param_crc", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8403 { &hf_cip_seg_safety_time_correction_conn_id, { "Time Correction Connection ID", "cip.safety_segment.time_correction_conn_id", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8404 { &hf_cip_seg_safety_max_fault_number, { "Max Fault Number", "cip.safety_segment.max_fault_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8405 { &hf_cip_seg_safety_init_timestamp, { "Initial Timestamp", "cip.safety_segment.init_timestamp", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8406 { &hf_cip_seg_safety_init_rollover, { "Initial Rollover Value", "cip.safety_segment.init_rollover", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8407 { &hf_cip_seg_safety_data, { "Safety Data", "cip.safety_segment.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8408 { &hf_cip_class_max_inst32, { "Max Instance", "cip.class.max_inst", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8409 { &hf_cip_class_num_inst32, { "Number of Instances", "cip.class.num_inst", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8410 { &hf_cip_reserved8, { "Reserved", "cip.reserved", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8411 { &hf_cip_reserved24, { "Reserved", "cip.reserved", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL }},
8412 { &hf_cip_pad8, { "Pad Byte", "cip.pad", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8413
8414 { &hf_cip_sc_get_attr_list_attr_count, { "Attribute Count", "cip.getlist.attr_count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8415 { &hf_cip_sc_get_attr_list_attr_status, { "Attribute Status", "cip.getlist.attr_status", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_gs_vals_ext, 0, NULL, HFILL }},
8416 { &hf_cip_sc_set_attr_list_attr_count, { "Attribute Count", "cip.setlist.attr_count", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8417 { &hf_cip_sc_set_attr_list_attr_status, { "Attribute Status", "cip.setlist.attr_status", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_gs_vals_ext, 0, NULL, HFILL }},
8418 { &hf_cip_sc_reset_param, { "Reset type", "cip.reset.type", FT_UINT8, BASE_DEC, VALS(cip_reset_type_vals), 0, NULL, HFILL }},
8419 { &hf_cip_sc_create_instance, { "Instance", "cip.create.instance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8420 { &hf_cip_sc_mult_serv_pack_num_services, { "Number of Services", "cip.msp.num_services", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8421 { &hf_cip_sc_mult_serv_pack_offset, { "Offset", "cip.msp.offset", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8422 { &hf_cip_find_next_object_max_instance, { "Maximum ID", "cip.find_next_object.max_instance", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8423 { &hf_cip_find_next_object_num_instances, { "Number of Instances", "cip.find_next_object.num_instances", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8424 { &hf_cip_find_next_object_instance_item, { "Instance", "cip.find_next_object.instance", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8425 { &hf_cip_sc_group_sync_is_sync, { "IsSynchronized", "cip.group_sync.is_sync", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8426 { &hf_cip_data, { "Data", "cip.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8427
8428 { &hf_id_vendor_id, { "Vendor ID", "cip.id.vendor_id", FT_UINT16, BASE_HEX | BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL } },
8429 { &hf_id_device_type, { "Device Type", "cip.id.device_type", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, NULL, HFILL }},
8430 { &hf_id_product_code, { "Product Code", "cip.id.product_code", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8431 { &hf_id_major_rev, { "Major Revision", "cip.id.major_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8432 { &hf_id_minor_rev, { "Minor Revision", "cip.id.minor_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8433 { &hf_id_status, { "Status", "cip.id.status", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8434 { &hf_id_serial_number, { "Serial Number", "cip.id.serial_number", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8435 { &hf_id_product_name, { "Product Name", "cip.id.product_name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8436 { &hf_id_state, { "State", "cip.id.state", FT_UINT8, BASE_HEX, VALS(cip_id_state_vals), 0, NULL, HFILL } },
8437 { &hf_id_config_value, { "Configuration Consistency Value", "cip.id.config_value", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL } },
8438 { &hf_id_heartbeat, { "Heartbeat Interval", "cip.id.heartbeat", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
8439 { &hf_id_status_owned, { "Owned", "cip.id.owned", FT_UINT16, BASE_DEC, NULL, 0x0001, NULL, HFILL } },
8440 { &hf_id_status_conf, { "Configured", "cip.id.conf", FT_UINT16, BASE_DEC, NULL, 0x0004, NULL, HFILL } },
8441 { &hf_id_status_extended1, { "Extended Device Status", "cip.id.ext", FT_UINT16, BASE_HEX, NULL, 0x00F0, NULL, HFILL } },
8442 { &hf_id_status_minor_fault_rec, { "Minor Recoverable Fault", "cip.id.minor_fault1", FT_UINT16, BASE_DEC, NULL, 0x0100, NULL, HFILL } },
8443 { &hf_id_status_minor_fault_unrec, { "Minor Unrecoverable Fault", "cip.id.minor_fault2", FT_UINT16, BASE_DEC, NULL, 0x0200, NULL, HFILL } },
8444 { &hf_id_status_major_fault_rec, { "Major Recoverable Fault", "cip.id.major_fault1", FT_UINT16, BASE_DEC, NULL, 0x0400, NULL, HFILL } },
8445 { &hf_id_status_major_fault_unrec, { "Major Unrecoverable Fault", "cip.id.major_fault2", FT_UINT16, BASE_DEC, NULL, 0x0800, NULL, HFILL } },
8446 { &hf_id_status_extended2, { "Extended Device Status 2", "cip.id.ext2", FT_UINT16, BASE_HEX, NULL, 0xF000, NULL, HFILL } },
8447
8448 { &hf_msg_rout_num_classes, { "Number of Classes", "cip.mr.num_classes", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8449 { &hf_msg_rout_classes, { "Class", "cip.mr.class", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_class_names_vals_ext, 0, NULL, HFILL }},
8450 { &hf_msg_rout_num_available, { "Number Available", "cip.mr.num_available", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8451 { &hf_msg_rout_num_active, { "Number Active", "cip.mr.num_active", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8452 { &hf_msg_rout_active_connections, { "Active Connection", "cip.mr.active_connections", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8453
8454 { &hf_conn_mgr_open_requests, { "Open Requests", "cip.cm.open_requests", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8455 { &hf_conn_mgr_open_format_rejects, { "Open Format Rejects", "cip.cm.open_format_rejects", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8456 { &hf_conn_mgr_open_resource_rejects, { "Open Resource Rejects", "cip.cm.open_resource_rejects", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8457 { &hf_conn_mgr_other_open_rejects, { "Other Open Rejects", "cip.cm.other_open_rejects", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8458 { &hf_conn_mgr_close_requests, { "Close Requests", "cip.cm.close_requests", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8459 { &hf_conn_close_format_requests, { "Close Format Requests", "cip.cm.close_format_requests", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8460 { &hf_conn_mgr_close_other_requests, { "Close Other Requests", "cip.cm.close_other_requests", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8461 { &hf_conn_mgr_conn_timouts, { "Connection Timeouts", "cip.cm.conn_timouts", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8462 { &hf_conn_mgr_num_conn_entries, { "Number of Connection Entries (Bits)", "cip.cm.conn_entries", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8463 { &hf_conn_mgr_num_conn_entries_bytes, { "Number of Connection Entries (Bytes)", "cip.cm.conn_entries_bytes", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8464 { &hf_conn_mgr_conn_open_bits, { "Connection Open Bits", "cip.cm.conn_open_bits", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8465 { &hf_conn_mgr_cpu_utilization, { "CPU Utilization", "cip.cm.cpu_util", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8466 { &hf_conn_mgr_max_buff_size, { "Max Buff Size", "cip.cm.max_buff_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
8467 { &hf_conn_mgr_buff_size_remaining, { "Buff Size Remaining", "cip.cm.buff_remain", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL } },
8468
8469 { &hf_stringi_number_char, { "Number of Characters", "cip.stringi.num", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
8470 { &hf_stringi_language_char, { "Language Chars", "cip.stringi.language_char", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
8471 { &hf_stringi_char_string_struct, { "Char String Struct", "cip.stringi.char_string_struct", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL } },
8472 { &hf_stringi_char_set, { "Char Set", "cip.stringi.char_set", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8473 { &hf_stringi_international_string, { "International String", "cip.stringi.int_string", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
8474
8475 { &hf_file_filename, { "File Name", "cip.file.file_name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
8476
8477 { &hf_time_sync_ptp_enable, { "PTP Enable", "cip.time_sync.ptp_enable", FT_BOOLEAN, 8, TFS(&tfs_enabled_disabled), 0, NULL, HFILL }},
8478 { &hf_time_sync_is_synchronized, { "Is Synchronized", "cip.time_sync.is_synchronized", FT_BOOLEAN, 8, TFS(&tfs_true_false), 0, NULL, HFILL }},
8479 { &hf_time_sync_sys_time_micro, { "System Time (Microseconds)", "cip.time_sync.sys_time_micro", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, NULL, HFILL }},
8480 { &hf_time_sync_sys_time_nano, { "System Time (Nanoseconds)", "cip.time_sync.sys_time_nano", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, NULL, HFILL }},
8481 { &hf_time_sync_offset_from_master, { "Offset from Master", "cip.time_sync.offset_from_master", FT_INT64, BASE_DEC, NULL, 0, NULL, HFILL }},
8482 { &hf_time_sync_max_offset_from_master, { "Max Offset from Master", "cip.time_sync.max_offset_from_master", FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL }},
8483 { &hf_time_sync_mean_path_delay_to_master, { "Mean Path Delay To Master", "cip.time_sync.mean_path_delay_to_master", FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL }},
8484 { &hf_time_sync_gm_clock_clock_id, { "Clock Identity", "cip.time_sync.gm_clock.clock_id", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8485 { &hf_time_sync_gm_clock_clock_class, { "Clock Class", "cip.time_sync.gm_clock.clock_class", FT_UINT16, BASE_DEC, VALS(cip_time_sync_clock_class_vals), 0, NULL, HFILL }},
8486 { &hf_time_sync_gm_clock_time_accuracy, { "Time Accuracy", "cip.time_sync.gm_clock.time_accuracy", FT_UINT16, BASE_DEC, VALS(cip_time_sync_time_accuracy_vals), 0, NULL, HFILL }},
8487 { &hf_time_sync_gm_clock_offset_scaled_log_variance, { "Offset Scaled Log Variance", "cip.time_sync.gm_clock.offset_scaled_log_variance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8488 { &hf_time_sync_gm_clock_current_utc_offset, { "Current UTC Offset", "cip.time_sync.gm_clock.current_utc_offset", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8489 { &hf_time_sync_gm_clock_time_property_flags, { "Time Property Flags", "cip.time_sync.gm_clock.time_property_flags", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8490 { &hf_time_sync_gm_clock_time_property_flags_leap61, { "Leap indicator 61", "cip.time_sync.gm_clock.time_property_flags.leap61", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
8491 { &hf_time_sync_gm_clock_time_property_flags_leap59, { "Leap indicator 59", "cip.time_sync.gm_clock.time_property_flags.leap59", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
8492 { &hf_time_sync_gm_clock_time_property_flags_current_utc_valid, { "Current UTC Offset Valid", "cip.time_sync.gm_clock.time_property_flags.current_utc_valid", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x04, NULL, HFILL }},
8493 { &hf_time_sync_gm_clock_time_property_flags_ptp_timescale, { "PTP Timescale", "cip.time_sync.gm_clock.time_property_flags.ptp_timescale", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x08, NULL, HFILL }},
8494 { &hf_time_sync_gm_clock_time_property_flags_time_traceable, { "Time traceable", "cip.time_sync.gm_clock.time_property_flags.time_traceable", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x10, NULL, HFILL }},
8495 { &hf_time_sync_gm_clock_time_property_flags_freq_traceable, { "Frequency traceable", "cip.time_sync.gm_clock.time_property_flags.freq_traceable", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x20, NULL, HFILL }},
8496 { &hf_time_sync_gm_clock_time_source, { "Time Source", "cip.time_sync.gm_clock.time_source", FT_UINT16, BASE_DEC, VALS(cip_time_sync_time_source_vals), 0, NULL, HFILL }},
8497 { &hf_time_sync_gm_clock_priority1, { "Priority1", "cip.time_sync.gm_clock.priority1", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8498 { &hf_time_sync_gm_clock_priority2, { "Priority2", "cip.time_sync.gm_clock.priority2", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8499 { &hf_time_sync_parent_clock_clock_id, { "Clock Identity", "cip.time_sync.parent_clock.clock_id", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8500 { &hf_time_sync_parent_clock_port_number, { "Port Number", "cip.time_sync.parent_clock.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8501 { &hf_time_sync_parent_clock_observed_offset_scaled_log_variance, { "Observed Offset Scaled Log Variance", "cip.time_sync.parent_clock.observed_offset_scaled_log_variance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8502 { &hf_time_sync_parent_clock_observed_phase_change_rate, { "Observed Phase Change Rate", "cip.time_sync.parent_clock.observed_phase_change_rate", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8503 { &hf_time_sync_local_clock_clock_id, { "Clock Identity", "cip.time_sync.local_clock.clock_id", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8504 { &hf_time_sync_local_clock_clock_class, { "Clock Class", "cip.time_sync.local_clock.clock_class", FT_UINT16, BASE_DEC, VALS(cip_time_sync_clock_class_vals), 0, NULL, HFILL }},
8505 { &hf_time_sync_local_clock_time_accuracy, { "Time Accuracy", "cip.time_sync.local_clock.time_accuracy", FT_UINT16, BASE_DEC, VALS(cip_time_sync_time_accuracy_vals), 0, NULL, HFILL }},
8506 { &hf_time_sync_local_clock_offset_scaled_log_variance, { "Offset Scaled Log Variance", "cip.time_sync.local_clock.offset_scaled_log_variance", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8507 { &hf_time_sync_local_clock_current_utc_offset, { "Current UTC Offset", "cip.time_sync.local_clock.current_utc_offset", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8508 { &hf_time_sync_local_clock_time_property_flags, { "Time Property Flags", "cip.time_sync.local_clock.time_property_flags", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8509 { &hf_time_sync_local_clock_time_property_flags_leap61, { "Leap indicator 61", "cip.time_sync.local_clock.time_property_flags.leap61", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x01, NULL, HFILL }},
8510 { &hf_time_sync_local_clock_time_property_flags_leap59, { "Leap indicator 59", "cip.time_sync.local_clock.time_property_flags.leap59", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x02, NULL, HFILL }},
8511 { &hf_time_sync_local_clock_time_property_flags_current_utc_valid, { "Current UTC Offset Valid", "cip.time_sync.local_clock.time_property_flags.current_utc_valid", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x04, NULL, HFILL }},
8512 { &hf_time_sync_local_clock_time_property_flags_ptp_timescale, { "PTP Timescale", "cip.time_sync.local_clock.time_property_flags.ptp_timescale", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x08, NULL, HFILL }},
8513 { &hf_time_sync_local_clock_time_property_flags_time_traceable, { "Time traceable", "cip.time_sync.local_clock.time_property_flags.time_traceable", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x10, NULL, HFILL }},
8514 { &hf_time_sync_local_clock_time_property_flags_freq_traceable, { "Frequency traceable", "cip.time_sync.local_clock.time_property_flags.freq_traceable", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x20, NULL, HFILL }},
8515 { &hf_time_sync_local_clock_time_source, { "Time Source", "cip.time_sync.local_clock.time_source", FT_UINT16, BASE_DEC, VALS(cip_time_sync_time_source_vals), 0, NULL, HFILL }},
8516 { &hf_time_sync_num_ports, { "Port Number", "cip.time_sync.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8517 { &hf_time_sync_port_state_info_num_ports, { "Number of Ports", "cip.time_sync.port_state_info.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8518 { &hf_time_sync_port_state_info_port_num, { "Port Number", "cip.time_sync.port_state_info.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8519 { &hf_time_sync_port_state_info_port_state, { "Port State", "cip.time_sync.port_state_info.port_state", FT_UINT16, BASE_DEC, VALS(cip_time_sync_port_state_vals), 0, NULL, HFILL }},
8520 { &hf_time_sync_port_enable_cfg_num_ports, { "Number of Ports", "cip.time_sync.port_enable_cfg.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8521 { &hf_time_sync_port_enable_cfg_port_num, { "Port Number", "cip.time_sync.port_enable_cfg.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8522 { &hf_time_sync_port_enable_cfg_port_enable, { "Port Enable", "cip.time_sync.port_enable_cfg.port_enable", FT_BOOLEAN, 16, TFS(&tfs_enabled_disabled), 0, NULL, HFILL }},
8523 { &hf_time_sync_port_log_announce_num_ports, { "Number of Ports", "cip.time_sync.port_log_announce.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8524 { &hf_time_sync_port_log_announce_port_num, { "Port Number", "cip.time_sync.port_log_announce.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8525 { &hf_time_sync_port_log_announce_interval, { "Port Log Announce Interval", "cip.time_sync.port_log_announce.interval", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8526 { &hf_time_sync_port_log_sync_num_ports, { "Number of Ports", "cip.time_sync.port_log_sync.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8527 { &hf_time_sync_port_log_sync_port_num, { "Port Number", "cip.time_sync.port_log_sync.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8528 { &hf_time_sync_port_log_sync_port_log_sync_interval, { "Port Log Sync Interval", "cip.time_sync.port_log_sync.port_log_sync_interval", FT_INT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8529 { &hf_time_sync_priority1, { "Priority1", "cip.time_sync.priority1", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8530 { &hf_time_sync_priority2, { "Priority2", "cip.time_sync.priority2", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8531 { &hf_time_sync_domain_number, { "Domain number", "cip.time_sync.domain_number", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8532 { &hf_time_sync_clock_type, { "Clock Type", "cip.time_sync.clock_type", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8533 { &hf_time_sync_clock_type_ordinary, { "Ordinary Clock", "cip.time_sync.clock_type.ordinary", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0080, NULL, HFILL }},
8534 { &hf_time_sync_clock_type_boundary, { "Boundary Clock", "cip.time_sync.clock_type.boundary", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0040, NULL, HFILL }},
8535 { &hf_time_sync_clock_type_end_to_end, { "End-to-End Transparent Clock", "cip.time_sync.clock_type.end_to_end", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0010, NULL, HFILL }},
8536 { &hf_time_sync_clock_type_management, { "Management Node", "cip.time_sync.clock_type.management", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0008, NULL, HFILL }},
8537 { &hf_time_sync_clock_type_slave_only, { "Slave Only", "cip.time_sync.clock_type.slave_only", FT_BOOLEAN, 16, TFS(&tfs_set_notset), 0x0100, NULL, HFILL }},
8538 { &hf_time_sync_manufacture_id_oui, { "Manufacture Identity OUI", "cip.time_sync.manufacture_id.oui", FT_UINT24, BASE_HEX, NULL, 0, NULL, HFILL }},
8539 { &hf_time_sync_manufacture_id_reserved, { "Reserved", "cip.time_sync.manufacture_id.reserved", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8540 { &hf_time_sync_prod_desc_size, { "Product Description Size", "cip.time_sync.prod_desc_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8541 { &hf_time_sync_prod_desc_str, { "Product Description", "cip.time_sync.prod_desc", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8542 { &hf_time_sync_revision_data_size, { "Revision Data Size", "cip.time_sync.revision_data_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8543 { &hf_time_sync_revision_data_str, { "Revision Data", "cip.time_sync.revision_data", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8544 { &hf_time_sync_user_desc_size, { "User Description Size", "cip.time_sync.user_desc_size", FT_UINT32, BASE_DEC, NULL, 0, NULL, HFILL }},
8545 { &hf_time_sync_user_desc_str, { "User Description", "cip.time_sync.user_desc", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8546 { &hf_time_sync_port_profile_id_info_num_ports, { "Number of Ports", "cip.time_sync.port_profile_id_info.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8547 { &hf_time_sync_port_profile_id_info_port_num, { "Port Number", "cip.time_sync.port_profile_id_info.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8548 { &hf_time_sync_port_profile_id_info_profile_id, { "Port Profile Identity", "cip.time_sync.port_profile_id_info.profile_id", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8549 { &hf_time_sync_port_phys_addr_info_num_ports, { "Number of Ports", "cip.time_sync.port_phys_addr_info.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8550 { &hf_time_sync_port_phys_addr_info_port_num, { "Port Number", "cip.time_sync.port_phys_addr_info.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8551 { &hf_time_sync_port_phys_addr_info_phys_proto, { "Physical Protocol", "cip.time_sync.port_profile_id_info.phys_proto", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8552 { &hf_time_sync_port_phys_addr_info_addr_size, { "Size of Address", "cip.time_sync.port_phys_addr_info.addr_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8553 { &hf_time_sync_port_phys_addr_info_phys_addr, { "Port Physical Address", "cip.time_sync.port_profile_id_info.phys_addr", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8554 { &hf_time_sync_port_proto_addr_info_num_ports, { "Number of Ports", "cip.time_sync.port_proto_addr_info.num_ports", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8555 { &hf_time_sync_port_proto_addr_info_port_num, { "Port Number", "cip.time_sync.port_proto_addr_info.port_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8556 { &hf_time_sync_port_proto_addr_info_network_proto, { "Network Protocol", "cip.time_sync.port_proto_addr_info.network_proto", FT_UINT16, BASE_DEC, VALS(cip_time_sync_network_protocol_vals), 0, NULL, HFILL }},
8557 { &hf_time_sync_port_proto_addr_info_addr_size, { "Size of Address", "cip.time_sync.port_proto_addr_info.addr_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8558 { &hf_time_sync_port_proto_addr_info_port_proto_addr, { "Port Protocol Address", "cip.time_sync.port_profile_id_info.port_proto_addr", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8559 { &hf_time_sync_steps_removed, { "Steps Removed", "cip.time_sync.steps_removed", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8560 { &hf_time_sync_sys_time_and_offset_time, { "System Time (Microseconds)", "cip.time_sync.sys_time_and_offset.time", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0, NULL, HFILL }},
8561 { &hf_time_sync_sys_time_and_offset_offset, { "System Offset (Microseconds)", "cip.time_sync.sys_time_and_offset.offset", FT_UINT64, BASE_DEC, NULL, 0, NULL, HFILL }},
8562 { &hf_port_entry_port, { "Entry Port", "cip.port.entry_port", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8563 { &hf_port_type, { "Port Type", "cip.port.type", FT_UINT16, BASE_DEC | BASE_RANGE_STRING, RVALS(cip_port_type_vals), 0, NULL, HFILL } },
8564 { &hf_port_number, { "Port Number", "cip.port.number", FT_UINT16, BASE_DEC, VALS(cip_port_number_vals), 0, NULL, HFILL } },
8565 { &hf_port_min_node_num, { "Minimum Node Number", "cip.port.min_node", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8566 { &hf_port_max_node_num, { "Maximum Node Number", "cip.port.max_node", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL } },
8567 { &hf_port_name, { "Port Name", "cip.port.name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL } },
8568 { &hf_port_num_comm_object_entries, { "Number of entries", "cip.port.num_comm_object_entries", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL } },
8569 { &hf_path_len_usint, { "Path Length", "cip.path_len", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL } },
8570 { &hf_path_len_uint, { "Path Length", "cip.path_len", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL } },
8571
8572 { &hf_32bitheader, { "32-bit Header", "cip.32bitheader", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL } },
8573 { &hf_32bitheader_roo, { "ROO", "cip.32bitheader.roo", FT_UINT32, BASE_HEX, NULL, 0xC, "Ready for Ownership of Outputs", HFILL } },
8574 { &hf_32bitheader_coo, { "COO", "cip.32bitheader.coo", FT_UINT32, BASE_HEX, NULL, 0x2, "Claim Output Ownership", HFILL } },
8575 { &hf_32bitheader_run_idle, { "Run/Idle", "cip.32bitheader.run_idle", FT_UINT32, BASE_HEX, VALS(cip_run_idle_vals), 0x1, NULL, HFILL } },
8576
8577 { &hf_cip_connection, { "CIP Connection Index", "cip.connection", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL } },
8578 };
8579
8580 static hf_register_info hf_cm[] = {
8581 { &hf_cip_cm_sc, { "Service", "cip.cm.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_cm), CIP_SC_MASK, NULL, HFILL }},
8582 { &hf_cip_cm_genstat, { "General Status", "cip.cm.genstat", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_gs_vals_ext, 0, NULL, HFILL }},
8583 { &hf_cip_cm_addstat_size, { "Additional Status Size", "cip.cm.addstat_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8584 { &hf_cip_cm_ext_status, { "Extended Status", "cip.cm.ext_status", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_cm_ext_st_vals_ext, 0, NULL, HFILL }},
8585 { &hf_cip_cm_add_status, { "Additional Status", "cip.cm.addstat", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8586 { &hf_cip_cm_priority, { "Priority", "cip.cm.priority", FT_UINT8, BASE_DEC, NULL, 0x10, NULL, HFILL }},
8587 { &hf_cip_cm_tick_time, { "Tick time", "cip.cm.tick_time", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }},
8588 { &hf_cip_cm_timeout_tick, { "Time-out ticks", "cip.cm.timeout_tick", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8589 { &hf_cip_cm_timeout, { "Actual Time Out", "cip.cm.timeout", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_milliseconds, 0, NULL, HFILL }},
8590 { &hf_cip_cm_ot_connid, { "O->T Network Connection ID", "cip.cm.ot_connid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8591 { &hf_cip_cm_to_connid, { "T->O Network Connection ID", "cip.cm.to_connid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8592 { &hf_cip_connid, { "Connection ID", "cip.connid", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8593 { &hf_cip_cm_conn_serial_num, { "Connection Serial Number", "cip.cm.conn_serial_num", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8594 { &hf_cip_cm_vendor, { "Originator Vendor ID", "cip.cm.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
8595 { &hf_cip_cm_timeout_multiplier, { "Connection Timeout Multiplier", "cip.cm.timeout_multiplier", FT_UINT8, BASE_DEC, VALS(cip_con_time_mult_vals), 0, NULL, HFILL }},
8596 { &hf_cip_cm_ot_rpi, { "O->T RPI", "cip.cm.otrpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8597 { &hf_cip_cm_ot_net_params32, { "O->T Network Connection Parameters", "cip.cm.ot_net_params", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8598 { &hf_cip_cm_ot_net_params16, { "O->T Network Connection Parameters", "cip.cm.ot_net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8599 { &hf_cip_cm_to_rpi, { "T->O RPI", "cip.cm.torpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8600 { &hf_cip_cm_to_net_params32, { "T->O Network Connection Parameters", "cip.cm.to_net_params", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8601 { &hf_cip_cm_to_net_params16, { "T->O Network Connection Parameters", "cip.cm.to_net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8602 { &hf_cip_cm_transport_type_trigger, { "Transport Type/Trigger", "cip.cm.transport_type_trigger", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8603 { &hf_cip_cm_conn_path_size, { "Connection Path Size", "cip.cm.connpath_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8604 { &hf_cip_cm_ot_api, { "O->T API", "cip.cm.otapi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8605 { &hf_cip_cm_to_api, { "T->O API", "cip.cm.toapi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8606 { &hf_cip_cm_app_reply_size, { "Application Reply Size", "cip.cm.app_reply_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8607 { &hf_cip_cm_app_reply_data , { "Application Reply", "cip.cm.app_reply_data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8608 { &hf_cip_cm_consumer_number, { "Consumer Number", "cip.cm.consumer_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8609 { &hf_cip_cm_targ_vendor_id, { "Target Vendor ID", "cip.cm.targ_vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
8610 { &hf_cip_cm_targ_dev_serial_num, { "Target Device Serial Number", "cip.cm.targ_dev_serial_num", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8611 { &hf_cip_cm_targ_conn_serial_num, { "Target Connection Serial Number", "cip.cm.targ_conn_serial_num", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8612 { &hf_cip_cm_initial_timestamp, { "Initial Timestamp", "cip.cm.initial_timestamp", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8613 { &hf_cip_cm_initial_rollover, { "Initial Rollover Value", "cip.cm.initial_rollover", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8614 { &hf_cip_cm_remain_path_size, { "Remaining Path Size", "cip.cm.remain_path_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8615 { &hf_cip_cm_msg_req_size, { "Embedded Message Request Size", "cip.cm.msg_req_size", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0, NULL, HFILL }},
8616 { &hf_cip_cm_route_path_size, { "Route Path Size", "cip.cm.route_path_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8617 { &hf_cip_cm_orig_serial_num, { "Originator Serial Number", "cip.cm.orig_serial_num", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8618 { &hf_cip_cm_fwo_con_size, { "Connection Size", "cip.cm.fwo.consize", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x01FF, "Fwd Open: Connection size", HFILL }},
8619 { &hf_cip_cm_lfwo_con_size, { "Connection Size", "cip.cm.fwo.consize", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0xFFFF, "Large Fwd Open: Connection size", HFILL }},
8620 { &hf_cip_cm_fwo_fixed_var, { "Connection Size Type", "cip.cm.fwo.f_v", FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200, "Fwd Open: Fixed or variable connection size", HFILL }},
8621 { &hf_cip_cm_lfwo_fixed_var, { "Connection Size Type", "cip.cm.fwo.f_v", FT_UINT32, BASE_DEC, VALS(cip_con_fw_vals), 0x02000000, "Large Fwd Open: Fixed or variable connection size", HFILL }},
8622 { &hf_cip_cm_fwo_prio, { "Priority", "cip.cm.fwo.prio", FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00, "Fwd Open: Connection priority", HFILL }},
8623 { &hf_cip_cm_lfwo_prio, { "Priority", "cip.cm.fwo.prio", FT_UINT32, BASE_DEC, VALS(cip_con_prio_vals), 0x0C000000, "Large Fwd Open: Connection priority", HFILL }},
8624 { &hf_cip_cm_fwo_typ, { "Connection Type", "cip.cm.fwo.type", FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000, "Fwd Open: Connection type", HFILL }},
8625 { &hf_cip_cm_lfwo_typ, { "Connection Type", "cip.cm.fwo.type", FT_UINT32, BASE_DEC, VALS(cip_con_type_vals), 0x60000000, "Large Fwd Open: Connection type", HFILL }},
8626 { &hf_cip_cm_fwo_own, { "Redundant Owner", "cip.cm.fwo.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, "Fwd Open: Redundant owner bit", HFILL }},
8627 { &hf_cip_cm_lfwo_own, { "Redundant Owner", "cip.cm.fwo.owner", FT_UINT32, BASE_DEC, VALS(cip_con_owner_vals), 0x80000000, "Large Fwd Open: Redundant owner bit", HFILL }},
8628 { &hf_cip_cm_fwo_dir, { "Direction", "cip.cm.fwo.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), CI_PRODUCTION_DIR_MASK, "Fwd Open: Direction", HFILL }},
8629 { &hf_cip_cm_fwo_trigg, { "Trigger", "cip.cm.fwo.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), CI_PRODUCTION_TRIGGER_MASK, "Fwd Open: Production trigger", HFILL }},
8630 { &hf_cip_cm_fwo_class, { "Class", "cip.cm.fwo.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), CI_TRANSPORT_CLASS_MASK, "Fwd Open: Transport Class", HFILL }},
8631 { &hf_cip_cm_gco_conn, { "Number of Connections", "cip.cm.gco.conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: Number of Connections", HFILL }},
8632 { &hf_cip_cm_gco_coo_conn, { "COO Connections", "cip.cm.gco.coo_conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: COO Connections", HFILL }},
8633 { &hf_cip_cm_gco_roo_conn, { "ROO Connections", "cip.cm.gco.roo_conn", FT_UINT8, BASE_DEC, NULL, 0, "GetConnOwner: ROO Connections", HFILL }},
8634 { &hf_cip_cm_gco_last_action, { "Last Action", "cip.cm.gco.la", FT_UINT8, BASE_DEC, VALS(cip_con_last_action_vals), 0, "GetConnOwner: Last Action", HFILL }},
8635 { &hf_cip_cm_ext112_ot_rpi_type, { "Trigger", "cip.cm.ext112otrpi_type", FT_UINT8, BASE_DEC, VALS(cip_cm_rpi_type_vals), 0, NULL, HFILL }},
8636 { &hf_cip_cm_ext112_to_rpi_type, { "Trigger", "cip.cm.ext112torpi_type", FT_UINT8, BASE_DEC, VALS(cip_cm_rpi_type_vals), 0, NULL, HFILL }},
8637 { &hf_cip_cm_ext112_ot_rpi, { "Acceptable O->T RPI", "cip.cm.ext112otrpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8638 { &hf_cip_cm_ext112_to_rpi, { "Acceptable T->O RPI", "cip.cm.ext112torpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8639 { &hf_cip_cm_ext126_size, { "Maximum Size", "cip.cm.ext126_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8640 { &hf_cip_cm_ext127_size, { "Maximum Size", "cip.cm.ext127_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8641 { &hf_cip_cm_ext128_size, { "Maximum Size", "cip.cm.ext128_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }}
8642 };
8643
8644 static hf_register_info hf_pccc[] = {
8645 { &hf_cip_pccc_sc, { "Service", "cip.pccc.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_pccc), CIP_SC_MASK, NULL, HFILL }},
8646 { &hf_cip_pccc_req_id_len, { "Requestor ID Length", "cip.pccc.req.id.len", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8647 { &hf_cip_pccc_cip_vend_id, { "CIP Vendor ID", "cip.pccc.cip.vend.id", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8648 { &hf_cip_pccc_cip_serial_num, { "CIP Serial Number", "cip.pccc.cip.serial.num", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8649 { &hf_cip_pccc_cmd_code, { "Command Code", "cip.pccc.cmd.code", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8650 { &hf_cip_pccc_sts_code, { "Status", "cip.pccc.gs.status", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_gs_st_vals_ext, 0, NULL, HFILL }},
8651 { &hf_cip_pccc_ext_sts_code, { "Extended Status", "cip.pccc.es.status", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_es_st_vals_ext, 0, NULL, HFILL }},
8652 { &hf_cip_pccc_tns_code, { "Transaction Code", "cip.pccc.tns.code", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8653 { &hf_cip_pccc_fnc_code_06, { "Function Code", "cip.pccc.fnc.code_06", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_fnc_06_vals_ext, 0, NULL, HFILL }},
8654 { &hf_cip_pccc_fnc_code_07, { "Function Code", "cip.pccc.fnc.code_07", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_fnc_07_vals_ext, 0, NULL, HFILL }},
8655 { &hf_cip_pccc_fnc_code_0f, { "Function Code", "cip.pccc.fnc.code_0f", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_fnc_0f_vals_ext, 0, NULL, HFILL }},
8656 { &hf_cip_pccc_byte_size, { "Byte Size", "cip.pccc.byte.size", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8657 { &hf_cip_pccc_file_num, { "File Number", "cip.pccc.file.num", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8658 { &hf_cip_pccc_file_type, { "File Type", "cip.pccc.file.type", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_file_type_vals_ext, 0, NULL, HFILL }},
8659 { &hf_cip_pccc_element_num, { "Element Number", "cip.pccc.element.num", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8660 { &hf_cip_pccc_subelement_num, { "Sub-Element Number", "cip.pccc.subelement.num", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8661 #if 0
8662 { &hf_cip_pccc_cpu_mode_3a, { "CPU Mode", "cip.pccc.cpu.mode_3a", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_cpu_mode_3a_vals_ext, 0, NULL, HFILL }},
8663 #endif
8664 { &hf_cip_pccc_cpu_mode_80, { "CPU Mode", "cip.pccc.cpu.mode_80", FT_UINT8, BASE_HEX|BASE_EXT_STRING, &cip_pccc_cpu_mode_80_vals_ext, 0, NULL, HFILL }},
8665 { &hf_cip_pccc_resp_code, { "Response Code", "cip.pccc.resp.code", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8666 { &hf_cip_pccc_execute_multi_count, { "Execute Multiple Command - Number of Commands", "cip.pccc.execute.multi.count", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8667 { &hf_cip_pccc_execute_multi_len, { "Execute Multiple Command - Command Length", "cip.pccc.execute.multi.len", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8668 { &hf_cip_pccc_execute_multi_fnc, { "Execute Multiple Command - Function Code", "cip.pccc.execute.multi.code", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8669
8670 { &hf_cip_pccc_data, { "Data", "cip.pccc.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}
8671 };
8672
8673 static hf_register_info hf_mb[] = {
8674 { &hf_cip_mb_sc, { "Service", "cip.mb.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_mb), CIP_SC_MASK, NULL, HFILL }},
8675 { &hf_cip_mb_read_coils_start_addr, { "Starting Address", "cip.mb.read_coils.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8676 { &hf_cip_mb_read_coils_num_coils, { "Quantity of Coils", "cip.mb.read_coils.num_coils", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8677 { &hf_cip_mb_read_coils_data, { "Data", "cip.mb.read_coils.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8678 { &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 }},
8679 { &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 }},
8680 { &hf_cip_mb_read_discrete_inputs_data, { "Data", "cip.mb.read_discrete_inputs.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8681 { &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 }},
8682 { &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 }},
8683 { &hf_cip_mb_read_holding_register_data, { "Data", "cip.mb.read_holding_register.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8684 { &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 }},
8685 { &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 }},
8686 { &hf_cip_mb_read_input_register_data, { "Data", "cip.mb.read_input_register.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8687 { &hf_cip_mb_write_coils_start_addr, { "Starting Address", "cip.mb.write_coils.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8688 { &hf_cip_mb_write_coils_outputs_forced, { "Outputs Forced", "cip.mb.write_coils.outputs_forced", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8689 { &hf_cip_mb_write_coils_num_coils, { "Quantity of Coils", "cip.mb.write_coils.num_coils", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8690 { &hf_cip_mb_write_coils_data, { "Data", "cip.mb.write_coils.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8691 { &hf_cip_mb_write_registers_start_addr, { "Starting Address", "cip.mb.write_registers.start_addr", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8692 { &hf_cip_mb_write_registers_outputs_forced, { "Outputs Forced", "cip.mb.write_registers.outputs_forced", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8693 { &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 }},
8694 { &hf_cip_mb_write_registers_data, { "Data", "cip.mb.write_registers.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8695 { &hf_cip_mb_data, { "Data", "cip.mb.data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }}
8696 };
8697
8698 static hf_register_info hf_cco[] = {
8699 { &hf_cip_cco_sc, { "Service", "cip.cco.sc", FT_UINT8, BASE_HEX, VALS(cip_sc_vals_cco), CIP_SC_MASK, NULL, HFILL }},
8700 { &hf_cip_cco_format_number, { "Format Number", "cip.cco.format_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8701 { &hf_cip_cco_edit_signature, { "Edit Signature", "cip.cco.edit_signature", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8702 { &hf_cip_cco_con_flags, { "Connection Flags", "cip.cco.connflags", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8703 { &hf_cip_cco_con_type, { "Connection O_T", "cip.cco.con", FT_UINT16, BASE_DEC, VALS(cip_con_vals), 0x0001, NULL, HFILL }},
8704 { &hf_cip_cco_ot_rtf, { "O->T real time transfer format", "cip.cco.otrtf", FT_UINT16, BASE_DEC, VALS(cip_con_rtf_vals), 0x000E, NULL, HFILL }},
8705 { &hf_cip_cco_to_rtf, { "T->O real time transfer format", "cip.cco.tortf", FT_UINT16, BASE_DEC, VALS(cip_con_rtf_vals), 0x0070, NULL, HFILL }},
8706 { &hf_cip_cco_tdi_vendor, { "Vendor ID", "cip.cco.tdi.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
8707 { &hf_cip_cco_tdi_devtype, { "Device Type", "cip.cco.tdi.devtype", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, NULL, HFILL }},
8708 { &hf_cip_cco_tdi_prodcode, { "Product Code", "cip.cco.tdi.product_code", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8709 { &hf_cip_cco_tdi_compatibility, { "Compatibility", "cip.cco.tdi.compatibility", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8710 { &hf_cip_cco_tdi_comp_bit, { "Compatibility", "cip.cco.tdi.comp_bit", FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80, NULL, HFILL }},
8711 { &hf_cip_cco_tdi_majorrev, { "Major Revision", "cip.cco.tdi.major_rev", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }},
8712 { &hf_cip_cco_tdi_minorrev, { "Minor Revision", "cip.cco.tdi.minor_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8713 { &hf_cip_cco_pdi_vendor, { "Vendor ID", "cip.cco.pdi.vendor", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_vendor_vals_ext, 0, NULL, HFILL }},
8714 { &hf_cip_cco_pdi_devtype, { "Device Type", "cip.cco.pdi.devtype", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_devtype_vals_ext, 0, NULL, HFILL }},
8715 { &hf_cip_cco_pdi_prodcode, { "Product Code", "cip.cco.pdi.product_code", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8716 { &hf_cip_cco_pdi_compatibility, { "Compatibility", "cip.cco.pdi.compatibility", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8717 { &hf_cip_cco_pdi_comp_bit, { "Compatibility", "cip.cco.pdi.comp_bit", FT_UINT8, BASE_HEX, VALS(cip_com_bit_vals), 0x80, NULL, HFILL }},
8718 { &hf_cip_cco_pdi_majorrev, { "Major Revision", "cip.cco.pdi.major_rev", FT_UINT8, BASE_DEC, NULL, 0x7F, NULL, HFILL }},
8719 { &hf_cip_cco_pdi_minorrev, { "Minor Revision", "cip.cco.pdi.minor_rev", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8720 { &hf_cip_cco_cs_data_index, { "CS Data Index Number", "cip.cco.cs_data_index", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8721 { &hf_cip_cco_timeout_multiplier, { "Connection Timeout Multiplier", "cip.cco.timeout_multiplier", FT_UINT8, BASE_DEC, VALS(cip_con_time_mult_vals), 0, NULL, HFILL }},
8722 { &hf_cip_cco_ot_rpi, { "O->T RPI", "cip.cco.otrpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8723 { &hf_cip_cco_ot_net_param32, { "O->T Network Connection Parameters", "cip.cco.ot_net_params", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8724 { &hf_cip_cco_ot_net_param16, { "O->T Network Connection Parameters", "cip.cco.ot_net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8725 { &hf_cip_cco_to_rpi, { "T->O RPI", "cip.cco.torpi", FT_UINT32, BASE_CUSTOM, CF_FUNC(cip_rpi_api_fmt), 0, NULL, HFILL }},
8726 { &hf_cip_cco_to_net_param16, { "T->O Network Connection Parameters", "cip.cco.to_net_params", FT_UINT32, BASE_HEX, NULL, 0, NULL, HFILL }},
8727 { &hf_cip_cco_to_net_param32, { "T->O Network Connection Parameters", "cip.cco.to_net_params", FT_UINT16, BASE_HEX, NULL, 0, NULL, HFILL }},
8728 { &hf_cip_cco_transport_type_trigger, { "Transport Type/Trigger", "cip.cco.transport_type_trigger", FT_UINT8, BASE_HEX, NULL, 0, NULL, HFILL }},
8729 { &hf_cip_cco_fwo_con_size, { "Connection Size", "cip.cco.consize", FT_UINT16, BASE_DEC, NULL, 0x01FF, NULL, HFILL }},
8730 { &hf_cip_cco_lfwo_con_size, { "Connection Size", "cip.cco.consize", FT_UINT32, BASE_DEC, NULL, 0xFFFF, NULL, HFILL }},
8731 { &hf_cip_cco_fwo_fixed_var, { "Connection Size Type", "cip.cco.f_v", FT_UINT16, BASE_DEC, VALS(cip_con_fw_vals), 0x0200, NULL, HFILL }},
8732 { &hf_cip_cco_lfwo_fixed_var, { "Connection Size Type", "cip.cco.f_v", FT_UINT32, BASE_DEC, VALS(cip_con_fw_vals), 0x02000000, NULL, HFILL }},
8733 { &hf_cip_cco_fwo_prio, { "Priority", "cip.cco.prio", FT_UINT16, BASE_DEC, VALS(cip_con_prio_vals), 0x0C00, NULL, HFILL }},
8734 { &hf_cip_cco_lfwo_prio, { "Priority", "cip.cco.prio", FT_UINT32, BASE_DEC, VALS(cip_con_prio_vals), 0x0C000000, NULL, HFILL }},
8735 { &hf_cip_cco_fwo_typ, { "Connection Type", "cip.cco.type", FT_UINT16, BASE_DEC, VALS(cip_con_type_vals), 0x6000, NULL, HFILL }},
8736 { &hf_cip_cco_lfwo_typ, { "Connection Type", "cip.cco.type", FT_UINT32, BASE_DEC, VALS(cip_con_type_vals), 0x60000000, NULL, HFILL }},
8737 { &hf_cip_cco_fwo_own, { "Redundant Owner", "cip.cco.owner", FT_UINT16, BASE_DEC, VALS(cip_con_owner_vals), 0x8000, NULL, HFILL }},
8738 { &hf_cip_cco_lfwo_own, { "Redundant Owner", "cip.cco.owner", FT_UINT32, BASE_DEC, VALS(cip_con_owner_vals), 0x80000000, NULL, HFILL }},
8739 { &hf_cip_cco_fwo_dir, { "Direction", "cip.cco.dir", FT_UINT8, BASE_DEC, VALS(cip_con_dir_vals), CI_PRODUCTION_DIR_MASK, NULL, HFILL }},
8740 { &hf_cip_cco_fwo_trigger, { "Trigger", "cip.cco.trigger", FT_UINT8, BASE_DEC, VALS(cip_con_trigg_vals), CI_PRODUCTION_TRIGGER_MASK, NULL, HFILL }},
8741 { &hf_cip_cco_fwo_class, { "Class", "cip.cco.transport", FT_UINT8, BASE_DEC, VALS(cip_con_class_vals), CI_TRANSPORT_CLASS_MASK, NULL, HFILL }},
8742 { &hf_cip_cco_conn_path_size, { "Connection Path Size", "cip.cco.connpath_size", FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_word_words, 0, NULL, HFILL }},
8743 { &hf_cip_cco_proxy_config_size, { "Proxy Config Data Size", "cip.cco.proxy_config_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8744 { &hf_cip_cco_target_config_size, { "Target Config Data Size", "cip.cco.target_config_size", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8745 { &hf_cip_cco_iomap_format_number, { "Format number", "cip.cco.iomap_format_number", FT_UINT16, BASE_DEC, NULL, 0, NULL, HFILL }},
8746 { &hf_cip_cco_iomap_size, { "Mapping data size", "cip.cco.iomap_size", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0, NULL, HFILL }},
8747 { &hf_cip_cco_connection_disable, { "Connection Disable", "cip.cco.connection_disable", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }},
8748 { &hf_cip_cco_net_conn_param_attr, { "Net Connection Parameter Attribute Selection", "cip.cco.net_conn_param_attr", FT_UINT8, BASE_DEC, NULL, 0, NULL, HFILL }},
8749 { &hf_cip_cco_proxy_config_data, { "Proxy Config Data", "cip.cco.proxy_config_data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8750 { &hf_cip_cco_target_config_data, { "Target Config Data", "cip.cco.target_config_data", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8751 { &hf_cip_cco_iomap_attribute, { "Attribute Data", "cip.cco.iomap", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8752 { &hf_cip_cco_safety, { "Safety Parameters", "cip.cco.safety", FT_BYTES, BASE_NONE, NULL, 0, NULL, HFILL }},
8753 { &hf_cip_cco_change_type, { "Change Type", "cip.cco.change_type", FT_UINT16, BASE_DEC, VALS(cip_cco_change_type_vals), 0, NULL, HFILL }},
8754 { &hf_cip_cco_connection_name, { "Connection Name", "cip.cco.connection_name", FT_STRING, BASE_NONE, NULL, 0, NULL, HFILL }},
8755 { &hf_cip_cco_ext_status, { "Extended Status", "cip.cco.ext_status", FT_UINT16, BASE_HEX|BASE_EXT_STRING, &cip_cm_ext_st_vals_ext, 0, NULL, HFILL }},
8756 };
8757
8758 /* Setup protocol subtree array */
8759 static gint *ett[] = {
8760 &ett_cip_class_generic,
8761 &ett_cip,
8762 &ett_path,
8763 &ett_path_seg,
8764 &ett_rrsc,
8765 &ett_mcsc,
8766 &ett_cia_path,
8767 &ett_data_seg,
8768 &ett_cmd_data,
8769 &ett_port_path,
8770 &ett_network_seg,
8771 &ett_network_seg_safety,
8772 &ett_network_seg_safety_time_correction_net_params,
8773 &ett_cip_seg_safety_tunid,
8774 &ett_cip_seg_safety_tunid_snn,
8775 &ett_cip_seg_safety_ounid,
8776 &ett_cip_seg_safety_ounid_snn,
8777 &ett_status_item,
8778 &ett_add_status_item,
8779 &ett_cip_get_attributes_all_item,
8780 &ett_cip_get_attribute_list,
8781 &ett_cip_get_attribute_list_item,
8782 &ett_cip_set_attribute_list,
8783 &ett_cip_set_attribute_list_item,
8784 &ett_cip_mult_service_packet,
8785 &ett_cip_msp_offset,
8786 &ett_time_sync_gm_clock_flags,
8787 &ett_time_sync_local_clock_flags,
8788 &ett_time_sync_port_state_info,
8789 &ett_time_sync_port_enable_cfg,
8790 &ett_time_sync_port_log_announce,
8791 &ett_time_sync_port_log_sync,
8792 &ett_time_sync_clock_type,
8793 &ett_time_sync_port_profile_id_info,
8794 &ett_time_sync_port_phys_addr_info,
8795 &ett_time_sync_port_proto_addr_info,
8796 &ett_id_status,
8797 &ett_32bitheader_tree,
8798 &ett_connection_info,
8799 };
8800
8801 static gint *ett_cm[] = {
8802 &ett_cip_class_cm,
8803 &ett_cm_rrsc,
8804 &ett_cm_mes_req,
8805 &ett_cm_ncp,
8806 &ett_cm_cmd_data,
8807 &ett_cm_ttt,
8808 &ett_cm_add_status_item,
8809 &ett_cip_cm_pid,
8810 &ett_cip_cm_safety
8811 };
8812
8813 static gint *ett_pccc[] = {
8814 &ett_cip_class_pccc,
8815 &ett_pccc_rrsc,
8816 &ett_pccc_req_id,
8817 &ett_pccc_cmd_data
8818 };
8819
8820 static gint *ett_mb[] = {
8821 &ett_cip_class_mb,
8822 &ett_mb_rrsc,
8823 &ett_mb_cmd_data
8824 };
8825
8826 static gint *ett_cco[] = {
8827 &ett_cip_class_cco,
8828 &ett_cco_iomap,
8829 &ett_cco_con_status,
8830 &ett_cco_con_flag,
8831 &ett_cco_tdi,
8832 &ett_cco_pdi,
8833 &ett_cco_ncp,
8834 &ett_cco_rrsc,
8835 &ett_cco_cmd_data,
8836 &ett_cco_ttt,
8837 };
8838
8839 static ei_register_info ei[] = {
8840 { &ei_mal_identity_revision, { "cip.malformed.id.revision", PI_MALFORMED, PI_ERROR, "Malformed Identity revision", EXPFILL }},
8841 { &ei_mal_identity_status, { "cip.malformed.id.status", PI_MALFORMED, PI_ERROR, "Malformed Identity status", EXPFILL } },
8842 { &ei_mal_msg_rout_num_classes, { "cip.malformed.msg_rout.num_classes", PI_MALFORMED, PI_ERROR, "Malformed Message Router Attribute 1", EXPFILL }},
8843 { &ei_mal_time_sync_gm_clock, { "cip.malformed.time_sync.gm_clock", PI_MALFORMED, PI_ERROR, "Malformed Grandmaster clock info", EXPFILL }},
8844 { &ei_mal_time_sync_parent_clock, { "cip.malformed.time_sync.parent_clock", PI_MALFORMED, PI_ERROR, "Malformed Parent clock info", EXPFILL }},
8845 { &ei_mal_time_sync_local_clock, { "cip.malformed.time_sync.local_clock", PI_MALFORMED, PI_ERROR, "Malformed Local clock info", EXPFILL }},
8846 { &ei_mal_time_sync_port_state_info, { "cip.malformed.time_sync.port_state_info", PI_MALFORMED, PI_ERROR, "Malformed Port State Info", EXPFILL }},
8847 { &ei_mal_time_sync_port_state_info_ports, { "cip.malformed.time_sync.port_state_info.ports", PI_MALFORMED, PI_ERROR, "Malformed Port State Info - too many ports", EXPFILL }},
8848 { &ei_mal_time_sync_port_enable_cfg, { "cip.malformed.time_sync.port_enable_cfg", PI_MALFORMED, PI_ERROR, "Malformed Port Enable Cfg", EXPFILL }},
8849 { &ei_mal_time_sync_port_enable_cfg_ports, { "cip.malformed.time_sync.port_enable_cfg.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Enable Cfg - too many ports", EXPFILL }},
8850 { &ei_mal_time_sync_port_log_announce, { "cip.malformed.time_sync.port_log_announce", PI_MALFORMED, PI_ERROR, "Malformed Port Log Announcement Interval Cfg", EXPFILL }},
8851 { &ei_mal_time_sync_port_log_announce_ports, { "cip.malformed.time_sync.port_log_announce.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Log Announcement Interval Cfg - too many ports", EXPFILL }},
8852 { &ei_mal_time_sync_port_log_sync, { "cip.malformed.time_sync.port_log_sync", PI_MALFORMED, PI_ERROR, "Malformed Port Log Sync Interval Cfg", EXPFILL }},
8853 { &ei_mal_time_sync_port_log_sync_ports, { "cip.malformed.time_sync.port_log_sync.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Log Sync Interval Cfg - too many ports", EXPFILL }},
8854 { &ei_mal_time_sync_clock_type, { "cip.malformed.time_sync.clock_type", PI_MALFORMED, PI_ERROR, "Malformed Clock Type", EXPFILL }},
8855 { &ei_mal_time_sync_manufacture_id, { "cip.malformed.time_sync.manufacture_id", PI_MALFORMED, PI_ERROR, "Malformed Manufacture Identity", EXPFILL }},
8856 { &ei_mal_time_sync_prod_desc, { "cip.malformed.time_sync.prod_desc", PI_MALFORMED, PI_ERROR, "Malformed Product Description", EXPFILL }},
8857 { &ei_mal_time_sync_prod_desc_64, { "cip.malformed.time_sync.prod_desc.limit_64", PI_PROTOCOL, PI_WARN, "Product Description limited to 64 characters", EXPFILL }},
8858 { &ei_mal_time_sync_prod_desc_size, { "cip.malformed.time_sync.prod_desc.size", PI_MALFORMED, PI_ERROR, "Malformed Product Description - invalid size", EXPFILL }},
8859 { &ei_mal_time_sync_revision_data, { "cip.malformed.time_sync.revision_data", PI_MALFORMED, PI_ERROR, "Malformed Revision Data", EXPFILL }},
8860 { &ei_mal_time_sync_revision_data_32, { "cip.malformed.time_sync.revision_data.limit_32", PI_PROTOCOL, PI_WARN, "Revision Data limited to 32 characters", EXPFILL }},
8861 { &ei_mal_time_sync_revision_data_size, { "cip.malformed.time_sync.revision_data.size", PI_MALFORMED, PI_ERROR, "Malformed Revision Data - invalid size", EXPFILL }},
8862 { &ei_mal_time_sync_user_desc, { "cip.malformed.time_sync.user_desc", PI_MALFORMED, PI_ERROR, "Malformed User Description", EXPFILL }},
8863 { &ei_mal_time_sync_user_desc_128, { "cip.malformed.time_sync.user_desc.limit_128", PI_PROTOCOL, PI_WARN, "User Description limited to 128 characters", EXPFILL }},
8864 { &ei_mal_time_sync_user_desc_size, { "cip.malformed.time_sync.user_desc.size", PI_MALFORMED, PI_ERROR, "Malformed User Description - invalid size", EXPFILL }},
8865 { &ei_mal_time_sync_port_profile_id_info, { "cip.malformed.time_sync.port_profile_id_info", PI_MALFORMED, PI_ERROR, "Malformed Port Profile Identity Info", EXPFILL }},
8866 { &ei_mal_time_sync_port_profile_id_info_ports, { "cip.malformed.time_sync.port_profile_id_info.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Profile Identity Info - too many ports", EXPFILL }},
8867 { &ei_mal_time_sync_port_phys_addr_info, { "cip.malformed.time_sync.port_phys_addr_info", PI_MALFORMED, PI_ERROR, "Malformed Port Physical Address Info", EXPFILL }},
8868 { &ei_mal_time_sync_port_phys_addr_info_ports, { "cip.malformed.time_sync.port_phys_addr_info.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Physical Address Info - too many ports", EXPFILL }},
8869 { &ei_mal_time_sync_port_proto_addr_info, { "cip.malformed.time_sync.port_proto_addr_info", PI_MALFORMED, PI_ERROR, "Malformed Port Protocol Address Info", EXPFILL }},
8870 { &ei_mal_time_sync_port_proto_addr_info_ports, { "cip.malformed.time_sync.port_proto_addr_info.ports", PI_MALFORMED, PI_ERROR, "Malformed Port Protocol Address Info - too many ports", EXPFILL }},
8871 { &ei_mal_time_sync_sys_time_and_offset, { "cip.malformed.time_sync.sys_time_and_offset", PI_MALFORMED, PI_ERROR, "Malformed System Time and Offset", EXPFILL }},
8872 { &ei_proto_log_seg_format, { "cip.unsupported.log_seg_format", PI_PROTOCOL, PI_WARN, "Unsupported Logical Segment Format", EXPFILL }},
8873 { &ei_mal_incomplete_epath, { "cip.malformed.incomplete_epath", PI_MALFORMED, PI_ERROR, "Incomplete EPATH", EXPFILL }},
8874 { &ei_proto_electronic_key_format, { "cip.unsupported.electronic_key_format", PI_PROTOCOL, PI_WARN, "Unsupported Electronic Key Format", EXPFILL }},
8875 { &ei_proto_special_segment_format, { "cip.unsupported.special_segment_format", PI_PROTOCOL, PI_WARN, "Unsupported Special Segment Format", EXPFILL }},
8876 { &ei_proto_log_seg_type, { "cip.unsupported.log_seg_type", PI_PROTOCOL, PI_WARN, "Unsupported Logical Segment Type", EXPFILL }},
8877 { &ei_proto_log_sub_seg_type, { "cip.unsupported.log_sub_seg_type", PI_PROTOCOL, PI_WARN, "Unsupported Sub-Segment Type", EXPFILL }},
8878 { &ei_proto_ext_string_format, { "cip.unsupported.ext_string_format", PI_PROTOCOL, PI_WARN, "Unsupported Extended String Format", EXPFILL } },
8879 { &ei_proto_ext_network, { "cip.malformed.ext_network", PI_PROTOCOL, PI_ERROR, "Malformed Extended Network Segment Format", EXPFILL } },
8880 { &ei_proto_seg_type, { "cip.unsupported.seg_type", PI_PROTOCOL, PI_WARN, "Unsupported Segment Type", EXPFILL }},
8881 { &ei_proto_unsupported_datatype, { "cip.unsupported.datatype", PI_PROTOCOL, PI_WARN, "Unsupported Datatype", EXPFILL }},
8882 { &ei_mal_serv_gal, { "cip.malformed.get_attribute_list", PI_MALFORMED, PI_ERROR, "Malformed Get Attribute List service", EXPFILL }},
8883 { &ei_mal_serv_gal_count, { "cip.malformed.get_attribute_list.count", PI_MALFORMED, PI_ERROR, "Malformed Get Attribute List attribute list count greater than packet size", EXPFILL }},
8884 { &ei_mal_serv_sal, { "cip.malformed.set_attribute_list", PI_MALFORMED, PI_ERROR, "Malformed Set Attribute List service", EXPFILL }},
8885 { &ei_mal_serv_sal_count, { "cip.malformed.set_attribute_list.count", PI_MALFORMED, PI_ERROR, "Malformed Set Attribute List attribute list count greater than packet size", EXPFILL }},
8886 { &ei_mal_msp_services, { "cip.malformed.msp.services", PI_MALFORMED, PI_WARN, "Multiple Service Packet too many services for packet", EXPFILL }},
8887 { &ei_mal_msp_inv_offset, { "cip.malformed.msp.inv_offset", PI_MALFORMED, PI_WARN, "Multiple Service Packet service invalid offset", EXPFILL }},
8888 { &ei_mal_msp_missing_services, { "cip.malformed.msp.missing_services", PI_MALFORMED, PI_ERROR, "Multiple Service Packet service missing Number of Services field", EXPFILL }},
8889 { &ei_mal_serv_find_next_object, { "cip.malformed.find_next_object", PI_MALFORMED, PI_ERROR, "Find Next Object service missing Number of List Members field", EXPFILL }},
8890 { &ei_mal_serv_find_next_object_count, { "cip.malformed.find_next_object.count", PI_MALFORMED, PI_ERROR, "Find Next Object instance list count greater than packet size", EXPFILL }},
8891 { &ei_mal_rpi_no_data, { "cip.malformed.rpi_no_data", PI_MALFORMED, PI_WARN, "RPI not acceptable - missing extended data", EXPFILL }},
8892 { &ei_mal_fwd_close_missing_data, { "cip.malformed.fwd_close_missing_data", PI_MALFORMED, PI_ERROR, "Forward Close response missing application reply data", EXPFILL }},
8893 { &ei_mal_opt_attr_list, { "cip.malformed.opt_attr_list", PI_MALFORMED, PI_ERROR, "Optional attribute list missing data", EXPFILL }},
8894 { &ei_mal_opt_service_list, { "cip.malformed.opt_service_list", PI_MALFORMED, PI_ERROR, "Optional service list missing data", EXPFILL }},
8895 { &ei_mal_padded_epath_size, { "cip.malformed.epath.size", PI_MALFORMED, PI_ERROR, "Malformed EPATH vs Size", EXPFILL } },
8896 { &ei_mal_missing_string_data, { "cip.malformed.missing_str_data", PI_MALFORMED, PI_ERROR, "Missing string data", EXPFILL } },
8897 };
8898
8899 module_t *cip_module;
8900 expert_module_t* expert_cip;
8901
8902 /* Register the protocol name and description */
8903 proto_cip = proto_register_protocol("Common Industrial Protocol",
8904 "CIP", "cip");
8905 cip_handle = register_dissector("cip", dissect_cip, proto_cip);
8906
8907 register_dissector("cip_implicit", dissect_cip_implicit, proto_cip);
8908
8909 /* Required function calls to register the header fields and subtrees used */
8910 proto_register_field_array(proto_cip, hf, array_length(hf));
8911 proto_register_subtree_array(ett, array_length(ett));
8912
8913 expert_cip = expert_register_protocol(proto_cip);
8914 expert_register_field_array(expert_cip, ei, array_length(ei));
8915
8916 cip_module = prefs_register_protocol(proto_cip, NULL);
8917 prefs_register_bool_preference(cip_module, "enhanced_info_column",
8918 "Display enhanced Info column data",
8919 "Whether the CIP dissector should display enhanced/verbose data in the Info column for CIP explicit messages",
8920 &cip_enhanced_info_column);
8921
8922 subdissector_class_table = register_dissector_table("cip.class.iface",
8923 "CIP Class Interface Handle", proto_cip, FT_UINT32, BASE_HEX);
8924 subdissector_symbol_table = register_dissector_table("cip.data_segment.iface",
8925 "CIP Data Segment Interface Handle", proto_cip, FT_UINT32, BASE_HEX);
8926
8927 /* Register the protocol name and description */
8928 proto_cip_class_generic = proto_register_protocol("CIP Class Generic",
8929 "CIPCLS", "cipcls");
8930
8931 /* Register the protocol name and description */
8932 proto_cip_class_cm = proto_register_protocol("CIP Connection Manager",
8933 "CIPCM", "cipcm");
8934 proto_register_field_array(proto_cip_class_cm, hf_cm, array_length(hf_cm));
8935 proto_register_subtree_array(ett_cm, array_length(ett_cm));
8936
8937 proto_cip_class_pccc = proto_register_protocol("CIP PCCC Object",
8938 "CIPPCCC", "cippccc");
8939 proto_register_field_array(proto_cip_class_pccc, hf_pccc, array_length(hf_pccc));
8940 proto_register_subtree_array(ett_pccc, array_length(ett_pccc));
8941
8942 proto_cip_class_mb = proto_register_protocol("CIP Modbus Object",
8943 "CIPMB", "cipmb");
8944 proto_register_field_array(proto_cip_class_mb, hf_mb, array_length(hf_mb));
8945 proto_register_subtree_array(ett_mb, array_length(ett_mb));
8946
8947 proto_cip_class_cco = proto_register_protocol("CIP Connection Configuration Object",
8948 "CIPCCO", "cipcco");
8949 proto_register_field_array(proto_cip_class_cco, hf_cco, array_length(hf_cco));
8950 proto_register_subtree_array(ett_cco, array_length(ett_cco));
8951
8952 /* Register a heuristic dissector on the service of the message so objects
8953 * can override the dissector for common services */
8954 heur_subdissector_service = register_heur_dissector_list("cip.sc", proto_cip);
8955
8956 build_get_attr_all_table();
8957 } /* end of proto_register_cip() */
8958
8959 void
proto_reg_handoff_cip(void)8960 proto_reg_handoff_cip(void)
8961 {
8962 dissector_handle_t cip_class_mb_handle;
8963
8964 /* Create dissector handles */
8965 /* Register for UCMM CIP data, using EtherNet/IP SendRRData service*/
8966 dissector_add_uint( "enip.srrd.iface", ENIP_CIP_INTERFACE, cip_handle );
8967
8968 dissector_add_uint("cip.connection.class", CI_CLS_MR, cip_handle);
8969
8970 /* Create and register dissector handle for generic class */
8971 cip_class_generic_handle = create_dissector_handle( dissect_cip_class_generic, proto_cip_class_generic );
8972 dissector_add_uint( "cip.class.iface", 0, cip_class_generic_handle );
8973
8974 /* Create and register dissector handle for Connection Manager */
8975 cip_class_cm_handle = create_dissector_handle( dissect_cip_class_cm, proto_cip_class_cm );
8976 dissector_add_uint( "cip.class.iface", CI_CLS_CM, cip_class_cm_handle );
8977
8978 /* Create and register dissector handle for the PCCC class */
8979 cip_class_pccc_handle = create_dissector_handle( dissect_cip_class_pccc, proto_cip_class_pccc );
8980 dissector_add_uint( "cip.class.iface", CI_CLS_PCCC, cip_class_pccc_handle );
8981
8982 /* Create and register dissector handle for Modbus Object */
8983 cip_class_mb_handle = create_dissector_handle( dissect_cip_class_mb, proto_cip_class_mb );
8984 dissector_add_uint( "cip.class.iface", CI_CLS_MB, cip_class_mb_handle );
8985 modbus_handle = find_dissector_add_dependency("modbus", proto_cip_class_mb);
8986
8987 /* Create and register dissector handle for Connection Configuration Object */
8988 cip_class_cco_handle = create_dissector_handle( dissect_cip_class_cco, proto_cip_class_cco );
8989 dissector_add_uint( "cip.class.iface", CI_CLS_CCO, cip_class_cco_handle );
8990 heur_dissector_add("cip.sc", dissect_class_cco_heur, "CIP Connection Configuration Object", "cco_cip", proto_cip_class_cco, HEURISTIC_ENABLE);
8991
8992 proto_enip = proto_get_id_by_filter_name( "enip" );
8993 proto_modbus = proto_get_id_by_filter_name( "modbus" );
8994
8995 } /* end of proto_reg_handoff_cip() */
8996
8997 /*
8998 * Editor modelines
8999 *
9000 * Local Variables:
9001 * c-basic-offset: 3
9002 * tab-width: 8
9003 * indent-tabs-mode: nil
9004 * End:
9005 *
9006 * ex: set shiftwidth=3 tabstop=8 expandtab:
9007 * :indentSize=3:tabSize=8:noTabs=true:
9008 */
9009