epan/dissectors/pidl/samr/samr.cnf cnf_dissect_lsa_BinaryString => lsarpc_dissect_str...
[wireshark-sm.git] / epan / dissectors / packet-ecmp.c
blob289245a63805d4469db22f9b5cb65e44afd056fe
1 /* packet-ecmp.c
3 * Copyright 2014, James Lynch <lynch007@gmail.com>, Control Techniques
4 * Copyright 2015, Luke Orehawa <lukeorehawa@gmail.com>, Control Techniques
6 * Revisions:
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
21 #include "config.h"
22 #include <epan/packet.h>
23 #include <epan/expert.h>
24 #include <epan/tfs.h>
25 #include <epan/unit_strings.h>
26 #include "packet-mbtcp.h"
28 #define PROTO_TAG_ECMP "ECMP"
29 #define ECMP_TCP_PORT 6160
31 void proto_reg_handoff_ecmp(void);
32 void proto_register_ecmp (void);
34 static dissector_handle_t ecmp_tcp_handle, ecmp_udp_handle;
36 /* Wireshark ID of the ECMP protocol */
37 static int proto_ecmp;
39 /* Used to set Modbus protocol data */
40 static int proto_modbus;
42 /* These are the handles of our subdissectors */
43 static dissector_handle_t modbus_handle;
45 /*smallest size of a packet, number of bytes*/
46 static const int ecmp_min_packet_size = 6;
48 /* ECMP request codes */
49 #define ECMP_COMMAND_IDENTIFY 0x00
50 #define ECMP_COMMAND_INFO 0x01
51 #define ECMP_COMMAND_INTERROGATE 0x02
52 #define ECMP_COMMAND_READ 0x10
53 #define ECMP_COMMAND_READWITHTYPE 0x11
54 #define ECMP_COMMAND_WRITE 0x12
55 #define ECMP_COMMAND_OBJECTINFO 0x13
56 #define ECMP_COMMAND_GETNEXTOBJECTS 0x14
57 #define ECMP_COMMAND_FILEOPEN 0x20
58 #define ECMP_COMMAND_FILEREAD 0x21
59 #define ECMP_COMMAND_FILEWRITE 0x22
60 #define ECMP_COMMAND_FILECLOSE 0x23
61 #define ECMP_COMMAND_FILEINFO 0x24
62 #define ECMP_COMMAND_FILEDELETE 0x25
63 #define ECMP_COMMAND_FILESTATE 0x26
64 #define ECMP_COMMAND_FILEPOS 0x27
65 #define ECMP_COMMAND_FILELIST 0x28
66 #define ECMP_COMMAND_FILEEXISTS 0x2a
67 #define ECMP_COMMAND_CYCLICLINK 0x31
68 #define ECMP_COMMAND_PROGRAMCONTROL 0x60
69 #define ECMP_COMMAND_PROGRAMSTATUS 0x61
70 #define ECMP_COMMAND_CYCLICFRAME 0x70
71 #define ECMP_COMMAND_TUNNELFRAME 0x73
72 #define ECMP_COMMAND_MODBUSPDU 0x74
74 /* cyclic display formats */
75 static const uint8_t cyclic_display_byte_format;
76 static const uint8_t cyclic_display_word_format = 1;
77 static const uint8_t cyclic_display_long_format = 2;
79 /* Addressing scheme Structure */
80 static const value_string address_scheme [] = {
81 { 0, "No Route" },
82 { 1, "Intercept" },
83 { 2, "Default Route" },
84 { 3, "Diagnostics" },
85 { 4, "Named" },
86 { 0, NULL }
87 /*other commands to be added */
90 /* Address Structure */
91 static const value_string diagnostic [] = {
92 { 0, "Status" },
93 { 1, "Alarm" },
94 { 2, "Network" },
95 { 3, "Application" },
96 { 0, NULL }
97 /*other commands to be added*/
100 /* Command Structure*/
101 static const value_string command_vals [] = {
102 { 0x00, "Identify"},
103 { 0x01, "Info"},
104 { 0x02, "Interrogate"},
105 { 0x10, "Read"},
106 { 0x11, "ReadWithType"},
107 { 0x12, "Write"},
108 { 0x13, "ObjectInfo"},
109 { 0x14, "GetNextObjects"},
110 { 0x20, "FileOpen"},
111 { 0x21, "FileRead"},
112 { 0x22, "FileWrite"},
113 { 0x23, "FileClose"},
114 { 0x24, "FileInfo"},
115 { 0x25, "FileDelete"},
116 { 0x26, "FileState"},
117 { 0x27, "FilePos"},
118 { 0x28, "FileList"},
119 { 0x2A, "FileExists"},
120 { 0x31, "CyclicSetup"},
121 { 0x60, "ProgramControl"},
122 { 0x61, "ProgramStatus"},
123 { 0x70, "CyclicFrame"},
124 { 0x73, "TunnelFrame"},
125 { 0x74, "ModbusPDU"},
126 { 0, NULL }
127 /*other commands to be added*/
130 /* Option Code structure*/
131 static const value_string option_code [] = {
132 { 0, "End of Options"},
133 { 1, "Dummy" },
134 { 2, "Process At" },
135 { 3, "Route to Custom Target"},
136 { 0, NULL }
137 /* other - "Unknown" */
140 /* Attribute type Structure */
141 static const value_string attribute [] = {
142 { 0, "Manufacturer Name" },
143 { 1, "Product Family" },
144 { 2, "Product Model" },
145 { 3, "Serial Number" },
146 { 4, "Order Number" },
147 { 5, "Date Code" },
148 { 6, "Device Name" },
149 { 7, "Version Summary" },
150 { 8, "Colour Codes" },
151 { 0, NULL }
152 /* other - Unknown*/
155 /* Status type Structure */
156 static const value_string status [] = {
157 { 0, "OK (no errors detected in request)" },
158 { 1, "OK, chunks follow" },
159 { 2, "Processing Request" },
160 { -1, "Error - Slave not ready" },
161 { -2, "Error - Request Too Long" },
162 { -3, "Error - Chunking Error" },
163 { 0, NULL }
164 /* other - Unknown*/
167 /* Category (device) structure*/
168 static const value_string category [] = {
169 { 0, "Drive" },
170 { 1, "Option Module" },
171 { 0, NULL }
174 /* Cyclic data alignment */
175 static const value_string cyclic_align [] = {
176 { 0, "8bit" },
177 { 1, "8bit" }, /* TODO: is this correct? */
178 { 2, "16bit" },
179 { 4, "32bit" },
180 { 8, "64bit" },
181 { 0, NULL }
184 /* Cyclic data scheme */
185 static const value_string cyclic_scheme [] = {
186 { 0, "Standard" },
187 { 1, "Synchronised" },
188 { 0, NULL }
191 /* Parameter addressing scheme */
192 static const value_string parameter_address_scheme [] = {
193 { 0, "Standard" },
194 { 1, "Slot Specific" },
195 { 3, "Variable" },
196 { 0, NULL }
199 #if 0
200 static const value_string route_address_scheme [] = {
201 { 1, "Intercept" },
202 { 2, "DefaultRoute" },
203 { 0, NULL }
205 #endif
207 /* Parameter access status */
208 static const value_string parameter_access_status [] = {
209 { 0, "OK" },
210 { 1, "OK - Converted"},
211 { 2, "OK - Clamped"},
212 { -1, "ERROR - Address Type"},
213 { -2, "ERROR - Timeout"},
214 { -3, "ERROR - Access Denied"},
215 { -4, "ERROR - Does not exist"},
216 { -5, "ERROR - Data Type"},
217 { -6, "ERROR - Failed Read"},
218 { -7, "ERROR - Failed Write"},
219 { -8, "ERROR - Not Readable"},
220 { -9, "ERROR - Not Writeable"},
221 { -10, "ERROR - Over Range"},
222 { -11, "ERROR - Request Invalid"},
223 { -12, "ERROR - Response Too Big"},
224 { -13, "ERROR - Decimal Place"},
225 { 0, NULL}
228 /* Parameter data types */
229 static const value_string parameter_data_types [] = {
230 { 0, "Boolean"},
231 { 1, "INT8"},
232 { 2, "UINT8"},
233 { 3, "INT16"},
234 { 4, "UINT16"},
235 { 5, "INT32"},
236 { 6, "UINT32"},
237 { 7, "INT64"},
238 { 8, "UINT64"},
239 { 9, "INT128"},
240 { 10, "UINT128"},
241 { 20, "SINGLE"},
242 { 21, "DOUBLE"},
243 { 30, "String ID"},
244 { 31, "String"},
245 { 0, NULL}
248 /* Info types */
249 static const value_string info_type [] = {
250 { 0, "No Information"},
251 { 1, "Lowest Numbered Parameter in Menu"},
252 { 2, "Highest Numbered Parameter in Menu"},
253 { 3, "Parameter Format"},
254 { 4, "Minimum Value allowed for Parameter"},
255 { 5, "Maximum Value allowed for Parameter"},
256 { 6, "Object Unit Information"},
257 { 7, "Data Type of Parameter"},
258 { 0, NULL }
261 /* Display formats */
262 static const value_string display_format [] = {
263 { 0, "Standard format"},
264 { 1, "Date format (xx,yy,zz)"},
265 { 2, "Time with seconds format (xx.yy.zz)"},
266 { 3, "Character format"},
267 { 4, "Binary format"},
268 { 5, "IP address format (www.xxx.yyy.zzz)"},
269 { 6, "MAC address format (AA:BB:CC:DD:EE:FF)"},
270 { 7, "Version number (ww.xx.yy.zz)"},
271 { 8, "Slot menu parameter format (x,yy,zzz)"},
272 { 0, NULL}
275 /* Format units */
276 static const value_string format_units [] = {
277 { 0, "No units"},
278 { 1, "Custom units"},
279 { 2, "Millimetres (mm)"},
280 { 3, "Metres (m)"},
281 { 4, "User units (UU)"},
282 { 5, "Revolutions (revs)"},
283 { 6, "Degrees (')"},
284 /* { 7, ""}, */
285 { 8, "General position unit"},
286 { 9, "Millimetres per second (mm/s)"},
287 { 10, "User units per millisecond (UU/ms)"},
288 { 11, "Revolutions per minute (Rpm)"},
289 { 12, "Hertz (Hz)"},
290 { 13, "Kilohertz (kHz)"},
291 { 14, "Megahertz (MHz)"},
292 { 15, "General speed unit (Hz, rpm, mm/s)"},
293 { 16, "Closed loop speed unit (rpm, mm/s)"},
294 { 17, "Seconds per one thousand millimetres per seconds (s/m/s)"},
295 { 18, "User units per millimetre per second (UU/mm/s)"},
296 { 19, "Seconds per one thousand revolution per minute (s/1000rpm)"},
297 { 20, "Seconds per one hundred hertz (s/100Hz)"},
298 { 21, "General acceleration unit"},
299 { 22, "Closed loop acceleration unit"},
300 { 23, "Seconds squared per one thousand millimetres per second (s^2/1000ms/s)"},
301 { 24, "Seconds squared per user units per millisecond (s^2/UU/ms"},
302 { 25, "Seconds squared per one thousand revolutions per minute (s^2/1000rpm)"},
303 { 26, "Seconds squared per one hundred hertz (s^2/100Hz)"},
304 { 27, "General jerk unit"},
305 { 28, "Closed loop jerk unit"},
306 { 29, "Messages per second (Msg/s)"},
307 { 30, "Hours (Hours)"},
308 { 31, "Minutes (Mins)"},
309 { 32, "Seconds (s)"},
310 { 33, "Milliseconds (ms)"},
311 { 34, "Microseconds (us)"},
312 { 35, "Nanoseconds (ns)"},
313 { 36, "Volts (V)"},
314 { 37, "Amperes (A)"},
315 { 38, "Ohms (Ohms)"},
316 { 39, "Millihenrys (mH)"},
317 { 40, "Kilowatts (kW)"},
318 { 41, "Kilo-Volt-Amps-Reactive (kVAr)"},
319 { 42, "Megawatt hours (MWh)"},
320 { 43, "Kilowatt hours (kWh)"},
321 { 44, "Degrees Celsius ('C)"},
322 { 45, "Reciprocal of degrees Celsius (/'C)"},
323 { 46, "Kilogram-metres squared (kgm^2)"},
324 { 47, "Newton metres (Nm)"},
325 { 48, "Newton metres per ampere (Nm/A)"},
326 { 49, "open-circuit volts per 1000rpm (V/1000rpm)"},
327 { 50, "Bits (Bits)"},
328 { 51, "Bytes (Bytes)"},
329 { 52, "Kilobytes (kB)"},
330 { 53, "Megabytes (MB)"},
331 { 54, "Bits per second (Bit/s)"},
332 { 55, "Baud (Baud)"},
333 { 56, "Kilobaud (kBaud)"},
334 { 57, "Megabaud (MBaud)"},
335 { 58, "Poles (Poles)"},
336 { 59, "Percent (%)"},
337 { 60, "Volts per millisecond (V/ms)"},
338 { 0, NULL}
341 /* File status */
342 static const value_string file_status [] = {
343 { 0, "Processing"},
344 { 1, "OK"},
345 { 2, "OK - More Data"},
346 { 3, "OK - EOF"},
347 { -1, "ERROR - File Handle"},
348 { -2, "ERROR - Blocked"},
349 { -3, "ERROR - Blocking Mode"},
350 { -4, "ERROR - Not in Progress"},
351 { -5, "ERROR - Not Found"},
352 { -6, "ERROR - Read Only"},
353 { -7, "ERROR - Write Only"},
354 { -8, "ERROR - Not Created"},
355 { -9, "ERROR - No Data"},
356 { -10, "ERROR - Wrong Mode"},
357 { -11, "ERROR - Too Big"},
358 { -12, "ERROR - Protected"},
359 { -13, "ERROR - CRC"},
360 { -14, "ERROR - Length"},
361 { -15, "ERROR - Too Many Open"},
362 { -16, "ERROR - Invalid File"},
363 { -17, "ERROR - Invalid Request"},
364 { -18, "ERROR - No Append"},
365 { -19, "ERROR - Invalid State"},
366 { -20, "ERROR - Incompatible"},
367 { -21, "ERROR - Uninitialized"},
368 { 0, NULL}
371 /* File status mode */
372 static const value_string file_status_mode [] = {
373 { 0, "Information"},
374 { 1, "Read"},
375 { 2, "Create"},
376 { 3, "Append"},
377 { 4, "New Directory"},
378 { 0, NULL}
381 /* File attributes */
382 static const value_string file_attributes [] = {
383 { 0, "File Length"},
384 { 1, "File Integrity"},
385 { 2, "Calculate CRC32"},
386 { 3, "File Attributes"},
387 { 4, "Creation Date and Time"},
388 { 5, "Modification Date and Time"},
389 { 0, NULL}
392 /* File reference position */
393 static const value_string file_ref_point [] = {
394 { 0, "SoF - Start of file"},
395 { 1, "EoF - End of file"},
396 { 2, "Current - Use current file pointer"},
397 { 0, NULL}
400 static const value_string cyclic_setup_mode [] = {
401 { 0, "Create"},
402 { 1, "Edit"},
403 { 2, "Finalise"},
404 { 3, "Delete"},
405 { 4, "Exist"},
406 { 5, "List"},
407 { 6, "Info"},
408 { 10, "Set"},
409 { 11, "Get"},
410 { 12, "Get mappings"},
411 { 0, NULL}
414 static const value_string cyclic_attributes [] = {
415 { 0, "State"},
416 { 1, "Rx/Tx"},
417 { 2, "Synchronised"},
418 { 3, "MEC Offset"},
419 { 4, "Sample Period"},
420 { 5, "MEC Delay"},
421 { 6, "Data Change"},
422 { 7, "Rx Timeout Handler"},
423 { 8, "Rx Data Late Handler"},
424 { 9, "Transport Address"},
425 { 10, "Max Mappings"},
426 { 11, "Number Of Mappings"},
427 { 12, "Mapping Item"},
428 { 13, "Saveable"},
429 { 128, "Max RX Links"},
430 { 129, "Max TX Links"},
431 { 130, "Max Mappings Per Link"},
432 { 131, "Max Sync RX Links"},
433 { 132, "Max Sync TX Links"},
434 { 133, "Max Mappings Per Sync Link"},
435 { 134, "'Process At' Queue Depth"},
436 { 135, "MEC Period"},
437 { 0, NULL}
440 static const value_string cyclic_setup_link_dir [] = {
441 { 0, "Rx"},
442 { 1, "Tx"},
443 { 0, NULL}
446 static const value_string cyclic_setup_link_exists [] = {
447 { 0, "Does not exist"},
448 { 1, "Exists"},
449 { 0, NULL}
452 static const value_string additional_scheme_vals [] = {
453 { 0, "None"},
454 { 1, "Generic"},
455 { 0, NULL}
458 /* Program Control - command codes */
459 static const value_string command_code_list [] = {
460 { 0, "Stop"},
461 { 1, "Start"},
462 { 2, "Reset"},
463 { 0, NULL }
464 /*other commands to be added*/
467 /* Program Control - sub command codes */
468 static const value_string sub_command_code_list [] = {
469 { 0, "Default"},
470 { 1, "User1"},
471 { 2, "User2"},
472 { 0, NULL }
473 /*other sub commands to be added*/
476 /* Program Control - status codes */
477 static const value_string status_list [] = {
478 { 0, "OK"},
479 { -1, "Error"},
480 { 0, NULL }
481 /*other status to be added*/
484 /* Program Status - running state codes */
485 static const value_string running_state_list [] = {
486 { 0, "Stopped"},
487 { 1, "Running"},
488 { 2, "Exception"},
489 { 3, "None (no program found in device)"},
490 { 0, NULL }
491 /*other status to be added*/
494 /* Interrogate - command support states */
495 static const value_string Interrogate_support_state [] = {
496 { 0, "Not Supported"},
497 { 1, "Supported"},
498 { 0, NULL }
499 /*other status to be added*/
502 /* Interrogate - command / option states */
503 static const value_string Interrogate_command_option_state [] = {
504 { 0, "Command"},
505 { 1, "Option"},
506 { 0, NULL }
507 /*other status to be added*/
510 static const value_string item_type_vals[] = {
511 { 0, "File"},
512 { 1, "Directory"},
513 { 0, NULL }
517 /* The following hf_* variables are used to hold the Wireshark IDs of
518 * our header fields; they are filled out when we call
519 * proto_register_field_array() in proto_register_ecmp()
521 static int hf_ecmp_command;
522 static int hf_ecmp_destination_address;
523 static int hf_ecmp_source_address;
524 static int hf_ecmp_diagnostic;
525 static int hf_ecmp_type_rr;
526 static int hf_ecmp_chunking;
527 static int hf_ecmp_max_response_size;
528 static int hf_ecmp_category;
529 static int hf_ecmp_option;
530 static int hf_ecmp_attribute;
531 static int hf_ecmp_no_of_attributes;
532 static int hf_ecmp_chunk_id;
533 static int hf_ecmp_transaction_id;
534 static int hf_ecmp_status;
535 static int hf_ecmp_drive_type;
536 static int hf_ecmp_drive_derivative;
537 static int hf_ecmp_drive_factory_fit_category_id;
538 static int hf_ecmp_category_id;
539 static int hf_ecmp_attribute_string;
540 static int hf_ecmp_file_name;
541 static int hf_ecmp_info_command;
542 static int hf_ecmp_directory;
543 static int hf_ecmp_names_scheme;
544 static int hf_ecmp_variable_name;
545 static int hf_ecmp_unit_id_string;
546 static int hf_ecmp_ecmp_string;
547 static int hf_ecmp_process_time;
548 static int hf_ecmp_cyclic_frame_time;
549 static int hf_ecmp_grandmaster;
550 static int hf_ecmp_data;
551 static int hf_ecmp_response_data;
553 static int hf_ecmp_cyclic_link_num;
554 static int hf_ecmp_cyclic_align;
555 static int hf_ecmp_cyclic_scheme;
556 static int hf_ecmp_cyclic_link_number_display;
558 /* Cyclic setup */
559 static int hf_ecmp_cyclic_setup_mode;
560 static int hf_ecmp_cyclic_setup_linkno;
561 static int hf_ecmp_cyclic_setup_dir;
562 static int hf_ecmp_cyclic_setup_attrib_count;
563 static int hf_ecmp_cyclic_setup_rsp_status;
564 static int hf_ecmp_cyclic_setup_rsp_err_idx;
565 static int hf_ecmp_cyclic_setup_attrib;
566 static int hf_ecmp_cyclic_setup_link_exists;
567 static int hf_ecmp_cyclic_link_req_resp;
569 /*for info command */
570 static int hf_ecmp_buffer_size;
571 static int hf_ecmp_max_response;
572 static int hf_ecmp_max_handle;
573 static int hf_ecmp_info_address;
575 /*for parameter access commands*/
576 static int hf_ecmp_parameter_address;
577 static int hf_ecmp_number_of_parameter_definitions;
578 static int hf_ecmp_number_of_parameter_responses;
579 static int hf_ecmp_parameter_status;
580 static int hf_ecmp_data_type;
581 static int hf_ecmp_info_type;
583 /* for file access commands */
584 static int hf_ecmp_file_status;
585 static int hf_ecmp_file_handle;
586 static int hf_ecmp_file_attributes;
587 static int hf_ecmp_file_ref_point;
590 /* for tunnel frame command */
591 #define TUNNEL_START_FLAG 0x01
592 #define TUNNEL_END_FLAG 0x02
593 #define TUNNEL_CHECK_OUTPUT_FLAG 0x04
595 static int hf_ecmp_tunnel_control;
596 static int hf_ecmp_tunnel_start_flag;
597 static int hf_ecmp_tunnel_end_flag;
598 static int hf_ecmp_tunnel_check_output_flag;
599 static int hf_ecmp_tunnel_size;
601 /* Generated from convert_proto_tree_add_text.pl */
602 static int hf_ecmp_physical_address;
603 static int hf_ecmp_logical_address;
604 static int hf_ecmp_primary_colour;
605 static int hf_ecmp_secondary_colour;
606 static int hf_ecmp_number_of_subsequent_object_requests;
607 static int hf_ecmp_number_of_decimal_places;
608 static int hf_ecmp_no_information_available;
609 static int hf_ecmp_param_format_bit_default_unipolar;
610 static int hf_ecmp_param_format_write_allowed;
611 static int hf_ecmp_param_format_read_not_allowed;
612 static int hf_ecmp_param_format_protected_from_destinations;
613 static int hf_ecmp_param_format_parameter_not_visible;
614 static int hf_ecmp_param_format_not_clonable;
615 static int hf_ecmp_param_format_voltage_or_current_rating_dependent;
616 static int hf_ecmp_param_format_parameter_has_no_default;
617 static int hf_ecmp_param_format_number_of_decimal_places;
618 static int hf_ecmp_param_format_variable_maximum_and_minimum;
619 static int hf_ecmp_param_format_string_parameter;
620 static int hf_ecmp_param_format_destination_set_up_parameter;
621 static int hf_ecmp_param_format_filtered_when_displayed;
622 static int hf_ecmp_param_format_pseudo_read_only;
623 static int hf_ecmp_param_format_display_format;
624 static int hf_ecmp_param_format_floating_point_value;
625 static int hf_ecmp_param_format_units;
626 static int hf_ecmp_string_id;
627 static int hf_ecmp_address_scheme_menu;
628 static int hf_ecmp_address_scheme_parameter;
629 static int hf_ecmp_address_scheme_slot;
630 static int hf_ecmp_address_scheme_null_byte_size;
631 static int hf_ecmp_display_unit_id;
632 static int hf_ecmp_data_boolean;
633 static int hf_ecmp_data_int8;
634 static int hf_ecmp_data_uint8;
635 static int hf_ecmp_data_int16;
636 static int hf_ecmp_data_uint16;
637 static int hf_ecmp_data_int32;
638 static int hf_ecmp_data_uint32;
639 static int hf_ecmp_data_int64;
640 static int hf_ecmp_data_uint64;
641 static int hf_ecmp_data_float;
642 static int hf_ecmp_data_double;
643 static int hf_ecmp_access_mode;
644 static int hf_ecmp_open_in_non_blocking_mode;
645 static int hf_ecmp_open_file_relative_to_specified_directory_handle;
646 static int hf_ecmp_file_access_mode;
647 static int hf_ecmp_additional_scheme;
648 static int hf_ecmp_scheme_data_length;
649 static int hf_ecmp_number_of_requested_bytes;
650 static int hf_ecmp_number_of_bytes_transferred;
651 static int hf_ecmp_crc;
652 static int hf_ecmp_ref_offset;
653 static int hf_ecmp_number_of_files_to_list;
654 static int hf_ecmp_file_hash;
655 static int hf_ecmp_item_type;
656 static int hf_ecmp_file_integrity;
657 static int hf_ecmp_display_attr_read_only;
658 static int hf_ecmp_display_attr_hidden;
659 static int hf_ecmp_display_attr_system;
660 static int hf_ecmp_display_attr_volume_label;
661 static int hf_ecmp_display_attr_subdirectory;
662 static int hf_ecmp_display_attr_archive;
663 static int hf_ecmp_display_creation;
664 static int hf_ecmp_display_modification;
665 static int hf_ecmp_interrogate_item_type;
666 static int hf_ecmp_interrogate_count;
667 static int hf_ecmp_modbus_pdu_size;
668 /* static int hf_ecmp_destination_scheme; */
669 static int hf_ecmp_program_control_target;
670 static int hf_ecmp_program_control_command;
671 static int hf_ecmp_program_control_sub_command;
672 static int hf_ecmp_program_control_status;
673 static int hf_ecmp_program_status_target;
674 static int hf_ecmp_program_status_status;
675 static int hf_ecmp_program_status_additional_items;
676 static int hf_ecmp_cyclic_setup_max_mappings;
677 static int hf_ecmp_cyclic_setup_start_offset;
678 static int hf_ecmp_cyclic_setup_tx_count;
679 static int hf_ecmp_cyclic_setup_rx_count;
680 static int hf_ecmp_udp_alignment;
681 static int hf_ecmp_udp_scheme;
682 static int hf_ecmp_cyclic_data;
683 static int hf_ecmp_version_summary;
684 static int hf_ecmp_min_param_menu;
685 static int hf_ecmp_max_param_menu;
686 static int hf_ecmp_file_length;
687 static int hf_ecmp_mec_offset;
688 static int hf_ecmp_sample_period;
689 static int hf_ecmp_rx_timeout;
690 static int hf_ecmp_rx_action;
691 static int hf_ecmp_rx_event_destination;
692 static int hf_ecmp_rx_event;
693 static int hf_ecmp_rx_late_handler_action;
694 static int hf_ecmp_rx_late_handler_event_destination;
695 static int hf_ecmp_rx_late_handler_event;
696 static int hf_ecmp_transport_addr_scheme;
697 static int hf_ecmp_transport_addr;
698 static int hf_ecmp_mapping_item_offset;
699 static int hf_ecmp_mapping_item_scheme;
700 static int hf_ecmp_setup_attribute;
701 static int hf_ecmp_mec_period;
702 static int hf_ecmp_interrogate_command;
703 /************************************************************/
705 /* These are the ids of the subtrees that we may be creating */
707 static int ett_ecmp;
708 static int ett_ecmp_address;
709 static int ett_ecmp_response_size;
710 static int ett_ecmp_command;
711 static int ett_ecmp_category;
712 static int ett_ecmp_option;
713 static int ett_ecmp_option_data;
714 static int ett_ecmp_attribute;
715 static int ett_ecmp_attribute_data;
716 static int ett_ecmp_cyclic_scheme;
717 static int ett_ecmp_info_type;
718 static int ett_ecmp_info_count;
719 static int ett_ecmp_interrogate_message;
720 static int ett_ecmp_param_address;
721 static int ett_ecmp_access_mode;
722 static int ett_ecmp_access_file;
723 static int ett_ecmp_file_read;
724 static int ett_ecmp_file_write;
725 static int ett_ecmp_file_info;
726 static int ett_ecmp_file_info_att;
727 static int ett_ecmp_file_position;
728 static int ett_ecmp_file_list_no;
729 static int ett_ecmp_file_list;
730 static int ett_ecmp_tunnel_3s_goodframe;
731 static int ett_ecmp_tunnel_3s_size;
732 static int ett_ecmp_tunnel_3s_service;
733 static int ett_cyclic_setup_attribs;
734 static int ett_cyclic_setup_attrib_item;
735 static int ett_cyclic_setup_transport_addr;
736 static int ett_ecmp_cyclic_data_32_bit_display;
737 static int ett_ecmp_cyclic_data_16_bit_display;
738 static int ett_ecmp_cyclic_data_8_bit_display;
739 static int ett_ecmp_modbus_pdu_message;
740 static int ett_ecmp_program_control_message;
741 static int ett_ecmp_program_status_message;
742 static expert_field ei_ecmp_unknown_command;
743 static expert_field ei_ecmp_color;
744 static expert_field ei_ecmp_option;
745 static expert_field ei_ecmp_item_type;
746 static expert_field ei_ecmp_options_not_implemented;
747 static expert_field ei_ecmp_info_type;
748 static expert_field ei_ecmp_attribute_type;
749 static expert_field ei_ecmp_parameter_addressing_scheme;
750 static expert_field ei_ecmp_data_type;
753 /*--------------------------------------------------------------------*/
754 /* General Commands and Framing Dissectors */
755 /*--------------------------------------------------------------------*/
756 /*a function to add the initial information about the transport layer (the first bits)*/
757 static int add_transport_layer_frame(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, int addr_type)
759 proto_item *ecmp_address_item = NULL;
760 proto_tree *ecmp_address_tree = NULL;
761 uint8_t byte_test;
763 ecmp_address_item = proto_tree_add_item(ecmp_tree, addr_type, tvb, offset, 1, ENC_BIG_ENDIAN);
765 byte_test = tvb_get_uint8(tvb, offset);
766 if ((byte_test != 0) && (byte_test != 1)) {
767 /* tree to display the data in the address*/
768 ecmp_address_tree = proto_item_add_subtree(ecmp_address_item, ett_ecmp_address);
770 switch (byte_test)
772 case 2: /* default route scheme*/
773 offset++;
775 /* displays the values of the addresses*/
776 proto_tree_add_item(ecmp_address_tree, hf_ecmp_physical_address, tvb, offset, 1, ENC_NA);
777 proto_tree_add_item(ecmp_address_tree, hf_ecmp_logical_address, tvb, offset, 1, ENC_NA);
778 break;
780 case 3:/* diagnostic scheme*/
781 proto_tree_add_item(ecmp_address_tree, hf_ecmp_diagnostic, tvb, offset, 1, ENC_BIG_ENDIAN);
782 offset++;
783 break;
784 case 4: /* Names scheme */
785 /* Calls a function to display the UTF-8 string data*/
786 proto_tree_add_item(ecmp_address_tree, hf_ecmp_names_scheme, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
787 offset += (tvb_get_ntohs(tvb, offset) + 2);
788 break;
791 offset++;
793 return offset;
797 /* a function to display option codes */
798 static int add_option_codes(int offset, packet_info *pinfo, tvbuff_t *tvb, proto_tree* ecmp_tree)
800 proto_item* ecmp_option_number_item = NULL;
801 proto_item* ecmp_option_item;
802 proto_tree* ecmp_option_tree;
803 proto_tree* ecmp_option_data_tree = NULL;
804 uint8_t option_code_display = 0;
805 uint16_t count = 0; /* number of times the loop iterates*/
806 int start_offset;
807 bool more_options = true;
809 offset++;
811 start_offset = offset;
812 ecmp_option_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_option, &ecmp_option_number_item, "Options" );
814 /* Loop to display all options */
815 while(more_options) /* loops until option code is 0*/
817 option_code_display = tvb_get_uint8(tvb, offset);
818 ecmp_option_item = proto_tree_add_item(ecmp_option_tree, hf_ecmp_option, tvb, offset, 1, ENC_BIG_ENDIAN);
819 offset++;
820 switch(option_code_display)
822 case 0:/* end of options*/
823 proto_item_append_text(ecmp_option_number_item, ": %d", count);
824 proto_item_set_len(ecmp_option_number_item, offset-start_offset);
825 more_options = false;
826 break;
827 case 1:/* dummy - 0 bytes of data */
828 break;
829 case 2:/* process at - 8 bytes of data */
830 ecmp_option_data_tree = proto_item_add_subtree(ecmp_option_item, ett_ecmp_option_data);
832 proto_tree_add_item(ecmp_option_data_tree, hf_ecmp_process_time, tvb, offset, 8, ENC_BIG_ENDIAN);
833 offset += 8;
834 break;
835 default: /* Option that is not recognised*/
836 proto_item_append_text(ecmp_option_number_item, "%d ", count);
837 expert_add_info(pinfo, ecmp_option_number_item, &ei_ecmp_option);
838 break;
840 count++;
842 return offset;
846 /* a function to display attributes */
847 static void add_attributes(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, bool request)
849 proto_item* ecmp_attribute_number_item = NULL;
850 proto_item* ecmp_attribute_item = NULL, *color_item;
851 proto_tree* ecmp_attribute_tree = NULL;
852 proto_tree* ecmp_attribute_data_tree = NULL;
853 uint8_t no_of_attributes = 0;
854 uint8_t a = 0; /*values used for looping*/
855 uint8_t b = 0;
856 uint8_t c = 0;
857 uint8_t check = 0;
858 uint16_t att_length = 0;
859 uint32_t color;
860 wmem_strbuf_t* pStr = NULL; /*char array for version string output*/
861 int start_offset = offset;
863 /*display the number of attributes*/
864 ecmp_attribute_number_item = proto_tree_add_item(ecmp_tree, hf_ecmp_no_of_attributes, tvb, offset, 1, ENC_BIG_ENDIAN);
865 ecmp_attribute_tree = proto_item_add_subtree(ecmp_attribute_number_item, ett_ecmp_attribute);
867 no_of_attributes = tvb_get_uint8(tvb, offset);
868 offset++;
870 for (a = 0; a < no_of_attributes; a++, offset++) {
871 /*attribute header*/
872 ecmp_attribute_item = proto_tree_add_item(ecmp_attribute_tree, hf_ecmp_attribute, tvb, offset, 1, ENC_BIG_ENDIAN );
873 ecmp_attribute_data_tree = proto_item_add_subtree(ecmp_attribute_item, ett_ecmp_attribute_data);
875 if (!request) {
876 /*code for dissecting the colour codes attribute*/
877 switch(tvb_get_uint8(tvb, offset))
879 case 8:
880 offset+= 1;
881 /*get length of attribute for error checking*/
882 offset+= 2;
884 /*output primary colour codes- the two bytes representing each colour are output as integers*/
885 color = tvb_get_ntohl(tvb, offset);
886 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_uint8(tvb, offset+1), tvb_get_uint8(tvb, offset+2), tvb_get_uint8(tvb, offset+3));
887 if ((color & 0xFF000000) != 0) {
888 /*error check for correct colour code format */
889 expert_add_info(pinfo, color_item, &ei_ecmp_color);
891 offset+= 4;
893 /*output secondary colour codes- the two bytes representing each colour are output as integers*/
894 color = tvb_get_ntohl(tvb, offset);
895 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_uint8(tvb, offset+1), tvb_get_uint8(tvb, offset+2), tvb_get_uint8(tvb, offset+3));
896 if ((color & 0xFF000000) != 0) {
897 /*error check for correct colour code format */
898 expert_add_info(pinfo, color_item, &ei_ecmp_color);
900 offset+= 4;
901 break;
902 /*code for dissecting the version summary attribute*/
903 case 7:
904 offset++;
905 att_length = tvb_get_ntohs(tvb, offset);
906 pStr = wmem_strbuf_create(pinfo->pool);
907 offset+= 2;
908 if (pStr != NULL) {
909 for (c = 0; c < att_length; c++, offset++) {
910 check = tvb_get_uint8(tvb,offset);
911 if (check == 'V' || check == '#' || check == '@') {
912 wmem_strbuf_append_c(pStr, ' ');
913 } else if (check == ';') {
914 /*display version summary parameter, e.g 'FW', 'BL', 'HW'*/
915 proto_tree_add_string(ecmp_attribute_data_tree, hf_ecmp_version_summary, tvb, offset-b, b, wmem_strbuf_get_str(pStr));
916 wmem_strbuf_truncate(pStr, 0);
917 } else if (check <= 0x7f) {
918 wmem_strbuf_append_c(pStr, check);
920 else {
921 wmem_strbuf_append_hex(pStr, check);
924 /*display last version summary parameter, e.g 'FW', 'BL', 'HW' as no deliminator to check for, just prints out rest of version string*/
925 proto_tree_add_string(ecmp_attribute_data_tree, hf_ecmp_version_summary, tvb, offset-b, b, wmem_strbuf_get_str(pStr));
926 offset-= 1;
928 break;
929 default:
930 /* displays the data inside the attribute*/
931 proto_tree_add_item(ecmp_attribute_data_tree, hf_ecmp_attribute_string, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
932 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
933 break;
938 proto_item_set_len(ecmp_attribute_number_item, offset-start_offset);
942 /* a function to display the category codes */
943 static int add_category_codes(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
945 proto_item *ecmp_category_item = NULL;
946 proto_tree *ecmp_category_tree = NULL;
947 uint8_t category_size = 0;
948 int start_offset = offset;
949 uint8_t category_value = tvb_get_uint8(tvb, offset);
951 /* displays the category and creates a tree to display further data*/
952 ecmp_category_item = proto_tree_add_item(ecmp_tree, hf_ecmp_category, tvb, offset, 1, ENC_BIG_ENDIAN);
953 ecmp_category_tree = proto_item_add_subtree(ecmp_category_item, ett_ecmp_category);
954 offset++;
956 category_size = tvb_get_uint8(tvb, offset);
957 offset++;
959 if(category_size==2 && category_value == 1) {
960 /*display "option module" and its ID*/
961 proto_tree_add_item(ecmp_category_tree, hf_ecmp_category_id, tvb, offset, 2, ENC_BIG_ENDIAN);
962 offset+=category_size;
963 } else if(category_size == 4 && category_value == 0) {
964 /*display "drive" and its data (product type, drive derivative and ID*/
965 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_type, tvb, offset, 1, ENC_BIG_ENDIAN);
966 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_derivative, tvb, offset+1, 1, ENC_BIG_ENDIAN);
967 proto_tree_add_item(ecmp_category_tree, hf_ecmp_drive_factory_fit_category_id, tvb, offset+2, 2, ENC_BIG_ENDIAN);
968 offset+=category_size;
970 } else {
971 /* Display unknown and its hex data */
972 proto_tree_add_item(ecmp_category_tree, hf_ecmp_data, tvb, offset, category_size, ENC_NA);
973 offset += category_size;
976 proto_item_set_len(ecmp_category_item, offset-start_offset);
977 return offset;
981 /* a function to display response size data */
982 static int get_response_size(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
984 proto_item* ecmp_max_response_item = NULL;
985 proto_tree* ecmp_response_size_tree = NULL;
986 uint8_t chunks = 0;
987 uint16_t max_response_size = 0;
989 /*get values for number of chunks and max response size*/
990 chunks = tvb_get_uint8(tvb, offset)>>4&0x0F;
991 max_response_size = tvb_get_ntohs(tvb, offset) & 0x0FFF;
993 /*display response subtree */
994 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);
996 /*display chunks and max response size in response subtree*/
997 proto_tree_add_item(ecmp_response_size_tree, hf_ecmp_chunking, tvb, offset, 2, ENC_BIG_ENDIAN);
998 proto_tree_add_item(ecmp_response_size_tree, hf_ecmp_max_response_size, tvb, offset, 2, ENC_BIG_ENDIAN);
999 offset+= 2;
1001 return offset;
1005 /* a function to display the command code and type (request/response) */
1006 static int add_command_codes(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree, uint8_t transaction_id_value, uint8_t* command_value)
1008 proto_tree *ecmp_command_tree;
1009 const char* command_str;
1010 uint8_t command = tvb_get_uint8(tvb, offset);
1011 *command_value = command & 0x7F;
1012 command_str = val_to_str(*command_value, command_vals, "Unknown Type (0x%02x)");
1014 /*display command subtree*/
1015 ecmp_command_tree = proto_tree_add_subtree_format(ecmp_tree, tvb, offset, 1, ett_ecmp_command, NULL, "Request Response Code: %s", command_str);
1017 /* Displays the command */
1018 proto_tree_add_item(ecmp_command_tree, hf_ecmp_command, tvb, offset, 1, ENC_BIG_ENDIAN);
1019 /* Displays the type (request/response) */
1020 proto_tree_add_item(ecmp_command_tree, hf_ecmp_type_rr, tvb, offset, 1, ENC_BIG_ENDIAN);
1022 /* Information displayed in the Info column*/
1023 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, %s. Transaction ID: %d",
1024 command_str, tfs_get_string(((command & 0x80) >> 7), &tfs_response_request),
1025 transaction_id_value);
1027 return offset;
1031 /* a function to add a cyclic frame query */
1032 static int add_cyclic_frame_query(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree )
1034 /* display the cyclic link number */
1035 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_num, tvb, offset++, 1, ENC_BIG_ENDIAN);
1036 return offset;
1040 /* a function to add a cyclic frame */
1041 static int add_cyclic_frame(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree )
1043 uint32_t scheme;
1044 proto_item *ecmp_scheme_item = NULL;
1045 proto_tree *ecmp_scheme_tree = NULL;
1046 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_num, tvb, offset++, 1, ENC_BIG_ENDIAN);
1047 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_align, tvb, offset++, 1, ENC_BIG_ENDIAN);
1048 ecmp_scheme_item = proto_tree_add_item_ret_uint(ecmp_tree, hf_ecmp_cyclic_scheme, tvb, offset++, 1, ENC_BIG_ENDIAN, &scheme);
1050 if (scheme == 1) {
1051 /* Create a new sub tree spawning off the scheme byte for the synchronisation scheme data to be placed. */
1052 ecmp_scheme_tree = proto_item_add_subtree(ecmp_scheme_item, ett_ecmp_cyclic_scheme);
1054 /* grandmaster */
1055 proto_tree_add_item( ecmp_scheme_tree, hf_ecmp_grandmaster, tvb, offset, 8, ENC_BIG_ENDIAN);
1056 offset += 8;
1058 proto_tree_add_item(ecmp_scheme_tree, hf_ecmp_cyclic_frame_time, tvb, offset, 8, ENC_BIG_ENDIAN);
1059 offset += 8;
1062 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, -1, ENC_NA);
1064 return tvb_reported_length(tvb);
1068 /* a function to display cyclic tvb data in byte (8-bit), word (16-bit), and long (32-bit) unsigned formats */
1069 static int display_raw_cyclic_data(uint8_t display, int offset, uint16_t buffer_size, tvbuff_t *tvb, packet_info *pinfo, proto_tree* ecmp_current_tree )
1071 /****************************************************************************************/
1072 /* */
1073 /* display_raw_cyclic_data - display the cyclic data in various formats. */
1074 /* */
1075 /* Parameters: display = selects desired display format. */
1076 /* 0 = BYTE_FORMAT (8-bits 1F 20 37 BC ... */
1077 /* 1 = WORD_FORMAT (16-bits 1F20 37BC 77F1 ... */
1078 /* 2 = LONG_FORMAT (32-bits 1F2037BC 0013F5CD ... */
1079 /* */
1080 /* offset = offset within tvb buffer where this data starts. */
1081 /* */
1082 /* buffer_size = number of bytes to be converted and displayed. */
1083 /* */
1084 /* tvb = buffer structure within Wireshark holding this frame. */
1085 /* */
1086 /* pinfo = packet info for this frame. */
1087 /* */
1088 /* ecmp_current_tree = the tree where the data is to be displayed. */
1089 /* */
1090 /* */
1091 /* Notes: we only display so many elements on a line (before continuing on next line) */
1092 /* */
1093 /* 16 elements per line for byte (8-bit) and word (16-bit) */
1094 /* 8 elements per line for long (32-bit) */
1095 /* */
1096 /* Programmer: Jim Lynch */
1097 /****************************************************************************************/
1099 /* bail out if the buffer size is zero */
1100 if (buffer_size == 0) {
1101 proto_tree_add_bytes_format_value(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, offset-1, 0, NULL, "No data");
1102 } else {
1103 /* define some variables */
1104 char* pdata = NULL; /* pointer to array that stores the formatted data string */
1105 uint16_t idx = 0; /* counts through formatted string array */
1106 uint8_t value8 = 0; /* placeholder for extracted 8-bit data */
1107 uint16_t value16 = 0; /* placeholder for extracted 16-bit data */
1108 uint32_t value32 = 0; /* placeholder for extracted 32-bit data */
1109 uint16_t num_elements_total = 0; /* contains total number of elements (byte/word/long) to be processed */
1110 const uint16_t num_byte_elements_per_line = 16; /* number of byte (8-bit) elements per line e.g. "1B " (3 chars per element) */
1111 const uint16_t num_word_elements_per_line = 16; /* number of word (16-bit) elements per line e.g. "A81B " (5 chars per element) */
1112 const uint16_t num_long_elements_per_line = 8; /* number of long (32-bit) elements per line e.g. "01F4A81B " (9 chars per element) */
1113 uint16_t num_elements_per_line = 8; /* counts the current number of elements per line */
1114 uint16_t num_elements = 0; /* counts the number of elements in the format string */
1115 uint16_t format_string_size = 0; /* size of dynamic array to hold the formatted string */
1116 uint16_t a = 0; /* value used for looping */
1117 int start_offset, line_offset;
1119 /* calculate format string array size and other stuff */
1120 /* */
1121 /* Note: format string does require a nul-terminator (the + 1 in the equations) */
1122 /* */
1123 /* display = 0: (byte format "1D 24 3F ... A3 " */
1124 /* format_string_size = (num_byte_elements_per_line * 3) + 1 */
1125 /* */
1126 /* display = 1: (word format "1D24 3F84 120B ... 1FA3 " */
1127 /* format_string_size = (num_word_elements_per_line * 5) + 1 */
1128 /* */
1129 /* display = 2: (byte format "1D243F84 9BC08F20 ... 28BB1FA3 " */
1130 /* format_string_size = (num_long_elements_per_line * 9) + 1 */
1131 /* */
1132 if (display == cyclic_display_byte_format) {
1133 format_string_size = (num_byte_elements_per_line * 3) + 1; /* format_string_size = 49 */
1134 num_elements_per_line = num_byte_elements_per_line; /* num_elements_per_line = 16 */
1135 num_elements_total = buffer_size;
1136 } else if (display == cyclic_display_word_format) {
1137 format_string_size = (num_word_elements_per_line * 5) + 1; /* format_string_size = 81 */
1138 num_elements_per_line = num_word_elements_per_line; /* num_elements_per_line = 16 */
1139 num_elements_total = buffer_size >> 1;
1140 } else if (display == cyclic_display_long_format) {
1141 format_string_size = (num_long_elements_per_line * 9) + 1; /* format_string_size = 73 */
1142 num_elements_per_line = num_long_elements_per_line; /* num_elements_per_line = 8 */
1143 num_elements_total = buffer_size >> 2;
1144 } else {
1145 format_string_size = (num_byte_elements_per_line * 3) + 1; /* format_string_size = 49 */
1146 num_elements_per_line = num_byte_elements_per_line; /* num_elements_per_line = 16 */
1147 num_elements_total = buffer_size;
1150 /* allocate dynamic memory for one line */
1151 pdata = (char *)wmem_alloc(pinfo->pool, format_string_size);
1153 /* OK, let's get started */
1154 idx = 0;
1155 num_elements = 0;
1157 line_offset = start_offset = offset;
1158 /* work through the display elements, 1 byte\word\long at a time */
1159 for (a = 0; a < num_elements_total; a++ )
1161 /* use Wireshark accessor function to get the next byte, word, or long data */
1162 if (display == cyclic_display_byte_format) {
1163 value8 = tvb_get_uint8(tvb, offset);
1164 offset++;
1165 } else if (display == cyclic_display_word_format) {
1166 value16 = tvb_get_ntohs(tvb, offset);
1167 offset += 2;
1168 } else if (display == cyclic_display_long_format) {
1169 value32 = tvb_get_ntohl(tvb, offset);
1170 offset += 4;
1173 /* increment the num_elements we've done on the current line */
1174 num_elements++;
1176 /* check if we hit the max number of byte elements per line */
1177 if (num_elements >= num_elements_per_line) {
1178 /* we hit end of the current line */
1179 /* add final value to string */
1180 if (display == cyclic_display_byte_format) {
1181 snprintf(&pdata[idx], 32, "%02x",value8);
1182 } else if (display == cyclic_display_word_format) {
1183 snprintf(&pdata[idx], 32, "%04x",value16);
1184 } else if (display == cyclic_display_long_format) {
1185 snprintf(&pdata[idx], 32, "%08x",value32);
1188 /* display the completed line in the sub-tree */
1189 proto_tree_add_bytes_format(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, offset, offset-line_offset, NULL, "%s", pdata);
1191 /* start the line over */
1192 idx = 0;
1193 num_elements = 0;
1194 line_offset = offset;
1196 } else {
1197 /* we're still adding to the current line */
1198 /* add current value to string */
1199 if (display == cyclic_display_byte_format) {
1200 snprintf(&pdata[idx], 32, "%02x ",value8);
1201 idx += 3;
1202 } else if (display == cyclic_display_word_format) {
1203 snprintf(&pdata[idx], 32, "%04x ",value16);
1204 idx += 5;
1205 } else if (display == cyclic_display_long_format) {
1206 snprintf(&pdata[idx], 32, "%08x ",value32);
1207 idx += 9;
1212 /* if we exited the loop, see if there's a partial line to display */
1213 if (num_elements > 0) {
1214 /* add null-terminator to partial line */
1215 pdata[idx] = 0x00;
1217 /* display the partial line in the sub-tree */
1218 proto_tree_add_bytes_format(ecmp_current_tree, hf_ecmp_cyclic_data, tvb, start_offset, offset-start_offset, NULL, "%s", pdata);
1221 return offset;
1225 /* a function returning the information requested by the 'info' command */
1226 static void add_info_response(int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
1228 proto_item* ecmp_info_address_item = NULL;
1229 proto_tree* ecmp_info_tree = NULL;
1230 proto_tree* ecmp_info_address_tree = NULL, *address_tree;
1231 uint16_t length = 0;
1232 uint8_t no_of_address = 0;
1233 uint8_t i = 0; /*for counting */
1235 length = tvb_reported_length(tvb);
1237 /*display info response tree */
1238 ecmp_info_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 6, ett_ecmp_info_type, NULL, "Response Information");
1240 /*display buffer size */
1241 proto_tree_add_item(ecmp_info_tree, hf_ecmp_buffer_size, tvb, offset, 2, ENC_BIG_ENDIAN);
1242 offset+= 2;
1244 /*display max response time */
1245 proto_tree_add_item(ecmp_info_tree, hf_ecmp_max_response, tvb, offset, 2, ENC_BIG_ENDIAN);
1246 offset+= 2;
1248 /*display max handle period */
1249 proto_tree_add_item(ecmp_info_tree, hf_ecmp_max_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1250 offset+= 2;
1252 if (length > offset) {
1253 /*display count of default server addresses */
1254 ecmp_info_address_item = proto_tree_add_item(ecmp_tree, hf_ecmp_info_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1255 ecmp_info_address_tree = proto_item_add_subtree(ecmp_info_address_item, ett_ecmp_info_count);
1256 no_of_address = tvb_get_uint8(tvb, offset);
1258 if (no_of_address > 0) {
1259 /*do code to display address data */
1260 for (i = 0; i < no_of_address; i++) {
1261 address_tree = proto_tree_add_subtree_format(ecmp_info_address_tree, tvb, offset, 1, ett_ecmp_address, NULL, "Address %d", i+1);
1262 proto_tree_add_item(address_tree, hf_ecmp_physical_address, tvb, offset, 1, ENC_NA);
1263 proto_tree_add_item(address_tree, hf_ecmp_logical_address, tvb, offset, 1, ENC_NA);
1264 offset+= 1;
1271 /*--------------------------------------------------------------------*/
1272 /* Parameter Access Commands */
1273 /*--------------------------------------------------------------------*/
1275 /* a function to display data given data_type */
1276 static int get_data_type(packet_info* pinfo, int offset, uint8_t data_type, tvbuff_t *tvb, proto_tree* ecmp_current_tree)
1278 /*switch to decide correct data_type dissection*/
1279 switch(data_type)
1281 case 0: /*display boolean*/
1282 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_boolean, tvb, offset, 1, ENC_NA);
1283 break;
1284 case 1: /*display INT8*/
1285 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int8, tvb, offset, 1, ENC_NA);
1286 break;
1287 case 2: /*display UINT8*/
1288 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint8, tvb, offset, 1, ENC_NA);
1289 break;
1290 case 3: /*display INT16*/
1291 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int16, tvb, offset, 2, ENC_BIG_ENDIAN);
1292 offset+= 1;
1293 break;
1294 case 4: /*display UINT16*/
1295 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint16, tvb, offset, 2, ENC_BIG_ENDIAN);
1296 offset+= 1;
1297 break;
1298 case 5: /*display INT32*/
1299 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int32, tvb, offset, 4, ENC_BIG_ENDIAN);
1300 offset+= 3;
1301 break;
1302 case 6: /*display UINT32*/
1303 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint32, tvb, offset, 4, ENC_BIG_ENDIAN);
1304 offset+= 3;
1305 break;
1306 case 7: /*display INT64*/
1307 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_int64, tvb, offset, 8, ENC_BIG_ENDIAN);
1308 offset+= 7;
1309 break;
1310 case 8: /*display UINT64*/
1311 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_uint64, tvb, offset, 8, ENC_BIG_ENDIAN);
1312 offset+= 7;
1313 break;
1314 case 9: /*display INT128*/
1315 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, 16, ENC_NA);
1316 offset += 15;
1317 break;
1318 case 10: /*display UINT128*/
1319 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, 16, ENC_NA);
1320 offset += 15;
1321 break;
1322 case 20:/*display single float*/
1323 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_float, tvb, offset, 4, ENC_BIG_ENDIAN);
1324 offset+= 3;
1325 break;
1326 case 21: /*display double float*/
1327 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data_double, tvb, offset, 8, ENC_BIG_ENDIAN);
1328 offset+= 7;
1329 break;
1330 case 30: /*display string ID*/
1331 proto_tree_add_item(ecmp_current_tree, hf_ecmp_string_id, tvb, offset, 2, ENC_NA|ENC_ASCII);
1332 offset++;
1333 break;
1334 case 32: /*display (ECMP) string*/
1335 proto_tree_add_item(ecmp_current_tree, hf_ecmp_ecmp_string, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1336 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1337 break;
1338 default: /*display untyped size*/
1339 if (data_type < 128) {
1340 proto_tree_add_expert(ecmp_current_tree, pinfo, &ei_ecmp_data_type, tvb, 0, -1);
1341 } else {
1342 proto_tree_add_item(ecmp_current_tree, hf_ecmp_data, tvb, offset, (data_type- 127), ENC_NA);
1343 offset += (data_type- 128);
1345 break;
1347 return offset;
1351 /* a function to add the parameter address schemes for 'read' command */
1352 static int get_address_scheme(packet_info* pinfo, int offset, uint8_t scheme, tvbuff_t *tvb, proto_tree* ecmp_parameter_tree)
1354 /*if address scheme is standard*/
1355 switch (scheme)
1357 case 0:
1358 /*display Menu no. */
1359 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1360 offset+= 2;
1362 /*display parameter no. */
1363 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_parameter, tvb, offset, 2, ENC_BIG_ENDIAN);
1364 offset++;
1365 break;
1367 case 1:/*if address scheme is slot specific*/
1368 /*display slot number*/
1369 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_slot, tvb, offset, 1, ENC_NA);
1370 offset++;
1372 /*display Menu no. */
1373 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1374 offset+= 2;
1376 /*display parameter no. */
1377 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_parameter, tvb, offset, 2, ENC_BIG_ENDIAN);
1378 offset++;
1379 break;
1381 case 3: /*if address scheme is variable*/
1382 /*display variable name */
1383 offset--;
1384 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_variable_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1385 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1386 break;
1388 case 4: /*if address scheme is NULL*/
1389 /*null size*/
1390 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_address_scheme_null_byte_size, tvb, offset, 1, ENC_NA);
1391 offset++;
1392 break;
1394 default:
1395 proto_tree_add_expert(ecmp_parameter_tree, pinfo, &ei_ecmp_parameter_addressing_scheme, tvb, offset, 1);
1397 return offset;
1401 /* a function to display an array of the read address schemes */
1402 static void get_parameter_definitions(packet_info* pinfo, int offset, uint8_t command_value, tvbuff_t *tvb, proto_tree* ecmp_tree)
1404 proto_item* ecmp_parameter_item = NULL;
1405 proto_tree* ecmp_parameter_number_tree = NULL;
1406 proto_tree* ecmp_parameter_tree = NULL;
1407 uint8_t count = 0;
1408 uint8_t a = 0;
1409 uint8_t data_type = 0;
1410 int8_t dec = 0;
1411 uint8_t scheme = 0;
1412 uint16_t n = 0;
1414 scheme = tvb_get_uint8(tvb, offset);
1416 ecmp_parameter_item = proto_tree_add_item(ecmp_tree, hf_ecmp_parameter_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1417 ecmp_parameter_tree = proto_item_add_subtree(ecmp_parameter_item, ett_ecmp_param_address);
1419 offset++;
1420 /* if "GetNextObjects" command */
1421 if(command_value == ECMP_COMMAND_GETNEXTOBJECTS)
1423 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1424 offset++;
1425 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_subsequent_object_requests, tvb, offset, 1, ENC_NA);
1426 }else
1428 /*display tree with count of definitions */
1429 ecmp_parameter_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_definitions, tvb, offset, 1, ENC_BIG_ENDIAN);
1430 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_parameter_item, ett_ecmp_param_address);
1432 count = tvb_get_uint8(tvb,offset);
1434 offset++;
1436 switch(scheme)/*sets n so that the tree highlights bytes in scheme specific data*/
1438 case 0:
1439 n = 4;
1440 break;
1441 case 1:
1442 n = 5;
1443 break;
1444 case 3:
1445 n = 1 + ((tvb_get_uint8(tvb, offset+1)<<8)|(tvb_get_uint8(tvb, offset+2)));
1446 break;
1447 default:
1448 n = 0;
1449 break;
1452 if (command_value == ECMP_COMMAND_OBJECTINFO) {
1453 n += 1;
1456 for (a = 0; a < count; a++) {
1457 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));
1459 if (command_value == ECMP_COMMAND_OBJECTINFO) {
1460 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_info_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1461 offset++;
1462 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1463 offset++;
1464 } else {
1465 /*output the address schemes of the parameter requests */
1466 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_tree);
1467 offset++;
1468 if (command_value == ECMP_COMMAND_WRITE) {
1469 data_type = tvb_get_uint8(tvb, offset);
1470 proto_tree_add_item(ecmp_parameter_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1471 offset++;
1472 dec = tvb_get_int8(tvb, offset);
1473 if (dec != -1) {
1474 proto_tree_add_int(ecmp_parameter_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec);
1475 } else {
1476 proto_tree_add_int_format_value(ecmp_parameter_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec, "0 (Invalid type)");
1478 offset++;
1479 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_tree);
1480 offset++;
1488 /* a function to show the "objectinfo" command response */
1489 static void get_object_info_response(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_tree)
1491 proto_item* ecmp_response_item = NULL;
1492 proto_tree* ecmp_parameter_number_tree = NULL;
1493 proto_tree* ecmp_parameter_response_tree = NULL;
1494 uint8_t count = 0; /*stores number of parameter read responses */
1495 uint8_t a = 0; /*counting varables */
1496 uint8_t n = 0;
1497 uint8_t info_type0 = 0;
1498 uint16_t length = 0;
1499 uint8_t data_type = 0;
1501 length = tvb_reported_length(tvb);
1503 ecmp_response_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_responses, tvb, offset, 1, ENC_BIG_ENDIAN);
1504 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_response_item, ett_ecmp_param_address);
1506 count = tvb_get_uint8(tvb, offset);
1508 if (count == 0) {
1509 offset++;
1510 proto_tree_add_item(ecmp_parameter_number_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1512 } else {
1513 /*display info data response */
1514 for (a = 0; a < count; a++) {
1515 if (a==0) {
1516 n = (length-offset)/count;
1518 offset++;
1519 /*display response header */
1520 proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1522 /*display response status */
1523 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1524 offset++;
1526 /*display response data */
1527 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_info_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1528 info_type0 = tvb_get_uint8(tvb, offset);
1530 switch(info_type0)
1532 case 0:
1533 /*no information available */
1534 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_no_information_available, tvb, offset, 1, ENC_NA);
1535 break;
1536 case 1:
1537 /*display min parameter in menu */
1538 offset++;
1539 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_min_param_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1540 offset++;
1541 break;
1542 case 2:
1543 /*display max parameter in menu */
1544 offset++;
1545 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_max_param_menu, tvb, offset, 2, ENC_BIG_ENDIAN);
1546 offset++;
1547 break;
1548 case 3:
1550 static int * const fields[] = {
1551 &hf_ecmp_param_format_bit_default_unipolar,
1552 &hf_ecmp_param_format_write_allowed,
1553 &hf_ecmp_param_format_read_not_allowed,
1554 &hf_ecmp_param_format_protected_from_destinations,
1555 &hf_ecmp_param_format_parameter_not_visible,
1556 &hf_ecmp_param_format_not_clonable,
1557 &hf_ecmp_param_format_voltage_or_current_rating_dependent,
1558 &hf_ecmp_param_format_parameter_has_no_default,
1559 &hf_ecmp_param_format_number_of_decimal_places,
1560 &hf_ecmp_param_format_variable_maximum_and_minimum,
1561 &hf_ecmp_param_format_string_parameter,
1562 &hf_ecmp_param_format_destination_set_up_parameter,
1563 &hf_ecmp_param_format_filtered_when_displayed,
1564 &hf_ecmp_param_format_pseudo_read_only,
1565 &hf_ecmp_param_format_display_format,
1566 &hf_ecmp_param_format_floating_point_value,
1567 &hf_ecmp_param_format_units,
1568 NULL
1571 /*display data for parameter format- UNITS and Display Format need dissecting? */
1572 offset++;
1573 proto_tree_add_bitmask_list(ecmp_parameter_response_tree, tvb, offset, 4, fields, ENC_BIG_ENDIAN);
1574 offset+= 3;
1576 break;
1577 case 4:
1578 /*display minimum allowed value*/
1579 offset++;
1580 data_type = tvb_get_uint8(tvb,offset);
1581 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1582 offset++;
1583 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1584 break;
1585 case 5:
1586 /*display maximum allowed value*/
1587 offset++;
1588 data_type = tvb_get_uint8(tvb,offset);
1589 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1590 offset++;
1591 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1592 break;
1593 case 6:
1594 /*display Units- ID string */
1595 offset++;
1596 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_string_id, tvb, offset, 2, ENC_NA|ENC_ASCII);
1597 offset++;
1598 break;
1599 case 7:
1600 /*display data type */
1601 offset++;
1602 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1603 break;
1604 default:
1605 expert_add_info(pinfo, ecmp_response_item, &ei_ecmp_info_type);
1606 break;
1613 /* a function to display an array of the read responses */
1614 static int get_parameter_responses(packet_info* pinfo, int offset, uint8_t command_value, tvbuff_t *tvb, proto_tree* ecmp_tree)
1616 proto_item* ecmp_response_item = NULL;
1617 proto_tree* ecmp_parameter_number_tree = NULL;
1618 proto_tree* ecmp_parameter_response_tree = NULL;
1619 uint8_t count = 0; /*stores number of parameter read responses */
1620 uint8_t a = 0; /*counting varables */
1621 uint8_t data_type = 0;
1622 uint8_t unit_id = 0;
1623 int8_t dec = 0;
1624 uint16_t n = 0;
1625 uint8_t st_error = 0;
1626 uint16_t length = 0;
1627 uint8_t scheme = 0;
1628 int start_offset;
1630 scheme = tvb_get_uint8(tvb, offset);
1631 length = tvb_reported_length(tvb);
1633 if (command_value == ECMP_COMMAND_GETNEXTOBJECTS) {
1634 /*display addressing scheme*/
1635 proto_tree_add_item(ecmp_tree, hf_ecmp_parameter_address, tvb, offset, 1, ENC_BIG_ENDIAN);
1636 offset++;
1639 /*display number of responses*/
1640 ecmp_response_item = proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_parameter_responses, tvb, offset, 1, ENC_BIG_ENDIAN);
1641 ecmp_parameter_number_tree = proto_item_add_subtree(ecmp_response_item, ett_ecmp_param_address);
1643 count = tvb_get_uint8(tvb, offset);
1645 if (count == 0) {
1646 offset++;
1647 if (command_value != ECMP_COMMAND_GETNEXTOBJECTS) {
1648 /*display parameter status*/
1649 proto_tree_add_item(ecmp_parameter_number_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1651 } else {
1652 /*loop for outputting parameter data responses*/
1653 for (a = 0; a < count; a++) {
1654 if (command_value == ECMP_COMMAND_WRITE) {
1655 if (a==0) {
1656 n = (length-offset)/count; /*set byte highlighting*/
1658 offset++;
1659 /*display response: (a+1)*/
1660 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1661 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1663 } else if (command_value == ECMP_COMMAND_GETNEXTOBJECTS) {
1664 if (a==0) {
1665 n = (length-offset)/count;
1667 offset++;
1668 /*display response: (a+1)*/
1669 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, n, ett_ecmp_command, NULL, "Response %d:", (a+1));
1670 offset = get_address_scheme(pinfo, offset, scheme, tvb, ecmp_parameter_response_tree);
1671 } else {
1672 /*if status is error */
1673 if (tvb_get_int8(tvb, offset+1) < 0) {
1674 /*output status*/
1675 st_error = 1;
1676 offset++;
1677 ecmp_parameter_response_tree = proto_tree_add_subtree_format(ecmp_parameter_number_tree, tvb, offset, 1, ett_ecmp_command, NULL, "Response %d:", (a+1));
1678 ecmp_response_item = proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1679 if ((a+1) != count) {
1680 /*loop to move to next data_type (skips bytes == 0)*/
1681 while(1) {
1682 if(tvb_get_uint8(tvb, offset+1)==0) {
1683 offset++;
1684 } else {
1685 break;
1689 } else {
1690 offset++;
1691 /*display response data_byte*/
1692 start_offset = offset;
1693 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));
1694 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_parameter_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1695 offset++;
1696 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_data_type, tvb, offset, 1, ENC_BIG_ENDIAN);
1697 data_type = tvb_get_uint8(tvb,offset);
1698 offset++;
1699 offset = get_data_type(pinfo, offset, data_type, tvb, ecmp_parameter_response_tree);
1701 /*if "ReadWithType" */
1702 if ((command_value == ECMP_COMMAND_READWITHTYPE) && (st_error!= 1)) {
1703 offset++;
1704 /*display decimal places*/
1705 dec = tvb_get_int8(tvb, offset);
1706 if (dec != -1) {
1707 proto_tree_add_int(ecmp_parameter_response_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec);
1708 } else {
1709 proto_tree_add_int_format_value(ecmp_parameter_response_tree, hf_ecmp_number_of_decimal_places, tvb, offset, 1, dec, "0 (Invalid type)");
1711 offset++;
1712 /*display unit ID*/
1713 unit_id = tvb_get_uint8(tvb, offset);
1714 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_display_unit_id, tvb, offset, 1, ENC_NA);
1715 if (unit_id == 255) {
1716 offset++;
1717 proto_tree_add_item(ecmp_parameter_response_tree, hf_ecmp_unit_id_string, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1718 offset += (tvb_get_ntohs(tvb, offset) + 2);
1722 proto_item_set_len(ecmp_response_item, offset-start_offset);
1728 return offset;
1732 /*--------------------------------------------------------------------*/
1733 /* File Access Commands */
1734 /*--------------------------------------------------------------------*/
1735 /* a function to dissect "FileOpen" command */
1736 static void file_open(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1738 proto_tree* ecmp_scheme_data_tree = NULL;
1739 uint8_t additional_scheme = 0;
1740 uint8_t relative = 0;
1742 if (request) {
1743 static int * const fields[] = {
1744 &hf_ecmp_open_in_non_blocking_mode,
1745 &hf_ecmp_open_file_relative_to_specified_directory_handle,
1746 &hf_ecmp_file_access_mode,
1747 NULL
1750 proto_tree_add_bitmask(ecmp_tree, tvb, offset, hf_ecmp_access_mode, ett_ecmp_access_mode, fields, ENC_BIG_ENDIAN);
1751 relative = (tvb_get_uint8(tvb, offset) & 0x40) ? 1 : 0;
1752 offset++;
1754 /*display additional scheme*/
1755 proto_tree_add_item(ecmp_tree, hf_ecmp_additional_scheme, tvb, offset, 1, ENC_BIG_ENDIAN);
1756 additional_scheme= tvb_get_uint8(tvb, offset);
1758 /*display file name*/
1759 proto_tree_add_item(ecmp_tree, hf_ecmp_file_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
1760 offset += (tvb_get_ntohs(tvb, offset+1) + 2);
1762 /*only show file handle in relative mode*/
1763 if (relative == 1) {
1764 offset++;
1766 /*display file handle*/
1767 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1770 if (additional_scheme == 1) {
1771 /*display additional data*/
1772 offset+= 2;
1773 ecmp_scheme_data_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, -1, ett_ecmp_access_file, NULL, "Additional scheme data");
1774 proto_tree_add_item(ecmp_scheme_data_tree, hf_ecmp_scheme_data_length, tvb, offset, 1, ENC_NA);
1775 offset++;
1776 proto_tree_add_item(ecmp_scheme_data_tree, hf_ecmp_data, tvb, offset, -1, ENC_NA);
1778 } else {
1779 /*display file status*/
1780 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1782 if (tvb_get_int8(tvb, offset) >= 0) {
1783 offset++;
1784 /*display file handle*/
1785 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1791 /* a function to dissect "FileRead" command */
1792 static void file_read(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1794 uint16_t req_bytes = 0;
1796 if (request) {
1797 /*display file handle*/
1798 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1799 offset+=2;
1801 /*display requested bytes*/
1802 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_requested_bytes, tvb, offset, 2, ENC_BIG_ENDIAN);
1804 } else {
1805 /*display file status*/
1806 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1808 if (tvb_get_int8(tvb, offset)>= 0) {
1809 offset++;
1811 /*display bytes for reading*/
1812 req_bytes = tvb_get_ntohs(tvb, offset);
1813 proto_tree_add_item(ecmp_tree, hf_ecmp_response_data, tvb, offset, req_bytes+2, ENC_NA);
1814 /*offset += (2+req_bytes);*/
1820 /* a function to dissect "FileWrite" command */
1821 static void file_write(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1823 uint16_t req_bytes;
1825 if (request) {
1826 /*display file handle*/
1827 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1828 offset+=2;
1830 /*display bytes for writing*/
1831 req_bytes = tvb_get_ntohs(tvb, offset);
1832 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset+2, req_bytes, ENC_NA);
1833 /*offset += (2+req_bytes);*/
1835 } else {
1836 /*display file status*/
1837 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1838 /*offset++;*/
1843 /*a function to dissect "FileClose" command*/
1844 static void file_close(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1846 if (request) {
1847 /*display file handle*/
1848 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1849 offset+=2;
1851 /*display number of data bytes transferred*/
1852 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_bytes_transferred, tvb, offset, 4, ENC_BIG_ENDIAN);
1853 offset+= 4;
1855 /*display CRC value*/
1856 proto_tree_add_item(ecmp_tree, hf_ecmp_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
1857 } else {
1858 /*display file status*/
1859 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1860 offset++;
1865 /*a function to display file attributes*/
1866 static int get_file_attribute(packet_info* pinfo, int offset, tvbuff_t *tvb, proto_tree* ecmp_current_tree)
1868 proto_item *ecmp_file_info_att_item;
1869 proto_tree *ecmp_file_info_att_tree;
1870 uint32_t attribute0;
1871 int start_offset = offset;
1873 ecmp_file_info_att_item = proto_tree_add_item_ret_uint(ecmp_current_tree,
1874 hf_ecmp_file_attributes, tvb, offset, 1, ENC_BIG_ENDIAN, &attribute0);
1875 offset++;
1876 ecmp_file_info_att_tree = proto_item_add_subtree(ecmp_file_info_att_item, ett_ecmp_file_info_att);
1878 switch(attribute0)
1880 case 0: /*display length of file*/
1881 proto_tree_add_item(ecmp_file_info_att_tree, hf_ecmp_file_length, tvb, offset, 4, ENC_BIG_ENDIAN);
1882 offset += 4;
1883 break;
1884 case 1: /*display integrity*/
1885 proto_tree_add_item(ecmp_file_info_att_tree, hf_ecmp_file_integrity, tvb, offset, 1, ENC_BIG_ENDIAN);
1886 offset++;
1887 break;
1888 case 2: /*display CRC*/
1889 proto_tree_add_item(ecmp_file_info_att_tree, hf_ecmp_crc, tvb, offset, 4, ENC_BIG_ENDIAN);
1890 offset += 4;
1891 break;
1892 case 3: /*display attrib*/
1894 static int * const fields[] = {
1895 &hf_ecmp_display_attr_read_only,
1896 &hf_ecmp_display_attr_hidden,
1897 &hf_ecmp_display_attr_system,
1898 &hf_ecmp_display_attr_volume_label,
1899 &hf_ecmp_display_attr_subdirectory,
1900 &hf_ecmp_display_attr_archive,
1901 NULL
1904 proto_tree_add_bitmask_list(ecmp_file_info_att_tree, tvb, offset, 1, fields, ENC_BIG_ENDIAN);
1905 offset++;
1907 break;
1908 case 4: /*display creation date*/
1909 proto_tree_add_item(ecmp_file_info_att_tree, hf_ecmp_display_creation, tvb, offset, 4, ENC_TIME_SECS|ENC_BIG_ENDIAN);
1910 offset += 4;
1911 break;
1912 case 5: /*display modification date*/
1913 proto_tree_add_item(ecmp_file_info_att_tree, hf_ecmp_display_modification, tvb, offset, 4, ENC_TIME_SECS|ENC_BIG_ENDIAN);
1914 offset += 4;
1915 break;
1916 default: /*display incorrect attribute type error*/
1917 proto_tree_add_expert(ecmp_file_info_att_tree, pinfo, &ei_ecmp_attribute_type, tvb, offset, 1);
1918 offset++;
1919 break;
1921 proto_item_set_len(ecmp_file_info_att_item, offset - start_offset);
1922 return offset;
1926 /*a function to dissect "FileInfo" command*/
1927 static void file_info(packet_info* pinfo, int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1929 proto_tree *ecmp_file_info_tree;
1930 uint32_t a, no_of_att;
1931 int start_offset;
1933 if (request) {
1934 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1935 offset+=2;
1937 start_offset = offset;
1938 ecmp_file_info_tree = proto_tree_add_subtree(ecmp_tree,
1939 tvb, offset, -1, ett_ecmp_file_info, NULL, "Requested Attributes");
1940 proto_tree_add_item_ret_uint(ecmp_file_info_tree,
1941 hf_ecmp_no_of_attributes, tvb, offset, 1, ENC_BIG_ENDIAN, &no_of_att);
1942 offset++;
1944 for (a = 0; a < no_of_att; a++) {
1945 proto_tree_add_item(ecmp_file_info_tree,
1946 hf_ecmp_file_attributes, tvb, offset, 1, ENC_BIG_ENDIAN);
1947 offset++;
1949 proto_item_set_len(ecmp_file_info_tree, offset - start_offset);
1950 } else {
1951 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1952 offset++;
1954 start_offset = offset;
1955 ecmp_file_info_tree = proto_tree_add_subtree(ecmp_tree,
1956 tvb, offset, -1, ett_ecmp_file_info, NULL, "Received Attributes");
1958 proto_tree_add_item_ret_uint(ecmp_file_info_tree,
1959 hf_ecmp_no_of_attributes, tvb, offset, 1, ENC_BIG_ENDIAN, &no_of_att);
1960 offset++;
1962 /*display attributes*/
1963 for (a = 0; a < no_of_att; a++) {
1964 offset = get_file_attribute(pinfo, offset, tvb, ecmp_file_info_tree);
1966 proto_item_set_len(ecmp_file_info_tree, offset-start_offset);
1971 /*a function to dissect "FileStatus"/"FileDelete" commands*/
1972 static void file_state_delete(uint16_t offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1974 if (request) {
1975 /*display file handle*/
1976 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1978 } else {
1979 /*display file status*/
1980 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
1985 /*a function to dissect "FilePos" command*/
1986 static void file_pos(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
1988 proto_tree* ecmp_file_position_tree = NULL;
1990 if (request) {
1991 /*display file handle*/
1992 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
1993 offset+=2;
1995 /*display "position" header*/
1996 ecmp_file_position_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 5, ett_ecmp_file_position, NULL, "Position");
1998 /*display reference point*/
1999 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_file_ref_point, tvb, offset, 1, ENC_BIG_ENDIAN);
2000 offset++;
2002 /*display offset from ref point*/
2003 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_ref_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2005 } else {
2006 /*display file status*/
2007 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2009 if(tvb_get_int8(tvb,offset) >= 0) {
2010 offset++;
2012 /*display offset from ref point*/
2013 proto_tree_add_item(ecmp_file_position_tree, hf_ecmp_ref_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2019 /*a function to dissect "FileList" command*/
2020 static void file_list(packet_info* pinfo, int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2022 proto_item* ecmp_file_list_item, *ecmp_file_list_item2, *item_type_item;
2023 proto_tree* ecmp_file_list_no_tree = NULL;
2024 proto_tree* ecmp_file_list_tree = NULL;
2025 uint8_t no_of_items = 0;
2026 uint8_t item_type = 0;
2027 uint8_t a = 0;
2028 uint16_t n = 0;
2029 int start_offset, start_offset2;
2031 if (request) {
2032 /*display file handle*/
2033 proto_tree_add_item(ecmp_tree, hf_ecmp_file_handle, tvb, offset, 2, ENC_BIG_ENDIAN);
2034 offset+= 2;
2036 /*display number of files to list*/
2037 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_files_to_list, tvb, offset, 1, ENC_NA);
2038 } else {
2039 /*display file status*/
2040 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2042 if (tvb_get_int8(tvb,offset) >= 0) {
2043 offset++;
2045 /*display number of files to list*/
2046 no_of_items = tvb_get_uint8(tvb, offset);
2047 proto_tree_add_item(ecmp_tree, hf_ecmp_number_of_files_to_list, tvb, offset, 1, ENC_NA);
2048 offset++;
2050 /*display hash value (dissection TBD)*/
2051 ecmp_file_list_item = proto_tree_add_item(ecmp_tree, hf_ecmp_file_hash, tvb, offset, 2, ENC_BIG_ENDIAN);
2052 offset++;
2054 /*display subtree for files*/
2055 start_offset = offset+1;
2056 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");
2058 /*display list of file names*/
2059 for (a = 0; a < no_of_items; a++) {
2060 start_offset2 = offset;
2061 offset++;
2062 item_type = tvb_get_uint8(tvb, offset);
2063 n = tvb_get_ntohs(tvb, offset+1);
2064 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);
2065 item_type_item = proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_item_type, tvb, offset, 1, ENC_NA);
2067 switch(item_type)
2069 case 0: /*if item type is "file"*/
2070 proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_file_name, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2071 break;
2073 case 1: /*if item type is "directory"*/
2074 proto_tree_add_item(ecmp_file_list_tree, hf_ecmp_directory, tvb, offset+1, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2075 break;
2077 default: /*if item type is not "file" or "directory"*/
2078 expert_add_info(pinfo, item_type_item, &ei_ecmp_item_type);
2079 break;
2081 offset+= n;
2083 proto_item_set_len(ecmp_file_list_item2, offset-start_offset2);
2086 proto_item_set_len(ecmp_file_list_item, (offset+1)-start_offset);
2092 /*a function to dissect "FileExists" command*/
2093 static void file_exists(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2095 if (request) {
2096 /*display filename*/
2097 proto_tree_add_item(ecmp_tree, hf_ecmp_file_name, tvb, offset, 2, ENC_BIG_ENDIAN|ENC_ASCII);
2098 } else {
2099 /*display file status*/
2100 proto_tree_add_item(ecmp_tree, hf_ecmp_file_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2105 static int add_cyclic_setup_attributes(packet_info* pinfo, int offset, uint16_t length, tvbuff_t *tvb, proto_tree* ecmp_tree)
2107 proto_item *cyclic_setup_attributes_root = NULL;
2108 proto_item *cyclic_setup_attributes = NULL;
2109 proto_item *cyclic_setup_attrib_item_root = NULL;
2110 proto_tree *cyclic_setup_attrib_item = NULL;
2111 uint8_t attrib;
2113 /* num attribs */
2114 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2116 /* attrib list */
2117 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2119 while (offset < length) {
2120 attrib = tvb_get_uint8(tvb, offset);
2121 cyclic_setup_attrib_item_root = proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2123 cyclic_setup_attrib_item = proto_item_add_subtree(cyclic_setup_attrib_item_root, ett_cyclic_setup_attrib_item);
2125 switch (attrib) {
2126 case 3: /* mec offset */
2128 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mec_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
2129 offset += 4;
2131 break;
2133 case 4: /* sample period */
2134 case 5: /* mec delay */
2136 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_sample_period, tvb, offset, 8, ENC_BIG_ENDIAN);
2137 offset += 8;
2139 break;
2141 case 7: /* rx timeout */
2143 /* tout */
2144 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_timeout, tvb, offset, 4, ENC_BIG_ENDIAN);
2145 offset += 4;
2147 /* action */
2148 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_action, tvb, offset++, 1, ENC_NA);
2150 /* event dest */
2151 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_event_destination, tvb, offset++, 1, ENC_NA);
2153 /* event */
2154 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_event, tvb, offset++, 1, ENC_NA);
2157 break;
2159 case 8: /* rx late handler */
2161 /* action */
2162 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_action, tvb, offset++, 1, ENC_NA);
2164 /* event dest */
2165 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_event_destination, tvb, offset++, 1, ENC_NA);
2167 /* event */
2168 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_rx_late_handler_event, tvb, offset++, 1, ENC_NA);
2170 break;
2172 case 9: /* transport addr */
2174 /* scheme */
2175 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_transport_addr_scheme, tvb, offset++, 1, ENC_NA);
2177 /* todo - make this check the scheme is actually 0! */
2179 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_transport_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
2180 offset += 4;
2182 break;
2184 case 12: /* mapping item */
2186 uint8_t addrScheme;
2188 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mapping_item_offset, tvb, offset++, 1, ENC_NA);
2190 addrScheme = tvb_get_uint8(tvb, offset);
2191 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mapping_item_scheme, tvb, offset++, 1, ENC_NA);
2193 offset = get_address_scheme(pinfo, offset, addrScheme, tvb, cyclic_setup_attrib_item);
2195 /* todo - should this be done in the last function itself??? */
2196 offset++;
2198 break;
2200 case 0: /* state */
2201 case 1: /* rx/tx */
2202 case 2: /* synchronised */
2203 case 6: /* data change */
2204 case 10: /* max mappings */
2205 case 11: /* num mappings */
2206 case 13: /* saveable */
2207 case 128: /* max rx links */
2208 case 129: /* max tx links */
2209 case 130: /* max mappings per link */
2210 case 131: /* max sync rx links */
2211 case 132: /* max sync tx links */
2212 case 133: /* max mappings per sync link */
2213 case 134: /* process at queue depth */
2215 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_setup_attribute, tvb, offset++, 1, ENC_NA);
2217 break;
2219 case 135: /* mec period */
2221 proto_tree_add_item(cyclic_setup_attrib_item, hf_ecmp_mec_period, tvb, offset, 4, ENC_BIG_ENDIAN);
2222 offset += 4;
2224 break;
2226 default:
2227 break;
2229 } /* attribute switch */
2230 } /* loop through list */
2232 return offset;
2236 static void cyclic_setup(packet_info* pinfo, uint16_t offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2238 uint16_t length = 0;
2239 proto_item* cyclic_setup_attributes_root = NULL;
2240 proto_item* cyclic_setup_attributes = NULL;
2241 uint8_t Mode;
2243 length = tvb_reported_length(tvb);
2245 /* if a request add the check output flag */
2246 if (request) {
2247 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, ENC_BIG_ENDIAN);
2249 Mode = tvb_get_uint8(tvb, offset);
2250 proto_tree_add_uint(ecmp_tree, hf_ecmp_cyclic_setup_mode, tvb, offset++, 1, Mode);
2252 switch (Mode) {
2253 case 0: /* create */
2254 case 10: /* set */
2256 /* link direction */
2257 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2259 /* add the attributesd as a tree */
2260 add_cyclic_setup_attributes(pinfo, offset, length, tvb, ecmp_tree);
2262 break;
2264 case 1: /* edit */
2265 case 2: /* finalise */
2266 case 3: /* delete */
2267 case 4: /* exist */
2268 /* link direction */
2269 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2270 break;
2272 case 5: /* list */
2273 /* tx/rx bits */
2274 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2275 break;
2277 case 11: /* get */
2278 case 6: /* info */
2280 if (Mode == 11) {
2281 /* link dir */
2282 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2285 /* num attribs */
2286 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2288 /* attrib list */
2289 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2290 while (offset < length) {
2291 proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2294 break;
2296 case 12: /* get mappings */
2298 /* link dir */
2299 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_dir, tvb, offset++, 1, ENC_BIG_ENDIAN);
2301 /* max mappings */
2302 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_max_mappings, tvb, offset++, 1, ENC_NA);
2304 /* start offset */
2305 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_start_offset, tvb, offset++, 1, ENC_NA);
2307 break;
2309 default:
2310 /* display payload as hex bytes */
2311 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2312 break;
2314 } else {
2315 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rsp_status, tvb, offset++, 1, ENC_BIG_ENDIAN);
2316 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rsp_err_idx, tvb, offset++, 1, ENC_BIG_ENDIAN);
2318 Mode = tvb_get_uint8(tvb, offset);
2319 proto_tree_add_uint(ecmp_tree, hf_ecmp_cyclic_setup_mode, tvb, offset++, 1, Mode);
2321 switch (Mode) {
2322 case 0: /* create */
2323 case 1: /* edit */
2324 case 2: /* finalise */
2325 case 3: /* delete */
2326 /* no mode specific data */
2327 break;
2329 case 4: /* exist */
2330 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_link_exists, tvb, offset++, 1, ENC_BIG_ENDIAN);
2331 break;
2333 case 5: /* list */
2335 uint8_t txCount, rxCount, linkno;
2337 /* num attribs */
2338 txCount = tvb_get_uint8(tvb, offset);
2339 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_tx_count, tvb, offset++, 1, ENC_NA);
2341 /* link list */
2342 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2343 while (txCount > 0) {
2344 linkno = tvb_get_uint8(tvb, offset);
2345 proto_tree_add_uint(cyclic_setup_attributes, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, linkno);
2346 txCount--;
2349 rxCount = tvb_get_uint8(tvb, offset);
2350 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_rx_count, tvb, offset++, 1, ENC_NA);
2352 /* link list */
2353 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2354 while (rxCount > 0) {
2355 linkno = tvb_get_uint8(tvb, offset);
2356 proto_tree_add_uint(cyclic_setup_attributes, hf_ecmp_cyclic_setup_linkno, tvb, offset++, 1, linkno);
2357 rxCount--;
2360 break;
2362 case 10: /* set */
2364 /* num attribs */
2365 cyclic_setup_attributes_root = proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_setup_attrib_count, tvb, offset++, 1, ENC_BIG_ENDIAN);
2367 /* attrib list */
2368 cyclic_setup_attributes = proto_item_add_subtree(cyclic_setup_attributes_root, ett_cyclic_setup_attribs);
2369 while (offset < length) {
2370 proto_tree_add_item(cyclic_setup_attributes, hf_ecmp_cyclic_setup_attrib, tvb, offset++, 1, ENC_BIG_ENDIAN);
2373 break;
2375 case 11: /* get */
2376 case 12: /* get mappings */
2377 case 6: /* info */
2378 /* add the attributesd as a tree */
2379 add_cyclic_setup_attributes(pinfo, offset, length, tvb, ecmp_tree);
2380 break;
2382 default:
2383 /* display payload as hex bytes */
2384 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2385 break;
2391 /*a function to dissect "ProgramStatus" command */
2392 static void program_status(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2394 /* Description:function to dissect Program Status command */
2395 /* */
2396 /* Inputs: */
2397 /* offset - current offset of pointer within the ECMP frame */
2398 /* command_value - function code of ECMP message */
2399 /* request - (1 = query, 0 = response) */
2400 /* tvb - Wireshark protocol tree */
2401 /* ecmp_tree - Wireshark protocol tree */
2402 /* tree - Wireshark protocol tree */
2403 /* */
2404 /* Returns: nothing */
2405 /* */
2406 /* Notes: for queries, the "offset" points to the "target". */
2407 /* for responses, the "offset" points to the "status". */
2408 /* */
2409 /* sample ECMP Request Frame */
2410 /* 0x61 - request code (program control) */
2411 /* 0x00 - option terminator */
2412 /* 0x00 - target (0 = default program) <======== offset */
2413 /* */
2414 /* sample ECMP Response Frame */
2415 /* 0xE1 - response code (program control) */
2416 /* 0x00 - option terminator */
2417 /* 0x01 - running state (0=Stopped, 1=Running ... ) <======== offset */
2418 /* 0x00 - additional items */
2420 proto_item* ecmp_program_status_message_tree = NULL;
2422 /* differentiate between ECMP query and response */
2423 if (request) {
2424 /*display the program control details sub-tree */
2425 ecmp_program_status_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_program_status_message, NULL, "Program Status: (Query)");
2427 /* read the target */
2428 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_target, tvb, offset, 1, ENC_NA);
2429 } else {
2430 /*display the program status details sub-tree */
2431 ecmp_program_status_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_program_status_message, NULL, "Program Status: (Response)");
2433 /* read and display the Status */
2434 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_status, tvb, offset, 1, ENC_NA);
2435 offset += 1;
2437 /* read and display the Additional Items */
2438 proto_tree_add_item(ecmp_program_status_message_tree, hf_ecmp_program_status_additional_items, tvb, offset, 1, ENC_NA);
2443 /*a function to dissect "ProgramControl" command */
2444 static void program_control(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2446 /* Description:function to dissect Program Control command */
2447 /* */
2448 /* Inputs: */
2449 /* offset - current offset of pointer within the ECMP frame */
2450 /* command_value - function code of ECMP message */
2451 /* request - (1 = query, 0 = response) */
2452 /* tvb - Wireshark protocol tree */
2453 /* ecmp_tree - Wireshark protocol tree */
2454 /* tree - Wireshark protocol tree */
2455 /* */
2456 /* Returns: nothing */
2457 /* */
2458 /* Notes: for queries, the "offset" points to the "target". */
2459 /* for responses, the "offset" points to the "status". */
2460 /* */
2461 /* sample ECMP Request Frame */
2462 /* 0x60 - request code (program control) */
2463 /* 0x00 - option terminator */
2464 /* 0x00 - target (0 = default program) <======== offset */
2465 /* 0x01 - command (1 = start the program) */
2466 /* 0x00 - sub command */
2467 /* */
2468 /* sample ECMP Response Frame */
2469 /* 0xE0 - response code (program control) */
2470 /* 0x00 - option terminator */
2471 /* 0x00 - status (0 = OK) <======== offset */
2472 /* */
2474 proto_item* ecmp_program_control_message_tree = NULL;
2476 /* differentiate between ECMP query and response */
2477 if (request) {
2478 /*display the program control details sub-tree */
2479 ecmp_program_control_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 3, ett_ecmp_program_control_message, NULL, "Program Control: (Query)");
2481 /* read the target */
2482 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_target, tvb, offset, 1, ENC_NA);
2483 offset += 1;
2485 /* read the command */
2486 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_command, tvb, offset, 1, ENC_NA);
2487 offset += 1;
2489 /* read the subcommand */
2490 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_sub_command, tvb, offset, 1, ENC_NA);
2491 } else {
2492 /*display the program control details sub-tree */
2493 ecmp_program_control_message_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 1, ett_ecmp_program_control_message, NULL, "Program Control: (Response)");
2495 /* read and display the Status */
2496 proto_tree_add_item(ecmp_program_control_message_tree, hf_ecmp_program_control_status, tvb, offset, 1, ENC_NA);
2501 /*a function to dissect "ModbusPDU" command */
2502 static void modbus_pdu(int offset, bool request, tvbuff_t *tvb, packet_info* pinfo, proto_tree* ecmp_tree)
2504 /* Description:function to dissect Modbus PDU ECMP transactions */
2505 /* */
2506 /* Inputs: */
2507 /* offset - current offset of pointer within the ECMP frame */
2508 /* command_value - function code of ECMP message */
2509 /* request - (1 = query, 0 = response) */
2510 /* tvb - Wireshark protocol tree */
2511 /* ecmp-tree - Wireshark protocol tree */
2512 /* tree - Wireshark protocol tree */
2513 /* */
2514 /* Returns: nothing */
2515 /* */
2516 /* Notes: for queries, the "offset" points to the "size". */
2517 /* for responses, the "offset" points to the size. */
2518 /* */
2519 /* sample ECMP Request Frame (Read Holding Registers) */
2520 /* 0x74 - request code (ModbusMaster) */
2521 /* 0x00 - option terminator */
2522 /* 0x00 - size msb <======== offset */
2523 /* 0x05 - size lsb */
2524 /* 0x03 - function code - read hold reg */
2525 /* 0x07 - register address (#20.021) msb */
2526 /* 0xE4 - register address lsb */
2527 /* 0x00 - number registers msb */
2528 /* 0x03 - number registers lsb */
2529 /* */
2530 /* sample ECMP Response Frame */
2531 /* 0xF4 - response code (ModbusMaster) */
2532 /* 0x00 - option terminator */
2533 /* 0x00 - size msb <======== offset */
2534 /* 0x08 - size lsb */
2535 /* 0x03 - function code - read hold reg */
2536 /* 0x06 - byte count */
2537 /* 0x30 - register #2021 value 12345 msb */
2538 /* 0x39 - register #2021 value lsb */
2539 /* 0x03 - register #2022 value 787 msb */
2540 /* 0x13 - register #2022 value lsb */
2541 /* 0x00 - register #2023 value 100 msb */
2542 /* 0x64 - register #2023 value lsb */
2544 tvbuff_t* next_tvb;
2545 uint16_t size = 0; /* from Modbus TCP/IP spec: number of bytes that follow */
2546 modbus_data_t modbus_data;
2548 /* differentiate between ECMP query and response */
2549 if (request) {
2550 /* read and display the Size */
2551 size = tvb_get_ntohs(tvb, offset);
2552 proto_tree_add_item(ecmp_tree, hf_ecmp_modbus_pdu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2553 offset += 2;
2555 /* keep packet context */
2556 modbus_data.packet_type = QUERY_PACKET;
2557 modbus_data.mbtcp_transid = 0;
2558 modbus_data.unit_id = 0;
2559 next_tvb = tvb_new_subset_length(tvb, offset, size);
2560 call_dissector_with_data(modbus_handle, next_tvb, pinfo, ecmp_tree, &modbus_data);
2562 } else {
2563 /* read and display the Size */
2564 size = tvb_get_ntohs(tvb, offset);
2565 proto_tree_add_item(ecmp_tree, hf_ecmp_modbus_pdu_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2566 offset += 2;
2568 modbus_data.packet_type = RESPONSE_PACKET;
2569 modbus_data.mbtcp_transid = 0;
2570 modbus_data.unit_id = 0;
2571 next_tvb = tvb_new_subset_length(tvb, offset, size);
2572 call_dissector_with_data(modbus_handle, next_tvb, pinfo, ecmp_tree, &modbus_data);
2577 /*a function to dissect "Interrogate" command */
2578 static void interrogate(packet_info* pinfo, int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2580 /* Description: function to dissect Interrogate command */
2581 /* */
2582 /* Inputs: */
2583 /* offset - current offset of pointer within the ECMP frame */
2584 /* request - (1 = query, 0 = response) */
2585 /* tvb - rather complex structure that has the frame data */
2586 /* ecmp-tree - Wireshark protocol tree */
2587 /* */
2588 /* Returns: nothing */
2589 /* */
2590 /* Notes: for queries, the "offset" points to the "item type". */
2591 /* for responses, the "offset" points to the "item type". */
2592 /* */
2593 /* sample ECMP Request Frame */
2594 /* 0x02 - request code (interrogate) */
2595 /* 0x00 - option terminator */
2596 /* 0x00 - item type (0=ECMP command, 1=ECMP option) <==== offset */
2597 /* 0x05 - count (number of commands/options to follow) */
2598 /* 0x10 - item code #1 ECMP Read command */
2599 /* 0x11 - item code #2 ECMP ReadWithType command */
2600 /* 0x12 - item code #3 ECMP Write command */
2601 /* 0x13 - item code #4 ECMP ObjectInfo command */
2602 /* 0x14 - item code #5 ECMP GetNextObject command */
2603 /* */
2604 /* sample ECMP Response Frame */
2605 /* 0x82 - response code (program control) */
2606 /* 0x00 - option terminator */
2607 /* 0x00 - item type (0=ECMP command, 1=ECMP option) <==== offset */
2608 /* 0x05 - count (number of commands/options to follow) */
2609 /* 0x10 - item code #1 */
2610 /* 0x01 - supported (ECMP Read command) */
2611 /* 0x11 - item code #2 */
2612 /* 0x01 - supported (ECMP ReadWithType command) */
2613 /* 0x12 - item code #3 */
2614 /* 0x01 - supported (ECMP Write command) */
2615 /* 0x13 - item code #4 */
2616 /* 0x01 - supported (ECMP ObjectInfo command) */
2617 /* 0x14 - item code #5 */
2618 /* 0x01 - supported (ECMP GetNextObject command) */
2619 /* */
2620 /* */
2621 /* Item Type: 0 = ECMP command */
2622 /* 1 = ECMP option (not currently implemented) */
2623 /* */
2624 /* Item Code: 0 .. 0x7F for commands */
2625 /* 0 .. 2 for options */
2626 /* */
2627 /* Item Support: 0 = not supported */
2628 /* 1 = supported */
2629 /* */
2632 const uint8_t interrogate_type_command = 0;
2634 proto_tree* ecmp_interrogate_message_tree = NULL, *ecmp_interrogate_tree;
2635 proto_item* ecmp_interrogate_message_item = NULL;
2636 uint8_t item_type = 0; /* 0=ECMP command, 1=ECMP option */
2637 uint8_t command_req = 0; /* ECMP command */
2638 uint8_t supported = 0; /* ECMP command support status: 1=supported, 0=not supported */
2639 uint32_t count = 0; /* number of ECMP commands to be checked */
2640 uint32_t j; /* loop counter */
2643 /* differentiate between ECMP query and response */
2644 if (request) {
2646 /* identify the ECMP command we're dissecting */
2647 ecmp_interrogate_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_interrogate_message, NULL, "Interrogate: (Query)");
2649 /* read the item_type (command/option setting) */
2650 item_type = tvb_get_uint8(tvb, offset);
2651 proto_tree_add_item(ecmp_interrogate_tree, hf_ecmp_interrogate_item_type, tvb, offset, 1, ENC_NA);
2652 offset += 1;
2654 /* read the count */
2655 count = tvb_get_uint8(tvb, offset);
2656 proto_tree_add_item(ecmp_interrogate_tree, hf_ecmp_interrogate_count, tvb, offset, 1, ENC_NA);
2657 offset += 1;
2659 /*create the interrogate details sub-tree */
2660 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");
2662 /* display the item_codes (commands to be checked) */
2663 if (item_type == interrogate_type_command) {
2664 /* loop on the commands */
2665 for (j = 0; j < count; j++) {
2667 /* display the commands to be checked */
2668 proto_tree_add_item(ecmp_interrogate_message_tree, hf_ecmp_interrogate_command, tvb, offset, 1, ENC_NA);
2669 offset += 1;
2671 proto_item_set_len(ecmp_interrogate_message_item, count);
2673 } else {
2674 expert_add_info(pinfo, ecmp_interrogate_message_item, &ei_ecmp_options_not_implemented);
2677 } else {
2678 /* identify the ECMP command we're dissecting */
2679 ecmp_interrogate_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_interrogate_message, NULL, "Interrogate: (Response)");
2681 /* read the item_type (command/option setting) */
2682 item_type = tvb_get_uint8(tvb, offset);
2683 offset += 1;
2685 /* read the count */
2686 count = tvb_get_uint8(tvb, offset);
2687 offset += 1;
2689 /* display the item_codes (commands to be checked) */
2690 if (item_type == interrogate_type_command) {
2692 /*create the interrogate details sub-tree */
2693 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");
2695 /* loop on the commands */
2696 for (j = 0; j < count; j++) {
2697 /* get the command code */
2698 command_req = tvb_get_uint8(tvb, offset);
2699 offset += 1;
2701 /* get the support status */
2702 supported = tvb_get_uint8(tvb, offset);
2703 offset += 1;
2705 /* display if the command is supported */
2706 proto_tree_add_uint_format(ecmp_interrogate_message_tree, hf_ecmp_interrogate_command, tvb, offset, 1, command_req, "%s: %s",
2707 try_val_to_str(command_req, command_vals),
2708 try_val_to_str(supported, Interrogate_support_state));
2711 } else {
2713 expert_add_info(pinfo, ecmp_interrogate_message_item, &ei_ecmp_options_not_implemented);
2719 static void tunnel_frame(int offset, bool request, tvbuff_t *tvb, proto_tree* ecmp_tree)
2721 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_control, tvb, offset, 1, ENC_BIG_ENDIAN);
2722 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_start_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2723 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_end_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2725 /* if a request add the check output flag */
2726 if (request) {
2727 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_check_output_flag, tvb, offset, 1, ENC_BIG_ENDIAN);
2730 offset+= 1;
2732 /* Payload length */
2733 proto_tree_add_item(ecmp_tree, hf_ecmp_tunnel_size, tvb, offset, 2, ENC_BIG_ENDIAN);
2734 offset+= 2;
2736 proto_tree_add_item(ecmp_tree, hf_ecmp_data, tvb, offset, tvb_reported_length_remaining(tvb, offset), ENC_NA);
2737 /*offset = tvb_reported_length(tvb);*/
2741 /* dissect_ecmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
2742 * -----------------------------------------------------------------
2744 * Purpose: Wireshark dissector for Emerson Control Techniques ECMP protocol
2747 * Inputs: tvbuff_t *tvb - complex buffer structure holding the packet's bytes
2748 * packet_info *pinfo - structure holding information about the packet
2749 * proto_tree *tree - pointer to top-level tree (print lines)
2751 * Outputs: none
2754 * Notes: if tree = NULL, packet capture is running and dissector will only write into the Summary Line (Info Field)
2756 * if tree is non-NULL, packet capture has stopped because a packet has been selected (clicked)
2757 * In this case, we will display quite a bit of additional information about the packet.
2760 * To inspect the frame buffer (very difficult using the *tvb pointer), it's best to add this little debug
2761 * code snippet at the top of the program to copy the frame buffer into an array that you can inspect.
2763 * static uint8_t jimbuf[512]; // temp buffer for current frame data
2764 * static int lenframe = 0; // num bytes in the frame
2765 * static int j = 0; // loop counter
2766 * static int16_t saved_offset = 0; // saves offset for later restoration
2768 * lenframe = tvb_captured_length(tvb); // get the length of the frame
2769 * saved_offset = offset; // temporarily save the "offset"
2771 * for (j = 0; j < lenframe; j++) { // loop to copy the frame buffer
2772 * jimbuf[j] = tvb_get_uint8(tvb, offset); // Wireshark function to read the frame buffer
2773 * offset += 1;
2775 * offset = saved_offset; // restore the offset
2778 * Authors: Sarah Bouremoum, Jim Lynch, Luke Orehawa, Others
2781 static int dissect_ecmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
2783 /* Initialize the items and trees*/
2784 proto_item *ecmp_item = NULL;
2785 proto_item *ecmp_transaction_id_item = NULL;
2786 proto_item *ecmp_chunk_id_item = NULL;
2787 proto_tree *ecmp_tree = NULL;
2789 /*initialise the values to be used */
2790 uint8_t command_value = 0;
2791 bool request;
2792 uint8_t transaction_id_value = 0;
2793 int offset = 0; /* index used to read data from the buffer*/
2794 int framelen = 0; /* number of bytes in the frame */
2796 /* note length of the UDP frame */
2797 framelen = tvb_reported_length(tvb);
2799 if (framelen < ecmp_min_packet_size) {
2800 return 0;
2803 /* this code block processes ECMP TCP messages (most of them) */
2804 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ECMP);
2805 col_clear(pinfo->cinfo,COL_INFO);
2808 /*declaration of variables*/
2809 offset = 4;
2811 /*display the first line of the tree (ECMP data)*/
2812 ecmp_item = proto_tree_add_item(tree, proto_ecmp, tvb, 0, -1, ENC_NA);
2813 ecmp_tree = proto_item_add_subtree(ecmp_item, ett_ecmp);
2815 /* display the information for the destination address */
2816 offset = add_transport_layer_frame(offset, tvb, ecmp_tree, hf_ecmp_destination_address);
2818 /* display the information for the source address */
2819 offset = add_transport_layer_frame(offset, tvb, ecmp_tree, hf_ecmp_source_address);
2821 /*display the transaction ID*/
2822 ecmp_transaction_id_item = proto_tree_add_item(ecmp_tree, hf_ecmp_transaction_id, tvb, offset, 1, ENC_BIG_ENDIAN );
2823 transaction_id_value = tvb_get_uint8(tvb, offset);
2825 if(transaction_id_value == 0) {
2826 proto_item_append_text(ecmp_transaction_id_item, "%s", " -> Not initiated by Request");
2828 offset++;
2830 request = ((tvb_get_uint8(tvb, offset+2) & 0x80) == 0);
2831 if (request) {
2832 /* Calls the function to display the Response size */
2833 offset = get_response_size(offset, tvb, ecmp_tree);
2835 /* Calls the function to display the command and request/response */
2836 offset = add_command_codes(pinfo, offset, tvb, ecmp_tree, transaction_id_value, &command_value);
2838 /* Calls the function to display the option codes and its data */
2839 offset = add_option_codes(offset, pinfo, tvb, ecmp_tree);
2841 /* up til here all code for the request should be the same */
2842 switch(command_value)
2844 case ECMP_COMMAND_IDENTIFY:
2845 /*Calls a method to display the attributes and its data */
2846 add_attributes(pinfo, offset, tvb, ecmp_tree, request);
2847 break;
2848 case ECMP_COMMAND_INFO:
2849 /* Info command is just the request code, nothing else to display */
2850 proto_tree_add_item(ecmp_tree, hf_ecmp_info_command, tvb, 0, -1, ENC_NA);
2851 /*do nothing, no more data is present */
2852 break;
2853 case ECMP_COMMAND_INTERROGATE:
2854 interrogate(pinfo, offset, request, tvb, ecmp_tree);
2855 break;
2856 case ECMP_COMMAND_READ:
2857 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2858 break;
2859 case ECMP_COMMAND_READWITHTYPE:
2860 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2861 break;
2862 case ECMP_COMMAND_WRITE:
2863 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2864 break;
2865 case ECMP_COMMAND_OBJECTINFO:
2866 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2867 break;
2868 case ECMP_COMMAND_GETNEXTOBJECTS:
2869 get_parameter_definitions(pinfo, offset, command_value, tvb, ecmp_tree);
2870 break;
2871 case ECMP_COMMAND_FILEOPEN:
2872 file_open(offset, request, tvb, ecmp_tree);
2873 break;
2874 case ECMP_COMMAND_FILEREAD:
2875 file_read(offset, request, tvb, ecmp_tree);
2876 break;
2877 case ECMP_COMMAND_FILEWRITE:
2878 file_write(offset, request, tvb, ecmp_tree);
2879 break;
2880 case ECMP_COMMAND_FILECLOSE:
2881 file_close(offset, request, tvb, ecmp_tree);
2882 break;
2883 case ECMP_COMMAND_FILEINFO:
2884 file_info(pinfo, offset, request, tvb, ecmp_tree);
2885 break;
2886 case ECMP_COMMAND_FILEDELETE:
2887 file_state_delete(offset, request, tvb, ecmp_tree);
2888 break;
2889 case ECMP_COMMAND_FILESTATE:
2890 file_state_delete(offset, request, tvb, ecmp_tree);
2891 break;
2892 case ECMP_COMMAND_FILEPOS:
2893 file_pos(offset, request, tvb, ecmp_tree);
2894 break;
2895 case ECMP_COMMAND_FILELIST:
2896 file_list(pinfo, offset, request, tvb, ecmp_tree);
2897 break;
2898 case ECMP_COMMAND_FILEEXISTS:
2899 file_exists(offset, request, tvb, ecmp_tree);
2900 break;
2901 case ECMP_COMMAND_CYCLICLINK:
2902 cyclic_setup(pinfo, offset, request, tvb, ecmp_tree);
2903 break;
2904 case ECMP_COMMAND_PROGRAMCONTROL:
2905 program_control(offset, request, tvb, ecmp_tree);
2906 break;
2907 case ECMP_COMMAND_PROGRAMSTATUS:
2908 program_status(offset, request, tvb, ecmp_tree);
2909 break;
2910 case ECMP_COMMAND_CYCLICFRAME:
2911 add_cyclic_frame_query(offset, tvb, ecmp_tree);
2912 break;
2913 case ECMP_COMMAND_TUNNELFRAME:
2914 tunnel_frame(offset, command_value, tvb, ecmp_tree);
2915 break;
2916 case ECMP_COMMAND_MODBUSPDU:
2917 modbus_pdu(offset, request, tvb, pinfo, ecmp_tree);
2918 break;
2919 default:
2920 proto_tree_add_expert(ecmp_tree, pinfo, &ei_ecmp_unknown_command, tvb, 0, -1);
2921 break;
2924 /* END of code to be modified */
2925 } else {
2926 uint8_t chunk_id_value = 0;
2927 int8_t status_value = 0;
2929 status_value = tvb_get_int8(tvb, offset); /*stores a signed value for status */
2931 proto_tree_add_item(ecmp_tree, hf_ecmp_status, tvb, offset, 1, ENC_BIG_ENDIAN);
2934 if (status_value >= 0) {
2935 offset++;
2936 chunk_id_value = tvb_get_uint8(tvb, offset);
2937 ecmp_chunk_id_item = proto_tree_add_item(ecmp_tree, hf_ecmp_chunk_id, tvb, offset, 1, ENC_BIG_ENDIAN);
2939 if(chunk_id_value == 0) {
2940 proto_item_append_text(ecmp_chunk_id_item, "%s", " -> Response is NOT Chunked");
2943 offset++;
2945 /* Calls the function to display the option codes */
2946 offset = add_command_codes(pinfo, offset, tvb, ecmp_tree, transaction_id_value, &command_value);
2948 if ((status_value == 0) || (status_value == 1)) {
2949 /* Calls a method to display option codes */
2950 offset = add_option_codes(offset, pinfo, tvb, ecmp_tree);
2952 /* up til here all code for the response should be the same */
2953 switch(command_value)
2955 case ECMP_COMMAND_IDENTIFY:
2956 /*Call a method to add category data */
2957 offset = add_category_codes(offset, tvb, ecmp_tree);
2958 /*Call a method to add attributes */
2959 add_attributes(pinfo, offset, tvb, ecmp_tree, request);
2960 break;
2961 case ECMP_COMMAND_INFO:
2962 add_info_response(offset, tvb, ecmp_tree);
2963 break;
2964 case ECMP_COMMAND_INTERROGATE:
2965 interrogate(pinfo, offset, request, tvb, ecmp_tree);
2966 break;
2967 case ECMP_COMMAND_READ:
2968 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2969 break;
2970 case ECMP_COMMAND_READWITHTYPE:
2971 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2972 break;
2973 case ECMP_COMMAND_WRITE:
2974 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2975 break;
2976 case ECMP_COMMAND_OBJECTINFO:
2977 get_object_info_response(pinfo, offset, tvb, ecmp_tree);
2978 break;
2979 case ECMP_COMMAND_GETNEXTOBJECTS:
2980 get_parameter_responses(pinfo, offset, command_value, tvb, ecmp_tree);
2981 break;
2982 case ECMP_COMMAND_FILEOPEN:
2983 file_open(offset, request, tvb, ecmp_tree);
2984 break;
2985 case ECMP_COMMAND_FILEREAD:
2986 file_read(offset, request, tvb, ecmp_tree);
2987 break;
2988 case ECMP_COMMAND_FILEWRITE:
2989 file_write(offset, request, tvb, ecmp_tree);
2990 break;
2991 case ECMP_COMMAND_FILECLOSE:
2992 file_close(offset, request, tvb, ecmp_tree);
2993 break;
2994 case ECMP_COMMAND_FILEINFO:
2995 file_info(pinfo, offset, request, tvb, ecmp_tree);
2996 break;
2997 case ECMP_COMMAND_FILEDELETE:
2998 file_state_delete(offset, request, tvb, ecmp_tree);
2999 break;
3000 case ECMP_COMMAND_FILESTATE:
3001 file_state_delete(offset, request, tvb, ecmp_tree);
3002 break;
3003 case ECMP_COMMAND_FILEPOS:
3004 file_pos(offset, request, tvb, ecmp_tree);
3005 break;
3006 case ECMP_COMMAND_FILELIST:
3007 file_list(pinfo, offset, request, tvb, ecmp_tree);
3008 break;
3009 case ECMP_COMMAND_FILEEXISTS:
3010 file_exists(offset, request, tvb, ecmp_tree);
3011 break;
3012 case ECMP_COMMAND_CYCLICLINK:
3013 cyclic_setup(pinfo, offset, request, tvb, ecmp_tree);
3014 break;
3015 case ECMP_COMMAND_PROGRAMCONTROL:
3016 program_control(offset, request, tvb, ecmp_tree);
3017 break;
3018 case ECMP_COMMAND_PROGRAMSTATUS:
3019 program_status(offset, request, tvb, ecmp_tree);
3020 break;
3021 case ECMP_COMMAND_CYCLICFRAME:
3022 add_cyclic_frame(offset, tvb, ecmp_tree);
3023 break;
3024 case ECMP_COMMAND_TUNNELFRAME:
3025 tunnel_frame(offset, command_value, tvb, ecmp_tree);
3026 break;
3027 case ECMP_COMMAND_MODBUSPDU:
3028 modbus_pdu(offset, request, tvb, pinfo, ecmp_tree);
3029 break;
3030 default:
3031 proto_tree_add_expert(ecmp_tree, pinfo, &ei_ecmp_unknown_command, tvb, 0, -1);
3032 break;
3034 /********************************* END of code to be modified ***********************************/
3039 return framelen;
3042 /* this code block processes ECMP UDP messages (cyclic data) */
3043 static int dissect_ecmp_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
3045 proto_item *ecmp_item = NULL;
3046 proto_tree *ecmp_tree = NULL;
3047 proto_tree *ecmp_cyclic_data_32_bit_display_tree = NULL;
3048 proto_tree *ecmp_cyclic_data_16_bit_display_tree = NULL;
3049 proto_tree *ecmp_cyclic_data_8_bit_display_tree = NULL;
3050 uint8_t command_value = 0;
3051 uint8_t type_value = 0;
3052 uint8_t transaction_id_value = 0;
3053 uint16_t offset = 0; /* index used to read data from the buffer*/
3054 int framelen = 0; /* number of bytes in the frame */
3055 uint8_t scheme = 0; /* 0=no scheme, 1=grandmaster setup */
3057 /* note length of the UDP frame */
3058 framelen = tvb_reported_length(tvb);
3060 if (framelen < ecmp_min_packet_size) {
3061 return 0;
3064 /* display the "ECMP" protocol indication in the PROTOCOL field */
3065 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ECMP);
3067 /* Clear out stuff in the info column */
3068 col_clear(pinfo->cinfo,COL_INFO);
3070 /* adjust offset to point at transaction ID */
3071 offset += 2;
3073 /*getting the information from the buffer*/
3074 transaction_id_value = tvb_get_uint8(tvb, offset);
3076 /* adjust offset to point at ECMP query/response code */
3077 offset += 3;
3079 /* calculate if it's a query or response (type_r_r) */
3080 type_value = tvb_get_uint8(tvb, offset);
3082 /* determine the ECMP command code */
3083 command_value = type_value & 0x7f;
3085 /* update offset to point to cyclic link number */
3086 offset += 2;
3088 /* Information displayed in the Info column*/
3089 col_add_fstr(pinfo->cinfo, COL_INFO, "%s, %s. Transaction ID: %d",
3090 val_to_str(command_value, command_vals, "Unknown Type:0x%02x"),
3091 tfs_get_string((type_value & 0x80) >> 7, &tfs_response_request),
3092 transaction_id_value);
3094 /*display the first line of the tree (ECMP data)*/
3095 ecmp_item = proto_tree_add_item(tree, proto_ecmp, tvb, 0, -1, ENC_NA); /*item created*/
3096 ecmp_tree = proto_item_add_subtree(ecmp_item, ett_ecmp); /*tree created*/
3098 /* indicate cyclic link message */
3099 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_req_resp, tvb, offset, 1, ENC_BIG_ENDIAN);
3101 /* display the cyclic link number */
3102 proto_tree_add_item(ecmp_tree, hf_ecmp_cyclic_link_number_display, tvb, offset, 1, ENC_BIG_ENDIAN);
3103 offset += 1;
3105 if (type_value & 0x80) {
3106 /* response data handled here */
3107 /* display the alignment */
3108 proto_tree_add_item(ecmp_tree, hf_ecmp_udp_alignment, tvb, offset, 1, ENC_NA);
3109 offset += 1;
3111 /* display the scheme */
3112 scheme = tvb_get_uint8(tvb, offset);
3113 proto_tree_add_item(ecmp_tree, hf_ecmp_udp_scheme, tvb, offset, 1, ENC_NA);
3114 offset += 1;
3116 /* if the scheme is 1, there is grandmaster data to be printed */
3117 if (scheme == 1) {
3118 proto_tree_add_item(ecmp_tree, hf_ecmp_grandmaster, tvb, offset, 8, ENC_BIG_ENDIAN);
3119 offset += 8;
3121 proto_tree_add_item(ecmp_tree, hf_ecmp_process_time, tvb, offset, 8, ENC_BIG_ENDIAN);
3122 offset += 8;
3125 /* create the Cyclic Data Display (uint32_t format) sub-tree */
3126 ecmp_cyclic_data_32_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_32_bit_display, NULL,
3127 "Cyclic Data (32-bit hex unsigned format): ");
3129 /* display the raw hex data for the cyclic data in a 32-bit format */
3130 display_raw_cyclic_data(cyclic_display_long_format, offset, framelen - offset, tvb, pinfo, ecmp_cyclic_data_32_bit_display_tree);
3132 /* create the Cyclic Data Display (uint16_t format) sub-tree */
3133 ecmp_cyclic_data_16_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_16_bit_display, NULL,
3134 "Cyclic Data (16-bit hex unsigned format): ");
3136 /* display the raw hex data for the cyclic data in a 16-bit format */
3137 display_raw_cyclic_data(cyclic_display_word_format, offset, framelen - offset, tvb, pinfo, ecmp_cyclic_data_16_bit_display_tree);
3139 /* display the raw hex data for the cyclic data in a uint8_t format */
3140 ecmp_cyclic_data_8_bit_display_tree = proto_tree_add_subtree(ecmp_tree, tvb, offset, 2, ett_ecmp_cyclic_data_8_bit_display, NULL,
3141 "Cyclic Data (8-bit hex unsigned format): ");
3143 /* display the raw hex data for the cyclic data in 8-bit format */
3144 display_raw_cyclic_data(cyclic_display_byte_format, offset, framelen - offset, tvb, pinfo, ecmp_cyclic_data_8_bit_display_tree);
3147 return tvb_reported_length(tvb);
3150 /* Function to register the protcol*/
3151 /* Wireshark literally scans this file (packet-ecmp.c) to find this function */
3152 /* note: this function MUST start in column 1, due to the scanning mentioned above */
3153 void proto_register_ecmp (void)
3155 /* A header field is something you can search/filter on.
3157 * We create a structure to register our fields. It consists of an
3158 * array of hf_register_info structures, each of which are of the format
3159 * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
3162 static hf_register_info hf[] = {
3164 { &hf_ecmp_destination_address,
3165 { "Destination Address scheme", "ecmp.destination_address", FT_UINT8, BASE_DEC, VALS(address_scheme), 0, NULL, HFILL }},
3167 { &hf_ecmp_source_address,
3168 { "Source Address scheme", "ecmp.source_address", FT_UINT8, BASE_DEC, VALS(address_scheme), 0, NULL, HFILL }},
3170 { &hf_ecmp_diagnostic,
3171 { "Diagnostic group", "ecmp.diagnostic", FT_UINT8, BASE_DEC, VALS(diagnostic), 0, NULL, HFILL }},
3173 { &hf_ecmp_command,
3174 { "Command", "ecmp.command", FT_UINT8, BASE_DEC, VALS(command_vals), 0x7F, NULL, HFILL }},
3176 { &hf_ecmp_option,
3177 { "Option", "ecmp.option", FT_UINT8, BASE_DEC, VALS(option_code), 0x0, NULL, HFILL }},
3179 { &hf_ecmp_type_rr,
3180 { "Type", "ecmp.type", FT_BOOLEAN, 8, TFS(&tfs_response_request), 0x80, "ECMP Type (request/response)", HFILL }},
3182 { &hf_ecmp_chunking,
3183 { "Chunks allowed","ecmp.chunking", FT_UINT16, BASE_DEC, NULL,0xF000, "ECMP number of chunks allowed", HFILL}},
3185 { &hf_ecmp_max_response_size,
3186 { "Maximum Response Size","ecmp.response_size", FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_byte_bytes), 0x0FFF, NULL, HFILL}},
3188 { &hf_ecmp_category,
3189 { "Device", "ecmp.category", FT_UINT8, BASE_DEC, VALS(category), 0x0, "ECMP Category (drive or option module)", HFILL }},
3191 { &hf_ecmp_attribute,
3192 { "Attribute", "ecmp.attribute", FT_UINT8, BASE_DEC, VALS(attribute), 0x0, NULL, HFILL }},
3194 { &hf_ecmp_no_of_attributes,
3195 { "Number of attributes", "ecmp.attribute_number", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3197 { &hf_ecmp_status,
3198 { "Status", "ecmp.status", FT_INT8, BASE_DEC, VALS(status), 0x0, NULL, HFILL }},
3200 { &hf_ecmp_chunk_id,
3201 { "Chunk ID", "ecmp.chunkID", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3203 { &hf_ecmp_transaction_id,
3204 { "Transaction ID", "ecmp.transactionID", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3206 { &hf_ecmp_drive_type,
3207 { "Product Type", "ecmp.drive_type", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3209 { &hf_ecmp_drive_derivative,
3210 { "Drive Derivative", "ecmp.drive_derivative", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3212 { &hf_ecmp_drive_factory_fit_category_id,
3213 { "Factory Fitted Option ID", "ecmp.drive_factory_fit_category_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3215 { &hf_ecmp_category_id,
3216 { "Option ID", "ecmp.category_id", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3218 { &hf_ecmp_cyclic_link_num,
3219 { "Cyclic Link Number", "ecmp.link_num", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3221 { &hf_ecmp_cyclic_align,
3222 { "Alignment", "ecmp.cyclic_align", FT_UINT8, BASE_DEC, VALS(cyclic_align), 0x0, "ECMP Cyclic Data Alignment", HFILL }},
3224 { &hf_ecmp_cyclic_scheme,
3225 { "Scheme", "ecmp.cyclic_scheme", FT_UINT8, BASE_DEC, VALS(cyclic_scheme), 0x0, "ECMP Cyclic Scheme", HFILL }},
3227 { &hf_ecmp_cyclic_link_number_display,
3228 { "Cyclic Link Number Display", "ecmp.link_num_display", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3230 { &hf_ecmp_buffer_size,
3231 {"Buffer Size", "ecmp.buffer_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3233 { &hf_ecmp_max_response,
3234 {"Maximum Response Time", "ecmp.max_response", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3236 { &hf_ecmp_max_handle,
3237 {"Maximum Handle Period", "ecmp.max_handle", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3239 { &hf_ecmp_info_address,
3240 {"Number of Default Route Addresses", "ecmp.count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3242 { &hf_ecmp_parameter_address,
3243 {"Parameter Addressing Scheme", "ecmp.parameter.address", FT_UINT8, BASE_DEC, VALS(parameter_address_scheme), 0x0, NULL, HFILL}},
3245 { &hf_ecmp_number_of_parameter_definitions,
3246 {"Number of Parameter Definitions", "ecmp.parameter.definitions", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3248 { &hf_ecmp_number_of_parameter_responses,
3249 {"Number of Parameter Responses", "ecmp.parameter.response", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3251 { &hf_ecmp_parameter_status,
3252 {"Parameter Status", "ecmp.parameter.status", FT_INT8, BASE_DEC, VALS(parameter_access_status), 0x0, NULL, HFILL}},
3254 { &hf_ecmp_data_type,
3255 {"Parameter Data Type", "ecmp.parameter.data_type", FT_UINT8, BASE_DEC, VALS(parameter_data_types), 0x0, NULL, HFILL}},
3257 { &hf_ecmp_info_type,
3258 {"Info Type", "ecmp.info_type", FT_UINT8, BASE_DEC, VALS(info_type), 0x0, NULL, HFILL}},
3260 { &hf_ecmp_file_status,
3261 {"File Status", "ecmp.file.status", FT_INT8, BASE_DEC, VALS(file_status), 0x0, NULL, HFILL}},
3263 { &hf_ecmp_file_handle,
3264 {"File Handle", "ecmp.file.handle", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL}},
3266 { &hf_ecmp_file_attributes,
3267 {"Attribute", "ecmp.file.attribute", FT_UINT8, BASE_DEC, VALS(file_attributes), 0x0, "File attributes", HFILL}},
3269 { &hf_ecmp_file_ref_point,
3270 {"Reference Point", "ecmp.file.reference", FT_UINT8, BASE_DEC, VALS(file_ref_point), 0x0, "File reference points", HFILL}},
3272 { &hf_ecmp_tunnel_control,
3273 {"Control", "ecmp.tunnel_control", FT_UINT8, BASE_DEC, NULL, 0x0, "Tunnel frame control field", HFILL}},
3275 { &hf_ecmp_tunnel_start_flag,
3276 {"Start", "ecmp.tunnel_control.start", FT_BOOLEAN, 8, NULL, TUNNEL_START_FLAG, "Tunnel frame control field start flag", HFILL}},
3278 { &hf_ecmp_tunnel_end_flag,
3279 {"End", "ecmp.tunnel_control.end", FT_BOOLEAN, 8, NULL, TUNNEL_END_FLAG, "Tunnel frame control field end flag", HFILL}},
3281 { &hf_ecmp_tunnel_check_output_flag,
3282 {"Check Output", "ecmp.tunnel_control.check", FT_BOOLEAN, 8, NULL, TUNNEL_CHECK_OUTPUT_FLAG, "Tunnel frame control field check output flag", HFILL}},
3284 { &hf_ecmp_tunnel_size,
3285 {"Size", "ecmp.tunnel_size", FT_UINT16, BASE_DEC, NULL, 0x0, "Tunnel frame payload size", HFILL}},
3287 { &hf_ecmp_cyclic_setup_mode,
3288 {"Mode", "ecmp.cyclic_setup.mode", FT_UINT8, BASE_DEC, VALS(cyclic_setup_mode), 0x0, "Cyclic setup mode", HFILL}},
3290 { &hf_ecmp_cyclic_setup_linkno,
3291 {"Link No", "ecmp.cyclic_setup.linkno", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup link no", HFILL}},
3293 { &hf_ecmp_cyclic_setup_dir,
3294 {"Direction", "ecmp.cyclic_setup.direction", FT_UINT8, BASE_DEC, VALS(cyclic_setup_link_dir), 0x0, "Cyclic setup link direction", HFILL}},
3296 { &hf_ecmp_cyclic_setup_attrib_count,
3297 {"Count", "ecmp.cyclic_setup.attrib_count", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup attribute count", HFILL}},
3299 { &hf_ecmp_cyclic_setup_attrib,
3300 {"Attribute", "ecmp.cyclic_setup.attrib", FT_UINT8, BASE_DEC, VALS(cyclic_attributes), 0x0, "Cyclic setup attribute", HFILL}},
3302 { &hf_ecmp_cyclic_setup_rsp_status,
3303 {"Status", "ecmp.cyclic_setup.rsp_status", FT_INT8, BASE_DEC, NULL, 0x0, "Cyclic setup status", HFILL}},
3305 { &hf_ecmp_cyclic_setup_rsp_err_idx,
3306 {"Error Index", "ecmp.cyclic_setup.rsp_err_idx", FT_UINT8, BASE_DEC, NULL, 0x0, "Cyclic setup error index", HFILL}},
3308 { &hf_ecmp_cyclic_setup_link_exists,
3309 {"Existence State", "ecmp.cyclic_setup.exists.state", FT_UINT8, BASE_DEC, VALS(cyclic_setup_link_exists), 0x0, "Cyclic setup exists state", HFILL}},
3311 { &hf_ecmp_cyclic_link_req_resp,
3312 {"Cyclic Link - Request-Response", "ecmp.cyclic_link.request.response", FT_BOOLEAN, BASE_NONE, TFS(&tfs_response_request), 0x0, "Cyclic link request - response", HFILL}},
3314 { &hf_ecmp_attribute_string,
3315 { "Attribute string", "ecmp.attribute_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3317 { &hf_ecmp_file_name,
3318 { "File name", "ecmp.file_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3320 { &hf_ecmp_directory,
3321 { "Directory", "ecmp.directory", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3323 { &hf_ecmp_names_scheme,
3324 { "Names Scheme", "ecmp.names_scheme", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3326 { &hf_ecmp_variable_name,
3327 { "Variable name", "ecmp.variable_name", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3329 { &hf_ecmp_unit_id_string,
3330 { "Unit ID String", "ecmp.unit_id_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3332 { &hf_ecmp_ecmp_string,
3333 { "ECMP string", "ecmp.ecmp_string", FT_UINT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3335 { &hf_ecmp_info_command,
3336 { "Info command data", "ecmp.info_command", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3338 { &hf_ecmp_process_time,
3339 { "ProcessAt time", "ecmp.processat_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3341 { &hf_ecmp_cyclic_frame_time,
3342 { "Cyclic frame time", "ecmp.cyclic_frame_time", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3344 { &hf_ecmp_grandmaster,
3345 { "Grandmaster", "ecmp.grandmaster", FT_EUI64, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3347 { &hf_ecmp_data,
3348 { "Data", "ecmp.data", FT_BYTES, SEP_SPACE, NULL, 0x0, NULL, HFILL }},
3350 { &hf_ecmp_response_data,
3351 { "Response Data", "ecmp.response_data", FT_BYTES, SEP_SPACE, NULL, 0x0, NULL, HFILL }},
3353 /* Generated from convert_proto_tree_add_text.pl */
3354 { &hf_ecmp_physical_address, { "Physical address", "ecmp.physical_address", FT_UINT8, BASE_DEC, NULL, 0x0F, NULL, HFILL }},
3355 { &hf_ecmp_logical_address, { "Logical address", "ecmp.logical_address", FT_UINT8, BASE_DEC, NULL, 0xF0, NULL, HFILL }},
3356 { &hf_ecmp_primary_colour, { "Primary Colour", "ecmp.primary_colour", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3357 { &hf_ecmp_secondary_colour, { "Secondary Colour", "ecmp.secondary_colour", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3358 { &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 }},
3359 { &hf_ecmp_number_of_decimal_places, { "Number of decimal places", "ecmp.number_of_decimal_places", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3360 { &hf_ecmp_no_information_available, { "No Information available", "ecmp.no_information_available", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3361 { &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 }},
3362 { &hf_ecmp_param_format_write_allowed, { "W- Write allowed", "ecmp.param_format.write_allowed", FT_UINT32, BASE_DEC, NULL, 0x00000002, NULL, HFILL }},
3363 { &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 }},
3364 { &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 }},
3365 { &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 }},
3366 { &hf_ecmp_param_format_not_clonable, { "NC- Not clonable", "ecmp.param_format.not_clonable", FT_UINT32, BASE_DEC, NULL, 0x00000020, NULL, HFILL }},
3367 { &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 }},
3368 { &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 }},
3369 { &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 }},
3370 { &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 }},
3371 { &hf_ecmp_param_format_string_parameter, { "TE- String parameter", "ecmp.param_format.string_parameter", FT_UINT32, BASE_DEC, NULL, 0x00002000, NULL, HFILL }},
3372 { &hf_ecmp_param_format_destination_set_up_parameter, { "DE- destination set-up parameter", "ecmp.param_format.destination_set_up_parameter", FT_UINT32, BASE_DEC, NULL, 0x00004000, NULL, HFILL }},
3373 { &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 }},
3374 { &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 }},
3375 { &hf_ecmp_param_format_display_format, { "DF- Display Format", "ecmp.param_format.display_format", FT_UINT32, BASE_DEC, VALS(display_format), 0x001E0000, NULL, HFILL }},
3376 { &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 }},
3377 { &hf_ecmp_param_format_units, { "UNITS", "ecmp.param_format.units", FT_UINT32, BASE_DEC, VALS(format_units), 0x0FC00000, NULL, HFILL }},
3378 { &hf_ecmp_string_id, { "String ID", "ecmp.string_id", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3379 { &hf_ecmp_address_scheme_menu, { "Menu", "ecmp.address_scheme.menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3380 { &hf_ecmp_address_scheme_parameter, { "Parameter", "ecmp.address_scheme.parameter", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3381 { &hf_ecmp_address_scheme_slot, { "Slot", "ecmp.address_scheme.slot", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3382 { &hf_ecmp_address_scheme_null_byte_size, { "NULL byte size", "ecmp.address_scheme.null_byte_size", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3383 { &hf_ecmp_display_unit_id, { "Unit ID", "ecmp.display_unit_id", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3384 { &hf_ecmp_data_boolean, { "Data", "ecmp.data.boolean", FT_UINT8, BASE_DEC, NULL, 0x01, NULL, HFILL }},
3385 { &hf_ecmp_data_int8, { "Data", "ecmp.data.int8", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3386 { &hf_ecmp_data_uint8, { "Data", "ecmp.data.uint8", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3387 { &hf_ecmp_data_int16, { "Data", "ecmp.data.int16", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3388 { &hf_ecmp_data_uint16, { "Data", "ecmp.data.uint16", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3389 { &hf_ecmp_data_int32, { "Data", "ecmp.data.int32", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3390 { &hf_ecmp_data_uint32, { "Data", "ecmp.data.uint32", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3391 { &hf_ecmp_data_int64, { "Data", "ecmp.data.int64", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3392 { &hf_ecmp_data_uint64, { "Data", "ecmp.data.uint64", FT_UINT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3393 { &hf_ecmp_data_float, { "Data", "ecmp.data.float", FT_FLOAT, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3394 { &hf_ecmp_data_double, { "Data", "ecmp.data.double", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3395 { &hf_ecmp_access_mode, { "Access Mode", "ecmp.access_mode", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL }},
3396 { &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 }},
3397 { &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 }},
3398 { &hf_ecmp_file_access_mode, { "File Access Mode", "ecmp.file_access_mode", FT_UINT8, BASE_DEC, VALS(file_status_mode), 0x0F, NULL, HFILL }},
3399 { &hf_ecmp_additional_scheme, { "Additional Scheme", "ecmp.additional_scheme", FT_UINT8, BASE_DEC, VALS(additional_scheme_vals), 0x0, NULL, HFILL }},
3400 { &hf_ecmp_scheme_data_length, { "Length", "ecmp.scheme_data_length", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3401 { &hf_ecmp_number_of_requested_bytes, { "Number of requested bytes", "ecmp.number_of_requested_bytes", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3402 { &hf_ecmp_number_of_bytes_transferred, { "Number of bytes transferred", "ecmp.number_of_bytes_transferred", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3403 { &hf_ecmp_crc, { "CRC", "ecmp.crc", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3404 { &hf_ecmp_ref_offset, { "Offset", "ecmp.ref_offset", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3405 { &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 }},
3406 { &hf_ecmp_file_hash, { "Hash", "ecmp.file_hash", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3407 { &hf_ecmp_item_type, { "Item type", "ecmp.item_type", FT_UINT8, BASE_DEC, VALS(item_type_vals), 0x0, NULL, HFILL }},
3408 { &hf_ecmp_file_integrity, { "File Integrity", "ecmp.file_integrity", FT_BOOLEAN, 8, TFS(&tfs_ok_error), 0x01, NULL, HFILL }},
3409 { &hf_ecmp_display_attr_read_only, { "Read Only", "ecmp.display_attr.read_only", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL }},
3410 { &hf_ecmp_display_attr_hidden, { "Hidden", "ecmp.display_attr.hidden", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL }},
3411 { &hf_ecmp_display_attr_system, { "System", "ecmp.display_attr.system", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL }},
3412 { &hf_ecmp_display_attr_volume_label, { "Volume Label", "ecmp.display_attr.volume_label", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL }},
3413 { &hf_ecmp_display_attr_subdirectory, { "Subdirectory", "ecmp.display_attr.subdirectory", FT_BOOLEAN, 8, NULL, 0x10, NULL, HFILL }},
3414 { &hf_ecmp_display_attr_archive, { "Archive", "ecmp.display_attr.archive", FT_BOOLEAN, 8, NULL, 0x20, NULL, HFILL }},
3415 { &hf_ecmp_display_creation, { "Display creation", "ecmp.display_creation", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3416 { &hf_ecmp_display_modification, { "Display modification", "ecmp.display_modification", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3417 { &hf_ecmp_interrogate_item_type, { "Item Type", "ecmp.interrogate_item_type", FT_UINT8, BASE_DEC, VALS(Interrogate_command_option_state), 0x0, NULL, HFILL }},
3418 { &hf_ecmp_interrogate_count, { "Count", "ecmp.interrogate_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3419 { &hf_ecmp_modbus_pdu_size, { "Size", "ecmp.modbus_pdu_size", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3420 #if 0
3421 { &hf_ecmp_destination_scheme, { "Destination Scheme", "ecmp.destination_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3422 #endif
3423 { &hf_ecmp_program_control_target, { "Target", "ecmp.program_control_target", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3424 { &hf_ecmp_program_control_command, { "Command", "ecmp.program_control_command", FT_UINT8, BASE_DEC, VALS(command_code_list), 0x0, NULL, HFILL }},
3425 { &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 }},
3426 { &hf_ecmp_program_control_status, { "Status", "ecmp.program_control_status", FT_UINT8, BASE_DEC, VALS(status_list), 0x0, NULL, HFILL }},
3427 { &hf_ecmp_program_status_target, { "Target", "ecmp.program_status_target", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3428 { &hf_ecmp_program_status_status, { "Status", "ecmp.program_status_status", FT_UINT8, BASE_DEC, VALS(running_state_list), 0x0, NULL, HFILL }},
3429 { &hf_ecmp_program_status_additional_items, { "Additional Items", "ecmp.program_status_additional_items", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3430 { &hf_ecmp_cyclic_setup_max_mappings, { "Max Mappings", "ecmp.cyclic_setup.max_mappings", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3431 { &hf_ecmp_cyclic_setup_start_offset, { "Start Offset", "ecmp.cyclic_setup.start_offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3432 { &hf_ecmp_cyclic_setup_tx_count, { "Tx Count", "ecmp.cyclic_setup.tx_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3433 { &hf_ecmp_cyclic_setup_rx_count, { "Rx Count", "ecmp.cyclic_setup.rx_count", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3434 { &hf_ecmp_udp_alignment, { "Alignment", "ecmp.udp_alignment", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3435 { &hf_ecmp_udp_scheme, { "Scheme", "ecmp.udp_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3436 { &hf_ecmp_cyclic_data, { "Cyclic Data", "ecmp.cyclic_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3437 { &hf_ecmp_version_summary, { "Version summary", "ecmp.version_summary", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3438 { &hf_ecmp_min_param_menu, { "Min parameter in menu", "ecmp.min_param_menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3439 { &hf_ecmp_max_param_menu, { "Max parameter in menu", "ecmp.max_param_menu", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3440 { &hf_ecmp_file_length, { "File length", "ecmp.file_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3441 { &hf_ecmp_mec_offset, { "mec_offset", "ecmp.mec_offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3442 { &hf_ecmp_sample_period, { "Sample period", "ecmp.sample_period", FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3443 { &hf_ecmp_rx_timeout, { "RX Timeout", "ecmp.rx_timeout", FT_UINT32, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microseconds), 0x0, NULL, HFILL }},
3444 { &hf_ecmp_rx_action, { "Action", "ecmp.rx_action", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3445 { &hf_ecmp_rx_event_destination, { "Event Destination", "ecmp.rx_event_destination", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3446 { &hf_ecmp_rx_event, { "Event", "ecmp.rx_event", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3447 { &hf_ecmp_rx_late_handler_action, { "Action", "ecmp.rx_late_handler_action", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3448 { &hf_ecmp_rx_late_handler_event_destination, { "Event Destination", "ecmp.rx_late_handler_event_destination", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3449 { &hf_ecmp_rx_late_handler_event, { "Event", "ecmp.rx_late_handler_event", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3450 { &hf_ecmp_transport_addr_scheme, { "Scheme", "ecmp.transport_addr_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3451 { &hf_ecmp_transport_addr, { "Transport address", "ecmp.transport_addr", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
3452 { &hf_ecmp_mapping_item_offset, { "Offset", "ecmp.mapping_item_offset", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3453 { &hf_ecmp_mapping_item_scheme, { "Scheme", "ecmp.mapping_item_scheme", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3454 { &hf_ecmp_setup_attribute, { "Attribute", "ecmp.setup_attribute", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3455 { &hf_ecmp_mec_period, { "mec period", "ecmp.mec_period", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
3456 { &hf_ecmp_interrogate_command, { "Command", "ecmp.interrogate_command", FT_UINT8, BASE_DEC, VALS(command_vals), 0x0, NULL, HFILL }}
3459 /* array to store pointers to the ids of the subtrees that we may be creating */
3460 static int *ett[] = {
3461 &ett_ecmp,
3462 &ett_ecmp_address,
3463 &ett_ecmp_response_size,
3464 &ett_ecmp_command,
3465 &ett_ecmp_category,
3466 &ett_ecmp_option,
3467 &ett_ecmp_option_data,
3468 &ett_ecmp_attribute,
3469 &ett_ecmp_attribute_data,
3470 &ett_ecmp_cyclic_scheme,
3471 &ett_ecmp_interrogate_message,
3472 &ett_ecmp_info_type,
3473 &ett_ecmp_info_count,
3474 &ett_ecmp_param_address,
3475 &ett_ecmp_access_mode,
3476 &ett_ecmp_access_file,
3477 &ett_ecmp_file_read,
3478 &ett_ecmp_file_write,
3479 &ett_ecmp_file_info,
3480 &ett_ecmp_file_info_att,
3481 &ett_ecmp_file_position,
3482 &ett_ecmp_file_list_no,
3483 &ett_ecmp_file_list,
3484 &ett_ecmp_tunnel_3s_goodframe,
3485 &ett_ecmp_tunnel_3s_size,
3486 &ett_ecmp_tunnel_3s_service,
3487 &ett_cyclic_setup_attribs,
3488 &ett_cyclic_setup_transport_addr,
3489 &ett_cyclic_setup_attrib_item,
3490 &ett_ecmp_cyclic_data_32_bit_display,
3491 &ett_ecmp_cyclic_data_16_bit_display,
3492 &ett_ecmp_cyclic_data_8_bit_display,
3493 &ett_ecmp_modbus_pdu_message,
3494 &ett_ecmp_program_control_message,
3495 &ett_ecmp_program_status_message
3498 static ei_register_info ei[] = {
3499 { &ei_ecmp_unknown_command, { "ecmp.unknown_command", PI_PROTOCOL, PI_WARN, "Unknown Command", EXPFILL }},
3500 { &ei_ecmp_color, { "ecmp.color_invalid", PI_PROTOCOL, PI_WARN, "Invalid color data value", EXPFILL }},
3501 { &ei_ecmp_option, { "ecmp.ecmp_option.unknown", PI_PROTOCOL, PI_WARN, "ERROR - Unrecognised Option Code", EXPFILL }},
3502 { &ei_ecmp_data_type, { "ecmp.data_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown Data Type", EXPFILL }},
3503 { &ei_ecmp_parameter_addressing_scheme, { "ecmp.incorrect_parameter_addressing_scheme", PI_PROTOCOL, PI_WARN, "Incorrect parameter addressing scheme", EXPFILL }},
3504 { &ei_ecmp_info_type, { "ecmp.info_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown info type", EXPFILL }},
3505 { &ei_ecmp_attribute_type, { "ecmp.attribute_type.unknown", PI_PROTOCOL, PI_WARN, "Wrong attribute type", EXPFILL }},
3506 { &ei_ecmp_item_type, { "ecmp.item_type.unknown", PI_PROTOCOL, PI_WARN, "Unknown item type", EXPFILL }},
3507 { &ei_ecmp_options_not_implemented, { "ecmp.options_not_implemented", PI_UNDECODED, PI_WARN, "ECMP Options Not Implemented", EXPFILL }}
3510 expert_module_t* expert_ecmp;
3512 proto_ecmp = proto_register_protocol ("ECMP", PROTO_TAG_ECMP, "ecmp");
3513 ecmp_tcp_handle = register_dissector("ecmp_tcp", dissect_ecmp_tcp, proto_ecmp);
3514 ecmp_udp_handle = register_dissector("ecmp_udp", dissect_ecmp_udp, proto_ecmp);
3517 /* full name short name and abbreviation (display filter name)*/
3518 proto_register_field_array(proto_ecmp, hf, array_length (hf));
3519 proto_register_subtree_array (ett, array_length (ett));
3520 expert_ecmp = expert_register_protocol(proto_ecmp);
3521 expert_register_field_array(expert_ecmp, ei, array_length(ei));
3524 /* Function to initialise the dissector*/
3525 /* Wireshark literally scans this file (packet-ecmp.c) to find this function */
3526 void proto_reg_handoff_ecmp(void)
3528 /* Cyclic frames are over UDP and non-cyclic are over TCP */
3529 dissector_add_uint_with_preference("udp.port", ECMP_TCP_PORT, ecmp_udp_handle);
3530 dissector_add_uint_with_preference("tcp.port", ECMP_TCP_PORT, ecmp_tcp_handle);
3532 /* Modbus dissector hooks */
3533 modbus_handle = find_dissector_add_dependency("modbus", proto_ecmp);
3534 proto_modbus = proto_get_id_by_filter_name( "modbus" );
3539 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3541 * Local variables:
3542 * c-basic-offset: 8
3543 * tab-width: 8
3544 * indent-tabs-mode: t
3545 * End:
3547 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
3548 * :indentSize=8:tabSize=8:noTabs=false: