Set the svn:eol-style property on all text files to "native", so that
[obnox/wireshark/wip.git] / packet-dnp.c
1 /* packet-DNP3.c
2  * Routines for DNP dissection
3  * Copyright 2003, Graham Bloice <graham.bloice@trihedral.com>
4  *
5  * $Id$
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34
35 #include <glib.h>
36
37 #ifdef NEED_SNPRINTF_H
38 # include "snprintf.h"
39 #endif
40
41 #include <epan/packet.h>
42 #include "prefs.h"
43 #include "reassemble.h"
44
45 /* DNP 3.0 constants */
46 #define DNP_HDR_LEN     10
47 #define TCP_PORT_DNP    20000
48 #define DNP3_CTL_DIR    0x80
49 #define DNP3_CTL_PRM    0x40
50 #define DNP3_CTL_FCB    0x20
51 #define DNP3_CTL_FCV    0x10
52 #define DNP3_CTL_RES    0x20
53 #define DNP3_CTL_DFC    0x10
54 #define DNP3_CTL_FUNC   0x0f
55
56 #define DNP3_DL_LEN_OFFS  0x02
57 #define DNP3_DL_CTL_OFFS  0x03
58 #define DNP3_DL_DST_OFFS  0x04
59 #define DNP3_DL_SRC_OFFS  0x06
60
61 #define DNP3_TR_FIR   0x40
62 #define DNP3_TR_FIN   0x80
63 #define DNP3_TR_SEQ   0x3f
64
65 #define AL_MAX_CHUNK_SIZE 16
66
67 #define DNP3_AL_CON   0x20
68 #define DNP3_AL_FIN   0x40
69 #define DNP3_AL_FIR   0x80
70 #define DNP3_AL_SEQ   0x1f
71 #define DNP3_AL_FUNC  0xff
72
73 #define DNP3_AL_CTL_OFFS  0x0
74 #define DNP3_AL_FUNC_OFFS 0x1
75
76 /* DL Function codes */
77 #define DL_FUNC_RESET_LINK  0x0
78 #define DL_FUNC_RESET_PROC  0x1
79 #define DL_FUNC_TEST_LINK 0x2
80 #define DL_FUNC_USER_DATA 0x3
81 #define DL_FUNC_UNC_DATA  0x4
82 #define DL_FUNC_LINK_STAT 0x9
83
84 #define DL_FUNC_ACK   0x0
85 #define DL_FUNC_NACK    0x1
86 #define DL_FUNC_STAT_LINK 0xB
87 #define DL_FUNC_NO_FUNC   0xE
88 #define DL_FUNC_NOT_IMPL  0xF
89
90 /* AL Function codes */
91 #define DL_AL_FUNC_CONFIRM  0x0
92 #define DL_AL_FUNC_READ     0x01
93 #define DL_AL_FUNC_WRITE    0x02
94 #define DL_AL_FUNC_DIROP    0x05
95 #define DL_AL_FUNC_RESPON   0x81
96
97 /* Initialize the protocol and registered fields */
98 static int proto_dnp3 = -1;
99 static int hf_dnp3_start = -1;
100 static int hf_dnp3_len = -1;
101 static int hf_dnp3_ctl = -1;
102 static int hf_dnp3_ctl_prifunc = -1;
103 static int hf_dnp3_ctl_secfunc = -1;
104 static int hf_dnp3_ctl_dir = -1;
105 static int hf_dnp3_ctl_prm = -1;
106 static int hf_dnp3_ctl_fcb = -1;
107 static int hf_dnp3_ctl_fcv = -1;
108 static int hf_dnp3_ctl_dfc = -1;
109 static int hf_dnp3_dst = -1;
110 static int hf_dnp3_src = -1;
111 static int hf_dnp_hdr_CRC = -1;
112 static int hf_dnp_hdr_CRC_bad = -1;
113 static int hf_dnp3_tr_ctl = -1;
114 static int hf_dnp3_tr_fin = -1;
115 static int hf_dnp3_tr_fir = -1;
116 static int hf_dnp3_tr_seq = -1;
117 static int hf_dnp3_al_ctl = -1;
118 static int hf_dnp3_al_fir = -1;
119 static int hf_dnp3_al_fin = -1;
120 static int hf_dnp3_al_con = -1;
121 static int hf_dnp3_al_seq = -1;
122 static int hf_dnp3_al_func = -1;
123
124 /* ************************************************************************* */
125 /*                   Header values for reassembly                            */
126 /* ************************************************************************* */
127 static int hf_fragments = -1;
128 static int hf_fragment = -1;
129 static int hf_fragment_overlap = -1;
130 static int hf_fragment_overlap_conflict = -1;
131 static int hf_fragment_multiple_tails = -1;
132 static int hf_fragment_too_long_fragment = -1;
133 static int hf_fragment_error = -1;
134 static int hf_fragment_reassembled_in = -1;
135
136 /* Control Function Code Values */
137 static const value_string dnp3_ctl_func_pri_vals[] = {
138   { DL_FUNC_RESET_LINK, "Reset of remote link" },
139   { DL_FUNC_RESET_PROC, "Reset of user process" },
140   { DL_FUNC_TEST_LINK,  "Test function for link" },
141   { DL_FUNC_USER_DATA,  "User Data" },
142   { DL_FUNC_UNC_DATA,   "Unconfirmed User Data" },
143   { DL_FUNC_LINK_STAT,  "Request Link Status" },
144   { 0, NULL }
145 };
146
147 static const value_string dnp3_ctl_func_sec_vals[] = {
148   { DL_FUNC_ACK,        "ACK" },
149   { DL_FUNC_NACK,       "NACK" },
150   { DL_FUNC_STAT_LINK,  "Status of Link" },
151   { DL_FUNC_NO_FUNC,    "Link service not functioning" },
152   { DL_FUNC_NOT_IMPL,   "Link service not used or implemented" },
153   { 0,  NULL }
154 };
155
156 static const value_string dnp3_ctl_flags_pri_vals[] = {
157   { DNP3_CTL_DIR, "DIR" },
158   { DNP3_CTL_PRM, "PRM" },
159   { DNP3_CTL_FCB, "FCB" },
160   { DNP3_CTL_FCV, "FCV" },
161   { 0,  NULL }
162 };
163
164 static const value_string dnp3_ctl_flags_sec_vals[] = {
165   { DNP3_CTL_DIR, "DIR" },
166   { DNP3_CTL_PRM, "PRM" },
167   { DNP3_CTL_RES, "RES" },
168   { DNP3_CTL_DFC, "DFC" },
169   { 0,  NULL }
170 };
171
172 static const value_string dnp3_tr_flags_vals[] = {
173   { DNP3_TR_FIN,  "FIN" },
174   { DNP3_TR_FIR,  "FIR" },
175   { 0,  NULL }
176 };
177
178 static const value_string dnp3_al_flags_vals[] = {
179   { DNP3_AL_FIR,  "FIR" },
180   { DNP3_AL_FIN,  "FIN" },
181   { DNP3_AL_CON,  "CON" },
182   { 0,  NULL }
183 };
184
185 /* Control Function Code Values */
186 static const value_string dnp3_al_func_vals[] = {
187   { DL_AL_FUNC_CONFIRM, "Confirm" },
188   { DL_AL_FUNC_READ,    "Read" },
189   { DL_AL_FUNC_WRITE,   "Write" },
190   { DL_AL_FUNC_DIROP,   "Direct Operate" },
191   { DL_AL_FUNC_RESPON,  "Response" },
192   { 0, NULL }
193 };
194
195 /* Initialize the subtree pointers */
196 static gint ett_dnp3 = -1;
197 static gint ett_dnp3_dl = -1;
198 static gint ett_dnp3_dl_ctl = -1;
199 static gint ett_dnp3_tr_ctl = -1;
200 static gint ett_dnp3_al_data = -1;
201 static gint ett_dnp3_al = -1;
202 static gint ett_dnp3_al_ctl = -1;
203 static gint ett_fragment = -1;
204 static gint ett_fragments = -1;
205
206 /* Tables for reassembly of fragments. */
207 static GHashTable *al_fragment_table = NULL;
208 static GHashTable *al_reassembled_table = NULL;
209
210 static const fragment_items frag_items = {
211   &ett_fragment,
212   &ett_fragments,
213   &hf_fragments,
214   &hf_fragment,
215   &hf_fragment_overlap,
216   &hf_fragment_overlap_conflict,
217   &hf_fragment_multiple_tails,
218   &hf_fragment_too_long_fragment,
219   &hf_fragment_error,
220   &hf_fragment_reassembled_in,
221   "fragments"
222 };
223
224 /*****************************************************************/
225 /*                                                               */
226 /* CRC LOOKUP TABLE                                              */
227 /* ================                                              */
228 /* The following CRC lookup table was generated automagically    */
229 /* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
230 /* Program V1.0 using the following model parameters:            */
231 /*                                                               */
232 /*    Width   : 2 bytes.                                         */
233 /*    Poly    : 0x3D65                                           */
234 /*    Reverse : TRUE.                                            */
235 /*                                                               */
236 /* For more information on the Rocksoft^tm Model CRC Algorithm,  */
237 /* see the document titled "A Painless Guide to CRC Error        */
238 /* Detection Algorithms" by Ross Williams                        */
239 /* (ross@guest.adelaide.edu.au.). This document is likely to be  */
240 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
241 /*                                                               */
242 /*****************************************************************/
243
244 static guint16 crctable[256] =
245 {
246  0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A,
247  0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13,
248  0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1,
249  0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78,
250  0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35,
251  0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC,
252  0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E,
253  0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7,
254  0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4,
255  0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D,
256  0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF,
257  0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26,
258  0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B,
259  0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2,
260  0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00,
261  0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489,
262  0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526,
263  0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF,
264  0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D,
265  0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4,
266  0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89,
267  0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300,
268  0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2,
269  0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B,
270  0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678,
271  0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1,
272  0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413,
273  0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A,
274  0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7,
275  0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E,
276  0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC,
277  0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235
278 };
279
280 /*****************************************************************/
281 /*                   End of CRC Lookup Table                     */
282 /*****************************************************************/
283
284 /* calculates crc given a buffer of characters and a length of buffer */
285 static guint16
286 calculateCRC(const void *buf, guint len) {
287   guint16 crc = 0;
288   const guint8 *p = (const guint8 *)buf;
289   while(len-- > 0)
290     crc = crctable[(crc ^ *p++) & 0xff] ^ (crc >> 8);
291   return ~crc;
292 }
293
294 /* function to print list of bit flags */
295 static guint
296 flags_to_str(guint8 val, const value_string *vs, gchar *const str)
297 {
298   guint i, fpos;
299
300   i = fpos = 0;
301   while (vs[i].strptr) {
302     if (val & vs[i].value) {
303       if (fpos) {
304         strcpy(&str[fpos], ", ");
305         fpos += 2;
306       }
307       strcpy(&str[fpos], vs[i].strptr);
308       fpos += strlen(vs[i].strptr);
309     }
310     i++;
311   }
312   return fpos;
313 }
314
315 /* Code to actually dissect the packets */
316
317 /* Application layer dissector */
318 static void
319 dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
320 {
321   guint8        al_ctl, al_seq, al_func;
322   gboolean      al_fir, al_fin, al_con;
323   gchar         flags[64] = "<None>";
324   guint         fpos = 0;
325   int           offset = 0;
326   proto_item   *ti = NULL, *tc;
327   proto_tree   *al_tree = NULL, *field_tree = NULL;
328   const gchar  *func_code_str;
329
330   /* Handle the control byte and function code */
331   al_ctl = tvb_get_guint8(tvb, DNP3_AL_CTL_OFFS);
332   al_seq = al_ctl & DNP3_AL_SEQ;
333   al_fir = al_ctl & DNP3_AL_FIR;
334   al_fin = al_ctl & DNP3_AL_FIN;
335   al_con = al_ctl & DNP3_AL_CON;
336   al_func = tvb_get_guint8(tvb, DNP3_AL_FUNC_OFFS);
337   func_code_str = val_to_str(al_func, dnp3_al_func_vals, "Unknown function (0x%02x)");
338
339   if (tree) {
340     /* format up the text representation */
341
342     fpos = flags_to_str(al_ctl, dnp3_al_flags_vals, flags);
343     if (fpos) {
344       strcpy(&flags[fpos], ", ");
345       fpos += 2;
346     }
347     flags[fpos] = '\0';
348
349     /* Add the al tree branch */
350     ti = proto_tree_add_text(tree, tvb, offset, -1,
351            "Application Layer: (%sSequence %d, %s)",
352            flags, al_seq, func_code_str);
353     al_tree = proto_item_add_subtree(ti, ett_dnp3_al);
354
355     /* al control byte subtree */
356     tc = proto_tree_add_uint_format(al_tree, hf_dnp3_al_ctl, tvb, offset, 1, al_ctl,
357             "Control: 0x%02x (%sSequence %d)", al_ctl, flags, al_seq);
358     field_tree = proto_item_add_subtree(tc, ett_dnp3_al_ctl);
359     proto_tree_add_boolean(field_tree, hf_dnp3_al_fir, tvb, offset, 1, al_ctl);
360     proto_tree_add_boolean(field_tree, hf_dnp3_al_fin, tvb, offset, 1, al_ctl);
361     proto_tree_add_boolean(field_tree, hf_dnp3_al_con, tvb, offset, 1, al_ctl);
362     proto_tree_add_item(field_tree, hf_dnp3_al_seq, tvb, offset, 1, al_ctl);
363     offset += 1;
364
365     /* AL function code byte  */
366     proto_tree_add_uint_format(al_tree, hf_dnp3_al_func, tvb, offset, 1, al_func,
367                 "Function Code: %s (0x%02x)", func_code_str, al_func);
368     offset += 1;
369   }
370   else
371     offset += 2;  /* No tree, correct offset */
372
373
374 }
375
376 /* Data Link and Transport layer dissector */
377 static void
378 dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
379 {
380
381 /* Set up structures needed to add the protocol subtree and manage it */
382     proto_item   *ti = NULL, *tdl, *tc, *al_chunks;
383     proto_tree   *dnp3_tree = NULL, *dl_tree = NULL, *tr_tree = NULL, *field_tree = NULL, *al_tree = NULL;
384     int           offset = 0;
385     gboolean      dl_prm, tr_fir, tr_fin;
386     guint8        dl_len, dl_ctl, dl_func, tr_ctl, tr_seq;
387     guint         fpos = 0;
388     gchar         flags[64] = "<None>";
389     const gchar  *func_code_str;
390     guint16       dl_dst, dl_src, dl_crc, calc_dl_crc;
391     guint8       *tmp = NULL, *tmp_ptr;
392     guint8        data_len;
393     gboolean      crc_OK = FALSE;
394     tvbuff_t     *al_tvb = NULL;
395     guint         i;
396     static guint  seq_number = 0;
397
398 /* Make entries in Protocol column and Info column on summary display */
399   if (check_col(pinfo->cinfo, COL_PROTOCOL))
400     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNP 3.0");
401
402   if (check_col(pinfo->cinfo, COL_INFO))
403     col_clear(pinfo->cinfo, COL_INFO);
404
405   dl_len = tvb_get_guint8(tvb, DNP3_DL_LEN_OFFS);
406   dl_ctl = tvb_get_guint8(tvb, DNP3_DL_CTL_OFFS);
407   dl_dst = tvb_get_letohs(tvb, DNP3_DL_DST_OFFS);
408   dl_src = tvb_get_letohs(tvb, DNP3_DL_SRC_OFFS);
409   dl_func = dl_ctl & DNP3_CTL_FUNC;
410   dl_prm = dl_ctl & DNP3_CTL_PRM;
411   func_code_str = val_to_str(dl_func, dl_prm ? dnp3_ctl_func_pri_vals : dnp3_ctl_func_sec_vals,
412            "Unknown function (0x%02x)");
413
414   if (check_col(pinfo->cinfo, COL_INFO))
415     col_append_fstr(pinfo->cinfo, COL_INFO, "len=%d, from %d to %d, %s",
416             dl_len, dl_src, dl_dst, func_code_str);
417
418   if (tree) {
419
420     /* create display subtree for the protocol */
421     ti = proto_tree_add_item(tree, proto_dnp3, tvb, offset, -1, FALSE);
422     dnp3_tree = proto_item_add_subtree(ti, ett_dnp3);
423
424     /* format up the text representation of the flags and function code */
425     fpos = flags_to_str(dl_ctl, dl_prm ? dnp3_ctl_flags_pri_vals : dnp3_ctl_flags_sec_vals, flags);
426     if (fpos) {
427       strcpy(&flags[fpos], ", ");
428       fpos += 2;
429     }
430     strcpy(&flags[fpos], func_code_str);
431     fpos += strlen(func_code_str);
432     flags[fpos] = '\0';
433
434     /* create subtree for data link layer */
435     tdl = proto_tree_add_text(dnp3_tree, tvb, offset, DNP_HDR_LEN,
436             "Data Link Layer, Len: %d, From: %d, To: %d, %s",
437             dl_len, dl_src, dl_dst, flags);
438     dl_tree = proto_item_add_subtree(tdl, ett_dnp3_dl);
439
440     /* start bytes */
441     proto_tree_add_item(dl_tree, hf_dnp3_start, tvb, offset, 2, FALSE);
442     offset += 2;
443
444     /* add length field */
445     proto_tree_add_item(dl_tree, hf_dnp3_len, tvb, offset, 1, FALSE);
446     offset += 1;
447
448     /* add control byte subtree */
449     tc = proto_tree_add_uint_format(dl_tree, hf_dnp3_ctl, tvb, offset, 1, dl_ctl,
450             "Control: 0x%02x (%s)", dl_ctl, flags);
451     field_tree = proto_item_add_subtree(tc, ett_dnp3_dl_ctl);
452
453     if (dl_prm) {
454       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, dl_ctl);
455       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, dl_ctl);
456       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_fcb, tvb, offset, 1, dl_ctl);
457       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_fcv, tvb, offset, 1, dl_ctl);
458       proto_tree_add_item(field_tree, hf_dnp3_ctl_prifunc, tvb, offset, 1, FALSE);
459     }
460     else {
461       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, dl_ctl);
462       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, dl_ctl);
463       proto_tree_add_boolean(field_tree, hf_dnp3_ctl_dfc, tvb, offset, 1, dl_ctl);
464       proto_tree_add_item(field_tree, hf_dnp3_ctl_secfunc, tvb, offset, 1, FALSE);
465     }
466       offset += 1;
467
468     /* add destination and source addresses */
469     proto_tree_add_item(dl_tree, hf_dnp3_dst, tvb, offset, 2, TRUE);
470     offset += 2;
471     proto_tree_add_item(dl_tree, hf_dnp3_src, tvb, offset, 2, TRUE);
472     offset += 2;
473
474     /* and header CRC */
475     dl_crc = tvb_get_letohs(tvb, offset);
476     calc_dl_crc = calculateCRC(tvb_get_ptr(tvb, 0, DNP_HDR_LEN - 2), DNP_HDR_LEN - 2);
477     if (dl_crc == calc_dl_crc)
478       proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb, offset, 2,
479                dl_crc, "CRC: 0x%04x (correct)", dl_crc);
480     else {
481       proto_tree_add_boolean_hidden(dl_tree, hf_dnp_hdr_CRC_bad, tvb,
482                   offset, 2, TRUE);
483       proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb,
484                offset, 2, dl_crc, "CRC: 0x%04x (incorrect, should be 0x%04x)",
485                      dl_crc, calc_dl_crc);
486     }
487     offset += 2;
488   }
489   else
490     offset += 10; /* No tree so correct offset */
491
492   /* get the transport layer byte */
493   tr_ctl = tvb_get_guint8(tvb, offset);
494   tr_seq = tr_ctl & DNP3_TR_SEQ;
495   tr_fir = tr_ctl & DNP3_TR_FIR;
496   tr_fin = tr_ctl & DNP3_TR_FIN;
497
498   if (tree) {
499     /* format up the text representation */
500     strcpy(flags, "<NONE>");
501
502     fpos = flags_to_str(tr_ctl, dnp3_tr_flags_vals, flags);
503     if (fpos) {
504       strcpy(&flags[fpos], ", ");
505       fpos += 2;
506     }
507     flags[fpos] = '\0';
508
509     tc = proto_tree_add_uint_format(dnp3_tree, hf_dnp3_tr_ctl, tvb, offset, 1, tr_ctl,
510             "Transport Layer: 0x%02x (%sSequence %d)", tr_ctl, flags, tr_seq);
511     tr_tree = proto_item_add_subtree(tc, ett_dnp3_tr_ctl);
512     proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fin, tvb, offset, 1, tr_ctl);
513     proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fir, tvb, offset, 1, tr_ctl);
514     proto_tree_add_item(tr_tree, hf_dnp3_tr_seq, tvb, offset, 1, tr_ctl);
515   }
516
517   /* Allocate AL chunk tree */
518   if (tree != NULL) {
519     al_chunks = proto_tree_add_text(tr_tree, tvb, offset + 1, -1, "Application data chunks");
520     al_tree = proto_item_add_subtree(al_chunks, ett_dnp3_al_data);
521   }
522
523   /* extract the application layer data, validating the CRCs */
524
525   data_len = dl_len - 5;
526   tmp = g_malloc(data_len);
527   tmp_ptr = tmp;
528   i = 0;
529   while(data_len > 0) {
530     guint8 chk_size;
531     guint16 calc_crc, act_crc;
532     chk_size = MIN(data_len, AL_MAX_CHUNK_SIZE);
533     tvb_memcpy(tvb, tmp_ptr, offset, chk_size);
534     calc_crc = calculateCRC(tmp_ptr, chk_size);
535     offset += chk_size;
536     tmp_ptr += chk_size;
537     act_crc = tvb_get_letohs(tvb, offset);
538     offset += 2;
539     crc_OK = calc_crc == act_crc;
540     if (crc_OK)
541     {
542       if (tree)
543         proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
544                 "Application Chunk %d Len: %d CRC 0x%04x",
545                 i, chk_size, act_crc);
546       data_len -= chk_size;
547     }
548     else
549     {
550       if (tree)
551         proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
552                 "Application Chunk %d Len: %d Bad CRC got 0x%04x expected 0x%04x",
553                 i, chk_size, act_crc, calc_crc);
554       data_len = 0;
555       break;
556     }
557     i++;
558   }
559
560   /* if all crc OK, set up new tvb */
561   if (crc_OK) {
562     al_tvb = tvb_new_real_data(&tmp[1], tmp_ptr-tmp, tmp_ptr-tmp);
563     tvb_set_free_cb(al_tvb, g_free);
564     tvb_set_child_real_data_tvbuff(tvb, al_tvb);
565
566     /* Check for fragmented packet */
567     if (! (tr_fir && tr_fin)) {
568       /* A fragmented packet */
569
570       fragment_data *fd_head;
571
572       /* if first fragment, update sequence id */
573       if (tr_fir) seq_number++;
574
575       /*
576       * If we've already seen this frame, look it up in the
577       * table of reassembled packets, otherwise add it to
578       * whatever reassembly is in progress, if any, and see
579       * if it's done.
580       */
581       fd_head = fragment_add_seq_check(al_tvb, 0, pinfo, seq_number,
582                al_fragment_table,
583                al_reassembled_table,
584                tr_seq,
585                tvb_reported_length(al_tvb),
586                !tr_fin);
587       if (fd_head != NULL) {
588         /* We have the complete payload */
589         al_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
590         tvb_set_child_real_data_tvbuff(tvb, al_tvb);
591         add_new_data_source(pinfo, al_tvb, "Reassembled DNP 3.0 Application Layer message");
592
593         if (tree)
594           /* Show all fragments. */
595           show_fragment_seq_tree(fd_head, &frag_items, tr_tree, pinfo, al_tvb);
596       }
597       else {
598         /* We don't have the complete reassembled payload. */
599         al_tvb = NULL;
600         if (check_col (pinfo->cinfo, COL_INFO))
601           col_append_str (pinfo->cinfo, COL_INFO,
602               " (Application Layer Message unreassembled)");
603       }
604     }
605     else {
606       /* No reassembly required */
607       add_new_data_source(pinfo, al_tvb, "DNP 3.0 Application Layer message");
608     }
609   }
610   else if (tree)
611       proto_tree_add_text(dnp3_tree, tvb, 11, -1,
612               "Application tvb allocation failed %d chunks", i);
613
614   if (!al_tvb && tmp) g_free(tmp);
615
616   if (al_tvb)
617     dissect_dnp3_al(al_tvb, pinfo, dnp3_tree);
618 }
619
620 static void
621 al_defragment_init(void)
622 {
623   fragment_table_init(&al_fragment_table);
624   reassembled_table_init(&al_reassembled_table);
625 }
626
627 /* Register the protocol with Ethereal */
628
629 void
630 proto_register_dnp3(void)
631 {
632
633 /* Setup list of header fields */
634   static hf_register_info hf[] = {
635     { &hf_dnp3_start,
636     { "Start Bytes", "dnp3.start", FT_UINT16, BASE_HEX, NULL, 0x0, "Start Bytes", HFILL }},
637
638     { &hf_dnp3_len,
639     { "Length", "dnp3.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Frame Data Length", HFILL }},
640
641     { &hf_dnp3_ctl,
642     { "Control", "dnp3.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Frame Control Byte", HFILL }},
643
644     { &hf_dnp3_ctl_prifunc,
645     { "Control Function Code", "dnp3.ctl.prifunc", FT_UINT8, BASE_DEC,
646       VALS(dnp3_ctl_func_pri_vals), DNP3_CTL_FUNC, "Frame Control Function Code", HFILL }},
647
648     { &hf_dnp3_ctl_secfunc,
649     { "Control Function Code", "dnp3.ctl.secfunc", FT_UINT8, BASE_DEC,
650       VALS(dnp3_ctl_func_sec_vals), DNP3_CTL_FUNC, "Frame Control Function Code", HFILL }},
651
652     { &hf_dnp3_ctl_dir,
653     { "Direction", "dnp3.ctl.dir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DIR, "", HFILL }},
654
655     { &hf_dnp3_ctl_prm,
656     { "Primary", "dnp3.ctl.prm", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_PRM, "", HFILL }},
657
658     { &hf_dnp3_ctl_fcb,
659     { "Frame Count Bit", "dnp3.ctl.fcb", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCB, "", HFILL }},
660
661     { &hf_dnp3_ctl_fcv,
662     { "Frame Count Valid", "dnp3.ctl.fcv", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCV, "", HFILL }},
663
664     { &hf_dnp3_ctl_dfc,
665     { "Data Flow Control", "dnp3.ctl.dfc", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DFC, "", HFILL }},
666
667     { &hf_dnp3_dst,
668     { "Destination", "dnp3.dst", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Address", HFILL }},
669
670     { &hf_dnp3_src,
671     { "Source", "dnp3.src", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Address", HFILL }},
672
673     { &hf_dnp_hdr_CRC,
674     { "CRC", "dnp.hdr.CRC", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
675
676     { &hf_dnp_hdr_CRC_bad,
677     { "Bad CRC", "dnp.hdr.CRC_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
678
679     { &hf_dnp3_tr_ctl,
680     { "Transport Control", "dnp3.tr.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Tranport Layer Control Byte", HFILL }},
681
682     { &hf_dnp3_tr_fin,
683     { "Final", "dnp3.tr.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIN, "", HFILL }},
684
685     { &hf_dnp3_tr_fir,
686     { "First", "dnp3.tr.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIR, "", HFILL }},
687
688     { &hf_dnp3_tr_seq,
689     { "Sequence", "dnp3.tr.seq", FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ, "Frame Sequence Number", HFILL }},
690
691     { &hf_dnp3_al_ctl,
692     { "Application Control", "dnp3.al.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Application Layer Control Byte", HFILL }},
693
694     { &hf_dnp3_al_fir,
695     { "First", "dnp3.al.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIR, "", HFILL }},
696
697     { &hf_dnp3_al_fin,
698     { "Final", "dnp3.al.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIN, "", HFILL }},
699
700     { &hf_dnp3_al_con,
701     { "Confirm", "dnp3.al.con", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_CON, "", HFILL }},
702
703     { &hf_dnp3_al_seq,
704     { "Sequence", "dnp3.al.seq", FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ, "Frame Sequence Number", HFILL }},
705
706     { &hf_dnp3_al_func,
707     { "Application Layer Function Code", "dnp3.al.func", FT_UINT8, BASE_DEC,
708       VALS(dnp3_al_func_vals), DNP3_AL_FUNC, "Application Function Code", HFILL }},
709
710     { &hf_fragment,
711     { "DNP 3.0 AL Fragment", "al.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragment", HFILL }},
712
713     { &hf_fragments,
714     { "DNP 3.0 AL Fragments", "al.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragments", HFILL }},
715
716     { &hf_fragment_overlap,
717     { "Fragment overlap", "al.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
718
719     { &hf_fragment_overlap_conflict,
720     { "Conflicting data in fragment overlap", "al.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
721       "Overlapping fragments contained conflicting data", HFILL }},
722
723     { &hf_fragment_multiple_tails,
724     { "Multiple tail fragments found", "al.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
725       "Several tails were found when defragmenting the packet", HFILL }},
726
727     { &hf_fragment_too_long_fragment,
728     { "Fragment too long", "al.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
729       "Fragment contained data past end of packet", HFILL }},
730
731     { &hf_fragment_error,
732     { "Defragmentation error", "al.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
733       "Defragmentation error due to illegal fragments", HFILL }},
734     { &hf_fragment_reassembled_in,
735     { "Reassembled PDU In Frame", "al.fragment.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
736       "This PDU is reassembled in this frame", HFILL }}
737   };
738
739 /* Setup protocol subtree array */
740   static gint *ett[] = {
741     &ett_dnp3,
742     &ett_dnp3_dl,
743     &ett_dnp3_dl_ctl,
744     &ett_dnp3_tr_ctl,
745     &ett_dnp3_al_data,
746     &ett_dnp3_al,
747     &ett_dnp3_al_ctl,
748     &ett_fragment,
749     &ett_fragments
750   };
751
752 /* Register the protocol name and description */
753   proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0",
754                    "DNP 3.0", "dnp3");
755
756 /* Required function calls to register the header fields and subtrees used */
757   proto_register_field_array(proto_dnp3, hf, array_length(hf));
758   proto_register_subtree_array(ett, array_length(ett));
759
760   al_defragment_init();
761 }
762
763
764 /* If this dissector uses sub-dissector registration add a registration routine.
765    This format is required because a script is used to find these routines and
766    create the code that calls these routines.
767 */
768 void
769 proto_reg_handoff_dnp3(void)
770 {
771   dissector_handle_t dnp3_handle;
772
773   dnp3_handle = create_dissector_handle(dissect_dnp3, proto_dnp3);
774   dissector_add("tcp.port", TCP_PORT_DNP, dnp3_handle);
775 }