As the gtk2 directory is no longer needed (GTK1 and 2 are using the same sources...
[obnox/wireshark/wip.git] / epan / dissectors / packet-mbtcp.c
1 /* packet-mbtcp.c
2  * Routines for Modbus/TCP dissection
3  * By Riaan Swart <rswart@cs.sun.ac.za>
4  * Copyright 2001, Institute for Applied Computer Science
5  *                                       University of Stellenbosch
6  *
7  * See
8  *
9  *      http://www.modicon.com/openmbus/
10  *
11  * for information on Modbus/TCP.
12  *
13  * $Id$
14  *
15  * Ethereal - Network traffic analyzer
16  * By Gerald Combs <gerald@ethereal.com>
17  * Copyright 1998 Gerald Combs
18  *
19  * This program is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU General Public License
21  * as published by the Free Software Foundation; either version 2
22  * of the License, or (at your option) any later version.
23  *
24  * This program is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27  * GNU General Public License for more details.
28  *
29  * You should have received a copy of the GNU General Public License
30  * along with this program; if not, write to the Free Software
31  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32  */
33
34 #ifdef HAVE_CONFIG_H
35 # include "config.h"
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include <glib.h>
43
44 #include <epan/packet.h>
45
46 #define DEBUG
47
48 #define TCP_PORT_MBTCP          502     /* Modbus/TCP located on TCP port 502 */
49
50 /* Modbus protocol function codes */
51 #define read_coils              1
52 #define read_input_discretes    2
53 #define read_mult_regs          3
54 #define read_input_regs         4
55 #define write_coil              5
56 #define write_single_reg        6
57 #define read_except_stat        7
58 #define diagnostics             8
59 #define program_484             9
60 #define poll_484                10
61 #define get_comm_event_ctrs     11
62 #define get_comm_event_log      12
63 #define program_584_984         13
64 #define poll_584_984            14
65 #define force_mult_coils        15
66 #define write_mult_regs         16
67 #define report_slave_id         17
68 #define program_884_u84         18
69 #define reset_comm_link         19
70 #define read_genl_ref           20
71 #define write_genl_ref          21
72 #define mask_write_reg          22
73 #define read_write_reg          23
74 #define read_fifo_queue         24
75 #define program_ConCept         40
76 #define firmware_replace        125
77 #define program_584_984_2       126
78 #define report_local_addr_mb    127
79
80 /* Modbus protocol exception codes */
81 #define illegal_function        0x01
82 #define illegal_address         0x02
83 #define illegal_value           0x03
84 #define illegal_response        0x04
85 #define acknowledge             0x05
86 #define slave_busy              0x06
87 #define negative_ack            0x07
88 #define memory_err              0x08
89 #define gateway_unavailable     0x0a
90 #define gateway_trgt_fail       0x0b
91
92 /* return codes of function classifying packets as query/response */
93 #define query_packet            0
94 #define response_packet         1
95 #define cannot_classify         2
96
97 /* Modbus header */
98 typedef struct _modbus_hdr {
99         guint8  unit_id;        /* unit identifier (previously slave addr) */
100         guint8  function_code;  /* Modbus function code */
101 } modbus_hdr;
102
103 /* Modbus/TCP header, containing the Modbus header */
104 typedef struct _mbtcp_hdr {
105         guint16         transaction_id;         /* copied by svr, usually 0 */
106         guint16         protocol_id;            /* always 0 */
107         guint16         len;                    /* len of data that follows */
108         modbus_hdr      mdbs_hdr;               /* mdbus hdr directly after mdbs/tcp hdr *
109                                                  * in packet */
110 } mbtcp_hdr;
111
112 /* Initialize the protocol and registered fields */
113 static int proto_mbtcp = -1;
114 static int hf_mbtcp_transid = -1;
115 static int hf_mbtcp_protid = -1;
116 static int hf_mbtcp_len = -1;
117 static int hf_mbtcp_unitid = -1;
118 static int hf_mbtcp_functioncode = -1;
119 static int hf_modbus_reference = -1;
120 static int hf_modbus_lreference = -1;
121 static int hf_modbus_reftype = -1;
122 static int hf_modbus_readref = -1;
123 static int hf_modbus_writeref = -1;
124 static int hf_modbus_wordcnt = -1;
125 static int hf_modbus_readwordcnt = -1;
126 static int hf_modbus_writewordcnt = -1;
127 static int hf_modbus_bytecnt = -1;
128 static int hf_modbus_lbytecnt = -1;
129 static int hf_modbus_bitcnt = -1;
130 static int hf_modbus_exceptioncode = -1;
131 static int hf_modbus_andmask = -1;
132 static int hf_modbus_ormask = -1;
133
134 /* Initialize the subtree pointers */
135 static gint ett_mbtcp = -1;
136 static gint ett_modbus_hdr = -1;
137 static gint ett_group_hdr = -1;
138
139 static int
140 classify_packet(packet_info *pinfo)
141 {
142         /* see if nature of packets can be derived from src/dst ports */
143         /* if so, return as found */
144         if ( ( 502 == pinfo->srcport && 502 != pinfo->destport ) ||
145                  ( 502 != pinfo->srcport && 502 == pinfo->destport ) ) {
146                 /* the slave is receiving queries on port 502 */
147                 if ( 502 == pinfo->srcport )
148                         return response_packet;
149                 else if ( 502 == pinfo->destport )
150                         return query_packet;
151         }
152         /* else, cannot classify */
153         return cannot_classify;
154 }
155
156 /* Translate function to string, as given on p6 of
157  * "Open Modbus/TCP Specification", release 1 by Andy Swales. */
158 static const value_string function_code_vals[] = {
159         { read_coils,                   "Read coils" },
160         { read_input_discretes,         "Read input discretes" },
161         { read_mult_regs,               "Read multiple registers" },
162         { read_input_regs,              "Read input registers" },
163         { write_coil,                   "Write coil" },
164         { write_single_reg,             "Write single register" },
165         { read_except_stat,             "Read exception status" },
166         { diagnostics,                  "Diagnostics" },
167         { program_484,                  "Program (484)" },
168         { poll_484,                     "Poll (484)" },
169         { get_comm_event_ctrs,          "Get Comm. Event Counters" },
170         { get_comm_event_log,           "Get Comm. Event Log" },
171         { program_584_984,              "Program (584/984)" },
172         { poll_584_984,                 "Poll (584/984)" },
173         { force_mult_coils,             "Force Multiple Coils" },
174         { write_mult_regs,              "Write Multiple Registers" },
175         { report_slave_id,              "Report Slave ID" },
176         { program_884_u84,              "Program 884/u84" },
177         { reset_comm_link,              "Reset Comm. Link (884/u84)" },
178         { read_genl_ref,                "Read General Reference" },
179         { write_genl_ref,               "Write General Reference" },
180         { mask_write_reg,               "Mask Write Register" },
181         { read_write_reg,               "Read Write Register" },
182         { read_fifo_queue,              "Read FIFO Queue" },
183         { program_ConCept,              "Program (ConCept)" },
184         { firmware_replace,             "Firmware replacement" },
185         { program_584_984_2,            "Program (584/984)" },
186         { report_local_addr_mb,         "Report local address (Modbus)" },
187         { 0,                            NULL }
188 };
189
190 static const value_string exception_code_vals[] = {
191         { illegal_function,     "Illegal function" },
192         { illegal_address,      "Illegal data address" },
193         { illegal_value,        "Illegal data value" },
194         { illegal_response,     "Illegal response length" },
195         { acknowledge,          "Acknowledge" },
196         { slave_busy,           "Slave device busy" },
197         { negative_ack,         "Negative acknowledge" },
198         { memory_err,           "Memory parity error" },
199         { gateway_unavailable,  "Gateway path unavailable" },
200         { gateway_trgt_fail,    "Gateway target device failed to respond" },
201         { 0,                    NULL }
202 };
203
204 /* Code to actually dissect the packets */
205 static void
206 dissect_mbtcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
207 {
208 /* Set up structures needed to add the protocol subtree and manage it */
209         mbtcp_hdr       mh;
210         proto_item      *mi, *mf;
211         proto_tree      *mbtcp_tree, *modbus_tree, *group_tree;
212         int             offset, group_offset, packet_type;
213         guint           i;
214         gint            packet_len, payload_start, payload_len;
215         char            *func_string = "", pkt_type_str[9] = "";
216         char            err_str[100] = "";
217         guint32         byte_cnt, group_byte_cnt, group_word_cnt;
218         guint32         packet_num;     /* num to uniquely identify different mbtcp
219                                          * packets in one TCP packet */
220         guint8          exception_code;
221         gboolean        exception_returned;
222
223 /* Make entries in Protocol column on summary display */
224         if (check_col(pinfo->cinfo, COL_PROTOCOL))
225                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Modbus/TCP");
226
227         if (check_col(pinfo->cinfo, COL_INFO))
228                 col_clear(pinfo->cinfo, COL_INFO);
229
230 /* Make entries in Info column on summary display */
231         offset = 0;
232         tvb_memcpy(tvb, (guint8 *)&mh, offset, sizeof(mbtcp_hdr));
233         mh.transaction_id                               =       g_ntohs(mh.transaction_id);
234         mh.protocol_id                                  =       g_ntohs(mh.protocol_id);
235         mh.len                                                  =       g_ntohs(mh.len);
236         if ( mh.mdbs_hdr.function_code & 0x80 ) {
237                 exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr));
238                 mh.mdbs_hdr.function_code ^= 0x80;
239                 exception_returned = TRUE;
240         }
241         else {
242                 exception_code = 0;
243                 exception_returned = FALSE;
244         }
245         func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals,
246             "Unknown function (%u)");
247         if (check_col(pinfo->cinfo, COL_INFO))
248         {
249                 packet_type = classify_packet(pinfo);
250                 switch ( packet_type ) {
251                         case query_packet :             strcpy(pkt_type_str, "query");
252                                                                                                 break;
253                         case response_packet :  strcpy(pkt_type_str, "response");
254                                                                                                 break;
255                         case cannot_classify :          strcpy(err_str, "Unable to classify as query or response.");
256                                                                                 strcpy(pkt_type_str, "unknown");
257                                                                                                 break;
258                         default :
259                                                                                                 break;
260                 }
261                 if ( exception_returned )
262                         strcpy(err_str, "Exception returned ");
263                 col_add_fstr(pinfo->cinfo, COL_INFO,
264                                 "%8s [%2u pkt(s)]: trans: %5u; unit: %3u, func: %3u: %s. %s",
265                                 pkt_type_str, 1, mh.transaction_id, (unsigned char) mh.mdbs_hdr.unit_id,
266                                 (unsigned char) mh.mdbs_hdr.function_code, func_string, err_str);
267         }
268
269         /* build up protocol tree and iterate over multiple packets */
270         packet_num = 0;
271         while (1) {
272                 packet_type = classify_packet(pinfo);
273                 packet_len = sizeof(mbtcp_hdr) - sizeof(modbus_hdr) + mh.len;
274
275                 /* if a tree exists, perform operations to add fields to it */
276                 if (tree) {
277                         mi = proto_tree_add_protocol_format(tree, proto_mbtcp, tvb, offset,
278                                         packet_len, "Modbus/TCP");
279                         mbtcp_tree = proto_item_add_subtree(mi, ett_mbtcp);
280
281                         /* Add items to protocol tree specific to Modbus/TCP Modbus/TCP */
282                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_transid, tvb, offset, 2,
283                                         mh.transaction_id);
284                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_protid, tvb, offset + 2, 2,
285                                         mh.protocol_id);
286                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_len, tvb, offset + 4, 2,
287                                         mh.len);
288                                         
289                         /* Add items to protocol tree specific to Modbus generic */
290                         mf = proto_tree_add_text(mbtcp_tree, tvb, offset + 6, mh.len,
291                                         "Modbus");
292                         modbus_tree = proto_item_add_subtree(mf, ett_modbus_hdr);
293                         proto_tree_add_uint(modbus_tree, hf_mbtcp_unitid, tvb, offset + 6, 1,
294                                         mh.mdbs_hdr.unit_id);
295                         mi = proto_tree_add_uint(modbus_tree, hf_mbtcp_functioncode, tvb, offset + 7, 1,
296                                         mh.mdbs_hdr.function_code);
297                                         
298                         /** detail payload as a function of exception/function code */
299                         func_string = val_to_str(mh.mdbs_hdr.function_code,
300                             function_code_vals, "Unknown function");
301                         payload_start = offset + 8;
302                         payload_len = mh.len - sizeof(modbus_hdr);
303                         if (exception_returned) {
304                                 proto_item_set_text(mi, "function %u:  %s.  Exception: %s",
305                                                 mh.mdbs_hdr.function_code,
306                                                 func_string,
307                                                 val_to_str(exception_code,
308                                                     exception_code_vals,
309                                                     "Unknown exception code (%u)"));
310                                 proto_tree_add_uint(modbus_tree, hf_modbus_exceptioncode, tvb, payload_start, 1,
311                                                 exception_code);
312                         }
313                         else {
314                                 proto_item_set_text(mi, "function %u:  %s", mh.mdbs_hdr.function_code,
315                                                 func_string);
316                                 switch (mh.mdbs_hdr.function_code) {
317                                         
318                                         case read_coils:                        
319                                         case read_input_discretes:      
320                                                 if (packet_type == query_packet) {
321                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
322                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
323                                                 }
324                                                 else if (packet_type == response_packet) {
325                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
326                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
327                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
328                                                 }
329                                                 break;
330                                                 
331                                         case read_mult_regs:            
332                                         case read_input_regs:           
333                                                 if (packet_type == query_packet) {
334                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
335                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
336                                                 }
337                                                 else if (packet_type == response_packet) {
338                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
339                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
340                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
341                                                 }
342                                                 break;
343                                                 
344                                         case write_coil:                        
345                                                 if (packet_type == query_packet) {
346                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
347                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data");
348                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding");
349                                                 }
350                                                 else if (packet_type == response_packet) {
351                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
352                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data");
353                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding");
354                                                 }
355                                                 break;
356                                                 
357                                         case write_single_reg:          
358                                                 if (packet_type == query_packet) {
359                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
360                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data");
361                                                 }
362                                                 else if (packet_type == response_packet) {
363                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
364                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data");
365                                                 }
366                                                 break;
367                                                 
368                                         case read_except_stat:          
369                                                 if (packet_type == response_packet)
370                                                         proto_tree_add_text(modbus_tree, tvb, payload_start, 1, "Data");
371                                                 break;
372                                                 
373                                         case force_mult_coils:          
374                                                 if (packet_type == query_packet) {
375                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
376                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
377                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
378                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1,
379                                                                         byte_cnt);
380                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data");
381                                                 }
382                                                 else if (packet_type == response_packet) {
383                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
384                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
385                                                 }
386                                                 break;
387                                                 
388                                         case write_mult_regs:           
389                                                 if (packet_type == query_packet) {
390                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
391                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
392                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
393                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1,
394                                                                         byte_cnt);
395                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data");
396                                                 }
397                                                 else if (packet_type == response_packet) {
398                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
399                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
400                                                 }
401                                                 break;
402                                                 
403                                         case read_genl_ref:                     
404                                                 if (packet_type == query_packet) {
405                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
406                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
407                                                                         byte_cnt);
408                                                                         
409                                                         /* add subtrees to describe each group of packet */
410                                                         group_offset = payload_start + 1;
411                                                         for (i = 0; i < byte_cnt / 7; i++) {
412                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 7,
413                                                                                 "Group %u", i);
414                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
415                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE);
416                                                                 proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE);
417                                                                 proto_tree_add_item(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, FALSE);
418                                                                 group_offset += 7;
419                                                         }
420                                                 }
421                                                 else if (packet_type == response_packet) {
422                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
423                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
424                                                                         byte_cnt);
425                                                                         
426                                                         /* add subtrees to describe each group of packet */
427                                                         group_offset = payload_start + 1;
428                                                         i = 0;
429                                                         while (byte_cnt > 0) {
430                                                                 group_byte_cnt = (guint32)tvb_get_guint8(tvb, group_offset);
431                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt + 1,
432                                                                                 "Group %u", i);
433                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
434                                                                 proto_tree_add_uint(group_tree, hf_modbus_bytecnt, tvb, group_offset, 1,
435                                                                                 group_byte_cnt);
436                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset + 1, 1, FALSE);
437                                                                 proto_tree_add_text(group_tree, tvb, group_offset + 2, group_byte_cnt - 1, "Data");
438                                                                 group_offset += (group_byte_cnt + 1);
439                                                                 byte_cnt -= (group_byte_cnt + 1);
440                                                                 i++;
441                                                         }
442                                                 }
443                                                 break;
444                                                 
445                                         case write_genl_ref:            
446                                                 if ((packet_type == query_packet) || (packet_type == response_packet)) {
447                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
448                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
449                                                                         byte_cnt);
450                                                                         
451                                                         /* add subtrees to describe each group of packet */
452                                                         group_offset = payload_start + 1;
453                                                         i = 0;
454                                                         while (byte_cnt > 0) {
455                                                                 group_word_cnt = tvb_get_ntohs(tvb, group_offset + 5);
456                                                                 group_byte_cnt = (2 * group_word_cnt) + 7;
457                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 
458                                                                                 group_byte_cnt, "Group %u", i);
459                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
460                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE);
461                                                                 proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE);
462                                                                 proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, 
463                                                                                 group_word_cnt);
464                                                                 proto_tree_add_text(group_tree, tvb, group_offset + 7, group_byte_cnt - 7, "Data");
465                                                                 group_offset += group_byte_cnt;
466                                                                 byte_cnt -= group_byte_cnt;
467                                                                 i++;
468                                                         }
469                                                 }
470                                                 break;
471                                                 
472                                         case mask_write_reg:            
473                                                 if ((packet_type == query_packet) || (packet_type == response_packet)) {
474                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
475                                                         proto_tree_add_item(modbus_tree, hf_modbus_andmask, tvb, payload_start + 2, 2, FALSE);
476                                                         proto_tree_add_item(modbus_tree, hf_modbus_ormask, tvb, payload_start + 4, 2, FALSE);
477                                                 }
478                                                 break;
479                                                 
480                                         case read_write_reg:            
481                                                 if (packet_type == query_packet) {
482                                                         proto_tree_add_item(modbus_tree, hf_modbus_readref, tvb, payload_start, 2, FALSE);
483                                                         proto_tree_add_item(modbus_tree, hf_modbus_readwordcnt, tvb, payload_start + 2, 2, FALSE);
484                                                         proto_tree_add_item(modbus_tree, hf_modbus_writeref, tvb, payload_start + 4, 2, FALSE);
485                                                         proto_tree_add_item(modbus_tree, hf_modbus_writewordcnt, tvb, payload_start + 6, 2, FALSE);
486                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 8);
487                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 8, 1,
488                                                                         byte_cnt);
489                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 9, byte_cnt, "Data");
490                                                 }
491                                                 else if (packet_type == response_packet) {
492                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
493                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
494                                                                         byte_cnt);
495                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
496                                                 }
497                                                 break;
498                                                 
499                                         case read_fifo_queue:           
500                                                 if (packet_type == query_packet)
501                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
502                                                 else if (packet_type == response_packet) {
503                                                         byte_cnt = (guint32)tvb_get_ntohs(tvb, payload_start);
504                                                         proto_tree_add_uint(modbus_tree, hf_modbus_lbytecnt, tvb, payload_start, 2,
505                                                                         byte_cnt);
506                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
507                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 4, byte_cnt - 2, "Data");
508                                                 }
509                                                 break;
510                                                 
511                                         case diagnostics:                       
512                                         case program_484:                       
513                                         case poll_484:                          
514                                         case get_comm_event_ctrs:       
515                                         case get_comm_event_log:        
516                                         case program_584_984:           
517                                         case poll_584_984:                      
518                                         case report_slave_id:           
519                                         case program_884_u84:           
520                                         case reset_comm_link:           
521                                         case program_ConCept:           
522                                         case firmware_replace:          
523                                         case program_584_984_2:         
524                                         case report_local_addr_mb:      
525                                                 /* these function codes are not part of the Modbus/TCP specification */
526                                         default:                                        
527                                                 if (payload_len > 0)
528                                                         proto_tree_add_text(modbus_tree, tvb, payload_start, payload_len, "Data");
529                                                 break;
530                                 }
531                         }
532                 }
533                 
534                 /* move onto next packet (if there) */
535                 offset += packet_len;
536                 packet_num++;
537                 if (tvb_reported_length_remaining(tvb, offset) > 0) {
538                         
539                         /* load header structure for next packet */
540                         tvb_memcpy(tvb, (guint8 *)&mh, offset, sizeof(mbtcp_hdr));
541                         mh.transaction_id                               =       g_ntohs(mh.transaction_id);
542                         mh.protocol_id                                  =       g_ntohs(mh.protocol_id);
543                         mh.len                                                  =       g_ntohs(mh.len);
544         
545                         if ( mh.mdbs_hdr.function_code & 0x80 ) {
546                                 exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr));
547                                 mh.mdbs_hdr.function_code ^= 0x80;
548                                 exception_returned = TRUE;
549                         } else
550                                 exception_returned = FALSE;
551                 }
552                 else
553                         break;
554         }
555 }
556
557
558 /* Register the protocol with Ethereal */
559
560 void
561 proto_register_modbus(void)
562 {
563
564 /* Setup list of header fields  See Section 1.6.1 for details*/
565         static hf_register_info hf[] = {
566                 /* Modbus/TCP header fields */
567                 { &hf_mbtcp_transid,
568                         { "transaction identifier",                     "modbus_tcp.trans_id",
569                         FT_UINT16, BASE_DEC, NULL, 0x0,
570                         "", HFILL }
571                 },
572                 { &hf_mbtcp_protid,
573                         { "protocol identifier",                        "modbus_tcp.prot_id",
574                         FT_UINT16, BASE_DEC, NULL, 0x0,
575                         "", HFILL }
576                 },
577                 { &hf_mbtcp_len,
578                         { "length",                                                     "modbus_tcp.len",
579                         FT_UINT16, BASE_DEC, NULL, 0x0,
580                         "", HFILL }
581                 },
582                 /* Modbus header fields */
583                 { &hf_mbtcp_unitid,
584                         { "unit identifier",                    "modbus_tcp.unit_id",
585                         FT_UINT8, BASE_DEC, NULL, 0x0,
586                         "", HFILL }
587                 },
588                 { &hf_mbtcp_functioncode,
589                         { "function code",                      "modbus_tcp.func_code",
590                         FT_UINT8, BASE_DEC, VALS(function_code_vals), 0x0,
591                         "", HFILL }
592                 },
593                 { &hf_modbus_reference,
594                         { "reference number",                   "modbus_tcp.reference_num",
595                         FT_UINT16, BASE_DEC, NULL, 0x0,
596                         "", HFILL }
597                 },
598                 { &hf_modbus_lreference,
599                         { "reference number (32 bit)",          "modbus_tcp.reference_num_32",
600                         FT_UINT32, BASE_DEC, NULL, 0x0,
601                         "", HFILL }
602                 },
603                 { &hf_modbus_reftype,
604                         { "reference type",                             "modbus_tcp.reference_type",
605                         FT_UINT8, BASE_DEC, NULL, 0x0,
606                         "", HFILL }
607                 },
608                 { &hf_modbus_readref,
609                         { "read reference number",              "modbus_tcp.read_reference_num",
610                         FT_UINT16, BASE_DEC, NULL, 0x0,
611                         "", HFILL }
612                 },
613                 { &hf_modbus_writeref,
614                         { "write reference number",             "modbus_tcp.write_reference_num",
615                         FT_UINT16, BASE_DEC, NULL, 0x0,
616                         "", HFILL }
617                 },
618                 { &hf_modbus_wordcnt,
619                         { "word count",                                 "modbus_tcp.word_cnt",
620                         FT_UINT16, BASE_DEC, NULL, 0x0,
621                         "", HFILL }
622                 },
623                 { &hf_modbus_readwordcnt,
624                         { "read word count",                            "modbus_tcp.read_word_cnt",
625                         FT_UINT16, BASE_DEC, NULL, 0x0,
626                         "", HFILL }
627                 },
628                 { &hf_modbus_writewordcnt,
629                         { "write word count",                   "modbus_tcp.write_word_cnt",
630                         FT_UINT16, BASE_DEC, NULL, 0x0,
631                         "", HFILL }
632                 },
633                 { &hf_modbus_bitcnt,
634                         { "bit count",                                  "modbus_tcp.bit_cnt",
635                         FT_UINT16, BASE_DEC, NULL, 0x0,
636                         "", HFILL }
637                 },
638                 { &hf_modbus_bytecnt,
639                         { "byte count",                                 "modbus_tcp.byte_cnt",
640                         FT_UINT8, BASE_DEC, NULL, 0x0,
641                         "", HFILL }
642                 },
643                 { &hf_modbus_lbytecnt,
644                         { "byte count (16-bit)",                        "modbus_tcp.byte_cnt_16",
645                         FT_UINT8, BASE_DEC, NULL, 0x0,
646                         "", HFILL }
647                 },
648                 { &hf_modbus_exceptioncode,
649                         { "exception code",                     "modbus_tcp.exception_code",
650                         FT_UINT8, BASE_DEC, VALS(exception_code_vals), 0x0,
651                         "", HFILL }
652                 },
653                 { &hf_modbus_andmask,
654                         { "AND mask",                                   "modbus_tcp.and_mask",
655                         FT_UINT16, BASE_HEX, NULL, 0x0,
656                         "", HFILL }
657                 },
658                 { &hf_modbus_ormask,
659                         { "OR mask",                                    "modbus_tcp.or_mask",
660                         FT_UINT16, BASE_HEX, NULL, 0x0,
661                         "", HFILL }
662                 }
663         };
664
665         /* Setup protocol subtree array */
666         static gint *ett[] = {
667                 &ett_mbtcp,
668                 &ett_modbus_hdr,
669                 &ett_group_hdr
670         };
671
672         /* Register the protocol name and description */
673         proto_mbtcp = proto_register_protocol("Modbus/TCP", "Modbus/TCP", "mbtcp");
674
675         /* Required function calls to register the header fields and subtrees used */
676         proto_register_field_array(proto_mbtcp, hf, array_length(hf));
677         proto_register_subtree_array(ett, array_length(ett));
678 }
679
680
681 /* If this dissector uses sub-dissector registration add a registration routine.
682    This format is required because a script is used to find these routines and
683    create the code that calls these routines.
684  */
685 void
686 proto_reg_handoff_mbtcp(void)
687 {
688         dissector_handle_t mbtcp_handle;
689
690         mbtcp_handle = create_dissector_handle(dissect_mbtcp, proto_mbtcp);
691         dissector_add("tcp.port", TCP_PORT_MBTCP, mbtcp_handle);
692 }