3 * Copyright 2014, James Lynch <lynch007@gmail.com>, Control Techniques
4 * Copyright 2015, Luke Orehawa <lukeorehawa@gmail.com>, Control Techniques
7 * - James Lynch 2014-07-22
8 * - Initial plugin development
9 * - Luke Orehawa 2015-11-26
10 * - Removed commands not yet in released specification
11 * - All commands implemented are as V0.26 of ECMP Specification
12 * - Modifications of code to meet Wireshark coding style and current APIs
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * SPDX-License-Identifier: GPL-2.0-or-later
23 #include <epan/packet.h>
24 #include <epan/expert.h>
25 #include "packet-mbtcp.h"
27 #define PROTO_TAG_ECMP "ECMP"
28 #define ECMP_TCP_PORT 6160
30 void proto_reg_handoff_ecmp(void);
31 void proto_register_ecmp (void);
33 /* Wireshark ID of the ECMP protocol */
34 static int proto_ecmp = -1;
36 /* Used to set Modbus protocol data */
37 static int proto_modbus = -1;
39 /* These are the handles of our subdissectors */
40 static dissector_handle_t modbus_handle = NULL;
42 /*smallest size of a packet, number of bytes*/
43 static const gint ecmp_min_packet_size = 6;
45 /* ECMP request codes */
46 #define ECMP_COMMAND_IDENTIFY 0x00
47 #define ECMP_COMMAND_INFO 0x01
48 #define ECMP_COMMAND_INTERROGATE 0x02
49 #define ECMP_COMMAND_READ 0x10
50 #define ECMP_COMMAND_READWITHTYPE 0x11
51 #define ECMP_COMMAND_WRITE 0x12
52 #define ECMP_COMMAND_OBJECTINFO 0x13
53 #define ECMP_COMMAND_GETNEXTOBJECTS 0x14
54 #define ECMP_COMMAND_FILEOPEN 0x20
55 #define ECMP_COMMAND_FILEREAD 0x21
56 #define ECMP_COMMAND_FILEWRITE 0x22
57 #define ECMP_COMMAND_FILECLOSE 0x23
58 #define ECMP_COMMAND_FILEINFO 0x24
59 #define ECMP_COMMAND_FILEDELETE 0x25
60 #define ECMP_COMMAND_FILESTATE 0x26
61 #define ECMP_COMMAND_FILEPOS 0x27
62 #define ECMP_COMMAND_FILELIST 0x28
63 #define ECMP_COMMAND_FILEEXISTS 0x2a
64 #define ECMP_COMMAND_CYCLICLINK 0x31
65 #define ECMP_COMMAND_PROGRAMCONTROL 0x60
66 #define ECMP_COMMAND_PROGRAMSTATUS 0x61
67 #define ECMP_COMMAND_CYCLICFRAME 0x70
68 #define ECMP_COMMAND_TUNNELFRAME 0x73
69 #define ECMP_COMMAND_MODBUSPDU 0x74
71 /* cyclic display formats */
72 static const guint8 cyclic_display_byte_format = 0;
73 static const guint8 cyclic_display_word_format = 1;
74 static const guint8 cyclic_display_long_format = 2;
76 /* Addressing scheme Structure */
77 static const value_string address_scheme [] = {
80 { 2, "Default Route" },
84 /*other commands to be added */
87 /* Address Structure */
88 static const value_string diagnostic [] = {
94 /*other commands to be added*/
97 /* Command Structure*/
98 static const value_string command_vals [] = {
101 { 0x02, "Interrogate"},
103 { 0x11, "ReadWithType"},
105 { 0x13, "ObjectInfo"},
106 { 0x14, "GetNextObjects"},
109 { 0x22, "FileWrite"},
110 { 0x23, "FileClose"},
112 { 0x25, "FileDelete"},
113 { 0x26, "FileState"},
116 { 0x2A, "FileExists"},
117 { 0x31, "CyclicSetup"},
118 { 0x60, "ProgramControl"},
119 { 0x61, "ProgramStatus"},
120 { 0x70, "CyclicFrame"},
121 { 0x73, "TunnelFrame"},
122 { 0x74, "ModbusPDU"},
124 /*other commands to be added*/
127 /* Command Structure for request/response */
128 static const value_string type_rr [] = {
132 /*other commands to be added*/
135 /* Option Code structure*/
136 static const value_string option_code [] = {
137 { 0, "End of Options"},
140 { 3, "Route to Custom Target"},
142 /* other - "Unknown" */
145 /* Attribute type Structure */
146 static const value_string attribute [] = {
147 { 0, "Manufacturer Name" },
148 { 1, "Product Family" },
149 { 2, "Product Model" },
150 { 3, "Serial Number" },
151 { 4, "Order Number" },
153 { 6, "Device Name" },
154 { 7, "Version Summary" },
155 { 8, "Colour Codes" },
160 /* Status type Structure */
161 static const value_string status [] = {
162 { 0, "OK (no errors detected in request)" },
163 { 1, "OK, chunks follow" },
164 { 2, "Processing Request" },
165 { -1, "Error - Slave not ready" },
166 { -2, "Error - Request Too Long" },
167 { -3, "Error - Chunking Error" },
172 /* Category (device) structure*/
173 static const value_string category [] = {
175 { 1, "Option Module" },
179 /* Cyclic data alignment */
180 static const value_string cyclic_align [] = {
189 /* Cyclic data scheme */
190 static const value_string cyclic_scheme [] = {
192 { 1, "Synchronised" },
196 /* Parameter addressing scheme */
197 static const value_string parameter_address_scheme [] = {
199 { 1, "Slot Specific" },
205 static const value_string route_address_scheme [] = {
207 { 2, "DefaultRoute" },
212 /* Parameter access status */
213 static const value_string parameter_access_status [] = {
215 { 1, "OK - Converted"},
216 { 2, "OK - Clamped"},
217 { -1, "ERROR - Address Type"},
218 { -2, "ERROR - Timeout"},
219 { -3, "ERROR - Access Denied"},
220 { -4, "ERROR - Does not exist"},
221 { -5, "ERROR - Data Type"},
222 { -6, "ERROR - Failed Read"},
223 { -7, "ERROR - Failed Write"},
224 { -8, "ERROR - Not Readable"},
225 { -9, "ERROR - Not Writeable"},
226 { -10, "ERROR - Over Range"},
227 { -11, "ERROR - Request Invalid"},
228 { -12, "ERROR - Response Too Big"},
229 { -13, "ERROR - Decimal Place"},
233 /* Parameter data types */
234 static const value_string parameter_data_types [] = {
254 static const value_string info_type [] = {
255 { 0, "No Information"},
256 { 1, "Lowest Numbered Parameter in Menu"},
257 { 2, "Highest Numbered Parameter in Menu"},
258 { 3, "Parameter Format"},
259 { 4, "Minimum Value allowed for Parameter"},
260 { 5, "Maximum Value allowed for Parameter"},
261 { 6, "Object Unit Information"},
262 { 7, "Data Type of Parameter"},
266 /* Display formats */
267 static const value_string display_format [] = {
268 { 0, "Standard format"},
269 { 1, "Date format (xx,yy,zz)"},
270 { 2, "Time with seconds format (xx.yy.zz)"},
271 { 3, "Character format"},
272 { 4, "Binary format"},
273 { 5, "IP address format (www.xxx.yyy.zzz)"},
274 { 6, "MAC address format (AA:BB:CC:DD:EE:FF)"},
275 { 7, "Version number (ww.xx.yy.zz)"},
276 { 8, "Slot menu parameter format (x,yy,zzz)"},
281 static const value_string format_units [] = {
283 { 1, "Custom units"},
284 { 2, "Millimetres (mm)"},
286 { 4, "User units (UU)"},
287 { 5, "Revolutions (revs)"},
290 { 8, "General position unit"},
291 { 9, "Millimetres per second (mm/s)"},
292 { 10, "User units per millisecond (UU/ms)"},
293 { 11, "Revolutions per minute (Rpm)"},
295 { 13, "Kilohertz (kHz)"},
296 { 14, "Megahertz (MHz)"},
297 { 15, "General speed unit (Hz, rpm, mm/s)"},
298 { 16, "Closed loop speed unit (rpm, mm/s)"},
299 { 17, "Seconds per one thousand millimetres per seconds (s/m/s)"},
300 { 18, "User units per millimetre per second (UU/mm/s)"},
301 { 19, "Seconds per one thousand revolution per minute (s/1000rpm)"},
302 { 20, "Seconds per one hundred hertz (s/100Hz)"},
303 { 21, "General acceleration unit"},
304 { 22, "Closed loop acceleration unit"},
305 { 23, "Seconds squared per one thousand millimetres per second (s^2/1000ms/s)"},
306 { 24, "Seconds squared per user units per millisecond (s^2/UU/ms"},
307 { 25, "Seconds squared per one thousand revolutions per minute (s^2/1000rpm)"},
308 { 26, "Seconds squared per one hundred hertz (s^2/100Hz)"},
309 { 27, "General jerk unit"},
310 { 28, "Closed loop jerk unit"},
311 { 29, "Messages per second (Msg/s)"},
312 { 30, "Hours (Hours)"},
313 { 31, "Minutes (Mins)"},
314 { 32, "Seconds (s)"},
315 { 33, "Milliseconds (ms)"},
316 { 34, "Microseconds (us)"},
317 { 35, "Nanoseconds (ns)"},
319 { 37, "Amperes (A)"},
320 { 38, "Ohms (Ohms)"},
321 { 39, "Millihenrys (mH)"},
322 { 40, "Kilowatts (kW)"},
323 { 41, "Kilo-Volt-Amps-Reactive (kVAr)"},
324 { 42, "Megawatt hours (MWh)"},
325 { 43, "Kilowatt hours (kWh)"},
326 { 44, "Degrees Celcius ('C)"},
327 { 45, "Reciprocal of degrees celcius (/'C)"},
328 { 46, "Kilogram-metres squared (kgm^2)"},
329 { 47, "Newton metres (Nm)"},
330 { 48, "Newton metres per ampere (Nm/A)"},
331 { 49, "open-circuit volts per 1000rpm (V/1000rpm)"},
332 { 50, "Bits (Bits)"},
333 { 51, "Bytes (Bytes)"},
334 { 52, "Kilobytes (kB)"},
335 { 53, "Megabytes (MB)"},
336 { 54, "Bits per second (Bit/s)"},
337 { 55, "Baud (Baud)"},
338 { 56, "Kilobaud (kBaud)"},
339 { 57, "Megabaud (MBaud)"},
340 { 58, "Poles (Poles)"},
341 { 59, "Percent (%)"},
342 { 60, "Volts per millisecond (V/ms)"},
347 static const value_string file_status [] = {
350 { 2, "OK - More Data"},
352 { -1, "ERROR - File Handle"},
353 { -2, "ERROR - Blocked"},
354 { -3, "ERROR - Blocking Mode"},
355 { -4, "ERROR - Not in Progress"},
356 { -5, "ERROR - Not Found"},
357 { -6, "ERROR - Read Only"},
358 { -7, "ERROR - Write Only"},
359 { -8, "ERROR - Not Created"},
360 { -9, "ERROR - No Data"},
361 { -10, "ERROR - Wrong Mode"},
362 { -11, "ERROR - Too Big"},
363 { -12, "ERROR - Protected"},
364 { -13, "ERROR - CRC"},
365 { -14, "ERROR - Length"},
366 { -15, "ERROR - Too Many Open"},
367 { -16, "ERROR - Invalid File"},
368 { -17, "ERROR - Invalid Request"},
369 { -18, "ERROR - No Append"},
370 { -19, "ERROR - Invalid State"},
371 { -20, "ERROR - Incompatible"},
372 { -21, "ERROR - Uninitialized"},
376 /* File status mode */
377 static const value_string file_status_mode [] = {
382 { 4, "New Directory"},
386 /* File attributes */
387 static const value_string file_attributes [] = {
389 { 1, "File Integrity"},
390 { 2, "Calculate CRC32"},
391 { 3, "File Attributes"},
392 { 4, "Creation Date and Time"},
393 { 5, "Modification Date and Time"},
397 /* File reference position */
398 static const value_string file_ref_point [] = {
399 { 0, "SoF - Start of file"},
400 { 1, "EoF - End of file"},
401 { 2, "Current - Use current file pointer"},
405 static const value_string cyclic_setup_mode [] = {
415 { 12, "Get mappings"},
419 static const value_string cyclic_attributes [] = {
422 { 2, "Synchronised"},
424 { 4, "Sample Period"},
427 { 7, "Rx Timeout Handler"},
428 { 8, "Rx Data Late Handler"},
429 { 9, "Transport Address"},
430 { 10, "Max Mappings"},
431 { 11, "Number Of Mappings"},
432 { 12, "Mapping Item"},
434 { 128, "Max RX Links"},
435 { 129, "Max TX Links"},
436 { 130, "Max Mappings Per Link"},
437 { 131, "Max Sync RX Links"},
438 { 132, "Max Sync TX Links"},
439 { 133, "Max Mappings Per Sync Link"},
440 { 134, "'Process At' Queue Depth"},
441 { 135, "MEC Period"},
445 static const value_string cyclic_setup_link_dir [] = {
451 static const value_string cyclic_setup_link_exists [] = {
452 { 0, "Does not exist"},
457 static const value_string cyclic_link_req_resp [] = {
463 static const value_string additional_scheme_vals [] = {
469 /* Program Control - command codes */
470 static const value_string command_code_list [] = {
475 /*other commands to be added*/
478 /* Program Control - sub command codes */
479 static const value_string sub_command_code_list [] = {
484 /*other sub commands to be added*/
487 /* Program Control - status codes */
488 static const value_string status_list [] = {
492 /*other status to be added*/
495 /* Program Status - running state codes */
496 static const value_string running_state_list [] = {
500 { 3, "None (no program found in device)"},
502 /*other status to be added*/
505 /* Interrogate - command support states */
506 static const value_string Interrogate_support_state [] = {
507 { 0, "Not Supported"},
510 /*other status to be added*/
513 /* Interrogate - command / option states */
514 static const value_string Interrogate_command_option_state [] = {
518 /*other status to be added*/
521 static const value_string item_type_vals[] = {
527 static const value_string file_integrity_vals[] = {
534 static const true_false_string tfs_not_expected_expected = { "Odd", "Even" };
537 /* The following hf_* variables are used to hold the Wireshark IDs of
538 * our header fields; they are filled out when we call
539 * proto_register_field_array() in proto_register_ecmp()
541 static gint hf_ecmp_command = -1;
542 static gint hf_ecmp_destination_address = -1;
543 static gint hf_ecmp_source_address = -1;
544 static gint hf_ecmp_diagnostic = -1;
545 static gint hf_ecmp_type_rr = -1;
546 static gint hf_ecmp_chunking = -1;
547 static gint hf_ecmp_max_response_size = -1;
548 static gint hf_ecmp_category = -1;
549 static gint hf_ecmp_option = -1;
550 static gint hf_ecmp_attribute = -1;
551 static gint hf_ecmp_no_of_attributes = -1;
552 static gint hf_ecmp_chunk_id = -1;
553 static gint hf_ecmp_transaction_id = -1;
554 static gint hf_ecmp_status = -1;
555 static gint hf_ecmp_drive_type = -1;
556 static gint hf_ecmp_drive_derivative = -1;
557 static gint hf_ecmp_drive_factory_fit_category_id = -1;
558 static gint hf_ecmp_category_id = -1;
559 static gint hf_ecmp_attribute_string = -1;
560 static gint hf_ecmp_file_name = -1;
561 static gint hf_ecmp_info_command = -1;
562 static gint hf_ecmp_directory = -1;
563 static gint hf_ecmp_names_scheme = -1;
564 static gint hf_ecmp_variable_name = -1;
565 static gint hf_ecmp_unit_id_string = -1;
566 static gint hf_ecmp_ecmp_string = -1;
567 static gint hf_ecmp_process_time = -1;
568 static gint hf_ecmp_cyclic_frame_time = -1;
569 static gint hf_ecmp_grandmaster = -1;
570 static gint hf_ecmp_data = -1;
571 static gint hf_ecmp_response_data = -1;
573 static gint hf_ecmp_cyclic_link_num = -1;
574 static gint hf_ecmp_cyclic_align = -1;
575 static gint hf_ecmp_cyclic_scheme = -1;
576 static gint hf_ecmp_cyclic_link_number_display = -1;
579 static gint hf_ecmp_cyclic_setup_mode = -1;
580 static gint hf_ecmp_cyclic_setup_linkno = -1;
581 static gint hf_ecmp_cyclic_setup_dir = -1;
582 static gint hf_ecmp_cyclic_setup_attrib_count = -1;
583 static gint hf_ecmp_cyclic_setup_rsp_status = -1;
584 static gint hf_ecmp_cyclic_setup_rsp_err_idx = -1;
585 static gint hf_ecmp_cyclic_setup_attrib = -1;
586 static gint hf_ecmp_cyclic_setup_link_exists = -1;
587 static gint hf_ecmp_cyclic_link_req_resp = -1;
589 /*for info command */
590 static gint hf_ecmp_buffer_size = -1;
591 static gint hf_ecmp_max_response = -1;
592 static gint hf_ecmp_max_handle = -1;
593 static gint hf_ecmp_info_address = -1;
595 /*for parameter access commands*/
596 static gint hf_ecmp_parameter_address = -1;
597 static gint hf_ecmp_number_of_parameter_definitions = -1;
598 static gint hf_ecmp_number_of_parameter_responses = -1;
599 static gint hf_ecmp_parameter_status = -1;
600 static gint hf_ecmp_data_type = -1;
601 static gint hf_ecmp_info_type = -1;
603 /* for file access commands */
604 static gint hf_ecmp_file_status = -1;
605 static gint hf_ecmp_file_handle = -1;
606 static gint hf_ecmp_file_attributes = -1;
607 static gint hf_ecmp_file_ref_point = -1;
610 /* for tunnel frame command */
611 #define TUNNEL_START_FLAG 0x01
612 #define TUNNEL_END_FLAG 0x02
613 #define TUNNEL_CHECK_OUTPUT_FLAG 0x04
615 static gint hf_ecmp_tunnel_control = -1;
616 static gint hf_ecmp_tunnel_start_flag = -1;
617 static gint hf_ecmp_tunnel_end_flag = -1;
618 static gint hf_ecmp_tunnel_check_output_flag = -1;
619 static gint hf_ecmp_tunnel_size = -1;
621 /* Generated from convert_proto_tree_add_text.pl */
622 static int hf_ecmp_physical_address = -1;
623 static int hf_ecmp_logical_address = -1;
624 static int hf_ecmp_primary_colour = -1;
625 static int hf_ecmp_secondary_colour = -1;
626 static int hf_ecmp_number_of_subsequent_object_requests = -1;
627 static int hf_ecmp_number_of_decimal_places = -1;
628 static int hf_ecmp_no_information_available = -1;
629 static int hf_ecmp_param_format_bit_default_unipolar = -1;
630 static int hf_ecmp_param_format_write_allowed = -1;
631 static int hf_ecmp_param_format_read_not_allowed = -1;
632 static int hf_ecmp_param_format_protected_from_destinations = -1;
633 static int hf_ecmp_param_format_parameter_not_visible = -1;
634 static int hf_ecmp_param_format_not_clonable = -1;
635 static int hf_ecmp_param_format_voltage_or_current_rating_dependent = -1;
636 static int hf_ecmp_param_format_parameter_has_no_default = -1;
637 static int hf_ecmp_param_format_number_of_decimal_places = -1;
638 static int hf_ecmp_param_format_variable_maximum_and_minimum = -1;
639 static int hf_ecmp_param_format_string_parameter = -1;
640 static int hf_ecmp_param_format_desitination_set_up_parameter = -1;
641 static int hf_ecmp_param_format_filtered_when_displayed = -1;
642 static int hf_ecmp_param_format_pseudo_read_only = -1;
643 static int hf_ecmp_param_format_display_format = -1;
644 static int hf_ecmp_param_format_floating_point_value = -1;
645 static int hf_ecmp_param_format_units = -1;
646 static int hf_ecmp_string_id = -1;
647 static int hf_ecmp_address_scheme_menu = -1;
648 static int hf_ecmp_address_scheme_parameter = -1;
649 static int hf_ecmp_address_scheme_slot = -1;
650 static int hf_ecmp_address_scheme_null_byte_size = -1;
651 static int hf_ecmp_display_unit_id = -1;
652 static int hf_ecmp_data_boolean = -1;
653 static int hf_ecmp_data_int8 = -1;
654 static int hf_ecmp_data_uint8 = -1;
655 static int hf_ecmp_data_int16 = -1;
656 static int hf_ecmp_data_uint16 = -1;
657 static int hf_ecmp_data_int32 = -1;
658 static int hf_ecmp_data_uint32 = -1;
659 static int hf_ecmp_data_int64 = -1;
660 static int hf_ecmp_data_uint64 = -1;
661 static int hf_ecmp_data_float = -1;
662 static int hf_ecmp_data_double = -1;
663 static int hf_ecmp_access_mode = -1;
664 static int hf_ecmp_open_in_non_blocking_mode = -1;
665 static int hf_ecmp_open_file_relative_to_specified_directory_handle = -1;
666 static int hf_ecmp_file_access_mode = -1;
667 static int hf_ecmp_additional_scheme = -1;
668 static int hf_ecmp_scheme_data_length = -1;
669 static int hf_ecmp_number_of_requested_bytes = -1;
670 static int hf_ecmp_number_of_bytes_transferred = -1;
671 static int hf_ecmp_crc = -1;
672 static int hf_ecmp_ref_offset = -1;
673 static int hf_ecmp_number_of_files_to_list = -1;
674 static int hf_ecmp_file_hash = -1;
675 static int hf_ecmp_item_type = -1;
676 static int hf_ecmp_file_integrity = -1;
677 static int hf_ecmp_display_attr_read_only = -1;
678 static int hf_ecmp_display_attr_hidden = -1;
679 static int hf_ecmp_display_attr_system = -1;
680 static int hf_ecmp_display_attr_volume_label = -1;
681 static int hf_ecmp_display_attr_subdirectory = -1;
682 static int hf_ecmp_display_attr_archive = -1;
683 static int hf_ecmp_display_creation = -1;
684 static int hf_ecmp_display_modification = -1;
685 static int hf_ecmp_interrogate_item_type = -1;
686 static int hf_ecmp_interrogate_count = -1;
687 static int hf_ecmp_modbus_pdu_size = -1;
688 /* static int hf_ecmp_destination_scheme = -1; */
689 static int hf_ecmp_program_control_target = -1;
690 static int hf_ecmp_program_control_command = -1;
691 static int hf_ecmp_program_control_sub_command = -1;
692 static int hf_ecmp_program_control_status = -1;
693 static int hf_ecmp_program_status_target = -1;
694 static int hf_ecmp_program_status_status = -1;
695 static int hf_ecmp_program_status_additional_items = -1;
696 static int hf_ecmp_cyclic_setup_max_mappings = -1;
697 static int hf_ecmp_cyclic_setup_start_offset = -1;
698 static int hf_ecmp_cyclic_setup_tx_count = -1;
699 static int hf_ecmp_cyclic_setup_rx_count = -1;
700 static int hf_ecmp_udp_alignment = -1;
701 static int hf_ecmp_udp_scheme = -1;
702 static int hf_ecmp_cyclic_data = -1;
703 static int hf_ecmp_version_summary = -1;
704 static int hf_ecmp_min_param_menu = -1;
705 static int hf_ecmp_max_param_menu = -1;
706 static int hf_ecmp_file_length = -1;
707 static int hf_ecmp_mec_offset = -1;
708 static int hf_ecmp_sample_period = -1;
709 static int hf_ecmp_rx_timeout = -1;
710 static int hf_ecmp_rx_action = -1;
711 static int hf_ecmp_rx_event_destination = -1;
712 static int hf_ecmp_rx_event = -1;
713 static int hf_ecmp_rx_late_handler_action = -1;
714 static int hf_ecmp_rx_late_handler_event_destination = -1;
715 static int hf_ecmp_rx_late_handler_event = -1;
716 static int hf_ecmp_transport_addr_scheme = -1;
717 static int hf_ecmp_transport_addr = -1;
718 static int hf_ecmp_mapping_item_offset = -1;
719 static int hf_ecmp_mapping_item_scheme = -1;
720 static int hf_ecmp_setup_attribute = -1;
721 static int hf_ecmp_mec_period = -1;
722 static int hf_ecmp_interrogate_command = -1;
723 /************************************************************/
725 /* These are the ids of the subtrees that we may be creating */
727 static gint ett_ecmp = -1;
728 static gint ett_ecmp_address= -1;
729 static gint ett_ecmp_response_size = -1;
730 static gint ett_ecmp_command = -1;
731 static gint ett_ecmp_category = -1;
732 static gint ett_ecmp_option = -1;
733 static gint ett_ecmp_option_data = -1;
734 static gint ett_ecmp_attribute = -1;
735 static gint ett_ecmp_attribute_data = -1;
736 static gint ett_ecmp_cyclic_scheme = -1;
737 static gint ett_ecmp_info_type = -1;
738 static gint ett_ecmp_info_count = -1;
739 static gint ett_ecmp_interrogate_message = -1;
740 static gint ett_ecmp_param_address = -1;
741 static gint ett_ecmp_access_mode = -1;
742 static gint ett_ecmp_access_file = -1;
743 static gint ett_ecmp_file_read = -1;
744 static gint ett_ecmp_file_write = -1;
745 static gint ett_ecmp_file_info = -1;
746 static gint ett_ecmp_file_info_att = -1;
747 static gint ett_ecmp_file_position = -1;
748 static gint ett_ecmp_file_list_no = -1;
749 static gint ett_ecmp_file_list = -1;
750 static gint ett_ecmp_tunnel_3s_goodframe = -1;
751 static gint ett_ecmp_tunnel_3s_size = -1;
752 static gint ett_ecmp_tunnel_3s_service = -1;
753 static gint ett_cyclic_setup_attribs = -1;
754 static gint ett_cyclic_setup_attrib_item = -1;
755 static gint ett_cyclic_setup_transport_addr = -1;
756 static gint ett_ecmp_cyclic_data_32_bit_display = -1;
757 static gint ett_ecmp_cyclic_data_16_bit_display = -1;
758 static gint ett_ecmp_cyclic_data_8_bit_display = -1;
759 static gint ett_ecmp_modbus_pdu_message = -1;
760 static gint ett_ecmp_program_control_message = -1;
761 static gint ett_ecmp_program_status_message = -1;
762 static expert_field ei_ecmp_unknown_command = EI_INIT;
763 static expert_field ei_ecmp_color = EI_INIT;
764 static expert_field ei_ecmp_option = EI_INIT;
765 static expert_field ei_ecmp_item_type = EI_INIT;
766 static expert_field ei_ecmp_options_not_implemented = EI_INIT;
767 static expert_field ei_ecmp_info_type = EI_INIT;
768 static expert_field ei_ecmp_attribute_type = EI_INIT;
769 static expert_field ei_ecmp_parameter_addressing_scheme = EI_INIT;
770 static expert_field ei_ecmp_data_type = EI_INIT;
773 /*--------------------------------------------------------------------*/
774 /* General Commands and Framing Dissectors */
775 /*--------------------------------------------------------------------*/
776 /*a function to add the initial information about the transport layer (the first bits)*/
777 static int add_transport_layer_frame(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, int addr_type)
779 proto_item *ecmp_address_item = NULL;
780 proto_tree *ecmp_address_tree = NULL;
783 ecmp_address_item = proto_tree_add_item(ecmp_tree, addr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
785 byte_test = tvb_get_guint8(tvb, offset);
786 if ((byte_test != 0) && (byte_test != 1)) {
787 /* tree to display the data in the address*/
788 ecmp_address_tree = proto_item_add_subtree(ecmp_address_item, ett_ecmp_address);
792 case 2: /* default route scheme*/
795 /* displays the values of the addresses*/
796 proto_tree_add_item(ecmp_address_tree, hf_ecmp_physical_address, tvb, offset, 1, ENC_NA);
797 proto_tree_add_item(ecmp_address_tree, hf_ecmp_logical_address, tvb, offset, 1, ENC_NA);
800 case 3:/* diagnostic scheme*/
801 proto_tree_add_item(ecmp_address_tree, hf_ecmp_diagnostic, tvb, offset, 1, ENC_BIG_ENDIAN);
804 case 4: /* Names scheme */
805 /* Calls a function to display the UTF-8 string data*/
806 proto_tree_add_item(ecmp_address_tree, hf_ecmp_names_scheme, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
807 offset += (tvb_get_ntohs(tvb, offset) + 2);
817 /* a function to display option codes */
818 static int add_option_codes(int offset, packet_info *pinfo, tvbuff_t *tvb, proto_tree* ecmp_tree)
820 proto_item* ecmp_option_number_item = NULL;
821 proto_item* ecmp_option_item;
822 proto_tree* ecmp_option_tree;
823 proto_tree* ecmp_option_data_tree = NULL;
824 guint8 option_code_display = 0;
825 guint16 count = 0; /* number of times the loop iterates*/
827 gboolean more_options = TRUE;
831 start_offset = offset;
832 ecmp_option_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_option, &ecmp_option_number_item, "Options" );
834 /* Loop to display all options */
835 while(more_options) /* loops until option code is 0*/
837 option_code_display = tvb_get_guint8(tvb, offset);
838 ecmp_option_item = proto_tree_add_item(ecmp_option_tree, hf_ecmp_option, tvb, offset, 1, ENC_BIG_ENDIAN);
840 switch(option_code_display)
842 case 0:/* end of options*/
843 proto_item_append_text(ecmp_option_number_item, ": %d", count);
844 proto_item_set_len(ecmp_option_number_item, offset-start_offset);
845 more_options = FALSE;
847 case 1:/* dummy - 0 bytes of data */
849 case 2:/* process at - 8 bytes of data */
850 ecmp_option_data_tree = proto_item_add_subtree(ecmp_option_item, ett_ecmp_option_data);
852 proto_tree_add_item(ecmp_option_data_tree, hf_ecmp_process_time, tvb, offset, 8, ENC_BIG_ENDIAN);
855 default: /* Option that is not recognised*/
856 proto_item_append_text(ecmp_option_number_item, "%d ", count);
857 expert_add_info(pinfo, ecmp_option_number_item, &ei_ecmp_option);
866 /* a function to display attributes */
867 static void add_attributes(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, gboolean request)
869 proto_item* ecmp_attribute_number_item = NULL;
870 proto_item* ecmp_attribute_item = NULL, *color_item;
871 proto_tree* ecmp_attribute_tree = NULL;
872 proto_tree* ecmp_attribute_data_tree = NULL;
873 guint8 no_of_attributes = 0;
874 guint8 a = 0; /*values used for looping*/
878 guint16 att_length = 0;
880 gchar* pStr = NULL; /*char array for version string output*/
881 int start_offset = offset;
883 /*display the number of attributes*/
884 ecmp_attribute_number_item = proto_tree_add_item(ecmp_tree, hf_ecmp_no_of_attributes, tvb, offset, 1, ENC_BIG_ENDIAN);
885 ecmp_attribute_tree = proto_item_add_subtree(ecmp_attribute_number_item, ett_ecmp_attribute);
887 no_of_attributes = tvb_get_guint8(tvb, offset);
890 for (a = 0; a < no_of_attributes; a++, offset++) {
892 ecmp_attribute_item = proto_tree_add_item(ecmp_attribute_tree, hf_ecmp_attribute, tvb, offset, 1, ENC_BIG_ENDIAN );
893 ecmp_attribute_data_tree = proto_item_add_subtree(ecmp_attribute_item, ett_ecmp_attribute_data);
896 /*code for dissecting the colour codes attribute*/
897 switch(tvb_get_guint8(tvb, offset))
901 /*get length of attribute for error checking*/
904 /*output primary colour codes- the two bytes representing each colour are output as integers*/
905 color = tvb_get_ntohl(tvb, offset);
906 color_item = proto_tree_add_uint_format_value(ecmp_attribute_data_tree, hf_ecmp_primary_colour, tvb, offset, 4, color, "(red) %d (green) %d (blue) %d", tvb_get_guint8(tvb, offset+1), tvb_get_guint8(tvb, offset+2), tvb_get_guint8(tvb, offset+3));
907 if ((color & 0xFF000000) != 0) {
908 /*error check for correct colour code format */
909 expert_add_info(pinfo, color_item, &ei_ecmp_color);
913 /*output secondary colour codes- the two bytes representing each colour are output as integers*/
914 color = tvb_get_ntohl(tvb, offset);
915 color_item = proto_tree_add_uint_format_value(ecmp_attribute_data_tree, hf_ecmp_secondary_colour, tvb, offset, 4, color, "(red) %d (green) %d (blue) %d", tvb_get_guint8(tvb, offset+1), tvb_get_guint8(tvb, offset+2), tvb_get_guint8(tvb, offset+3));
916 if ((color & 0xFF000000) != 0) {
917 /*error check for correct colour code format */
918 expert_add_info(pinfo, color_item, &ei_ecmp_color);
922 /*code for dissecting the version summary attribute*/
925 att_length = tvb_get_ntohs(tvb, offset);
926 pStr = (gchar *)wmem_alloc(wmem_packet_scope(), att_length+1); /* 100 char buffer */
930 for (c = 0; c < att_length; c++, offset++) {
931 check = tvb_get_guint8(tvb,offset);
932 if((check == 'V')||(check == '#')||(check == '@')) {
935 } else if(tvb_get_guint8(tvb,offset)== (';')) {
937 /*display version summary parameter, e.g 'FW', 'BL', 'HW'*/
938 proto_tree_add_string(ecmp_attribute_data_tree, hf_ecmp_version_summary, tvb, offset-b, b, pStr);
941 pStr[b] = (gchar)tvb_get_guint8(tvb,offset);
946 /*display last version summary parameter, e.g 'FW', 'BL', 'HW' as no deliminator to check for, just prints out rest of version string*/
947 proto_tree_add_string(ecmp_attribute_data_tree, hf_ecmp_version_summary, tvb, offset-b, b, pStr);
952 /* displays the data inside the attribute*/
953 proto_tree_add_item(ecmp_attribute_data_tree, hf_ecmp_attribute_string, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
954 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
960 proto_item_set_len(ecmp_attribute_number_item, offset-start_offset);
964 /* a function to display the category codes */
965 static int add_category_codes(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
967 proto_item *ecmp_category_item = NULL;
968 proto_tree *ecmp_category_tree = NULL;
969 guint8 category_size = 0;
970 int start_offset = offset;
971 guint8 category_value = tvb_get_guint8(tvb, offset);
973 /* displays the category and creates a tree to display further data*/
974 ecmp_category_item = proto_tree_add_item(ecmp_tree, hf_ecmp_category, tvb, offset, 1, ENC_BIG_ENDIAN);
975 ecmp_category_tree = proto_item_add_subtree(ecmp_category_item, ett_ecmp_category);
978 category_size = tvb_get_guint8(tvb, offset);
981 if(category_size==2 && category_value == 1) {
982 /*display "option module" and its ID*/
983 proto_tree_add_item(ecmp_category_tree, hf_ecmp_category_id, tvb, offset, 2, ENC_BIG_ENDIAN);
984 offset+=category_size;
985 } else if(category_size == 4 && category_value == 0) {
986 /*display "drive" and its data (product type, drive derivative and ID*/
987 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_type, tvb, offset, 1, ENC_BIG_ENDIAN);
988 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_derivative, tvb, offset+1, 1, ENC_BIG_ENDIAN);
989 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_factory_fit_category_id, tvb, offset+2, 2, ENC_BIG_ENDIAN);
990 offset+=category_size;
993 /* Display unknown and its hex data */
994 proto_tree_add_item(ecmp_category_tree, hf_ecmp_data, tvb, offset, category_size, ENC_NA);
995 offset += category_size;
998 proto_item_set_len(ecmp_category_item, offset-start_offset);
1003 /* a function to display response size data */
1004 static int get_response_size(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
1006 proto_item* ecmp_max_response_item = NULL;
1007 proto_tree* ecmp_response_size_tree = NULL;
1009 guint16 max_response_size = 0;
1011 /*get values for number of chunks and max response size*/
1012 chunks = tvb_get_guint8(tvb, offset)>>4&0x0F;
1013 max_response_size = tvb_get_ntohs(tvb, offset) & 0x0FFF;
1015 /*display response subtree */
1016 ecmp_response_size_tree = proto_tree_add_subtree_format(ecmp_tree, tvb, offset, 2, ett_ecmp_response_size, &ecmp_max_response_item, "Response Size: %X, %X (%d)", chunks, max_response_size, max_response_size);
1018 /*display chunks and max response size in response subtree*/
1019 proto_tree_add_item(ecmp_response_size_tree, hf_ecmp_chunking, tvb, offset, 2, ENC_BIG_ENDIAN);
1020 proto_tree_add_item(ecmp_response_size_tree, hf_ecmp_max_response_size, tvb, offset, 2, ENC_BIG_ENDIAN);
1027 /* a function to display the command code and type (request/response) */
1028 static int add_command_codes(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, guint8 transaction_id_value, guint8* command_value)
1030 proto_tree *ecmp_command_tree;
1031 const gchar* command_str;
1034 command = tvb_get_guint8(tvb, offset);
1035 *command_value = command & 0x7F;
1036 command_str = val_to_str(*command_value, command_vals, "Unknown Type (0x%02x)");
1038 /*display command subtree*/
1039 ecmp_command_tree = proto_tree_add_subtree_format(ecmp_tree, tvb, offset, 1, ett_ecmp_command, NULL, "Request Response Code: %s", command_str);
1041 /* Displays the command */
1042 proto_tree_add_item(ecmp_command_tree, hf_ecmp_command, tvb, offset, 1, ENC_BIG_ENDIAN);
1043 /* Displays the type (request/response) */
1044 proto_tree_add_item(ecmp_command_tree, hf_ecmp_type_rr, tvb, offset, 1, ENC_BIG_ENDIAN);
1046 /* Information displayed in the Info column*/
1047 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, %s. Transaction ID: %d",
1048 command_str, val_to_str(((command & 0x80) >> 7), type_rr, "Unknown Type (0x%02x)"), transaction_id_value);
1054 /* a function to add a cyclic frame query */
1055 static int add_cyclic_frame_query(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree )
1057 /* display the cyclic link number */
1058 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_num, tvb, offset++, 1, ENC_BIG_ENDIAN);
1063 /* a function to add a cyclic frame */
1064 static int add_cyclic_frame(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree )
1067 proto_item *ecmp_scheme_item = NULL;
1068 proto_tree *ecmp_scheme_tree = NULL;
1069 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_num, tvb, offset++, 1, ENC_BIG_ENDIAN);
1070 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_align, tvb, offset++, 1, ENC_BIG_ENDIAN);
1073 scheme = tvb_get_guint8(tvb, offset);
1075 ecmp_scheme_item = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_scheme, tvb, offset++, 1, ENC_BIG_ENDIAN);
1078 /* Create a new sub tree spawning off the scheme byte for the synchronisation scheme data to be placed. */
1079 ecmp_scheme_tree = proto_item_add_subtree(ecmp_scheme_item, ett_ecmp_cyclic_scheme);
1082 proto_tree_add_item( ecmp_scheme_tree, hf_ecmp_grandmaster, tvb, offset, 8, ENC_BIG_ENDIAN);
1085 proto_tree_add_item(ecmp_scheme_tree, hf_ecmp_cyclic_frame_time, tvb, offset, 8, ENC_BIG_ENDIAN);
1089 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, -1, ENC_NA);
1091 return tvb_reported_length(tvb);
1095 /* a function to display cyclic tvb data in byte (8-bit), word (16-bit), and long (32-bit) unsigned formats */
1096 static int display_raw_cyclic_data(guint8 display, int offset, guint16 buffer_size, tvbuff_t *tvb, proto_tree* ecmp_current_tree )
1098 /****************************************************************************************/
1100 /* display_raw_cyclic_data - display the cyclic data in various formats. */
1102 /* Parameters: display = selects desired display format. */
1103 /* 0 = BYTE_FORMAT (8-bits 1F 20 37 BC ... */
1104 /* 1 = WORD_FORMAT (16-bits 1F20 37BC 77F1 ... */
1105 /* 2 = LONG_FORMAT (32-bits 1F2037BC 0013F5CD ... */
1107 /* offset = offset within tvb buffer where this data starts. */
1109 /* buffer_size = number of bytes to be converted and displayed. */
1111 /* tvb = buffer structure within Wireshark holding this frame. */
1113 /* ecmp_current_tree = the tree where the data is to be displayed. */
1116 /* Notes: we only display so many elements on a line (before continuing on next line) */
1118 /* 16 elements per line for byte (8-bit) and word (16-bit) */
1119 /* 8 elements per line for long (32-bit) */
1121 /* Programmer: Jim Lynch */
1122 /****************************************************************************************/
1124 /* bail out if the buffer size is zero */
1125 if (buffer_size == 0) {
1126 proto_tree_add_bytes_format_value(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, offset-1, 0, NULL, "No data");
1128 /* define some variables */
1129 gchar* pdata = NULL; /* pointer to array that stores the formatted data string */
1130 guint16 idx = 0; /* counts through formatted string array */
1131 guint8 value8 = 0; /* placeholder for extracted 8-bit data */
1132 guint16 value16 = 0; /* placeholder for extracted 16-bit data */
1133 guint32 value32 = 0; /* placeholder for extracted 32-bit data */
1134 guint16 num_elements_total = 0; /* contains total number of elements (byte/word/long) to be processed */
1135 const guint16 num_byte_elements_per_line = 16; /* number of byte (8-bit) elements per line e.g. "1B " (3 chars per element) */
1136 const guint16 num_word_elements_per_line = 16; /* number of word (16-bit) elements per line e.g. "A81B " (5 chars per element) */
1137 const guint16 num_long_elements_per_line = 8; /* number of long (32-bit) elements per line e.g. "01F4A81B " (9 chars per element) */
1138 guint16 num_elements_per_line = 8; /* counts the current number of elements per line */
1139 guint16 num_elements = 0; /* counts the number of elements in the format string */
1140 guint16 format_string_size = 0; /* size of dynamic array to hold the formatted string */
1141 guint16 a = 0; /* value used for looping */
1142 int start_offset, line_offset;
1144 /* calculate format string array size and other stuff */
1146 /* Note: format string does require a nul-terminator (the + 1 in the equations) */
1148 /* display = 0: (byte format "1D 24 3F ... A3 " */
1149 /* format_string_size = (num_byte_elements_per_line * 3) + 1 */
1151 /* display = 1: (word format "1D24 3F84 120B ... 1FA3 " */
1152 /* format_string_size = (num_word_elements_per_line * 5) + 1 */
1154 /* display = 2: (byte format "1D243F84 9BC08F20 ... 28BB1FA3 " */
1155 /* format_string_size = (num_long_elements_per_line * 9) + 1 */
1157 if (display == cyclic_display_byte_format) {
1158 format_string_size = (num_byte_elements_per_line * 3) + 1; /* format_string_size = 49 */
1159 num_elements_per_line = num_byte_elements_per_line; /* num_elements_per_line = 16 */
1160 num_elements_total = buffer_size;
1161 } else if (display == cyclic_display_word_format) {
1162 format_string_size = (num_word_elements_per_line * 5) + 1; /* format_string_size = 81 */
1163 num_elements_per_line = num_word_elements_per_line; /* num_elements_per_line = 16 */
1164 num_elements_total = buffer_size >> 1;
1165 } else if (display == cyclic_display_long_format) {
1166 format_string_size = (num_long_elements_per_line * 9) + 1; /* format_string_size = 73 */
1167 num_elements_per_line = num_long_elements_per_line; /* num_elements_per_line = 8 */
1168 num_elements_total = buffer_size >> 2;
1170 format_string_size = (num_byte_elements_per_line * 3) + 1; /* format_string_size = 49 */
1171 num_elements_per_line = num_byte_elements_per_line; /* num_elements_per_line = 16 */
1172 num_elements_total = buffer_size;
1175 /* allocate dynamic memory for one line */
1176 pdata = (gchar *)wmem_alloc(wmem_packet_scope(), format_string_size);
1178 /* OK, let's get started */
1182 line_offset = start_offset = offset;
1183 /* work through the display elements, 1 byte\word\long at a time */
1184 for (a = 0; a < num_elements_total; a++ )
1186 /* use Wireshark accessor function to get the next byte, word, or long data */
1187 if (display == cyclic_display_byte_format) {
1188 value8 = tvb_get_guint8(tvb, offset);
1190 } else if (display == cyclic_display_word_format) {
1191 value16 = tvb_get_ntohs(tvb, offset);
1193 } else if (display == cyclic_display_long_format) {
1194 value32 = tvb_get_ntohl(tvb, offset);
1198 /* increment the num_elements we've done on the current line */
1201 /* check if we hit the max number of byte elements per line */
1202 if (num_elements >= num_elements_per_line) {
1203 /* we hit end of the current line */
1204 /* add final value to string */
1205 if (display == cyclic_display_byte_format) {
1206 g_snprintf(&pdata[idx], 32, "%02x",value8);
1207 } else if (display == cyclic_display_word_format) {
1208 g_snprintf(&pdata[idx], 32, "%04x",value16);
1209 } else if (display == cyclic_display_long_format) {
1210 g_snprintf(&pdata[idx], 32, "%08x",value32);
1213 /* display the completed line in the sub-tree */
1214 proto_tree_add_bytes_format(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, offset, offset-line_offset, NULL, "%s", pdata);
1216 /* start the line over */
1219 line_offset = offset;
1222 /* we're still adding to the current line */
1223 /* add current value to string */
1224 if (display == cyclic_display_byte_format) {
1225 g_snprintf(&pdata[idx], 32, "%02x ",value8);
1227 } else if (display == cyclic_display_word_format) {
1228 g_snprintf(&pdata[idx], 32, "%04x ",value16);
1230 } else if (display == cyclic_display_long_format) {
1231 g_snprintf(&pdata[idx], 32, "%08x ",value32);
1237 /* if we exited the loop, see if there's a partial line to display */
1238 if (num_elements > 0) {
1239 /* add null-terminator to partial line */
1242 /* display the partial line in the sub-tree */
1243 proto_tree_add_bytes_format(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, start_offset, offset-start_offset, NULL, "%s", pdata);
1250 /* a function returning the information requested by the 'info' command */
1251 static void add_info_response(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
1253 proto_item* ecmp_info_address_item = NULL;
1254 proto_tree* ecmp_info_tree = NULL;
1255 proto_tree* ecmp_info_address_tree = NULL, *address_tree;
1257 guint8 no_of_address = 0;
1258 guint8 i = 0; /*for counting */
1260 length = tvb_reported_length(tvb);
1262 /*display info response tree */
1263 ecmp_info_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 6, ett_ecmp_info_type, NULL, "Response Information");
1265 /*display buffer size */
1266 proto_tree_add_item(ecmp_info_tree, hf_ecmp_buffer_size, tvb, offset, 2, ENC_BIG_ENDIAN);
1269 /*display max response time */
1270 proto_tree_add_item(ecmp_info_tree, hf_ecmp_max_response, tvb, offset, 2, ENC_BIG_ENDIAN);
1273 /*display max handle period */
1274 proto_tree_add_item(ecmp_info_tree, hf_ecmp_max_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1277 if (length > offset) {
1278 /*display count of default server addresses */
1279 ecmp_info_address_item = proto_tree_add_item(ecmp_tree, hf_ecmp_info_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1280 ecmp_info_address_tree = proto_item_add_subtree(ecmp_info_address_item, ett_ecmp_info_count);
1281 no_of_address = tvb_get_guint8(tvb, offset);
1283 if (no_of_address > 0) {
1284 /*do code to display address data */
1285 for (i = 0; i < no_of_address; i++) {
1286 address_tree = proto_tree_add_subtree_format(ecmp_info_address_tree, tvb, offset, 1, ett_ecmp_address, NULL, "Address %d", i+1);
1287 proto_tree_add_item(address_tree, hf_ecmp_physical_address, tvb, offset, 1, ENC_NA);
1288 proto_tree_add_item(address_tree, hf_ecmp_logical_address, tvb, offset, 1, ENC_NA);
1296 /*--------------------------------------------------------------------*/
1297 /* Parameter Access Commands */
1298 /*--------------------------------------------------------------------*/
1300 /* a function to display data given data_type */
1301 static int get_data_type(packet_info* pinfo, int offset, guint8 data_type, tvbuff_t *tvb, proto_tree* ecmp_current_tree)
1303 /*switch to decide correct data_type dissection*/
1306 case 0: /*display boolean*/
1307 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_boolean, tvb, offset, 1, ENC_NA);
1309 case 1: /*display INT8*/
1310 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int8, tvb, offset, 1, ENC_NA);
1312 case 2: /*display UINT8*/
1313 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint8, tvb, offset, 1, ENC_NA);
1315 case 3: /*display INT16*/
1316 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int16, tvb, offset, 2, ENC_BIG_ENDIAN);
1319 case 4: /*display UINT16*/
1320 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint16, tvb, offset, 2, ENC_BIG_ENDIAN);
1323 case 5: /*display INT32*/
1324 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int32, tvb, offset, 4, ENC_BIG_ENDIAN);
1327 case 6: /*display UINT32*/
1328 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint32, tvb, offset, 4, ENC_BIG_ENDIAN);
1331 case 7: /*display INT64*/
1332 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int64, tvb, offset, 8, ENC_BIG_ENDIAN);
1335 case 8: /*display UINT64*/
1336 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint64, tvb, offset, 8, ENC_BIG_ENDIAN);
1339 case 9: /*display INT128*/
1340 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, 16, ENC_NA);
1343 case 10: /*display UINT128*/
1344 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, 16, ENC_NA);
1347 case 20:/*display single float*/
1348 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_float, tvb, offset, 4, ENC_BIG_ENDIAN);
1351 case 21: /*display double float*/
1352 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_double, tvb, offset, 8, ENC_BIG_ENDIAN);
1355 case 30: /*display string ID*/
1356 proto_tree_add_item(ecmp_current_tree, hf_ecmp_string_id, tvb, offset, 2, ENC_NA|ENC_ASCII);
1359 case 32: /*display (ECMP) string*/
1360 proto_tree_add_item(ecmp_current_tree, hf_ecmp_ecmp_string, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1361 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1363 default: /*display untyped size*/
1364 if (data_type < 128) {
1365 proto_tree_add_expert(ecmp_current_tree, pinfo, &ei_ecmp_data_type, tvb, 0, -1);
1367 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, (data_type- 127), ENC_NA);
1368 offset += (data_type- 128);
1376 /* a function to add the parameter address schemes for 'read' command */
1377 static int get_address_scheme(packet_info* pinfo, int offset, guint8 scheme, tvbuff_t *tvb, proto_tree* ecmp_parameter_tree)
1379 /*if address scheme is standard*/
1383 /*display Menu no. */
1384 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1387 /*display parameter no. */
1388 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_parameter, tvb, offset, 2, ENC_BIG_ENDIAN);
1392 case 1:/*if address scheme is slot specific*/
1393 /*display slot number*/
1394 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_slot, tvb, offset, 1, ENC_NA);
1397 /*display Menu no. */
1398 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1401 /*display parameter no. */
1402 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_parameter, tvb, offset, 2, ENC_BIG_ENDIAN);
1406 case 3: /*if address scheme is variable*/
1407 /*display variable name */
1409 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_variable_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1410 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1413 case 4: /*if address scheme is NULL*/
1415 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_null_byte_size, tvb, offset, 1, ENC_NA);
1420 proto_tree_add_expert(ecmp_parameter_tree, pinfo, &ei_ecmp_parameter_addressing_scheme, tvb, offset, 1);
1426 /* a function to display an array of the read address schemes */
1427 static void get_parameter_definitions(packet_info* pinfo, int offset, guint8 command_value, tvbuff_t *tvb, proto_tree* ecmp_tree)
1429 proto_item* ecmp_parameter_item = NULL;
1430 proto_tree* ecmp_parameter_number_tree = NULL;
1431 proto_tree* ecmp_parameter_tree = NULL;
1434 guint8 data_type = 0;
1439 scheme = tvb_get_guint8(tvb, offset);
1441 ecmp_parameter_item = proto_tree_add_item(ecmp_tree, hf_ecmp_parameter_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1442 ecmp_parameter_tree = proto_item_add_subtree(ecmp_parameter_item, ett_ecmp_param_address);
1445 /* if "GetNextObjects" command */
1446 if(command_value == ECMP_COMMAND_GETNEXTOBJECTS)
1448 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1450 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_subsequent_object_requests, tvb, offset, 1, ENC_NA);
1453 /*display tree with count of definitions */
1454 ecmp_parameter_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_definitions, tvb, offset, 1, ENC_BIG_ENDIAN);
1455 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_parameter_item, ett_ecmp_param_address);
1457 count = tvb_get_guint8(tvb,offset);
1461 switch(scheme)/*sets n so that the tree highlights bytes in scheme specific data*/
1470 n = 1 + ((tvb_get_guint8(tvb, offset+1)<<8)|(tvb_get_guint8(tvb, offset+2)));
1477 if (command_value == ECMP_COMMAND_OBJECTINFO) {
1481 for (a = 0; a < count; a++) {
1482 ecmp_parameter_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_param_address, NULL, "Parameter Definition %d:", (a+1));
1484 if (command_value == ECMP_COMMAND_OBJECTINFO) {
1485 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_info_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1487 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1490 /*output the address schemes of the parameter requests */
1491 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1493 if (command_value == ECMP_COMMAND_WRITE) {
1494 data_type = tvb_get_guint8(tvb, offset);
1495 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1497 dec = tvb_get_gint8(tvb, offset);
1499 proto_tree_add_int(ecmp_parameter_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec);
1501 proto_tree_add_int_format_value(ecmp_parameter_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec, "0 (Invalid type)");
1504 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_tree);
1513 /* a function to show the "objectinfo" command response */
1514 static void get_object_info_response(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
1516 proto_item* ecmp_response_item = NULL;
1517 proto_tree* ecmp_parameter_number_tree = NULL;
1518 proto_tree* ecmp_parameter_response_tree = NULL;
1519 guint8 count = 0; /*stores number of parameter read responses */
1520 guint8 a = 0; /*counting varables */
1522 guint8 info_type0 = 0;
1524 guint8 data_type = 0;
1526 length = tvb_reported_length(tvb);
1528 ecmp_response_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_responses, tvb, offset, 1, ENC_BIG_ENDIAN);
1529 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_response_item, ett_ecmp_param_address);
1531 count = tvb_get_guint8(tvb, offset);
1535 proto_tree_add_item(ecmp_parameter_number_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1538 /*display info data response */
1539 for (a = 0; a < count; a++) {
1541 n = (length-offset)/count;
1544 /*display response header */
1545 proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1547 /*display response status */
1548 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1551 /*display response data */
1552 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_info_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1553 info_type0 = tvb_get_guint8(tvb, offset);
1558 /*no information available */
1559 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_no_information_available, tvb, offset, 1, ENC_NA);
1562 /*display min parameter in menu */
1564 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_min_param_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1568 /*display max parameter in menu */
1570 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_max_param_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1575 static const int * fields[] = {
1576 &hf_ecmp_param_format_bit_default_unipolar,
1577 &hf_ecmp_param_format_write_allowed,
1578 &hf_ecmp_param_format_read_not_allowed,
1579 &hf_ecmp_param_format_protected_from_destinations,
1580 &hf_ecmp_param_format_parameter_not_visible,
1581 &hf_ecmp_param_format_not_clonable,
1582 &hf_ecmp_param_format_voltage_or_current_rating_dependent,
1583 &hf_ecmp_param_format_parameter_has_no_default,
1584 &hf_ecmp_param_format_number_of_decimal_places,
1585 &hf_ecmp_param_format_variable_maximum_and_minimum,
1586 &hf_ecmp_param_format_string_parameter,
1587 &hf_ecmp_param_format_desitination_set_up_parameter,
1588 &hf_ecmp_param_format_filtered_when_displayed,
1589 &hf_ecmp_param_format_pseudo_read_only,
1590 &hf_ecmp_param_format_display_format,
1591 &hf_ecmp_param_format_floating_point_value,
1592 &hf_ecmp_param_format_units,
1596 /*display data for parameter format- UNITS and Display Format need dissecting? */
1598 proto_tree_add_bitmask_list(ecmp_parameter_response_tree, tvb, offset, 4, fields, ENC_BIG_ENDIAN);
1603 /*display minimum allowed value*/
1605 data_type = tvb_get_guint8(tvb,offset);
1606 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1608 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1611 /*display maximum allowed value*/
1613 data_type = tvb_get_guint8(tvb,offset);
1614 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1616 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1619 /*display Units- ID string */
1621 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_string_id, tvb, offset, 2, ENC_NA|ENC_ASCII);
1625 /*display data type */
1627 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1630 expert_add_info(pinfo, ecmp_response_item, &ei_ecmp_info_type);
1638 /* a function to display an array of the read responses */
1639 static int get_parameter_responses(packet_info* pinfo, int offset, guint8 command_value, tvbuff_t *tvb, proto_tree* ecmp_tree)
1641 proto_item* ecmp_response_item = NULL;
1642 proto_tree* ecmp_parameter_number_tree = NULL;
1643 proto_tree* ecmp_parameter_response_tree = NULL;
1644 guint8 count = 0; /*stores number of parameter read responses */
1645 guint8 a = 0; /*counting varables */
1646 guint8 data_type = 0;
1650 guint8 st_error = 0;
1655 scheme = tvb_get_guint8(tvb, offset);
1656 length = tvb_reported_length(tvb);
1658 if (command_value == ECMP_COMMAND_GETNEXTOBJECTS) {
1659 /*display addressing scheme*/
1660 proto_tree_add_item(ecmp_tree, hf_ecmp_parameter_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1664 /*display number of responses*/
1665 ecmp_response_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_responses, tvb, offset, 1, ENC_BIG_ENDIAN);
1666 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_response_item, ett_ecmp_param_address);
1668 count = tvb_get_guint8(tvb, offset);
1672 if (command_value != ECMP_COMMAND_GETNEXTOBJECTS) {
1673 /*display parameter status*/
1674 proto_tree_add_item(ecmp_parameter_number_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1677 /*loop for outputting parameter data responses*/
1678 for (a = 0; a < count; a++) {
1679 if (command_value == ECMP_COMMAND_WRITE) {
1681 n = (length-offset)/count; /*set byte highlighting*/
1684 /*display response: (a+1)*/
1685 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1686 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1688 } else if (command_value == ECMP_COMMAND_GETNEXTOBJECTS) {
1690 n = (length-offset)/count;
1693 /*display response: (a+1)*/
1694 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1695 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_response_tree);
1697 /*if status is error */
1698 if (tvb_get_gint8(tvb, offset+1) < 0) {
1702 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, 1, ett_ecmp_command, NULL, "Response %d:", (a+1));
1703 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1704 if ((a+1) != count) {
1705 /*loop to move to next data_type (skips bytes == 0)*/
1707 if(tvb_get_guint8(tvb, offset+1)==0) {
1716 /*display response data_byte*/
1717 start_offset = offset;
1718 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, 0, ett_ecmp_command, &ecmp_response_item, "Response %d:", (a+1));
1719 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1721 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1722 data_type = tvb_get_guint8(tvb,offset);
1724 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1726 /*if "ReadWithType" */
1727 if ((command_value == ECMP_COMMAND_READWITHTYPE) && (st_error!= 1)) {
1729 /*display decimal places*/
1730 dec = tvb_get_gint8(tvb, offset);
1732 proto_tree_add_int(ecmp_parameter_response_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec);
1734 proto_tree_add_int_format_value(ecmp_parameter_response_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec, "0 (Invalid type)");
1738 unit_id = tvb_get_guint8(tvb, offset);
1739 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_display_unit_id, tvb, offset, 1, ENC_NA);
1740 if (unit_id == 255) {
1742 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_unit_id_string, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1743 offset += (tvb_get_ntohs(tvb, offset) + 2);
1747 proto_item_set_len(ecmp_response_item, offset-start_offset);
1757 /*--------------------------------------------------------------------*/
1758 /* File Access Commands */
1759 /*--------------------------------------------------------------------*/
1760 /* a function to dissect "FileOpen" command */
1761 static void file_open(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1763 proto_tree* ecmp_scheme_data_tree = NULL;
1764 guint8 additional_scheme = 0;
1765 guint8 relative = 0;
1768 static const int * fields[] = {
1769 &hf_ecmp_open_in_non_blocking_mode,
1770 &hf_ecmp_open_file_relative_to_specified_directory_handle,
1771 &hf_ecmp_file_access_mode,
1775 proto_tree_add_bitmask(ecmp_tree, tvb, offset, hf_ecmp_access_mode, ett_ecmp_access_mode, fields, ENC_BIG_ENDIAN);
1776 relative = (tvb_get_guint8(tvb, offset) & 0x40) ? 1 : 0;
1779 /*display additional scheme*/
1780 proto_tree_add_item(ecmp_tree, hf_ecmp_additional_scheme, tvb, offset, 1, ENC_BIG_ENDIAN);
1781 additional_scheme= tvb_get_guint8(tvb, offset);
1783 /*display file name*/
1784 proto_tree_add_item(ecmp_tree, hf_ecmp_file_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1785 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1787 /*only show file handle in relative mode*/
1788 if (relative == 1) {
1791 /*display file handle*/
1792 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1795 if (additional_scheme == 1) {
1796 /*display additional data*/
1798 ecmp_scheme_data_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, -1, ett_ecmp_access_file, NULL, "Additional scheme data");
1799 proto_tree_add_item(ecmp_scheme_data_tree, hf_ecmp_scheme_data_length, tvb, offset, 1, ENC_NA);
1801 proto_tree_add_item(ecmp_scheme_data_tree, hf_ecmp_data, tvb, offset, -1, ENC_NA);
1804 /*display file status*/
1805 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1807 if (tvb_get_gint8(tvb, offset) >= 0) {
1809 /*display file handle*/
1810 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1816 /* a function to dissect "FileRead" command */
1817 static void file_read(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1819 guint16 req_bytes = 0;
1822 /*display file handle*/
1823 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1826 /*display requested bytes*/
1827 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_requested_bytes, tvb, offset, 2, ENC_BIG_ENDIAN);
1830 /*display file status*/
1831 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1833 if (tvb_get_gint8(tvb, offset)>= 0) {
1836 /*display bytes for reading*/
1837 req_bytes = tvb_get_ntohs(tvb, offset);
1838 proto_tree_add_item(ecmp_tree, hf_ecmp_response_data, tvb, offset, req_bytes+2, ENC_NA);
1839 /*offset += (2+req_bytes);*/
1845 /* a function to dissect "FileWrite" command */
1846 static void file_write(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1851 /*display file handle*/
1852 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1855 /*display bytes for writing*/
1856 req_bytes = tvb_get_ntohs(tvb, offset);
1857 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset+2, req_bytes, ENC_NA);
1858 /*offset += (2+req_bytes);*/
1861 /*display file status*/
1862 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1868 /*a function to dissect "FileClose" command*/
1869 static void file_close(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1872 /*display file handle*/
1873 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1876 /*display number of data bytes transferred*/
1877 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_bytes_transferred, tvb, offset, 4, ENC_BIG_ENDIAN);
1880 /*display CRC value*/
1881 proto_tree_add_item(ecmp_tree, hf_ecmp_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
1883 /*display file status*/
1884 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1890 /*a function to display file attributes*/
1891 static int get_file_attribute(packet_info* pinfo, int offset, guint8 attribute0, tvbuff_t *tvb, proto_tree* ecmp_current_tree)
1897 case 0: /*display length of file*/
1898 proto_tree_add_item(ecmp_current_tree, hf_ecmp_file_length, tvb, offset, 4, ENC_BIG_ENDIAN);
1901 case 1: /*display integrity*/
1902 proto_tree_add_item(ecmp_current_tree, hf_ecmp_file_integrity, tvb, offset, 1, ENC_BIG_ENDIAN);
1904 case 2: /*display CRC*/
1905 proto_tree_add_item(ecmp_current_tree, hf_ecmp_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
1908 case 3: /*display attrib*/
1910 static const int * fields[] = {
1911 &hf_ecmp_display_attr_read_only,
1912 &hf_ecmp_display_attr_hidden,
1913 &hf_ecmp_display_attr_system,
1914 &hf_ecmp_display_attr_volume_label,
1915 &hf_ecmp_display_attr_subdirectory,
1916 &hf_ecmp_display_attr_archive,
1920 proto_tree_add_bitmask_list(ecmp_current_tree, tvb, offset, 1, fields, ENC_BIG_ENDIAN);
1923 case 4: /*display creation date*/
1924 ts.secs = tvb_get_ntohl(tvb, offset);
1926 proto_tree_add_time(ecmp_current_tree, hf_ecmp_display_creation, tvb, offset, 4, &ts);
1929 case 5: /*display modification date*/
1930 ts.secs = tvb_get_ntohl(tvb, offset);
1932 proto_tree_add_time(ecmp_current_tree, hf_ecmp_display_modification, tvb, offset, 4, &ts);
1935 default: /*display incorrect attribute type error*/
1936 proto_tree_add_expert(ecmp_current_tree, pinfo, &ei_ecmp_attribute_type, tvb, offset, 1);
1943 /*a function to dissect "FileInfo" command*/
1944 static void file_info(packet_info* pinfo, int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1946 proto_item* ecmp_file_info_item = NULL;
1947 proto_tree* ecmp_file_info_tree = NULL;
1948 proto_tree* ecmp_file_info_att_tree = NULL;
1949 guint8 no_of_att = 0;
1950 guint8 attribute0 = 0;
1955 /*display file handle*/
1956 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1959 /*display number of attributes*/
1960 no_of_att = tvb_get_guint8(tvb, offset);
1961 ecmp_file_info_item = proto_tree_add_uint(ecmp_tree, hf_ecmp_no_of_attributes, tvb, offset, 1, no_of_att);
1962 ecmp_file_info_tree = proto_item_add_subtree(ecmp_file_info_item, ett_ecmp_file_info);
1965 /*display attributes*/
1966 for (a = 0; a < no_of_att; a++) {
1967 ecmp_file_info_item = proto_tree_add_item(ecmp_file_info_tree, hf_ecmp_file_attributes, tvb, offset, 1, ENC_BIG_ENDIAN);
1968 ecmp_file_info_att_tree = proto_item_add_subtree(ecmp_file_info_item, ett_ecmp_file_info_att);
1969 attribute0 = tvb_get_guint8(tvb, offset);
1971 offset = get_file_attribute(pinfo, offset, attribute0, tvb, ecmp_file_info_att_tree);
1974 proto_item_set_len(ecmp_file_info_item, no_of_att);
1976 /*display file status*/
1977 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1981 /*display number of attributes*/
1982 no_of_att = tvb_get_guint8(tvb, offset);
1983 ecmp_file_info_item = proto_tree_add_uint(ecmp_tree, hf_ecmp_no_of_attributes, tvb, offset, 1, no_of_att);
1984 ecmp_file_info_tree = proto_item_add_subtree(ecmp_file_info_item, ett_ecmp_file_info);
1985 start_offset = offset;
1987 /*display attributes*/
1988 for (a = 0; a < no_of_att; a++) {
1990 ecmp_file_info_item = proto_tree_add_item(ecmp_file_info_tree, hf_ecmp_file_attributes, tvb, offset, 1, ENC_BIG_ENDIAN);
1991 ecmp_file_info_att_tree = proto_item_add_subtree(ecmp_file_info_item, ett_ecmp_file_info_att);
1992 attribute0 = tvb_get_guint8(tvb, offset);
1994 offset = get_file_attribute(pinfo, offset, attribute0, tvb, ecmp_file_info_att_tree);
1996 proto_item_set_len(ecmp_file_info_item, offset-start_offset);
2001 /*a function to dissect "FileStatus"/"FileDelete" commands*/
2002 static void file_state_delete(guint16 offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2005 /*display file handle*/
2006 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
2009 /*display file status*/
2010 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2015 /*a function to dissect "FilePos" command*/
2016 static void file_pos(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2018 proto_tree* ecmp_file_position_tree = NULL;
2021 /*display file handle*/
2022 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
2025 /*display "position" header*/
2026 ecmp_file_position_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 5, ett_ecmp_file_position, NULL, "Position");
2028 /*display reference point*/
2029 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_file_ref_point, tvb, offset, 1, ENC_BIG_ENDIAN);
2032 /*display offset from ref point*/
2033 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_ref_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2036 /*display file status*/
2037 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2039 if(tvb_get_gint8(tvb,offset) >= 0) {
2042 /*display offset from ref point*/
2043 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_ref_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2049 /*a function to dissect "FileList" command*/
2050 static void file_list(packet_info* pinfo, int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2052 proto_item* ecmp_file_list_item, *ecmp_file_list_item2, *item_type_item;
2053 proto_tree* ecmp_file_list_no_tree = NULL;
2054 proto_tree* ecmp_file_list_tree = NULL;
2055 guint8 no_of_items = 0;
2056 guint8 item_type = 0;
2059 int start_offset, start_offset2;
2062 /*display file handle*/
2063 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
2066 /*display number of files to list*/
2067 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_files_to_list, tvb, offset, 1, ENC_NA);
2069 /*display file status*/
2070 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2072 if (tvb_get_gint8(tvb,offset) >= 0) {
2075 /*display number of files to list*/
2076 no_of_items = tvb_get_guint8(tvb, offset);
2077 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_files_to_list, tvb, offset, 1, ENC_NA);
2080 /*display hash value (dissection TBD)*/
2081 ecmp_file_list_item = proto_tree_add_item(ecmp_tree, hf_ecmp_file_hash, tvb, offset, 2, ENC_BIG_ENDIAN);
2084 /*display subtree for files*/
2085 start_offset = offset+1;
2086 ecmp_file_list_no_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset+1, no_of_items, ett_ecmp_file_list_no, &ecmp_file_list_item, "Files");
2088 /*display list of file names*/
2089 for (a = 0; a < no_of_items; a++) {
2090 start_offset2 = offset;
2092 item_type = tvb_get_guint8(tvb, offset);
2093 n = tvb_get_ntohs(tvb, offset+1);
2094 ecmp_file_list_tree = proto_tree_add_subtree_format(ecmp_file_list_no_tree, tvb, offset, n+2, ett_ecmp_file_list, &ecmp_file_list_item2, "File %d:", a+1);
2095 item_type_item = proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_item_type, tvb, offset, 1, ENC_NA);
2099 case 0: /*if item type is "file"*/
2100 proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_file_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2103 case 1: /*if item type is "directory"*/
2104 proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_directory, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2107 default: /*if item type is not "file" or "directory"*/
2108 expert_add_info(pinfo, item_type_item, &ei_ecmp_item_type);
2113 proto_item_set_len(ecmp_file_list_item2, offset-start_offset2);
2116 proto_item_set_len(ecmp_file_list_item, (offset+1)-start_offset);
2122 /*a function to dissect "FileExists" command*/
2123 static void file_exists(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2126 /*display filename*/
2127 proto_tree_add_item(ecmp_tree, hf_ecmp_file_name, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2129 /*display file status*/
2130 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2135 static int add_cyclic_setup_attributes(packet_info* pinfo, int offset, guint16 length, tvbuff_t *tvb, proto_tree* ecmp_tree)
2137 proto_item *cyclic_setup_attributes_root = NULL;
2138 proto_item *cyclic_setup_attributes = NULL;
2139 proto_item *cyclic_setup_attrib_item_root = NULL;
2140 proto_tree *cyclic_setup_attrib_item = NULL;
2144 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2147 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2149 while (offset < length) {
2150 attrib = tvb_get_guint8(tvb, offset);
2151 cyclic_setup_attrib_item_root = proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2153 cyclic_setup_attrib_item = proto_item_add_subtree(cyclic_setup_attrib_item_root, ett_cyclic_setup_attrib_item);
2156 case 3: /* mec offset */
2158 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mec_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2163 case 4: /* sample period */
2164 case 5: /* mec delay */
2166 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_sample_period, tvb, offset, 8, ENC_BIG_ENDIAN);
2171 case 7: /* rx timeout */
2174 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_timeout, tvb, offset, 4, ENC_BIG_ENDIAN);
2178 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_action, tvb, offset++, 1, ENC_NA);
2181 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_event_destination, tvb, offset++, 1, ENC_NA);
2184 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_event, tvb, offset++, 1, ENC_NA);
2189 case 8: /* rx late handler */
2192 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_action, tvb, offset++, 1, ENC_NA);
2195 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_event_destination, tvb, offset++, 1, ENC_NA);
2198 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_event, tvb, offset++, 1, ENC_NA);
2202 case 9: /* transport addr */
2205 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_transport_addr_scheme, tvb, offset++, 1, ENC_NA);
2207 /* todo - make this check the scheme is actually 0! */
2209 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_transport_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
2214 case 12: /* mapping item */
2218 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mapping_item_offset, tvb, offset++, 1, ENC_NA);
2220 addrScheme = tvb_get_guint8(tvb, offset);
2221 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mapping_item_scheme, tvb, offset++, 1, ENC_NA);
2223 offset = get_address_scheme(pinfo, offset, addrScheme, tvb, cyclic_setup_attrib_item);
2225 /* todo - should this be done in the last function itself??? */
2232 case 2: /* synchronised */
2233 case 6: /* data change */
2234 case 10: /* max mappings */
2235 case 11: /* num mappings */
2236 case 13: /* saveable */
2237 case 128: /* max rx links */
2238 case 129: /* max tx links */
2239 case 130: /* max mappings per link */
2240 case 131: /* max sync rx links */
2241 case 132: /* max sync tx links */
2242 case 133: /* max mappings per sync link */
2243 case 134: /* process at queue depth */
2245 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_setup_attribute, tvb, offset++, 1, ENC_NA);
2249 case 135: /* mec period */
2251 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mec_period, tvb, offset, 4, ENC_BIG_ENDIAN);
2259 } /* attribute switch */
2260 } /* loop through list */
2266 static void cyclic_setup(packet_info* pinfo, guint16 offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2269 proto_item* cyclic_setup_attributes_root = NULL;
2270 proto_item* cyclic_setup_attributes = NULL;
2273 length = tvb_reported_length(tvb);
2275 /* if a request add the check output flag */
2277 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, ENC_BIG_ENDIAN);
2279 Mode = tvb_get_guint8(tvb, offset);
2280 proto_tree_add_uint(ecmp_tree, hf_ecmp_cyclic_setup_mode, tvb, offset++, 1, Mode);
2283 case 0: /* create */
2286 /* link direction */
2287 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2289 /* add the attributesd as a tree */
2290 add_cyclic_setup_attributes(pinfo, offset, length, tvb, ecmp_tree);
2295 case 2: /* finalise */
2296 case 3: /* delete */
2298 /* link direction */
2299 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2304 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2312 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2316 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2319 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2320 while (offset < length) {
2321 proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2326 case 12: /* get mappings */
2329 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2332 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_max_mappings, tvb, offset++, 1, ENC_NA);
2335 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_start_offset, tvb, offset++, 1, ENC_NA);
2340 /* display payload as hex bytes */
2341 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2345 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rsp_status, tvb, offset++, 1, ENC_BIG_ENDIAN);
2346 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rsp_err_idx, tvb, offset++, 1, ENC_BIG_ENDIAN);
2348 Mode = tvb_get_guint8(tvb, offset);
2349 proto_tree_add_uint(ecmp_tree, hf_ecmp_cyclic_setup_mode, tvb, offset++, 1, Mode);
2352 case 0: /* create */
2354 case 2: /* finalise */
2355 case 3: /* delete */
2356 /* no mode specific data */
2360 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_link_exists, tvb, offset++, 1, ENC_BIG_ENDIAN);
2365 guint8 txCount, rxCount, linkno;
2368 txCount = tvb_get_guint8(tvb, offset);
2369 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_tx_count, tvb, offset++, 1, ENC_NA);
2372 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2373 while (txCount > 0) {
2374 linkno = tvb_get_guint8(tvb, offset);
2375 proto_tree_add_uint(cyclic_setup_attributes, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, linkno);
2379 rxCount = tvb_get_guint8(tvb, offset);
2380 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rx_count, tvb, offset++, 1, ENC_NA);
2383 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2384 while (rxCount > 0) {
2385 linkno = tvb_get_guint8(tvb, offset);
2386 proto_tree_add_uint(cyclic_setup_attributes, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, linkno);
2395 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2398 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2399 while (offset < length) {
2400 proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2406 case 12: /* get mappings */
2408 /* add the attributesd as a tree */
2409 add_cyclic_setup_attributes(pinfo, offset, length, tvb, ecmp_tree);
2413 /* display payload as hex bytes */
2414 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2421 /*a function to dissect "ProgramStatus" command */
2422 static void program_status(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2424 /* Description:function to dissect Program Status command */
2427 /* offset - current offset of pointer within the ECMP frame */
2428 /* command_value - function code of ECMP message */
2429 /* request - (1 = query, 0 = response) */
2430 /* tvb - Wireshark protocol tree */
2431 /* ecmp_tree - Wireshark protocol tree */
2432 /* tree - Wireshark protocol tree */
2434 /* Returns: nothing */
2436 /* Notes: for queries, the "offset" points to the "target". */
2437 /* for responses, the "offset" points to the "status". */
2439 /* sample ECMP Request Frame */
2440 /* 0x61 - request code (program control) */
2441 /* 0x00 - option terminator */
2442 /* 0x00 - target (0 = default program) <======== offset */
2444 /* sample ECMP Response Frame */
2445 /* 0xE1 - response code (program control) */
2446 /* 0x00 - option terminator */
2447 /* 0x01 - running state (0=Stopped, 1=Running ... ) <======== offset */
2448 /* 0x00 - additional items */
2450 proto_item* ecmp_program_status_message_tree = NULL;
2452 /* differentiate between ECMP query and response */
2454 /*display the program control details sub-tree */
2455 ecmp_program_status_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_program_status_message, NULL, "Program Status: (Query)");
2457 /* read the target */
2458 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_target, tvb, offset, 1, ENC_NA);
2460 /*display the program status details sub-tree */
2461 ecmp_program_status_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_program_status_message, NULL, "Program Status: (Response)");
2463 /* read and display the Status */
2464 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_status, tvb, offset, 1, ENC_NA);
2467 /* read and display the Additional Items */
2468 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_additional_items, tvb, offset, 1, ENC_NA);
2473 /*a function to dissect "ProgramControl" command */
2474 static void program_control(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2476 /* Description:function to dissect Program Control command */
2479 /* offset - current offset of pointer within the ECMP frame */
2480 /* command_value - function code of ECMP message */
2481 /* request - (1 = query, 0 = response) */
2482 /* tvb - Wireshark protocol tree */
2483 /* ecmp_tree - Wireshark protocol tree */
2484 /* tree - Wireshark protocol tree */
2486 /* Returns: nothing */
2488 /* Notes: for queries, the "offset" points to the "target". */
2489 /* for responses, the "offset" points to the "status". */
2491 /* sample ECMP Request Frame */
2492 /* 0x60 - request code (program control) */
2493 /* 0x00 - option terminator */
2494 /* 0x00 - target (0 = default program) <======== offset */
2495 /* 0x01 - command (1 = start the program) */
2496 /* 0x00 - sub command */
2498 /* sample ECMP Response Frame */
2499 /* 0xE0 - response code (program control) */
2500 /* 0x00 - option terminator */
2501 /* 0x00 - status (0 = OK) <======== offset */
2504 proto_item* ecmp_program_control_message_tree = NULL;
2506 /* differentiate between ECMP query and response */
2508 /*display the program control details sub-tree */
2509 ecmp_program_control_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 3, ett_ecmp_program_control_message, NULL, "Program Control: (Query)");
2511 /* read the target */
2512 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_target, tvb, offset, 1, ENC_NA);
2515 /* read the command */
2516 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_command, tvb, offset, 1, ENC_NA);
2519 /* read the subcommand */
2520 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_sub_command, tvb, offset, 1, ENC_NA);
2522 /*display the program control details sub-tree */
2523 ecmp_program_control_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_program_control_message, NULL, "Program Control: (Response)");
2525 /* read and display the Status */
2526 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_status, tvb, offset, 1, ENC_NA);
2531 /*a function to dissect "ModbusPDU" command */
2532 static void modbus_pdu(int offset, gboolean request, tvbuff_t *tvb, packet_info* pinfo, proto_tree* ecmp_tree)
2534 /* Description:function to dissect Modbus PDU ECMP transactions */
2537 /* offset - current offset of pointer within the ECMP frame */
2538 /* command_value - function code of ECMP message */
2539 /* request - (1 = query, 0 = response) */
2540 /* tvb - Wireshark protocol tree */
2541 /* ecmp-tree - Wireshark protocol tree */
2542 /* tree - Wireshark protocol tree */
2544 /* Returns: nothing */
2546 /* Notes: for queries, the "offset" points to the "size". */
2547 /* for responses, the "offset" points to the size. */
2549 /* sample ECMP Request Frame (Read Holding Registers) */
2550 /* 0x74 - request code (ModbusMaster) */
2551 /* 0x00 - option terminator */
2552 /* 0x00 - size msb <======== offset */
2553 /* 0x05 - size lsb */
2554 /* 0x03 - function code - read hold reg */
2555 /* 0x07 - register address (#20.021) msb */
2556 /* 0xE4 - register address lsb */
2557 /* 0x00 - number registers msb */
2558 /* 0x03 - number registers lsb */
2560 /* sample ECMP Response Frame */
2561 /* 0xF4 - response code (ModbusMaster) */
2562 /* 0x00 - option terminator */
2563 /* 0x00 - size msb <======== offset */
2564 /* 0x08 - size lsb */
2565 /* 0x03 - function code - read hold reg */
2566 /* 0x06 - byte count */
2567 /* 0x30 - register #2021 value 12345 msb */
2568 /* 0x39 - register #2021 value lsb */
2569 /* 0x03 - register #2022 value 787 msb */
2570 /* 0x13 - register #2022 value lsb */
2571 /* 0x00 - register #2023 value 100 msb */
2572 /* 0x64 - register #2023 value lsb */
2575 guint16 size = 0; /* from Modbus TCP/IP spec: number of bytes that follow */
2578 /* differentiate between ECMP query and response */
2580 /* read and display the Size */
2581 size = tvb_get_ntohs(tvb, offset);
2582 proto_tree_add_item(ecmp_tree, hf_ecmp_modbus_pdu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2585 /* keep packet context */
2586 packet_type = QUERY_PACKET;
2587 next_tvb = tvb_new_subset_length(tvb, offset, size);
2588 call_dissector_with_data(modbus_handle, next_tvb, pinfo, ecmp_tree, &packet_type);
2591 /* read and display the Size */
2592 size = tvb_get_ntohs(tvb, offset);
2593 proto_tree_add_item(ecmp_tree, hf_ecmp_modbus_pdu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2596 packet_type = RESPONSE_PACKET;
2597 next_tvb = tvb_new_subset_length(tvb, offset, size);
2598 call_dissector_with_data(modbus_handle, next_tvb, pinfo, ecmp_tree, &packet_type);
2603 /*a function to dissect "Interrogate" command */
2604 static void interrogate(packet_info* pinfo, int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2606 /* Description: function to dissect Interrogate command */
2609 /* offset - current offset of pointer within the ECMP frame */
2610 /* request - (1 = query, 0 = response) */
2611 /* tvb - rather complex structure that has the frame data */
2612 /* ecmp-tree - Wireshark protocol tree */
2614 /* Returns: nothing */
2616 /* Notes: for queries, the "offset" points to the "item type". */
2617 /* for responses, the "offset" points to the "item type". */
2619 /* sample ECMP Request Frame */
2620 /* 0x02 - request code (interrogate) */
2621 /* 0x00 - option terminator */
2622 /* 0x00 - item type (0=ECMP command, 1=ECMP option) <==== offset */
2623 /* 0x05 - count (number of commands/options to follow) */
2624 /* 0x10 - item code #1 ECMP Read command */
2625 /* 0x11 - item code #2 ECMP ReadWithType command */
2626 /* 0x12 - item code #3 ECMP Write command */
2627 /* 0x13 - item code #4 ECMP ObjectInfo command */
2628 /* 0x14 - item code #5 ECMP GetNextObject command */
2630 /* sample ECMP Response Frame */
2631 /* 0x82 - response code (program control) */
2632 /* 0x00 - option terminator */
2633 /* 0x00 - item type (0=ECMP command, 1=ECMP option) <==== offset */
2634 /* 0x05 - count (number of commands/options to follow) */
2635 /* 0x10 - item code #1 */
2636 /* 0x01 - supported (ECMP Read command) */
2637 /* 0x11 - item code #2 */
2638 /* 0x01 - supported (ECMP ReadWithType command) */
2639 /* 0x12 - item code #3 */
2640 /* 0x01 - supported (ECMP Write command) */
2641 /* 0x13 - item code #4 */
2642 /* 0x01 - supported (ECMP ObjectInfo command) */
2643 /* 0x14 - item code #5 */
2644 /* 0x01 - supported (ECMP GetNextObject command) */
2647 /* Item Type: 0 = ECMP command */
2648 /* 1 = ECMP option (not currently implemented) */
2650 /* Item Code: 0 .. 0x7F for commands */
2651 /* 0 .. 2 for options */
2653 /* Item Support: 0 = not supported */
2658 const guint8 interrogate_type_command = 0;
2660 proto_tree* ecmp_interrogate_message_tree = NULL, *ecmp_interrogate_tree;
2661 proto_item* ecmp_interrogate_message_item = NULL;
2662 guint8 item_type = 0; /* 0=ECMP command, 1=ECMP option */
2663 guint8 command_req = 0; /* ECMP command */
2664 guint8 supported = 0; /* ECMP command support status: 1=supported, 0=not supported */
2665 guint32 count = 0; /* number of ECMP commands to be checked */
2666 guint32 j; /* loop counter */
2669 /* differentiate between ECMP query and response */
2672 /* identify the ECMP command we're dissecting */
2673 ecmp_interrogate_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_interrogate_message, NULL, "Interrogate: (Query)");
2675 /* read the item_type (command/option setting) */
2676 item_type = tvb_get_guint8(tvb, offset);
2677 proto_tree_add_item(ecmp_interrogate_tree, hf_ecmp_interrogate_item_type, tvb, offset, 1, ENC_NA);
2680 /* read the count */
2681 count = tvb_get_guint8(tvb, offset);
2682 proto_tree_add_item(ecmp_interrogate_tree, hf_ecmp_interrogate_count, tvb, offset, 1, ENC_NA);
2685 /*create the interrogate details sub-tree */
2686 ecmp_interrogate_message_tree = proto_tree_add_subtree(ecmp_interrogate_tree, tvb, offset, count, ett_ecmp_interrogate_message, &ecmp_interrogate_message_item, "ECMP Commands to be Checked");
2688 /* display the item_codes (commands to be checked) */
2689 if (item_type == interrogate_type_command) {
2690 /* loop on the commands */
2691 for (j = 0; j < count; j++) {
2693 /* display the commands to be checked */
2694 proto_tree_add_item(ecmp_interrogate_message_tree, hf_ecmp_interrogate_command, tvb, offset, 1, ENC_NA);
2697 proto_item_set_len(ecmp_interrogate_message_item, count);
2700 expert_add_info(pinfo, ecmp_interrogate_message_item, &ei_ecmp_options_not_implemented);
2704 /* identify the ECMP command we're dissecting */
2705 ecmp_interrogate_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_interrogate_message, NULL, "Interrogate: (Response)");
2707 /* read the item_type (command/option setting) */
2708 item_type = tvb_get_guint8(tvb, offset);
2711 /* read the count */
2712 count = tvb_get_guint8(tvb, offset);
2715 /* display the item_codes (commands to be checked) */
2716 if (item_type == interrogate_type_command) {
2718 /*create the interrogate details sub-tree */
2719 ecmp_interrogate_message_tree = proto_tree_add_subtree(ecmp_interrogate_tree, tvb, offset, 1, ett_ecmp_interrogate_message, &ecmp_interrogate_message_item, "ECMP Commands Supported");
2721 /* loop on the commands */
2722 for (j = 0; j < count; j++) {
2723 /* get the command code */
2724 command_req = tvb_get_guint8(tvb, offset);
2727 /* get the support status */
2728 supported = tvb_get_guint8(tvb, offset);
2731 /* display if the command is supported */
2732 proto_tree_add_uint_format(ecmp_interrogate_message_tree, hf_ecmp_interrogate_command, tvb, offset, 1, command_req, "%s: %s",
2733 try_val_to_str(command_req, command_vals),
2734 try_val_to_str(supported, Interrogate_support_state));
2739 expert_add_info(pinfo, ecmp_interrogate_message_item, &ei_ecmp_options_not_implemented);
2745 static void tunnel_frame(int offset, gboolean request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2747 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_control, tvb, offset, 1, ENC_BIG_ENDIAN);
2748 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_start_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2749 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_end_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2751 /* if a request add the check output flag */
2753 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_check_output_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2758 /* Payload length */
2759 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2762 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2763 /*offset = tvb_reported_length(tvb);*/
2767 /* dissect_ecmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2768 * -----------------------------------------------------------------
2770 * Purpose: Wireshark dissector for Emerson Control Techniques ECMP protocol
2773 * Inputs: tvbuff_t *tvb - complex buffer structure holding the packet's bytes
2774 * packet_info *pinfo - structure holding information about the packet
2775 * proto_tree *tree - pointer to top-level tree (print lines)
2780 * Notes: if tree = NULL, packet capture is running and dissector will only write into the Summary Line (Info Field)
2782 * if tree is non-NULL, packet capture has stopped because a packet has been selected (clicked)
2783 * In this case, we will display quite a bit of additional information about the packet.
2786 * To inspect the frame buffer (very difficult using the *tvb pointer), it's best to add this little debug
2787 * code snippet at the top of the program to copy the frame buffer into an array that you can inspect.
2789 * static guint8 jimbuf[512]; // temp buffer for current frame data
2790 * static gint lenframe = 0; // num bytes in the frame
2791 * static gint j = 0; // loop counter
2792 * static gint16 saved_offset = 0; // saves offset for later restoration
2794 * lenframe = tvb_captured_length(tvb); // get the length of the frame
2795 * saved_offset = offset; // temporarily save the "offset"
2797 * for (j = 0; j < lenframe; j++) { // loop to copy the frame buffer
2798 * jimbuf[j] = tvb_get_guint8(tvb, offset); // Wireshark function to read the frame buffer
2801 * offset = saved_offset; // restore the offset
2804 * Authors: Sarah Bouremoum, Jim Lynch, Luke Orehawa, Others
2807 static int dissect_ecmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2809 /* Initialize the items and trees*/
2810 proto_item *ecmp_item = NULL;
2811 proto_item *ecmp_transaction_id_item = NULL;
2812 proto_item *ecmp_chunk_id_item = NULL;
2813 proto_tree *ecmp_tree = NULL;
2815 /*initialise the values to be used */
2816 guint8 command_value = 0;
2818 guint8 transaction_id_value = 0;
2819 int offset = 0; /* index used to read data from the buffer*/
2820 gint framelen = 0; /* number of bytes in the frame */
2822 /* note length of the UDP frame */
2823 framelen = tvb_reported_length(tvb);
2825 if (framelen < ecmp_min_packet_size) {
2829 /* this code block processes ECMP TCP messages (most of them) */
2830 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ECMP);
2831 col_clear(pinfo->cinfo,COL_INFO);
2834 /*declaration of variables*/
2837 /*display the first line of the tree (ECMP data)*/
2838 ecmp_item = proto_tree_add_item(tree, proto_ecmp, tvb, 0, -1, ENC_NA);
2839 ecmp_tree = proto_item_add_subtree(ecmp_item, ett_ecmp);
2841 /* display the information for the destination address */
2842 offset = add_transport_layer_frame(offset, tvb, ecmp_tree, hf_ecmp_destination_address);
2844 /* display the information for the source address */
2845 offset = add_transport_layer_frame(offset, tvb, ecmp_tree, hf_ecmp_source_address);
2847 /*display the transaction ID*/
2848 ecmp_transaction_id_item = proto_tree_add_item(ecmp_tree, hf_ecmp_transaction_id, tvb, offset, 1, ENC_BIG_ENDIAN );
2849 transaction_id_value = tvb_get_guint8(tvb, offset);
2851 if(transaction_id_value == 0) {
2852 proto_item_append_text(ecmp_transaction_id_item, "%s", " -> Not initiated by Request");
2856 request = ((tvb_get_guint8(tvb, offset+2) & 0x80) == 0);
2858 /* Calls the function to display the Response size */
2859 offset = get_response_size(offset, tvb, ecmp_tree);
2861 /* Calls the function to display the command and request/response */
2862 offset = add_command_codes(pinfo, offset, tvb, ecmp_tree, transaction_id_value, &command_value);
2864 /* Calls the function to display the option codes and its data */
2865 offset = add_option_codes(offset, pinfo, tvb, ecmp_tree);
2867 /* up til here all code for the request should be the same */
2868 switch(command_value)
2870 case ECMP_COMMAND_IDENTIFY:
2871 /*Calls a method to display the attributes and its data */
2872 add_attributes(pinfo, offset, tvb, ecmp_tree, request);
2874 case ECMP_COMMAND_INFO:
2875 /* Info command is just the request code, nothing else to display */
2876 proto_tree_add_item(ecmp_tree, hf_ecmp_info_command, tvb, 0, -1, ENC_NA);
2877 /*do nothing, no more data is present */
2879 case ECMP_COMMAND_INTERROGATE:
2880 interrogate(pinfo, offset, request, tvb, ecmp_tree);
2882 case ECMP_COMMAND_READ:
2883 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2885 case ECMP_COMMAND_READWITHTYPE:
2886 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2888 case ECMP_COMMAND_WRITE:
2889 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2891 case ECMP_COMMAND_OBJECTINFO:
2892 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2894 case ECMP_COMMAND_GETNEXTOBJECTS:
2895 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2897 case ECMP_COMMAND_FILEOPEN:
2898 file_open(offset, request, tvb, ecmp_tree);
2900 case ECMP_COMMAND_FILEREAD:
2901 file_read(offset, request, tvb, ecmp_tree);
2903 case ECMP_COMMAND_FILEWRITE:
2904 file_write(offset, request, tvb, ecmp_tree);
2906 case ECMP_COMMAND_FILECLOSE:
2907 file_close(offset, request, tvb, ecmp_tree);
2909 case ECMP_COMMAND_FILEINFO:
2910 file_info(pinfo, offset, request, tvb, ecmp_tree);
2912 case ECMP_COMMAND_FILEDELETE:
2913 file_state_delete(offset, request, tvb, ecmp_tree);
2915 case ECMP_COMMAND_FILESTATE:
2916 file_state_delete(offset, request, tvb, ecmp_tree);
2918 case ECMP_COMMAND_FILEPOS:
2919 file_pos(offset, request, tvb, ecmp_tree);
2921 case ECMP_COMMAND_FILELIST:
2922 file_list(pinfo, offset, request, tvb, ecmp_tree);
2924 case ECMP_COMMAND_FILEEXISTS:
2925 file_exists(offset, request, tvb, ecmp_tree);
2927 case ECMP_COMMAND_CYCLICLINK:
2928 cyclic_setup(pinfo, offset, request, tvb, ecmp_tree);
2930 case ECMP_COMMAND_PROGRAMCONTROL:
2931 program_control(offset, request, tvb, ecmp_tree);
2933 case ECMP_COMMAND_PROGRAMSTATUS:
2934 program_status(offset, request, tvb, ecmp_tree);
2936 case ECMP_COMMAND_CYCLICFRAME:
2937 add_cyclic_frame_query(offset, tvb, ecmp_tree);
2939 case ECMP_COMMAND_TUNNELFRAME:
2940 tunnel_frame(offset, command_value, tvb, ecmp_tree);
2942 case ECMP_COMMAND_MODBUSPDU:
2943 modbus_pdu(offset, request, tvb, pinfo, ecmp_tree);
2946 proto_tree_add_expert(ecmp_tree, pinfo, &ei_ecmp_unknown_command, tvb, 0, -1);
2950 /* END of code to be modified */
2952 guint8 chunk_id_value = 0;
2953 gint8 status_value = 0;
2955 status_value = tvb_get_gint8(tvb, offset); /*stores a signed value for status */
2957 proto_tree_add_item(ecmp_tree, hf_ecmp_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2960 if (status_value >= 0) {
2962 chunk_id_value = tvb_get_guint8(tvb, offset);
2963 ecmp_chunk_id_item = proto_tree_add_item(ecmp_tree, hf_ecmp_chunk_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2965 if(chunk_id_value == 0) {
2966 proto_item_append_text(ecmp_chunk_id_item, "%s", " -> Response is NOT Chunked");
2971 /* Calls the function to display the option codes */
2972 offset = add_command_codes(pinfo, offset, tvb, ecmp_tree, transaction_id_value, &command_value);
2974 if ((status_value == 0) || (status_value == 1)) {
2975 /* Calls a method to display option codes */
2976 offset = add_option_codes(offset, pinfo, tvb, ecmp_tree);
2978 /* up til here all code for the response should be the same */
2979 switch(command_value)
2981 case ECMP_COMMAND_IDENTIFY:
2982 /*Call a method to add category data */
2983 offset = add_category_codes(offset, tvb, ecmp_tree);
2984 /*Call a method to add attributes */
2985 add_attributes(pinfo, offset, tvb, ecmp_tree, request);
2987 case ECMP_COMMAND_INFO:
2988 add_info_response(offset, tvb, ecmp_tree);
2990 case ECMP_COMMAND_INTERROGATE:
2991 interrogate(pinfo, offset, request, tvb, ecmp_tree);
2993 case ECMP_COMMAND_READ:
2994 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2996 case ECMP_COMMAND_READWITHTYPE:
2997 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2999 case ECMP_COMMAND_WRITE:
3000 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
3002 case ECMP_COMMAND_OBJECTINFO:
3003 get_object_info_response(pinfo, offset, tvb, ecmp_tree);
3005 case ECMP_COMMAND_GETNEXTOBJECTS:
3006 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
3008 case ECMP_COMMAND_FILEOPEN:
3009 file_open(offset, request, tvb, ecmp_tree);
3011 case ECMP_COMMAND_FILEREAD:
3012 file_read(offset, request, tvb, ecmp_tree);
3014 case ECMP_COMMAND_FILEWRITE:
3015 file_write(offset, request, tvb, ecmp_tree);
3017 case ECMP_COMMAND_FILECLOSE:
3018 file_close(offset, request, tvb, ecmp_tree);
3020 case ECMP_COMMAND_FILEINFO:
3021 file_info(pinfo, offset, request, tvb, ecmp_tree);
3023 case ECMP_COMMAND_FILEDELETE:
3024 file_state_delete(offset, request, tvb, ecmp_tree);
3026 case ECMP_COMMAND_FILESTATE:
3027 file_state_delete(offset, request, tvb, ecmp_tree);
3029 case ECMP_COMMAND_FILEPOS:
3030 file_pos(offset, request, tvb, ecmp_tree);
3032 case ECMP_COMMAND_FILELIST:
3033 file_list(pinfo, offset, request, tvb, ecmp_tree);
3035 case ECMP_COMMAND_FILEEXISTS:
3036 file_exists(offset, request, tvb, ecmp_tree);
3038 case ECMP_COMMAND_CYCLICLINK:
3039 cyclic_setup(pinfo, offset, request, tvb, ecmp_tree);
3041 case ECMP_COMMAND_PROGRAMCONTROL:
3042 program_control(offset, request, tvb, ecmp_tree);
3044 case ECMP_COMMAND_PROGRAMSTATUS:
3045 program_status(offset, request, tvb, ecmp_tree);
3047 case ECMP_COMMAND_CYCLICFRAME:
3048 add_cyclic_frame(offset, tvb, ecmp_tree);
3050 case ECMP_COMMAND_TUNNELFRAME:
3051 tunnel_frame(offset, command_value, tvb, ecmp_tree);
3053 case ECMP_COMMAND_MODBUSPDU:
3054 modbus_pdu(offset, request, tvb, pinfo, ecmp_tree);
3057 proto_tree_add_expert(ecmp_tree, pinfo, &ei_ecmp_unknown_command, tvb, 0, -1);
3060 /********************************* END of code to be modified ***********************************/
3068 /* this code block processes ECMP UDP messages (cyclic data) */
3069 static int dissect_ecmp_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3071 proto_item *ecmp_item = NULL;
3072 proto_tree *ecmp_tree = NULL;
3073 proto_tree *ecmp_cyclic_data_32_bit_display_tree = NULL;
3074 proto_tree *ecmp_cyclic_data_16_bit_display_tree = NULL;
3075 proto_tree *ecmp_cyclic_data_8_bit_display_tree = NULL;
3076 guint8 command_value = 0;
3077 guint8 type_value = 0;
3078 guint8 transaction_id_value = 0;
3079 guint16 offset = 0; /* index used to read data from the buffer*/
3080 gint framelen = 0; /* number of bytes in the frame */
3081 guint8 scheme = 0; /* 0=no scheme, 1=grandmaster setup */
3083 /* note length of the UDP frame */
3084 framelen = tvb_reported_length(tvb);
3086 if (framelen < ecmp_min_packet_size) {
3090 /* display the "ECMP" protocol indication in the PROTOCOL field */
3091 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ECMP);
3093 /* Clear out stuff in the info column */
3094 col_clear(pinfo->cinfo,COL_INFO);
3096 /* adjust offset to point at transaction ID */
3099 /*getting the information from the buffer*/
3100 transaction_id_value = tvb_get_guint8(tvb, offset);
3102 /* adjust offset to point at ECMP query/response code */
3105 /* calculate if it's a query or response (type_r_r) */
3106 type_value = tvb_get_guint8(tvb, offset);
3108 /* determine the ECMP command code */
3109 command_value = type_value & 0x7f;
3111 /* update offset to point to cyclic link number */
3114 /* Information displayed in the Info column*/
3115 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, %s. Transaction ID: %d",
3116 val_to_str(command_value, command_vals, "Unknown Type:0x%02x"),
3117 val_to_str((type_value & 0x80) >> 7, type_rr, "Unknown Type:0x%02x"), transaction_id_value);
3119 /*display the first line of the tree (ECMP data)*/
3120 ecmp_item = proto_tree_add_item(tree, proto_ecmp, tvb, 0, -1, ENC_NA); /*item created*/
3121 ecmp_tree = proto_item_add_subtree(ecmp_item, ett_ecmp); /*tree created*/
3123 /* indicate cyclic link message */
3124 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_req_resp, tvb, offset, 1, ENC_BIG_ENDIAN);
3126 /* display the cyclic link number */
3127 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_number_display, tvb, offset, 1, ENC_BIG_ENDIAN);
3130 if (type_value & 0x80) {
3131 /* response data handled here */
3132 /* display the alignment */
3133 proto_tree_add_item(ecmp_tree, hf_ecmp_udp_alignment, tvb, offset, 1, ENC_NA);
3136 /* display the scheme */
3137 scheme = tvb_get_guint8(tvb, offset);
3138 proto_tree_add_item(ecmp_tree, hf_ecmp_udp_scheme, tvb, offset, 1, ENC_NA);
3141 /* if the scheme is 1, there is grandmaster data to be printed */
3143 proto_tree_add_item(ecmp_tree, hf_ecmp_grandmaster, tvb, offset, 8, ENC_BIG_ENDIAN);
3146 proto_tree_add_item(ecmp_tree, hf_ecmp_process_time, tvb, offset, 8, ENC_BIG_ENDIAN);
3150 /* create the Cyclic Data Display (guint32 format) sub-tree */
3151 ecmp_cyclic_data_32_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_32_bit_display, NULL,
3152 "Cyclic Data (32-bit hex unsigned format): ");
3154 /* display the raw hex data for the cyclic data in a 32-bit format */
3155 display_raw_cyclic_data(cyclic_display_long_format, offset, framelen - offset, tvb, ecmp_cyclic_data_32_bit_display_tree);
3157 /* create the Cyclic Data Display (guint16 format) sub-tree */
3158 ecmp_cyclic_data_16_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_16_bit_display, NULL,
3159 "Cyclic Data (16-bit hex unsigned format): ");
3161 /* display the raw hex data for the cyclic data in a 16-bit format */
3162 display_raw_cyclic_data(cyclic_display_word_format, offset, framelen - offset, tvb, ecmp_cyclic_data_16_bit_display_tree);
3164 /* display the raw hex data for the cyclic data in a guint8 format */
3165 ecmp_cyclic_data_8_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_8_bit_display, NULL,
3166 "Cyclic Data (8-bit hex unsigned format): ");
3168 /* display the raw hex data for the cyclic data in 8-bit format */
3169 display_raw_cyclic_data(cyclic_display_byte_format, offset, framelen - offset, tvb, ecmp_cyclic_data_8_bit_display_tree);
3172 return tvb_reported_length(tvb);
3175 /* Function to register the protcol*/
3176 /* Wireshark literally scans this file (packet-ecmp.c) to find this function */
3177 /* note: this function MUST start in column 1, due to the scanning mentioned above */
3178 void proto_register_ecmp (void)
3180 /* A header field is something you can search/filter on.
3182 * We create a structure to register our fields. It consists of an
3183 * array of hf_register_info structures, each of which are of the format
3184 * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
3187 static hf_register_info hf[] = {
3189 { &hf_ecmp_destination_address,
3190 { "Destination Address scheme", "ecmp.destination_address", FT_UINT8, BASE_DEC, VALS(address_scheme), 0, NULL, HFILL }},
3192 { &hf_ecmp_source_address,
3193 { "Source Address scheme", "ecmp.source_address", FT_UINT8, BASE_DEC, VALS(address_scheme), 0, NULL, HFILL }},
3195 { &hf_ecmp_diagnostic,
3196 { "Diagnostic group", "ecmp.diagnostic", FT_UINT8, BASE_DEC, VALS(diagnostic), 0, NULL, HFILL }},
3199 { "Command", "ecmp.command", FT_UINT8, BASE_DEC, VALS(command_vals), 0x7F, NULL, HFILL }},
3202 { "Option", "ecmp.option", FT_UINT8, BASE_DEC, VALS(option_code), 0x0, NULL, HFILL }},
3205 { "Type", "ecmp.type", FT_UINT8, BASE_DEC, VALS(type_rr), 0x80, "ECMP Type (request/response)", HFILL }},
3207 { &hf_ecmp_chunking,
3208 { "Chunks allowed","ecmp.chunking", FT_UINT16, BASE_DEC, NULL,0xF000, "ECMP number of chunks allowed", HFILL}},
3210 { &hf_ecmp_max_response_size,
3211 { "Maximum Response Size","ecmp.response_size", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_byte_bytes, 0x0FFF, NULL, HFILL}},
3213 { &hf_ecmp_category,
3214 { "Device", "ecmp.category", FT_UINT8, BASE_DEC, VALS(category), 0x0, "ECMP Category (drive or option module)", HFILL }},
3216 { &hf_ecmp_attribute,
3217 { "Attribute", "ecmp.attribute", FT_UINT8, BASE_DEC, VALS(attribute), 0x0, NULL, HFILL }},
3219 { &hf_ecmp_no_of_attributes,
3220 { "Number of attributes", "ecmp.attribute_number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3223 { "Status", "ecmp.status", FT_INT8, BASE_DEC, VALS(status), 0x0, NULL, HFILL }},
3225 { &hf_ecmp_chunk_id,
3226 { "Chunk ID", "ecmp.chunkID", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3228 { &hf_ecmp_transaction_id,
3229 { "Transaction ID", "ecmp.transactionID", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3231 { &hf_ecmp_drive_type,
3232 { "Product Type", "ecmp.drive_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3234 { &hf_ecmp_drive_derivative,
3235 { "Drive Derivative", "ecmp.drive_derivative", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3237 { &hf_ecmp_drive_factory_fit_category_id,
3238 { "Factory Fitted Option ID", "ecmp.drive_factory_fit_category_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3240 { &hf_ecmp_category_id,
3241 { "Option ID", "ecmp.category_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3243 { &hf_ecmp_cyclic_link_num,
3244 { "Cyclic Link Number", "ecmp.link_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3246 { &hf_ecmp_cyclic_align,
3247 { "Alignment", "ecmp.cyclic_align", FT_UINT8, BASE_DEC, VALS(cyclic_align), 0x0, "ECMP Cyclic Data Alignment", HFILL }},
3249 { &hf_ecmp_cyclic_scheme,
3250 { "Scheme", "ecmp.cyclic_scheme", FT_UINT8, BASE_DEC, VALS(cyclic_scheme), 0x0, "ECMP Cyclic Scheme", HFILL }},
3252 { &hf_ecmp_cyclic_link_number_display,
3253 { "Cyclic Link Number Display", "ecmp.link_num_display", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3255 { &hf_ecmp_buffer_size,
3256 {"Buffer Size", "ecmp.buffer_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3258 { &hf_ecmp_max_response,
3259 {"Maximum Response Time", "ecmp.max_response", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3261 { &hf_ecmp_max_handle,
3262 {"Maximum Handle Period", "ecmp.max_handle", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3264 { &hf_ecmp_info_address,
3265 {"Number of Default Route Addresses", "ecmp.count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3267 { &hf_ecmp_parameter_address,
3268 {"Parameter Addressing Scheme", "ecmp.parameter.address", FT_UINT8, BASE_DEC, VALS(parameter_address_scheme), 0x0, NULL, HFILL}},
3270 { &hf_ecmp_number_of_parameter_definitions,
3271 {"Number of Parameter Definitions", "ecmp.parameter.definitions", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3273 { &hf_ecmp_number_of_parameter_responses,
3274 {"Number of Parameter Responses", "ecmp.parameter.response", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3276 { &hf_ecmp_parameter_status,
3277 {"Parameter Status", "ecmp.parameter.status", FT_INT8, BASE_DEC, VALS(parameter_access_status), 0x0, NULL, HFILL}},
3279 { &hf_ecmp_data_type,
3280 {"Parameter Data Type", "ecmp.parameter.data_type", FT_UINT8, BASE_DEC, VALS(parameter_data_types), 0x0, NULL, HFILL}},
3282 { &hf_ecmp_info_type,
3283 {"Info Type", "ecmp.info_type", FT_UINT8, BASE_DEC, VALS(info_type), 0x0, NULL, HFILL}},
3285 { &hf_ecmp_file_status,
3286 {"File Status", "ecmp.file.status", FT_INT8, BASE_DEC, VALS(file_status), 0x0, NULL, HFILL}},
3288 { &hf_ecmp_file_handle,
3289 {"File Handle", "ecmp.file.handle", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3291 { &hf_ecmp_file_attributes,
3292 {"Attribute", "ecmp.file.attribute", FT_UINT8, BASE_DEC, VALS(file_attributes), 0x0, "File attributes", HFILL}},
3294 { &hf_ecmp_file_ref_point,
3295 {"Reference Point", "ecmp.file.reference", FT_UINT8, BASE_DEC, VALS(file_ref_point), 0x0, "File reference points", HFILL}},
3297 { &hf_ecmp_tunnel_control,
3298 {"Control", "ecmp.tunnel_control", FT_UINT8, BASE_DEC, NULL, 0x0, "Tunnel frame control field", HFILL}},
3300 { &hf_ecmp_tunnel_start_flag,
3301 {"Start", "ecmp.tunnel_control.start", FT_BOOLEAN, 8, NULL, TUNNEL_START_FLAG, "Tunnel frame control field start flag", HFILL}},
3303 { &hf_ecmp_tunnel_end_flag,
3304 {"End", "ecmp.tunnel_control.end", FT_BOOLEAN, 8, NULL, TUNNEL_END_FLAG, "Tunnel frame control field end flag", HFILL}},
3306 { &hf_ecmp_tunnel_check_output_flag,
3307 {"Check Output", "ecmp.tunnel_control.check", FT_BOOLEAN, 8, NULL, TUNNEL_CHECK_OUTPUT_FLAG, "Tunnel frame control field check output flag", HFILL}},
3309 { &hf_ecmp_tunnel_size,
3310 {"Size", "ecmp.tunnel_size", FT_UINT16, BASE_DEC, NULL, 0x0, "Tunnel frame payload size", HFILL}},
3312 { &hf_ecmp_cyclic_setup_mode,
3313 {"Mode", "ecmp.cyclic_setup.mode", FT_UINT8, BASE_DEC, VALS(cyclic_setup_mode), 0x0, "Cyclic setup mode", HFILL}},
3315 { &hf_ecmp_cyclic_setup_linkno,
3316 {"Link No", "ecmp.cyclic_setup.linkno", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup link no", HFILL}},
3318 { &hf_ecmp_cyclic_setup_dir,
3319 {"Direction", "ecmp.cyclic_setup.direction", FT_UINT8, BASE_DEC, VALS(cyclic_setup_link_dir), 0x0, "Cyclic setup link direction", HFILL}},
3321 { &hf_ecmp_cyclic_setup_attrib_count,
3322 {"Count", "ecmp.cyclic_setup.attrib_count", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup attribute count", HFILL}},
3324 { &hf_ecmp_cyclic_setup_attrib,
3325 {"Attribute", "ecmp.cyclic_setup.attrib", FT_UINT8, BASE_DEC, VALS(cyclic_attributes), 0x0, "Cyclic setup attribute", HFILL}},
3327 { &hf_ecmp_cyclic_setup_rsp_status,
3328 {"Status", "ecmp.cyclic_setup.rsp_status", FT_INT8, BASE_DEC, NULL, 0x0, "Cyclic setup status", HFILL}},
3330 { &hf_ecmp_cyclic_setup_rsp_err_idx,
3331 {"Error Index", "ecmp.cyclic_setup.rsp_err_idx", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup error index", HFILL}},
3333 { &hf_ecmp_cyclic_setup_link_exists,
3334 {"Existence State", "ecmp.cyclic_setup.exists.state", FT_UINT8, BASE_DEC, VALS(cyclic_setup_link_exists), 0x0, "Cyclic setup exists state", HFILL}},
3336 { &hf_ecmp_cyclic_link_req_resp,
3337 {"Cyclic Link - Request-Response", "ecmp.cyclic_link.request.response", FT_UINT8, BASE_DEC, VALS(cyclic_link_req_resp), 0x0, "Cyclic link request - response", HFILL}},
3339 { &hf_ecmp_attribute_string,
3340 { "Attribute string", "ecmp.attribute_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3342 { &hf_ecmp_file_name,
3343 { "File name", "ecmp.file_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3345 { &hf_ecmp_directory,
3346 { "Directory", "ecmp.directory", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3348 { &hf_ecmp_names_scheme,
3349 { "Names Scheme", "ecmp.names_scheme", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3351 { &hf_ecmp_variable_name,
3352 { "Variable name", "ecmp.variable_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3354 { &hf_ecmp_unit_id_string,
3355 { "Unit ID String", "ecmp.unit_id_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3357 { &hf_ecmp_ecmp_string,
3358 { "ECMP string", "ecmp.ecmp_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3360 { &hf_ecmp_info_command,
3361 { "Info command data", "ecmp.info_command", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3363 { &hf_ecmp_process_time,
3364 { "ProcessAt time", "ecmp.processat_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3366 { &hf_ecmp_cyclic_frame_time,
3367 { "Cyclic frame time", "ecmp.cyclic_frame_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3369 { &hf_ecmp_grandmaster,
3370 { "Grandmaster", "ecmp.grandmaster", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3373 { "Data", "ecmp.data", FT_BYTES, SEP_SPACE, NULL, 0x0, NULL, HFILL }},
3375 { &hf_ecmp_response_data,
3376 { "Response Data", "ecmp.response_data", FT_BYTES, SEP_SPACE, NULL, 0x0, NULL, HFILL }},
3378 /* Generated from convert_proto_tree_add_text.pl */
3379 { &hf_ecmp_physical_address, { "Physical address", "ecmp.physical_address", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }},
3380 { &hf_ecmp_logical_address, { "Logical address", "ecmp.logical_address", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }},
3381 { &hf_ecmp_primary_colour, { "Primary Colour", "ecmp.primary_colour", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3382 { &hf_ecmp_secondary_colour, { "Secondary Colour", "ecmp.secondary_colour", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3383 { &hf_ecmp_number_of_subsequent_object_requests, { "Number of subsequent object requests", "ecmp.number_of_subsequent_object_requests", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3384 { &hf_ecmp_number_of_decimal_places, { "Number of decimal places", "ecmp.number_of_decimal_places", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3385 { &hf_ecmp_no_information_available, { "No Information available", "ecmp.no_information_available", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3386 { &hf_ecmp_param_format_bit_default_unipolar, { "BU- Bit default/Unipolar", "ecmp.param_format.bit_default_unipolar", FT_UINT32, BASE_DEC, NULL, 0x00000001, NULL, HFILL }},
3387 { &hf_ecmp_param_format_write_allowed, { "W- Write allowed", "ecmp.param_format.write_allowed", FT_UINT32, BASE_DEC, NULL, 0x00000002, NULL, HFILL }},
3388 { &hf_ecmp_param_format_read_not_allowed, { "NR- Read not allowed", "ecmp.param_format.read_not_allowed", FT_UINT32, BASE_DEC, NULL, 0x00000004, NULL, HFILL }},
3389 { &hf_ecmp_param_format_protected_from_destinations, { "PT- Protected from destinations", "ecmp.param_format.protected_from_destinations", FT_UINT32, BASE_DEC, NULL, 0x00000008, NULL, HFILL }},
3390 { &hf_ecmp_param_format_parameter_not_visible, { "NV- Parameter not visible", "ecmp.param_format.parameter_not_visible", FT_UINT32, BASE_DEC, NULL, 0x00000010, NULL, HFILL }},
3391 { &hf_ecmp_param_format_not_clonable, { "NC- Not clonable", "ecmp.param_format.not_clonable", FT_UINT32, BASE_DEC, NULL, 0x00000020, NULL, HFILL }},
3392 { &hf_ecmp_param_format_voltage_or_current_rating_dependent, { "RA- Voltage or current rating dependent", "ecmp.param_format.voltage_or_current_rating_dependent", FT_UINT32, BASE_DEC, NULL, 0x00000040, NULL, HFILL }},
3393 { &hf_ecmp_param_format_parameter_has_no_default, { "ND- Parameter has no default", "ecmp.param_format.parameter_has_no_default", FT_UINT32, BASE_DEC, NULL, 0x00000080, NULL, HFILL }},
3394 { &hf_ecmp_param_format_number_of_decimal_places, { "DP- Number of Decimal places", "ecmp.param_format.number_of_decimal_places", FT_UINT32, BASE_DEC, NULL, 0x00000F00, NULL, HFILL }},
3395 { &hf_ecmp_param_format_variable_maximum_and_minimum, { "VM- Variable maximum and minimum", "ecmp.param_format.variable_maximum_and_minimum", FT_UINT32, BASE_DEC, NULL, 0x00001000, NULL, HFILL }},
3396 { &hf_ecmp_param_format_string_parameter, { "TE- String parameter", "ecmp.param_format.string_parameter", FT_UINT32, BASE_DEC, NULL, 0x00002000, NULL, HFILL }},
3397 { &hf_ecmp_param_format_desitination_set_up_parameter, { "DE- Desitination set-up parameter", "ecmp.param_format.desitination_set_up_parameter", FT_UINT32, BASE_DEC, NULL, 0x00004000, NULL, HFILL }},
3398 { &hf_ecmp_param_format_filtered_when_displayed, { "FI- Filtered when displayed", "ecmp.param_format.filtered_when_displayed", FT_UINT32, BASE_DEC, NULL, 0x00008000, NULL, HFILL }},
3399 { &hf_ecmp_param_format_pseudo_read_only, { "PR- Pseudo read only", "ecmp.param_format.pseudo_read_only", FT_UINT32, BASE_DEC, NULL, 0x00010000, NULL, HFILL }},
3400 { &hf_ecmp_param_format_display_format, { "DF- Display Format", "ecmp.param_format.display_format", FT_UINT32, BASE_DEC, VALS(display_format), 0x001E0000, NULL, HFILL }},
3401 { &hf_ecmp_param_format_floating_point_value, { "FL- Floating point value", "ecmp.param_format.floating_point_value", FT_UINT32, BASE_DEC, NULL, 0x00200000, NULL, HFILL }},
3402 { &hf_ecmp_param_format_units, { "UNITS", "ecmp.param_format.units", FT_UINT32, BASE_DEC, VALS(format_units), 0x0FC00000, NULL, HFILL }},
3403 { &hf_ecmp_string_id, { "String ID", "ecmp.string_id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3404 { &hf_ecmp_address_scheme_menu, { "Menu", "ecmp.address_scheme.menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3405 { &hf_ecmp_address_scheme_parameter, { "Parameter", "ecmp.address_scheme.parameter", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3406 { &hf_ecmp_address_scheme_slot, { "Slot", "ecmp.address_scheme.slot", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3407 { &hf_ecmp_address_scheme_null_byte_size, { "NULL byte size", "ecmp.address_scheme.null_byte_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3408 { &hf_ecmp_display_unit_id, { "Unit ID", "ecmp.display_unit_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3409 { &hf_ecmp_data_boolean, { "Data", "ecmp.data.boolean", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }},
3410 { &hf_ecmp_data_int8, { "Data", "ecmp.data.int8", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3411 { &hf_ecmp_data_uint8, { "Data", "ecmp.data.uint8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3412 { &hf_ecmp_data_int16, { "Data", "ecmp.data.int16", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3413 { &hf_ecmp_data_uint16, { "Data", "ecmp.data.uint16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3414 { &hf_ecmp_data_int32, { "Data", "ecmp.data.int32", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3415 { &hf_ecmp_data_uint32, { "Data", "ecmp.data.uint32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3416 { &hf_ecmp_data_int64, { "Data", "ecmp.data.int64", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3417 { &hf_ecmp_data_uint64, { "Data", "ecmp.data.uint64", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3418 { &hf_ecmp_data_float, { "Data", "ecmp.data.float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3419 { &hf_ecmp_data_double, { "Data", "ecmp.data.double", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3420 { &hf_ecmp_access_mode, { "Access Mode", "ecmp.access_mode", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3421 { &hf_ecmp_open_in_non_blocking_mode, { "Open in non-blocking mode", "ecmp.open_in_non_blocking_mode", FT_BOOLEAN, 8, NULL, 0x80, NULL, HFILL }},
3422 { &hf_ecmp_open_file_relative_to_specified_directory_handle, { "Open file relative to specified directory handle", "ecmp.open_file_relative_to_specified_directory_handle", FT_BOOLEAN, 8, NULL, 0x40, NULL, HFILL }},
3423 { &hf_ecmp_file_access_mode, { "File Access Mode", "ecmp.file_access_mode", FT_UINT8, BASE_DEC, VALS(file_status_mode), 0x0F, NULL, HFILL }},
3424 { &hf_ecmp_additional_scheme, { "Additional Scheme", "ecmp.additional_scheme", FT_UINT8, BASE_DEC, VALS(additional_scheme_vals), 0x0, NULL, HFILL }},
3425 { &hf_ecmp_scheme_data_length, { "Length", "ecmp.scheme_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3426 { &hf_ecmp_number_of_requested_bytes, { "Number of requested bytes", "ecmp.number_of_requested_bytes", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3427 { &hf_ecmp_number_of_bytes_transferred, { "Number of bytes transferred", "ecmp.number_of_bytes_transferred", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3428 { &hf_ecmp_crc, { "CRC", "ecmp.crc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3429 { &hf_ecmp_ref_offset, { "Offset", "ecmp.ref_offset", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3430 { &hf_ecmp_number_of_files_to_list, { "Number of files to list", "ecmp.number_of_files_to_list", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3431 { &hf_ecmp_file_hash, { "Hash", "ecmp.file_hash", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3432 { &hf_ecmp_item_type, { "Item type", "ecmp.item_type", FT_UINT8, BASE_DEC, VALS(item_type_vals), 0x0, NULL, HFILL }},
3433 { &hf_ecmp_file_integrity, { "File Integrity", "ecmp.file_integrity", FT_UINT8, BASE_DEC, VALS(file_integrity_vals), 0x01, NULL, HFILL }},
3434 { &hf_ecmp_display_attr_read_only, { "Read Only", "ecmp.display_attr.read_only", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
3435 { &hf_ecmp_display_attr_hidden, { "Hidden", "ecmp.display_attr.hidden", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
3436 { &hf_ecmp_display_attr_system, { "System", "ecmp.display_attr.system", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
3437 { &hf_ecmp_display_attr_volume_label, { "Volume Label", "ecmp.display_attr.volume_label", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
3438 { &hf_ecmp_display_attr_subdirectory, { "Subdirectory", "ecmp.display_attr.subdirectory", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
3439 { &hf_ecmp_display_attr_archive, { "Archive", "ecmp.display_attr.archive", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
3440 { &hf_ecmp_display_creation, { "Display creation", "ecmp.display_creation", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3441 { &hf_ecmp_display_modification, { "Display modification", "ecmp.display_modification", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3442 { &hf_ecmp_interrogate_item_type, { "Item Type", "ecmp.interrogate_item_type", FT_UINT8, BASE_DEC, VALS(Interrogate_command_option_state), 0x0, NULL, HFILL }},
3443 { &hf_ecmp_interrogate_count, { "Count", "ecmp.interrogate_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3444 { &hf_ecmp_modbus_pdu_size, { "Size", "ecmp.modbus_pdu_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3446 { &hf_ecmp_destination_scheme, { "Destination Scheme", "ecmp.destination_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3448 { &hf_ecmp_program_control_target, { "Target", "ecmp.program_control_target", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3449 { &hf_ecmp_program_control_command, { "Command", "ecmp.program_control_command", FT_UINT8, BASE_DEC, VALS(command_code_list), 0x0, NULL, HFILL }},
3450 { &hf_ecmp_program_control_sub_command, { "Sub-Command", "ecmp.program_control_sub_command", FT_UINT8, BASE_DEC, VALS(sub_command_code_list), 0x0, NULL, HFILL }},
3451 { &hf_ecmp_program_control_status, { "Status", "ecmp.program_control_status", FT_UINT8, BASE_DEC, VALS(status_list), 0x0, NULL, HFILL }},
3452 { &hf_ecmp_program_status_target, { "Target", "ecmp.program_status_target", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3453 { &hf_ecmp_program_status_status, { "Status", "ecmp.program_status_status", FT_UINT8, BASE_DEC, VALS(running_state_list), 0x0, NULL, HFILL }},
3454 { &hf_ecmp_program_status_additional_items, { "Additional Items", "ecmp.program_status_additional_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3455 { &hf_ecmp_cyclic_setup_max_mappings, { "Max Mappings", "ecmp.cyclic_setup.max_mappings", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3456 { &hf_ecmp_cyclic_setup_start_offset, { "Start Offset", "ecmp.cyclic_setup.start_offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3457 { &hf_ecmp_cyclic_setup_tx_count, { "Tx Count", "ecmp.cyclic_setup.tx_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3458 { &hf_ecmp_cyclic_setup_rx_count, { "Rx Count", "ecmp.cyclic_setup.rx_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3459 { &hf_ecmp_udp_alignment, { "Alignment", "ecmp.udp_alignment", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3460 { &hf_ecmp_udp_scheme, { "Scheme", "ecmp.udp_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3461 { &hf_ecmp_cyclic_data, { "Cyclic Data", "ecmp.cyclic_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3462 { &hf_ecmp_version_summary, { "Version summary", "ecmp.version_summary", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3463 { &hf_ecmp_min_param_menu, { "Min parameter in menu", "ecmp.min_param_menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3464 { &hf_ecmp_max_param_menu, { "Max parameter in menu", "ecmp.max_param_menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3465 { &hf_ecmp_file_length, { "File length", "ecmp.file_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3466 { &hf_ecmp_mec_offset, { "mec_offset", "ecmp.mec_offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3467 { &hf_ecmp_sample_period, { "Sample period", "ecmp.sample_period", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3468 { &hf_ecmp_rx_timeout, { "RX Timeout", "ecmp.rx_timeout", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, &units_microseconds, 0x0, NULL, HFILL }},
3469 { &hf_ecmp_rx_action, { "Action", "ecmp.rx_action", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3470 { &hf_ecmp_rx_event_destination, { "Event Destination", "ecmp.rx_event_destination", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3471 { &hf_ecmp_rx_event, { "Event", "ecmp.rx_event", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3472 { &hf_ecmp_rx_late_handler_action, { "Action", "ecmp.rx_late_handler_action", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3473 { &hf_ecmp_rx_late_handler_event_destination, { "Event Destination", "ecmp.rx_late_handler_event_destination", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3474 { &hf_ecmp_rx_late_handler_event, { "Event", "ecmp.rx_late_handler_event", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3475 { &hf_ecmp_transport_addr_scheme, { "Scheme", "ecmp.transport_addr_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3476 { &hf_ecmp_transport_addr, { "Transport address", "ecmp.transport_addr", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3477 { &hf_ecmp_mapping_item_offset, { "Offset", "ecmp.mapping_item_offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3478 { &hf_ecmp_mapping_item_scheme, { "Scheme", "ecmp.mapping_item_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3479 { &hf_ecmp_setup_attribute, { "Attribute", "ecmp.setup_attribute", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3480 { &hf_ecmp_mec_period, { "mec period", "ecmp.mec_period", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3481 { &hf_ecmp_interrogate_command, { "Command", "ecmp.interrogate_command", FT_UINT8, BASE_DEC, VALS(command_vals), 0x0, NULL, HFILL }}
3484 /* array to store pointers to the ids of the subtrees that we may be creating */
3485 static gint *ett[] = {
3488 &ett_ecmp_response_size,
3492 &ett_ecmp_option_data,
3493 &ett_ecmp_attribute,
3494 &ett_ecmp_attribute_data,
3495 &ett_ecmp_cyclic_scheme,
3496 &ett_ecmp_interrogate_message,
3497 &ett_ecmp_info_type,
3498 &ett_ecmp_info_count,
3499 &ett_ecmp_param_address,
3500 &ett_ecmp_access_mode,
3501 &ett_ecmp_access_file,
3502 &ett_ecmp_file_read,
3503 &ett_ecmp_file_write,
3504 &ett_ecmp_file_info,
3505 &ett_ecmp_file_info_att,
3506 &ett_ecmp_file_position,
3507 &ett_ecmp_file_list_no,
3508 &ett_ecmp_file_list,
3509 &ett_ecmp_tunnel_3s_goodframe,
3510 &ett_ecmp_tunnel_3s_size,
3511 &ett_ecmp_tunnel_3s_service,
3512 &ett_cyclic_setup_attribs,
3513 &ett_cyclic_setup_transport_addr,
3514 &ett_cyclic_setup_attrib_item,
3515 &ett_ecmp_cyclic_data_32_bit_display,
3516 &ett_ecmp_cyclic_data_16_bit_display,
3517 &ett_ecmp_cyclic_data_8_bit_display,
3518 &ett_ecmp_modbus_pdu_message,
3519 &ett_ecmp_program_control_message,
3520 &ett_ecmp_program_status_message
3523 static ei_register_info ei[] = {
3524 { &ei_ecmp_unknown_command, { "ecmp.unknown_command", PI_PROTOCOL, PI_WARN, "Unknown Command", EXPFILL }},
3525 { &ei_ecmp_color, { "ecmp.color_invalid", PI_PROTOCOL, PI_WARN, "Invalid color data value", EXPFILL }},
3526 { &ei_ecmp_option, { "ecmp.ecmp_option.unknown", PI_PROTOCOL, PI_WARN, "ERROR - Unrecognised Option Code", EXPFILL }},
3527 { &ei_ecmp_data_type, { "ecmp.data_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Data Type", EXPFILL }},
3528 { &ei_ecmp_parameter_addressing_scheme, { "ecmp.incorrect_parameter_addressing_scheme", PI_PROTOCOL, PI_WARN, "Incorrect parameter addressing scheme", EXPFILL }},
3529 { &ei_ecmp_info_type, { "ecmp.info_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown info type", EXPFILL }},
3530 { &ei_ecmp_attribute_type, { "ecmp.attribute_type.unknown", PI_PROTOCOL, PI_WARN, "Wrong attribute type", EXPFILL }},
3531 { &ei_ecmp_item_type, { "ecmp.item_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown item type", EXPFILL }},
3532 { &ei_ecmp_options_not_implemented, { "ecmp.options_not_implemented", PI_UNDECODED, PI_WARN, "ECMP Options Not Implemented", EXPFILL }}
3535 expert_module_t* expert_ecmp;
3537 proto_ecmp = proto_register_protocol ("ECMP", PROTO_TAG_ECMP, "ecmp");
3539 /* full name short name and abbreviation (display filter name)*/
3540 proto_register_field_array(proto_ecmp, hf, array_length (hf));
3541 proto_register_subtree_array (ett, array_length (ett));
3542 expert_ecmp = expert_register_protocol(proto_ecmp);
3543 expert_register_field_array(expert_ecmp, ei, array_length(ei));
3546 /* Function to initialise the dissector*/
3547 /* Wireshark literally scans this file (packet-ecmp.c) to find this function */
3548 void proto_reg_handoff_ecmp(void)
3550 dissector_handle_t ecmp_tcp_handle, ecmp_udp_handle;
3552 ecmp_tcp_handle = create_dissector_handle(dissect_ecmp_tcp, proto_ecmp);
3553 ecmp_udp_handle = create_dissector_handle(dissect_ecmp_udp, proto_ecmp);
3555 /* Cyclic frames are over UDP and non-cyclic are over TCP */
3556 dissector_add_uint_with_preference("udp.port", ECMP_TCP_PORT, ecmp_udp_handle);
3557 dissector_add_uint_with_preference("tcp.port", ECMP_TCP_PORT, ecmp_tcp_handle);
3559 /* Modbus dissector hooks */
3560 modbus_handle = find_dissector_add_dependency("modbus", proto_ecmp);
3561 proto_modbus = proto_get_id_by_filter_name( "modbus" );
3566 * Editor modelines - http://www.wireshark.org/tools/modelines.html
3571 * indent-tabs-mode: t
3574 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
3575 * :indentSize=8:tabSize=8:noTabs=false: