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