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