update to modbus/tcp
[metze/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 int
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         const char      *func_string = "";
216         char            *pkt_type_str = "";
217         char            *err_str = "";
218         guint32         byte_cnt, group_byte_cnt, group_word_cnt;
219         guint32         packet_num;     /* num to uniquely identify different mbtcp
220                                          * packets in one TCP packet */
221         guint8          exception_code;
222         gboolean        exception_returned;
223         guint8          fc;
224
225         mh.transaction_id = tvb_get_ntohs(tvb, 0);
226         mh.protocol_id = tvb_get_ntohs(tvb, 2);
227         mh.len = tvb_get_ntohs(tvb, 4);
228         mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, 6);
229         mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, 7);
230
231
232         /* check that it actually looks like Modbus/TCP */
233         /* protocol id == 0 */
234         if( mh.protocol_id != 0 ){
235                 return 0;
236         }
237         /* length is at least 2 (unit_id + function_code) */
238         if( mh.len < 2 ){
239                 return 0;
240         }
241         /* function code is in the set 1-24, 40, 125-127.
242          * Note that function code is only 7 bits.
243          */
244         fc=mh.mdbs_hdr.function_code&0x7f;
245         if( (fc<1)
246           ||(fc>127)
247           ||((fc>24)&&(fc<40))
248           ||((fc>40)&&(fc<125)) ){
249                 return 0;
250         }
251
252
253         /* Make entries in Protocol column on summary display */
254         if (check_col(pinfo->cinfo, COL_PROTOCOL))
255                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Modbus/TCP");
256
257         if (check_col(pinfo->cinfo, COL_INFO))
258                 col_clear(pinfo->cinfo, COL_INFO);
259
260
261         /* Make entries in Info column on summary display */
262         offset = 0;
263
264         if ( mh.mdbs_hdr.function_code & 0x80 ) {
265                 exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr));
266                 mh.mdbs_hdr.function_code ^= 0x80;
267                 exception_returned = TRUE;
268         }
269         else {
270                 exception_code = 0;
271                 exception_returned = FALSE;
272         }
273         func_string = val_to_str(mh.mdbs_hdr.function_code, function_code_vals,
274             "Unknown function (%u)");
275         if (check_col(pinfo->cinfo, COL_INFO))
276         {
277                 packet_type = classify_packet(pinfo);
278                 switch ( packet_type ) {
279                         case QUERY_PACKET :             pkt_type_str="query";
280                                                                                                 break;
281                         case RESPONSE_PACKET :  pkt_type_str="response";
282                                                                                                 break;
283                         case CANNOT_CLASSIFY :          err_str="Unable to classify as query or response.";
284                                                                                 pkt_type_str="unknown";
285                                                                                                 break;
286                         default :
287                                                                                                 break;
288                 }
289                 if ( exception_returned )
290                         err_str="Exception returned ";
291                 col_add_fstr(pinfo->cinfo, COL_INFO,
292                                 "%8s [%2u pkt(s)]: trans: %5u; unit: %3u, func: %3u: %s. %s",
293                                 pkt_type_str, 1, mh.transaction_id, (unsigned char) mh.mdbs_hdr.unit_id,
294                                 (unsigned char) mh.mdbs_hdr.function_code, func_string, err_str);
295         }
296
297         /* build up protocol tree and iterate over multiple packets */
298         packet_num = 0;
299         while (1) {
300                 packet_type = classify_packet(pinfo);
301                 packet_len = sizeof(mbtcp_hdr) - sizeof(modbus_hdr) + mh.len;
302
303                 /* if a tree exists, perform operations to add fields to it */
304                 if (tree) {
305                         mi = proto_tree_add_protocol_format(tree, proto_mbtcp, tvb, offset,
306                                         packet_len, "Modbus/TCP");
307                         mbtcp_tree = proto_item_add_subtree(mi, ett_mbtcp);
308
309                         /* Add items to protocol tree specific to Modbus/TCP Modbus/TCP */
310                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_transid, tvb, offset, 2,
311                                         mh.transaction_id);
312                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_protid, tvb, offset + 2, 2,
313                                         mh.protocol_id);
314                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_len, tvb, offset + 4, 2,
315                                         mh.len);
316                                         
317                         proto_tree_add_uint(mbtcp_tree, hf_mbtcp_unitid, tvb, offset + 6, 1,
318                                         mh.mdbs_hdr.unit_id);
319
320
321                         /* Add items to protocol tree specific to Modbus generic */
322                         mf = proto_tree_add_text(mbtcp_tree, tvb, offset + 6, mh.len,
323                                         "Modbus");
324                         modbus_tree = proto_item_add_subtree(mf, ett_modbus_hdr);
325                         mi = proto_tree_add_uint(modbus_tree, hf_mbtcp_functioncode, tvb, offset + 7, 1,
326                                         mh.mdbs_hdr.function_code);
327                                         
328                         /** detail payload as a function of exception/function code */
329                         func_string = val_to_str(mh.mdbs_hdr.function_code,
330                             function_code_vals, "Unknown function");
331                         payload_start = offset + 8;
332                         payload_len = mh.len - sizeof(modbus_hdr);
333                         if (exception_returned) {
334                                 proto_item_set_text(mi, "function %u:  %s.  Exception: %s",
335                                                 mh.mdbs_hdr.function_code,
336                                                 func_string,
337                                                 val_to_str(exception_code,
338                                                     exception_code_vals,
339                                                     "Unknown exception code (%u)"));
340                                 proto_tree_add_uint(modbus_tree, hf_modbus_exceptioncode, tvb, payload_start, 1,
341                                                 exception_code);
342                         }
343                         else {
344                                 proto_item_set_text(mi, "function %u:  %s", mh.mdbs_hdr.function_code,
345                                                 func_string);
346                                 switch (mh.mdbs_hdr.function_code) {
347                                         
348                                         case READ_COILS:                        
349                                         case READ_INPUT_DISCRETES:      
350                                                 if (packet_type == QUERY_PACKET) {
351                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
352                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
353                                                 }
354                                                 else if (packet_type == RESPONSE_PACKET) {
355                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
356                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
357                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
358                                                 }
359                                                 break;
360                                                 
361                                         case READ_MULT_REGS:            
362                                         case READ_INPUT_REGS:           
363                                                 if (packet_type == QUERY_PACKET) {
364                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
365                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
366                                                 }
367                                                 else if (packet_type == RESPONSE_PACKET) {
368                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
369                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1, byte_cnt);
370                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
371                                                 }
372                                                 break;
373                                                 
374                                         case WRITE_COIL:                        
375                                                 if (packet_type == QUERY_PACKET) {
376                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
377                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data");
378                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding");
379                                                 }
380                                                 else if (packet_type == RESPONSE_PACKET) {
381                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
382                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 1, "Data");
383                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 3, 1, "Padding");
384                                                 }
385                                                 break;
386                                                 
387                                         case WRITE_SINGLE_REG:          
388                                                 if (packet_type == QUERY_PACKET) {
389                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
390                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data");
391                                                 }
392                                                 else if (packet_type == RESPONSE_PACKET) {
393                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
394                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 2, 2, "Data");
395                                                 }
396                                                 break;
397                                                 
398                                         case READ_EXCEPT_STAT:          
399                                                 if (packet_type == RESPONSE_PACKET)
400                                                         proto_tree_add_text(modbus_tree, tvb, payload_start, 1, "Data");
401                                                 break;
402                                                 
403                                         case FORCE_MULT_COILS:          
404                                                 if (packet_type == QUERY_PACKET) {
405                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
406                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
407                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
408                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1,
409                                                                         byte_cnt);
410                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data");
411                                                 }
412                                                 else if (packet_type == RESPONSE_PACKET) {
413                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
414                                                         proto_tree_add_item(modbus_tree, hf_modbus_bitcnt, tvb, payload_start + 2, 2, FALSE);
415                                                 }
416                                                 break;
417                                                 
418                                         case WRITE_MULT_REGS:           
419                                                 if (packet_type == QUERY_PACKET) {
420                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
421                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
422                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 4);
423                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 4, 1,
424                                                                         byte_cnt);
425                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 5, byte_cnt, "Data");
426                                                 }
427                                                 else if (packet_type == RESPONSE_PACKET) {
428                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
429                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
430                                                 }
431                                                 break;
432                                                 
433                                         case READ_GENL_REF:                     
434                                                 if (packet_type == QUERY_PACKET) {
435                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
436                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
437                                                                         byte_cnt);
438                                                                         
439                                                         /* add subtrees to describe each group of packet */
440                                                         group_offset = payload_start + 1;
441                                                         for (i = 0; i < byte_cnt / 7; i++) {
442                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 7,
443                                                                                 "Group %u", i);
444                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
445                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE);
446                                                                 proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE);
447                                                                 proto_tree_add_item(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, FALSE);
448                                                                 group_offset += 7;
449                                                         }
450                                                 }
451                                                 else if (packet_type == RESPONSE_PACKET) {
452                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
453                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
454                                                                         byte_cnt);
455                                                                         
456                                                         /* add subtrees to describe each group of packet */
457                                                         group_offset = payload_start + 1;
458                                                         i = 0;
459                                                         while (byte_cnt > 0) {
460                                                                 group_byte_cnt = (guint32)tvb_get_guint8(tvb, group_offset);
461                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, group_byte_cnt + 1,
462                                                                                 "Group %u", i);
463                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
464                                                                 proto_tree_add_uint(group_tree, hf_modbus_bytecnt, tvb, group_offset, 1,
465                                                                                 group_byte_cnt);
466                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset + 1, 1, FALSE);
467                                                                 proto_tree_add_text(group_tree, tvb, group_offset + 2, group_byte_cnt - 1, "Data");
468                                                                 group_offset += (group_byte_cnt + 1);
469                                                                 byte_cnt -= (group_byte_cnt + 1);
470                                                                 i++;
471                                                         }
472                                                 }
473                                                 break;
474                                                 
475                                         case WRITE_GENL_REF:            
476                                                 if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) {
477                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
478                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
479                                                                         byte_cnt);
480                                                                         
481                                                         /* add subtrees to describe each group of packet */
482                                                         group_offset = payload_start + 1;
483                                                         i = 0;
484                                                         while (byte_cnt > 0) {
485                                                                 group_word_cnt = tvb_get_ntohs(tvb, group_offset + 5);
486                                                                 group_byte_cnt = (2 * group_word_cnt) + 7;
487                                                                 mi = proto_tree_add_text( modbus_tree, tvb, group_offset, 
488                                                                                 group_byte_cnt, "Group %u", i);
489                                                                 group_tree = proto_item_add_subtree(mi, ett_group_hdr);
490                                                                 proto_tree_add_item(group_tree, hf_modbus_reftype, tvb, group_offset, 1, FALSE);
491                                                                 proto_tree_add_item(group_tree, hf_modbus_lreference, tvb, group_offset + 1, 4, FALSE);
492                                                                 proto_tree_add_uint(group_tree, hf_modbus_wordcnt, tvb, group_offset + 5, 2, 
493                                                                                 group_word_cnt);
494                                                                 proto_tree_add_text(group_tree, tvb, group_offset + 7, group_byte_cnt - 7, "Data");
495                                                                 group_offset += group_byte_cnt;
496                                                                 byte_cnt -= group_byte_cnt;
497                                                                 i++;
498                                                         }
499                                                 }
500                                                 break;
501                                                 
502                                         case MASK_WRITE_REG:            
503                                                 if ((packet_type == QUERY_PACKET) || (packet_type == RESPONSE_PACKET)) {
504                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
505                                                         proto_tree_add_item(modbus_tree, hf_modbus_andmask, tvb, payload_start + 2, 2, FALSE);
506                                                         proto_tree_add_item(modbus_tree, hf_modbus_ormask, tvb, payload_start + 4, 2, FALSE);
507                                                 }
508                                                 break;
509                                                 
510                                         case READ_WRITE_REG:            
511                                                 if (packet_type == QUERY_PACKET) {
512                                                         proto_tree_add_item(modbus_tree, hf_modbus_readref, tvb, payload_start, 2, FALSE);
513                                                         proto_tree_add_item(modbus_tree, hf_modbus_readwordcnt, tvb, payload_start + 2, 2, FALSE);
514                                                         proto_tree_add_item(modbus_tree, hf_modbus_writeref, tvb, payload_start + 4, 2, FALSE);
515                                                         proto_tree_add_item(modbus_tree, hf_modbus_writewordcnt, tvb, payload_start + 6, 2, FALSE);
516                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start + 8);
517                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start + 8, 1,
518                                                                         byte_cnt);
519                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 9, byte_cnt, "Data");
520                                                 }
521                                                 else if (packet_type == RESPONSE_PACKET) {
522                                                         byte_cnt = (guint32)tvb_get_guint8(tvb, payload_start);
523                                                         proto_tree_add_uint(modbus_tree, hf_modbus_bytecnt, tvb, payload_start, 1,
524                                                                         byte_cnt);
525                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 1, byte_cnt, "Data");
526                                                 }
527                                                 break;
528                                                 
529                                         case READ_FIFO_QUEUE:           
530                                                 if (packet_type == QUERY_PACKET)
531                                                         proto_tree_add_item(modbus_tree, hf_modbus_reference, tvb, payload_start, 2, FALSE);
532                                                 else if (packet_type == RESPONSE_PACKET) {
533                                                         byte_cnt = (guint32)tvb_get_ntohs(tvb, payload_start);
534                                                         proto_tree_add_uint(modbus_tree, hf_modbus_lbytecnt, tvb, payload_start, 2,
535                                                                         byte_cnt);
536                                                         proto_tree_add_item(modbus_tree, hf_modbus_wordcnt, tvb, payload_start + 2, 2, FALSE);
537                                                         proto_tree_add_text(modbus_tree, tvb, payload_start + 4, byte_cnt - 2, "Data");
538                                                 }
539                                                 break;
540                                                 
541                                         case DIAGNOSTICS:                       
542                                         case PROGRAM_484:                       
543                                         case POLL_484:                          
544                                         case GET_COMM_EVENT_CTRS:       
545                                         case GET_COMM_EVENT_LOG:        
546                                         case PROGRAM_584_984:           
547                                         case POLL_584_984:                      
548                                         case REPORT_SLAVE_ID:           
549                                         case PROGRAM_884_U84:           
550                                         case RESET_COMM_LINK:           
551                                         case PROGRAM_CONCEPT:           
552                                         case FIRMWARE_REPLACE:          
553                                         case PROGRAM_584_984_2:         
554                                         case REPORT_LOCAL_ADDR_MB:      
555                                                 /* these function codes are not part of the Modbus/TCP specification */
556                                         default:                                        
557                                                 if (payload_len > 0)
558                                                         proto_tree_add_text(modbus_tree, tvb, payload_start, payload_len, "Data");
559                                                 break;
560                                 }
561                         }
562                 }
563                 
564                 /* move onto next packet (if there) */
565                 offset += packet_len;
566                 packet_num++;
567                 if (tvb_reported_length_remaining(tvb, offset) > 0) {
568                         
569                         /* load header structure for next packet */
570                         mh.transaction_id = tvb_get_ntohs(tvb, offset+0);
571                         mh.protocol_id = tvb_get_ntohs(tvb, offset+2);
572                         mh.len = tvb_get_ntohs(tvb, offset+4);
573                         mh.mdbs_hdr.unit_id = tvb_get_guint8(tvb, offset+6);
574                         mh.mdbs_hdr.function_code = tvb_get_guint8(tvb, offset+7);
575
576         
577                         if ( mh.mdbs_hdr.function_code & 0x80 ) {
578                                 exception_code = tvb_get_guint8(tvb, offset + sizeof(mbtcp_hdr));
579                                 mh.mdbs_hdr.function_code ^= 0x80;
580                                 exception_returned = TRUE;
581                         } else
582                                 exception_returned = FALSE;
583                 }
584                 else
585                         break;
586         }
587
588         return tvb_length(tvb);
589 }
590
591
592 /* Register the protocol with Ethereal */
593
594 void
595 proto_register_modbus(void)
596 {
597
598 /* Setup list of header fields  See Section 1.6.1 for details*/
599         static hf_register_info hf[] = {
600                 /* Modbus/TCP header fields */
601                 { &hf_mbtcp_transid,
602                         { "transaction identifier",                     "modbus_tcp.trans_id",
603                         FT_UINT16, BASE_DEC, NULL, 0x0,
604                         "", HFILL }
605                 },
606                 { &hf_mbtcp_protid,
607                         { "protocol identifier",                        "modbus_tcp.prot_id",
608                         FT_UINT16, BASE_DEC, NULL, 0x0,
609                         "", HFILL }
610                 },
611                 { &hf_mbtcp_len,
612                         { "length",                                                     "modbus_tcp.len",
613                         FT_UINT16, BASE_DEC, NULL, 0x0,
614                         "", HFILL }
615                 },
616                 /* Modbus header fields */
617                 { &hf_mbtcp_unitid,
618                         { "unit identifier",                    "modbus_tcp.unit_id",
619                         FT_UINT8, BASE_DEC, NULL, 0x0,
620                         "", HFILL }
621                 },
622                 { &hf_mbtcp_functioncode,
623                         { "function code",                      "modbus_tcp.func_code",
624                         FT_UINT8, BASE_DEC, VALS(function_code_vals), 0x0,
625                         "", HFILL }
626                 },
627                 { &hf_modbus_reference,
628                         { "reference number",                   "modbus_tcp.reference_num",
629                         FT_UINT16, BASE_DEC, NULL, 0x0,
630                         "", HFILL }
631                 },
632                 { &hf_modbus_lreference,
633                         { "reference number (32 bit)",          "modbus_tcp.reference_num_32",
634                         FT_UINT32, BASE_DEC, NULL, 0x0,
635                         "", HFILL }
636                 },
637                 { &hf_modbus_reftype,
638                         { "reference type",                             "modbus_tcp.reference_type",
639                         FT_UINT8, BASE_DEC, NULL, 0x0,
640                         "", HFILL }
641                 },
642                 { &hf_modbus_readref,
643                         { "read reference number",              "modbus_tcp.read_reference_num",
644                         FT_UINT16, BASE_DEC, NULL, 0x0,
645                         "", HFILL }
646                 },
647                 { &hf_modbus_writeref,
648                         { "write reference number",             "modbus_tcp.write_reference_num",
649                         FT_UINT16, BASE_DEC, NULL, 0x0,
650                         "", HFILL }
651                 },
652                 { &hf_modbus_wordcnt,
653                         { "word count",                                 "modbus_tcp.word_cnt",
654                         FT_UINT16, BASE_DEC, NULL, 0x0,
655                         "", HFILL }
656                 },
657                 { &hf_modbus_readwordcnt,
658                         { "read word count",                            "modbus_tcp.read_word_cnt",
659                         FT_UINT16, BASE_DEC, NULL, 0x0,
660                         "", HFILL }
661                 },
662                 { &hf_modbus_writewordcnt,
663                         { "write word count",                   "modbus_tcp.write_word_cnt",
664                         FT_UINT16, BASE_DEC, NULL, 0x0,
665                         "", HFILL }
666                 },
667                 { &hf_modbus_bitcnt,
668                         { "bit count",                                  "modbus_tcp.bit_cnt",
669                         FT_UINT16, BASE_DEC, NULL, 0x0,
670                         "", HFILL }
671                 },
672                 { &hf_modbus_bytecnt,
673                         { "byte count",                                 "modbus_tcp.byte_cnt",
674                         FT_UINT8, BASE_DEC, NULL, 0x0,
675                         "", HFILL }
676                 },
677                 { &hf_modbus_lbytecnt,
678                         { "byte count (16-bit)",                        "modbus_tcp.byte_cnt_16",
679                         FT_UINT8, BASE_DEC, NULL, 0x0,
680                         "", HFILL }
681                 },
682                 { &hf_modbus_exceptioncode,
683                         { "exception code",                     "modbus_tcp.exception_code",
684                         FT_UINT8, BASE_DEC, VALS(exception_code_vals), 0x0,
685                         "", HFILL }
686                 },
687                 { &hf_modbus_andmask,
688                         { "AND mask",                                   "modbus_tcp.and_mask",
689                         FT_UINT16, BASE_HEX, NULL, 0x0,
690                         "", HFILL }
691                 },
692                 { &hf_modbus_ormask,
693                         { "OR mask",                                    "modbus_tcp.or_mask",
694                         FT_UINT16, BASE_HEX, NULL, 0x0,
695                         "", HFILL }
696                 }
697         };
698
699         /* Setup protocol subtree array */
700         static gint *ett[] = {
701                 &ett_mbtcp,
702                 &ett_modbus_hdr,
703                 &ett_group_hdr
704         };
705
706         /* Register the protocol name and description */
707         proto_mbtcp = proto_register_protocol("Modbus/TCP", "Modbus/TCP", "mbtcp");
708
709         /* Required function calls to register the header fields and subtrees used */
710         proto_register_field_array(proto_mbtcp, hf, array_length(hf));
711         proto_register_subtree_array(ett, array_length(ett));
712 }
713
714
715 /* If this dissector uses sub-dissector registration add a registration routine.
716    This format is required because a script is used to find these routines and
717    create the code that calls these routines.
718  */
719 void
720 proto_reg_handoff_mbtcp(void)
721 {
722         dissector_handle_t mbtcp_handle;
723
724         mbtcp_handle = new_create_dissector_handle(dissect_mbtcp, proto_mbtcp);
725         dissector_add("tcp.port", TCP_PORT_MBTCP, mbtcp_handle);
726 }