change a whole bunch of ethereal into wireshark
[obnox/wireshark/wip.git] / epan / dissectors / packet-dnp.c
1 /* packet-dnp3.c
2  * Routines for DNP dissection
3  * Copyright 2003, Graham Bloice <graham.bloice@trihedral.com>
4  *
5  * DNP3.0 Application Layer Object dissection added by Chris Bontje (chrisbontje@shaw.ca)
6  * Copyright 2005
7  *
8  * $Id$
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <math.h>
37 #include <glib.h>
38 #include <time.h>
39
40 #include <epan/packet.h>
41 #include <epan/prefs.h>
42 #include <epan/reassemble.h>
43
44 /*
45  * See
46  *
47  * http://www.dnp.org/
48  *
49  * although note that you have to join the DNP organization to get to
50  * see the protocol specs online - otherwise, you have to buy a
51  * dead-tree version.
52  *
53  * ...Application Layer Notes...
54  *
55  * Application Layer Decoding based on information available in
56  * DNP3 Basic 4 Documentation Set, specifically the document:
57  * "DNP V3.00 Application Layer" v0.03 P009-0PD.APP
58  */
59
60 /***************************************************************************/
61 /* DNP 3.0 Constants */
62 /***************************************************************************/
63 #define DNP_HDR_LEN     10
64 #define TCP_PORT_DNP    20000
65 #define UDP_PORT_DNP    20000
66
67 /***************************************************************************/
68 /* Datalink and Transport Layer Bit-Masks */
69 /***************************************************************************/
70 #define DNP3_CTL_DIR    0x80
71 #define DNP3_CTL_PRM    0x40
72 #define DNP3_CTL_FCB    0x20
73 #define DNP3_CTL_FCV    0x10
74 #define DNP3_CTL_RES    0x20
75 #define DNP3_CTL_DFC    0x10
76 #define DNP3_CTL_FUNC   0x0f
77
78 #define DNP3_TR_FIR   0x40
79 #define DNP3_TR_FIN   0x80
80 #define DNP3_TR_SEQ   0x3f
81
82 #define AL_MAX_CHUNK_SIZE 16
83
84 /***************************************************************************/
85 /* Data Link Function codes */
86 /***************************************************************************/
87 /* Primary to Secondary */
88 #define DL_FUNC_RESET_LINK  0x00
89 #define DL_FUNC_RESET_PROC  0x01
90 #define DL_FUNC_TEST_LINK   0x02
91 #define DL_FUNC_USER_DATA   0x03
92 #define DL_FUNC_UNC_DATA    0x04
93 #define DL_FUNC_LINK_STAT   0x09
94
95 /* Secondary to Primary */
96 #define DL_FUNC_ACK         0x00
97 #define DL_FUNC_NACK        0x01
98 #define DL_FUNC_STAT_LINK   0x0B
99 #define DL_FUNC_NO_FUNC     0x0E
100 #define DL_FUNC_NOT_IMPL    0x0F
101
102 /***************************************************************************/
103 /* Application Layer Bit-Masks */
104 /***************************************************************************/
105 #define DNP3_AL_CON   0x20
106 #define DNP3_AL_FIN   0x40
107 #define DNP3_AL_FIR   0x80
108 #define DNP3_AL_SEQ   0x1f
109 #define DNP3_AL_FUNC  0xff
110
111 /***************************************************************************/
112 /* Application Layer Function codes */
113 /***************************************************************************/
114 #define AL_FUNC_CONFIRM    0x00    /* 00  - Confirm */
115 #define AL_FUNC_READ       0x01    /* 01  - Read */
116 #define AL_FUNC_WRITE      0x02    /* 02  - Write */
117 #define AL_FUNC_SELECT     0x03    /* 03  - Select */
118 #define AL_FUNC_OPERATE    0x04    /* 04  - Operate */
119 #define AL_FUNC_DIROP      0x05    /* 05  - Direct Operate */
120 #define AL_FUNC_DIROPNACK  0x06    /* 06  - Direct Operate No ACK */
121 #define AL_FUNC_FRZ        0x07    /* 07  - Immediate Freeze */
122 #define AL_FUNC_FRZNACK    0x08    /* 08  - Immediate Freeze No ACK */
123 #define AL_FUNC_FRZCLR     0x09    /* 09  - Freeze and Clear */
124 #define AL_FUNC_FRZCLRNACK 0x0A    /* 10  - Freeze and Clear No ACK */
125 #define AL_FUNC_FRZT       0x0B    /* 11  - Freeze With Time */
126 #define AL_FUNC_FRZTNACK   0x0C    /* 12  - Freeze With Time No ACK */
127 #define AL_FUNC_COLDRST    0x0D    /* 13  - Cold Restart */
128 #define AL_FUNC_WARMRST    0x0E    /* 14  - Warm Restart */
129 #define AL_FUNC_INITDATA   0x0F    /* 15  - Initialize Data */
130 #define AL_FUNC_INITAPP    0x10    /* 16  - Initialize Application */
131 #define AL_FUNC_STARTAPP   0x11    /* 17  - Start Application */
132 #define AL_FUNC_STOPAPP    0x12    /* 18  - Stop Application */
133 #define AL_FUNC_SAVECFG    0x13    /* 19  - Save Configuration */
134 #define AL_FUNC_ENSPMSG    0x14    /* 20  - Enable Spontaneous Msg */
135 #define AL_FUNC_DISSPMSG   0x15    /* 21  - Disable Spontaneous Msg */
136 #define AL_FUNC_ASSIGNCL   0x16    /* 22  - Assign Classes */
137 #define AL_FUNC_DELAYMST   0x17    /* 23  - Delay Measurement */
138 #define AL_FUNC_RESPON     0x81    /* 129 - Response */
139 #define AL_FUNC_UNSOLI     0x82    /* 130 - Unsolicited Response */
140
141 /***************************************************************************/
142 /* Application Layer Internal Indication (IIN) bits */
143 /* 2 Bytes, message formatting: [First Octet] | [Second Octet] */
144 /***************************************************************************/
145 /* Octet 1 */
146 #define AL_IIN_BMSG        0x0100   /* Bit 0 - Broadcast message rx'd */
147 #define AL_IIN_CLS1D       0x0200   /* Bit 1 - Class 1 Data Available */
148 #define AL_IIN_CLS2D       0x0400   /* Bit 2 - Class 2 Data Available */
149 #define AL_IIN_CLS3D       0x0800   /* Bit 3 - Class 3 Data Available */
150 #define AL_IIN_TSR         0x1000   /* Bit 4 - Time Sync Req'd from Master */
151 #define AL_IIN_DOL         0x2000   /* Bit 5 - Digital Outputs in Local Mode */
152 #define AL_IIN_DT          0x4000   /* Bit 6 - Device Trouble */
153 #define AL_IIN_RST         0x8000   /* Bit 7 - Device Restart */
154
155 /* Octet 2 */
156                         /* 0x0001      Bit 0 - Reserved */
157 #define AL_IIN_OBJU        0x0002   /* Bit 1 - Requested Objects Unknown */
158 #define AL_IIN_PIOOR       0x0004   /* Bit 2 - Parameters Invalid or Out of Range */
159 #define AL_IIN_EBO         0x0008   /* Bit 3 - Event Buffer Overflow */
160 #define AL_IIN_OAE         0x0010   /* Bit 4 - Operation Already Executing */
161 #define AL_IIN_CC          0x0020   /* Bit 5 - Device Configuration Corrupt */
162                         /* 0x0040      Bit 6 - Reserved */
163                         /* 0x0080      Bit 7 - Reserved */
164
165 /***************************************************************************/
166 /* Application Layer Data Object Qualifier */
167 /***************************************************************************/
168 /* Bit-Masks */
169 #define AL_OBJQ_INDEX      0x70     /* x111xxxx Masks Index from Qualifier */
170 #define AL_OBJQ_CODE       0x0F     /* xxxx1111 Masks Code from Qualifier */
171
172 /* Index Size (3-bits x111xxxx)            */
173 /* When Qualifier Code != 11               */
174 #define AL_OBJQL_IDX_NI    0x00    /* Objects are Packed with no index */
175 #define AL_OBJQL_IDX_1O    0x01    /* Objects are prefixed w/ 1-octet index */
176 #define AL_OBJQL_IDX_2O    0x02    /* Objects are prefixed w/ 2-octet index */
177 #define AL_OBJQL_IDX_4O    0x03    /* Objects are prefixed w/ 4-octet index */
178 #define AL_OBJQL_IDX_1OS   0x04    /* Objects are prefixed w/ 1-octet object size */
179 #define AL_OBJQL_IDX_2OS   0x05    /* Objects are prefixed w/ 2-octet object size */
180 #define AL_OBJQL_IDX_4OS   0x06    /* Objects are prefixed w/ 4-octet object size */
181
182 /* When Qualifier Code == 11 */
183 #define AL_OBJQL_IDX11_1OIS    0x01    /* 1 octet identifier size */
184 #define AL_OBJQL_IDX11_2OIS    0x02    /* 2 octet identifier size */
185 #define AL_OBJQL_IDX11_4OIS    0x03    /* 4 octet identifier size */
186
187 /* Qualifier Code (4-bits) */
188 /* 4-bits ( xxxx1111 ) */
189 #define AL_OBJQL_CODE_SSI8     0x00    /* 00 8-bit Start and Stop Indices in Range Field */
190 #define AL_OBJQL_CODE_SSI16    0x01    /* 01 16-bit Start and Stop Indices in Range Field */
191 #define AL_OBJQL_CODE_SSI32    0x02    /* 02 32-bit Start and Stop Indices in Range Field */
192 #define AL_OBJQL_CODE_AA8      0x03    /* 03 8-bit Absolute Address in Range Field */
193 #define AL_OBJQL_CODE_AA16     0x04    /* 04 16-bit Absolute Address in Range Field */
194 #define AL_OBJQL_CODE_AA32     0x05    /* 05 32-bit Absolute Address in Range Field */
195 #define AL_OBJQL_CODE_R0       0x06    /* 06 Length of Range field is 0 (no range field) */
196 #define AL_OBJQL_CODE_SF8      0x07    /* 07 8-bit Single Field Quantity */
197 #define AL_OBJQL_CODE_SF16     0x08    /* 08 16-bit Single Field Quantity */
198 #define AL_OBJQL_CODE_SF32     0x09    /* 09 32-bit Single Field Quantity */
199                            /*  0x0A       10 Reserved  */
200 #define AL_OBJQL_CODE_FF       0x0B    /* 11 Free-format Qualifier */
201                            /*  0x0C       12 Reserved  */
202                            /*  0x0D       13 Reserved  */
203                            /*  0x0E       14 Reserved  */
204                            /*  0x0F       15 Reserved  */
205
206 /***************************************************************************/
207 /* Application Layer Data Object Definitions                               */
208 /***************************************************************************/
209 /* Binary Input Objects */
210 #define AL_OBJ_BI_ALL      0x0100   /* 01 00 Binary Input All Variations */
211 #define AL_OBJ_BI_1BIT     0x0101   /* 01 01 Single-bit Binary Input */
212 #define AL_OBJ_BI_STAT     0x0102   /* 01 02 Binary Input With Status */
213 #define AL_OBJ_BIC_ALL     0x0200   /* 02 00 Binary Input Change All Variations */
214 #define AL_OBJ_BIC_NOTIME  0x0201   /* 02 01 Binary Input Change Without Time */
215 #define AL_OBJ_BIC_TIME    0x0202   /* 02 02 Binary Input Change With Time */
216 #define AL_OBJ_BIC_RTIME   0x0203   /* 02 03 Binary Input Change With Relative Time */
217
218 /* Binary Input Quality Flags */
219 #define AL_OBJ_BI_FLAG0    0x0001   /* Point Online (0=Offline; 1=Online) */
220 #define AL_OBJ_BI_FLAG1    0x0002   /* Restart (0=Normal; 1=Restart) */
221 #define AL_OBJ_BI_FLAG2    0x0004   /* Comms Lost (0=Normal; 1=Lost) */
222 #define AL_OBJ_BI_FLAG3    0x0008   /* Remote Force (0=Normal; 1=Forced) */
223 #define AL_OBJ_BI_FLAG4    0x0010   /* Local Force (0=Normal; 1=Forced) */
224 #define AL_OBJ_BI_FLAG5    0x0020   /* Chatter Filter (0=Normal; 1=Filter On) */
225 #define AL_OBJ_BI_FLAG6    0x0040   /* Reserved */
226 #define AL_OBJ_BI_FLAG7    0x0080   /* Point State (0=Off; 1=On) */
227
228 /***************************************************************************/
229 /* Binary Output Objects */
230 #define AL_OBJ_BO          0x0A01   /* 10 01 Binary Output */
231 #define AL_OBJ_BO_STAT     0x0A02   /* 10 02 Binary Output Status */
232 #define AL_OBJ_CTLOP_BLK   0x0C01   /* 12 01 Control Relay Output Block */
233                         /* 0x0C02      12 02 Pattern Control Block */
234                         /* 0x0C03      12 03 Pattern Mask */
235
236 #define AL_OBJCTLC_CODE    0x0F    /* Bit-Mask xxxx1111 for Control Code 'Code' */
237 #define AL_OBJCTLC_MISC    0x30    /* Bit-Mask xx11xxxx for Control Code Misc Values */
238 #define AL_OBJCTLC_TC      0xC0    /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */
239
240 #define AL_OBJCTLC_CODE0   0x00    /* xxxx0000 NUL Operation; only process R attribute */
241 #define AL_OBJCTLC_CODE1   0x01    /* xxxx0001 Pulse On ^On-Time -> vOff-Time, remain off */
242 #define AL_OBJCTLC_CODE2   0x02    /* xxxx0010 Pulse Off vOff-Time -> ^On-Time, remain on */
243 #define AL_OBJCTLC_CODE3   0x03    /* xxxx0011 Latch On */
244 #define AL_OBJCTLC_CODE4   0x04    /* xxxx0100 Latch Off */
245                         /* 0x05-0x15  Reserved */
246
247 #define AL_OBJCTLC_QUEUE   0x10    /* xxx1xxxx for Control Code 'Queue' */
248 #define AL_OBJCTLC_CLEAR   0x20    /* xx1xxxxx for Control Code 'Clear' */
249
250 #define AL_OBJCTLC_TC0     0x00    /* 00xxxxxx NUL */
251 #define AL_OBJCTLC_TC1     0x40    /* 01xxxxxx Close */
252 #define AL_OBJCTLC_TC2     0x80    /* 10xxxxxx Trip */
253
254 #define AL_OBJCTL_STAT0    0x00    /* Request Accepted, Initiated or Queued */
255 #define AL_OBJCTL_STAT1    0x01    /* Request Not Accepted; Arm-timer expired */
256 #define AL_OBJCTL_STAT2    0x02    /* Request Not Accepted; No 'SELECT' rx'd */
257 #define AL_OBJCTL_STAT3    0x03    /* Request Not Accepted; Format errors in ctrl request */
258 #define AL_OBJCTL_STAT4    0x04    /* Control Operation Not Supported for this point */
259 #define AL_OBJCTL_STAT5    0x05    /* Request Not Accepted; Ctrl Queue full or pt. active */
260 #define AL_OBJCTL_STAT6    0x06    /* Request Not Accepted; Ctrl HW Problems */
261
262 /* Binary Output Quality Flags */
263 #define AL_OBJ_BO_FLAG0    0x0001   /* Point Online (0=Offline; 1=Online) */
264 #define AL_OBJ_BO_FLAG1    0x0002   /* Restart (0=Normal; 1=Restart) */
265 #define AL_OBJ_BO_FLAG2    0x0004   /* Comms Lost (0=Normal; 1=Lost) */
266 #define AL_OBJ_BO_FLAG3    0x0008   /* Remote Force (0=Normal; 1=Forced) */
267 #define AL_OBJ_BO_FLAG4    0x0010   /* Local Force (0=Normal; 1=Forced) */
268 #define AL_OBJ_BO_FLAG5    0x0020   /* Reserved */
269 #define AL_OBJ_BO_FLAG6    0x0040   /* Reserved */
270 #define AL_OBJ_BO_FLAG7    0x0080   /* Point State (0=Off; 1=On) */
271
272 /***************************************************************************/
273 /* Counter Objects */
274 #define AL_OBJ_CTR_ALL     0x1400   /* 20 00 Binary Counter All Variations */
275 #define AL_OBJ_CTR_32      0x1401   /* 20 01 32-Bit Binary Counter */
276 #define AL_OBJ_CTR_16      0x1402   /* 20 02 16-Bit Binary Counter */
277 #define AL_OBJ_DCTR_32     0x1403   /* 20 03 32-Bit Delta Counter */
278 #define AL_OBJ_DCTR_16     0x1404   /* 20 04 16-Bit Delta Counter */
279 #define AL_OBJ_CTR_32NF    0x1405   /* 20 05 32-Bit Binary Counter Without Flag */
280 #define AL_OBJ_CTR_16NF    0x1406   /* 20 06 16-Bit Binary Counter Without Flag */
281                         /* 0x1407      20 07 32-Bit Delta Counter Without Flag */
282                         /* 0x1408      20 08 16-Bit Delta Counter Without Flag */
283 #define AL_OBJ_FCTR_32     0x1501   /* 21 01 32-Bit Frozen Counter */
284 #define AL_OBJ_FCTR_16     0x1502   /* 21 02 16-Bit Frozen Counter */
285                         /* 0x1503      21 03 32-Bit Frozen Delta Counter */
286                         /* 0x1504      21 04 16-Bit Frozen Delta Counter */
287                         /* 0x1505      21 05 32-Bit Frozen Counter w/ Time of Freeze */
288                         /* 0x1506      21 06 16-Bit Frozen Counter w/ Time of Freeze */
289                         /* 0x1507      21 07 32-Bit Frozen Delta Counter w/ Time of Freeze */
290                         /* 0x1508      21 08 16-Bit Frozen Delta Counter w/ Time of Freeze */
291                         /* 0x1509      21 09 32-Bit Frozen Counter Without Flag */
292                         /* 0x1510      21 10 16-Bit Frozen Counter Without Flag */
293                         /* 0x1511      21 11 32-Bit Frozen Delta Counter Without Flag */
294                         /* 0x1512      21 12 16-Bit Frozen Delta Counter Without Flag */
295 #define AL_OBJ_CTRC_ALL    0x1600   /* 22 00 Counter Change Event All Variations */
296 #define AL_OBJ_CTRC_32     0x1601   /* 22 01 32-Bit Counter Change Event w/o Time */
297 #define AL_OBJ_CTRC_16     0x1602   /* 22 02 16-Bit Counter Change Event w/o Time */
298                         /* 0x1603      22 03 32-Bit Delta Counter Change Event w/o Time */
299                         /* 0x1604      22 04 16-Bit Delta Counter Change Event w/o Time */
300                         /* 0x1605      22 05 32-Bit Counter Change Event With Time */
301                         /* 0x1606      22 06 16-Bit Counter Change Event With Time */
302                         /* 0x1607      22 07 32-Bit Delta Counter Change Event With Time */
303                         /* 0x1608      22 08 16-Bit Delta Counter Change Event With Time */
304                         /* 0x1701      23 01 32-Bit Counter Change Event w/o Time */
305                         /* 0x1702      23 02 16-Bit Frozen Counter Change Event w/o Time */
306                         /* 0x1703      23 03 32-Bit Frozen Delta Counter Change Event w/o Time */
307
308 /* Counter Quality Flags */
309 #define AL_OBJ_CTR_FLAG0   0x0001   /* Point Online (0=Offline; 1=Online) */
310 #define AL_OBJ_CTR_FLAG1   0x0002   /* Restart (0=Normal; 1=Restart) */
311 #define AL_OBJ_CTR_FLAG2   0x0004   /* Comms Lost (0=Normal; 1=Lost) */
312 #define AL_OBJ_CTR_FLAG3   0x0008   /* Remote Force (0=Normal; 1=Forced) */
313 #define AL_OBJ_CTR_FLAG4   0x0010   /* Local Force (0=Normal; 1=Forced) */
314 #define AL_OBJ_CTR_FLAG5   0x0020   /* Roll-over (0=Normal; 1=Roll-Over) */
315 #define AL_OBJ_CTR_FLAG6   0x0040   /* Reserved */
316 #define AL_OBJ_CTR_FLAG7   0x0080   /* Reserved */
317
318 /***************************************************************************/
319 /* Analog Input Objects */
320 #define AL_OBJ_AI_ALL      0x1E00   /* 30 00 Analog Input All Variations */
321 #define AL_OBJ_AI_32       0x1E01   /* 30 01 32-Bit Analog Input */
322 #define AL_OBJ_AI_16       0x1E02   /* 30 02 16-Bit Analog Input */
323 #define AL_OBJ_AI_32NF     0x1E03   /* 30 03 32-Bit Analog Input Without Flag */
324 #define AL_OBJ_AI_16NF     0x1E04   /* 30 04 16-Bit Analog Input Without Flag */
325                         /* 0x1F01      31 01 32-Bit Frozen Analog Input */
326                         /* 0x1F02      31 02 16-Bit Frozen Analog Input */
327                         /* 0x1F03      31 03 32-Bit Frozen Analog Input w/ Time of Freeze */
328                         /* 0x1F04      31 04 16-Bit Frozen Analog Input w/ Time of Freeze */
329                         /* 0x1F05      31 05 32-Bit Frozen Analog Input Without Flag */
330                         /* 0x1F06      31 06 16-Bit Frozen Analog Input Without Flag */
331 #define AL_OBJ_AIC_ALL     0x2000   /* 32 00 Analog Input Change All Variations */
332 #define AL_OBJ_AIC_32NT    0x2001   /* 32 01 32-Bit Analog Change Event w/o Time */
333 #define AL_OBJ_AIC_16NT    0x2002   /* 32 02 16-Bit Analog Change Event w/o Time */
334 #define AL_OBJ_AIC_32T     0x2003   /* 32 03 32-Bit Analog Change Event w/ Time */
335 #define AL_OBJ_AIC_16T     0x2004   /* 32 04 16-Bit Analog Change Event w/ Time */
336                         /* 0x2101      33 01 32-Bit Frozen Analog Event w/o Time */
337                         /* 0x2102      33 02 16-Bit Frozen Analog Event w/o Time */
338                         /* 0x2103      33 03 32-Bit Frozen Analog Event w/ Time */
339                         /* 0x2104      33 04 16-Bit Frozen Analog Event w/ Time */
340
341 /* Analog Input Quality Flags */
342 #define AL_OBJ_AI_FLAG0    0x0001   /* Point Online (0=Offline; 1=Online) */
343 #define AL_OBJ_AI_FLAG1    0x0002   /* Restart (0=Normal; 1=Restart) */
344 #define AL_OBJ_AI_FLAG2    0x0004   /* Comms Lost (0=Normal; 1=Lost) */
345 #define AL_OBJ_AI_FLAG3    0x0008   /* Remote Force (0=Normal; 1=Forced) */
346 #define AL_OBJ_AI_FLAG4    0x0010   /* Local Force (0=Normal; 1=Forced) */
347 #define AL_OBJ_AI_FLAG5    0x0020   /* Over-Range (0=Normal; 1=Over-Range) */
348 #define AL_OBJ_AI_FLAG6    0x0040   /* Reference Check (0=Normal; 1=Error) */
349 #define AL_OBJ_AI_FLAG7    0x0080   /* Reserved */
350
351 /***************************************************************************/
352 /* Analog Output Objects */
353 #define AL_OBJ_AO_32       0x2801   /* 40 01 32-Bit Analog Output Status */
354 #define AL_OBJ_AO_16       0x2802   /* 40 02 16-Bit Analog Output Status */
355 #define AL_OBJ_AO_32OPB    0x2901   /* 41 01 32-Bit Analog Output Block */
356 #define AL_OBJ_AO_16OPB    0x2902   /* 41 02 16-Bit Analog Output Block */
357
358 /* Analog Output Quality Flags */
359 #define AL_OBJ_AO_FLAG0    0x0001   /* Point Online (0=Offline; 1=Online) */
360 #define AL_OBJ_AO_FLAG1    0x0002   /* Restart (0=Normal; 1=Restart) */
361 #define AL_OBJ_AO_FLAG2    0x0004   /* Comms Lost (0=Normal; 1=Lost) */
362 #define AL_OBJ_AO_FLAG3    0x0008   /* Remote Force (0=Normal; 1=Forced) */
363 #define AL_OBJ_AO_FLAG4    0x0010   /* Reserved */
364 #define AL_OBJ_AO_FLAG5    0x0020   /* Reserved */
365 #define AL_OBJ_AO_FLAG6    0x0040   /* Reserved */
366 #define AL_OBJ_AO_FLAG7    0x0080   /* Reserved */
367
368 /***************************************************************************/
369 /* Time Objects */
370 #define AL_OBJ_TD          0x3201   /* 50 01 Time and Date */
371 #define AL_OBJ_TDI         0x3202   /* 50 02 Time and Date w/ Interval */
372 #define AL_OBJ_TDCTO       0x3301   /* 51 01 Time and Date CTO */
373 #define AL_OBJ_UTDCTO      0x3302   /* 51 02 Unsynchronized Time and Date CTO */
374 #define AL_OBJ_TDELAYC     0x3401   /* 52 01 Time Delay Coarse */
375 #define AL_OBJ_TDELAYF     0x3402   /* 52 02 Time Delay Fine */
376
377 /***************************************************************************/
378 /* Class Data Objects */
379 #define AL_OBJ_CLASS0      0x3C01   /* 60 01 Class 0 Data */
380 #define AL_OBJ_CLASS1      0x3C02   /* 60 02 Class 1 Data */
381 #define AL_OBJ_CLASS2      0x3C03   /* 60 03 Class 2 Data */
382 #define AL_OBJ_CLASS3      0x3C04   /* 60 04 Class 3 Data */
383
384 /***************************************************************************/
385 /* Device Objects */
386 #define AL_OBJ_IIN         0x5001   /* 80 01 Internal Indications */
387
388 /***************************************************************************/
389 /* End of Application Layer Data Object Definitions */
390 /***************************************************************************/
391
392 /* Initialize the protocol and registered fields */
393 static int proto_dnp3 = -1;
394 static int hf_dnp3_start = -1;
395 static int hf_dnp3_len = -1;
396 static int hf_dnp3_ctl = -1;
397 static int hf_dnp3_ctl_prifunc = -1;
398 static int hf_dnp3_ctl_secfunc = -1;
399 static int hf_dnp3_ctl_dir = -1;
400 static int hf_dnp3_ctl_prm = -1;
401 static int hf_dnp3_ctl_fcb = -1;
402 static int hf_dnp3_ctl_fcv = -1;
403 static int hf_dnp3_ctl_dfc = -1;
404 static int hf_dnp3_dst = -1;
405 static int hf_dnp3_src = -1;
406 static int hf_dnp_hdr_CRC = -1;
407 static int hf_dnp_hdr_CRC_bad = -1;
408 static int hf_dnp3_tr_ctl = -1;
409 static int hf_dnp3_tr_fin = -1;
410 static int hf_dnp3_tr_fir = -1;
411 static int hf_dnp3_tr_seq = -1;
412 static int hf_dnp3_al_ctl = -1;
413 static int hf_dnp3_al_fir = -1;
414 static int hf_dnp3_al_fin = -1;
415 static int hf_dnp3_al_con = -1;
416 static int hf_dnp3_al_seq = -1;
417 static int hf_dnp3_al_func = -1;
418 /* Added for Application Layer Decoding */
419 static int hf_dnp3_al_iin = -1;
420 static int hf_dnp3_al_iin_bmsg = -1;
421 static int hf_dnp3_al_iin_cls1d = -1;
422 static int hf_dnp3_al_iin_cls2d = -1;
423 static int hf_dnp3_al_iin_cls3d = -1;
424 static int hf_dnp3_al_iin_tsr = -1;
425 static int hf_dnp3_al_iin_dol = -1;
426 static int hf_dnp3_al_iin_dt = -1;
427 static int hf_dnp3_al_iin_rst = -1;
428 static int hf_dnp3_al_iin_obju = -1;
429 static int hf_dnp3_al_iin_pioor = -1;
430 static int hf_dnp3_al_iin_ebo = -1;
431 static int hf_dnp3_al_iin_oae = -1;
432 static int hf_dnp3_al_iin_cc = -1;
433 static int hf_dnp3_al_obj = -1;
434 static int hf_dnp3_al_objq_index = -1;
435 static int hf_dnp3_al_objq_code = -1;
436 static int hf_dnp3_al_range_start8 = -1;
437 static int hf_dnp3_al_range_stop8 = -1;
438 static int hf_dnp3_al_range_start16 = -1;
439 static int hf_dnp3_al_range_stop16 = -1;
440 static int hf_dnp3_al_range_start32 = -1;
441 static int hf_dnp3_al_range_stop32 = -1;
442 static int hf_dnp3_al_range_abs8 = -1;
443 static int hf_dnp3_al_range_abs16 = -1;
444 static int hf_dnp3_al_range_abs32 = -1;
445 static int hf_dnp3_al_range_quant8 = -1;
446 static int hf_dnp3_al_range_quant16 = -1;
447 static int hf_dnp3_al_range_quant32 = -1;
448 /*static int hf_dnp3_al_objq = -1;
449   static int hf_dnp3_al_nobj = -1; */
450 static int hf_dnp3_al_ptnum = -1;
451 static int hf_dnp3_al_biq_b0 = -1;
452 static int hf_dnp3_al_biq_b1 = -1;
453 static int hf_dnp3_al_biq_b2 = -1;
454 static int hf_dnp3_al_biq_b3 = -1;
455 static int hf_dnp3_al_biq_b4 = -1;
456 static int hf_dnp3_al_biq_b5 = -1;
457 static int hf_dnp3_al_biq_b6 = -1;
458 static int hf_dnp3_al_biq_b7 = -1;
459 static int hf_dnp3_al_boq_b0 = -1;
460 static int hf_dnp3_al_boq_b1 = -1;
461 static int hf_dnp3_al_boq_b2 = -1;
462 static int hf_dnp3_al_boq_b3 = -1;
463 static int hf_dnp3_al_boq_b4 = -1;
464 static int hf_dnp3_al_boq_b5 = -1;
465 static int hf_dnp3_al_boq_b6 = -1;
466 static int hf_dnp3_al_boq_b7 = -1;
467 static int hf_dnp3_al_ctrq_b0 = -1;
468 static int hf_dnp3_al_ctrq_b1 = -1;
469 static int hf_dnp3_al_ctrq_b2 = -1;
470 static int hf_dnp3_al_ctrq_b3 = -1;
471 static int hf_dnp3_al_ctrq_b4 = -1;
472 static int hf_dnp3_al_ctrq_b5 = -1;
473 static int hf_dnp3_al_ctrq_b6 = -1;
474 static int hf_dnp3_al_ctrq_b7 = -1;
475 static int hf_dnp3_al_aiq_b0 = -1;
476 static int hf_dnp3_al_aiq_b1 = -1;
477 static int hf_dnp3_al_aiq_b2 = -1;
478 static int hf_dnp3_al_aiq_b3 = -1;
479 static int hf_dnp3_al_aiq_b4 = -1;
480 static int hf_dnp3_al_aiq_b5 = -1;
481 static int hf_dnp3_al_aiq_b6 = -1;
482 static int hf_dnp3_al_aiq_b7 = -1;
483 static int hf_dnp3_al_aoq_b0 = -1;
484 static int hf_dnp3_al_aoq_b1 = -1;
485 static int hf_dnp3_al_aoq_b2 = -1;
486 static int hf_dnp3_al_aoq_b3 = -1;
487 static int hf_dnp3_al_aoq_b4 = -1;
488 static int hf_dnp3_al_aoq_b5 = -1;
489 static int hf_dnp3_al_aoq_b6 = -1;
490 static int hf_dnp3_al_aoq_b7 = -1;
491
492 /* ************************************************************************* */
493 /*                   Header values for reassembly                            */
494 /* ************************************************************************* */
495 static int hf_fragments = -1;
496 static int hf_fragment = -1;
497 static int hf_fragment_overlap = -1;
498 static int hf_fragment_overlap_conflict = -1;
499 static int hf_fragment_multiple_tails = -1;
500 static int hf_fragment_too_long_fragment = -1;
501 static int hf_fragment_error = -1;
502 static int hf_fragment_reassembled_in = -1;
503
504 /***************************************************************************/
505 /* Value String Look-Ups */
506 /***************************************************************************/
507 static const value_string dnp3_ctl_func_pri_vals[] = {
508   { DL_FUNC_RESET_LINK, "Reset of Remote Link" },
509   { DL_FUNC_RESET_PROC, "Reset of User Process" },
510   { DL_FUNC_TEST_LINK,  "Test Function For Link" },
511   { DL_FUNC_USER_DATA,  "User Data" },
512   { DL_FUNC_UNC_DATA,   "Unconfirmed User Data" },
513   { DL_FUNC_LINK_STAT,  "Request Link Status" },
514   { 0, NULL }
515 };
516
517 static const value_string dnp3_ctl_func_sec_vals[] = {
518   { DL_FUNC_ACK,        "ACK" },
519   { DL_FUNC_NACK,       "NACK" },
520   { DL_FUNC_STAT_LINK,  "Status of Link" },
521   { DL_FUNC_NO_FUNC,    "Link Service Not Functioning" },
522   { DL_FUNC_NOT_IMPL,   "Link Service Not Used or Implemented" },
523   { 0,  NULL }
524 };
525
526 static const value_string dnp3_ctl_flags_pri_vals[] = {
527   { DNP3_CTL_DIR, "DIR" },
528   { DNP3_CTL_PRM, "PRM" },
529   { DNP3_CTL_FCB, "FCB" },
530   { DNP3_CTL_FCV, "FCV" },
531   { 0,  NULL }
532 };
533
534 static const value_string dnp3_ctl_flags_sec_vals[] = {
535   { DNP3_CTL_DIR, "DIR" },
536   { DNP3_CTL_PRM, "PRM" },
537   { DNP3_CTL_RES, "RES" },
538   { DNP3_CTL_DFC, "DFC" },
539   { 0,  NULL }
540 };
541
542 static const value_string dnp3_tr_flags_vals[] = {
543   { DNP3_TR_FIN,  "FIN" },
544   { DNP3_TR_FIR,  "FIR" },
545   { 0,  NULL }
546 };
547
548 static const value_string dnp3_al_flags_vals[] = {
549   { DNP3_AL_FIR,  "FIR" },
550   { DNP3_AL_FIN,  "FIN" },
551   { DNP3_AL_CON,  "CON" },
552   { 0,  NULL }
553 };
554
555 /* Application Layer Function Code Values */
556 static const value_string dnp3_al_func_vals[] = {
557   { AL_FUNC_CONFIRM,    "Confirm" },
558   { AL_FUNC_READ,       "Read" },
559   { AL_FUNC_WRITE,      "Write" },
560   { AL_FUNC_SELECT,     "Select" },
561   { AL_FUNC_OPERATE,    "Operate" },
562   { AL_FUNC_DIROP,      "Direct Operate" },
563   { AL_FUNC_DIROPNACK,  "Direct Operate No Ack" },
564   { AL_FUNC_FRZ,        "Immediate Freeze" },
565   { AL_FUNC_FRZNACK,    "Immediate Freeze No Ack" },
566   { AL_FUNC_FRZCLR,     "Freeze and Clear" },
567   { AL_FUNC_FRZCLRNACK, "Freeze and Clear No ACK" },
568   { AL_FUNC_FRZT,       "Freeze With Time" },
569   { AL_FUNC_FRZTNACK,   "Freeze With Time No ACK" },
570   { AL_FUNC_COLDRST,    "Cold Restart" },
571   { AL_FUNC_WARMRST,    "Warm Restart" },
572   { AL_FUNC_INITDATA,   "Initialize Data" },
573   { AL_FUNC_INITAPP,    "Initialize Application" },
574   { AL_FUNC_STARTAPP,   "Start Application" },
575   { AL_FUNC_STOPAPP,    "Stop Application" },
576   { AL_FUNC_SAVECFG,    "Save Configuration" },
577   { AL_FUNC_ENSPMSG,    "Enable Spontaneous Messages" },
578   { AL_FUNC_DISSPMSG,   "Disable Spontaneous Messages" },
579   { AL_FUNC_ASSIGNCL,   "Assign Classes" },
580   { AL_FUNC_DELAYMST,   "Delay Measurement" },
581   { AL_FUNC_RESPON,     "Response" },
582   { AL_FUNC_UNSOLI,     "Unsolicited Response" },
583   { 0, NULL }
584 };
585
586 /* Application Layer Internal Indication (IIN) bit Values */
587 static const value_string dnp3_al_iin_vals[] = {
588   { AL_IIN_BMSG,    "Broadcast message Rx'd" },
589   { AL_IIN_CLS1D,   "Class 1 Data Available" },
590   { AL_IIN_CLS2D,   "Class 2 Data Available" },
591   { AL_IIN_CLS3D,   "Class 3 Data Available" },
592   { AL_IIN_TSR,     "Time Sync Required from Master" },
593   { AL_IIN_DOL,     "Digital Outputs in Local Mode" },
594   { AL_IIN_DT,      "Device Trouble" },
595   { AL_IIN_RST,     "Device Restart" },
596   { AL_IIN_OBJU,    "Requested Objects Unknown" },
597   { AL_IIN_PIOOR,   "Parameters Invalid or Out of Range" },
598   { AL_IIN_EBO,     "Event Buffer Overflow" },
599   { AL_IIN_OAE,     "Operation Already Executing" },
600   { AL_IIN_CC,      "Device Configuration Corrupt" },
601   { 0, NULL }
602 };
603
604 /* Application Layer Object Qualifier Index Values When Qualifier Code != 11 */
605 static const value_string dnp3_al_objq_index_vals[] = {
606   { AL_OBJQL_IDX_NI,    "None" },
607   { AL_OBJQL_IDX_1O,    "1-Octet Indexing" },
608   { AL_OBJQL_IDX_2O,    "2-Octet Indexing" },
609   { AL_OBJQL_IDX_4O,    "4-Octet Indexing" },
610   { AL_OBJQL_IDX_1OS,   "1-Octet Object Size" },
611   { AL_OBJQL_IDX_2OS,   "2-Octet Object Size" },
612   { AL_OBJQL_IDX_4OS,   "4-Octet Object Size" },
613   { 0, NULL }
614 };
615
616 /* Application Layer Object Qualifier Code Values */
617 static const value_string dnp3_al_objq_code_vals[] = {
618   { AL_OBJQL_CODE_SSI8,     "8-bit Start and Stop Indices" },
619   { AL_OBJQL_CODE_SSI16,    "16-bit Start and Stop Indices" },
620   { AL_OBJQL_CODE_SSI32,    "32-bit Start and Stop Indices" },
621   { AL_OBJQL_CODE_AA8,      "8-bit Absolute Address in Range Field" },
622   { AL_OBJQL_CODE_AA16,     "16-bit Absolute Address in Range Field" },
623   { AL_OBJQL_CODE_AA32,     "32-bit Absolute Address in Range Field" },
624   { AL_OBJQL_CODE_R0,       "No Range Field" },
625   { AL_OBJQL_CODE_SF8,      "8-bit Single Field Quantity" },
626   { AL_OBJQL_CODE_SF16,     "16-bit Single Field Quantity" },
627   { AL_OBJQL_CODE_SF32,     "32-bit Single Field Quantity" },
628   { AL_OBJQL_CODE_FF,       "Free-format Qualifier" },
629   { 0, NULL }
630 };
631
632 /* Application Layer Data Object Values */
633 static const value_string dnp3_al_obj_vals[] = {
634   { AL_OBJ_BI_ALL,     "Binary Input All Variations (Obj:01, Var:All)" },
635   { AL_OBJ_BI_1BIT,    "Single-Bit Binary Input (Obj:01, Var:01)" },
636   { AL_OBJ_BI_STAT,    "Binary Input With Status (Obj:01, Var:02)" },
637   { AL_OBJ_BIC_ALL,    "Binary Input Change All Variations (Obj:02, Var:All)" },
638   { AL_OBJ_BIC_NOTIME, "Binary Input Change Without Time (Obj:02, Var:01)" },
639   { AL_OBJ_BIC_TIME,   "Binary Input Change With Time (Obj:02, Var:02)" },
640   { AL_OBJ_BIC_RTIME,  "Binary Input Change With Relative Time (Obj:02, Var:03)" },
641   { AL_OBJ_BO,         "Binary Output (Obj:10, Var:01)" },
642   { AL_OBJ_BO_STAT,    "Binary Output Status (Obj:10, Var:02)" },
643   { AL_OBJ_CTLOP_BLK,  "Control Relay Output Block (Obj:12, Var:01)" },
644   { AL_OBJ_CTR_ALL,    "Binary Counter All Variations (Obj:20, Var:All)" },
645   { AL_OBJ_CTR_32,     "32-Bit Binary Counter (Obj:20, Var:01)" },
646   { AL_OBJ_CTR_16,     "16-Bit Binary Counter (Obj:20, Var:02)" },
647   { AL_OBJ_CTR_32NF,   "32-Bit Binary Counter Without Flag (Obj:20, Var:05)" },
648   { AL_OBJ_CTR_16NF,   "16-Bit Binary Counter Without Flag (Obj:20, Var:06)" },
649   { AL_OBJ_FCTR_32,    "32-Bit Frozen Counter (Obj:21, Var:01)"},
650   { AL_OBJ_FCTR_16,    "16-Bit Frozen Counter (Obj:21, Var:02)"},
651   { AL_OBJ_CTRC_ALL,   "Binary Counter Change All Variations (Obj:22, Var:All)" },
652   { AL_OBJ_CTRC_32,    "32-Bit Counter Change Event w/o Time (Obj:22, Var:01)" },
653   { AL_OBJ_CTRC_16,    "16-Bit Counter Change Event w/o Time (Obj:22, Var:02)" },
654   { AL_OBJ_AI_ALL,     "Analog Input All Variations (Obj:30, Var:All)" },
655   { AL_OBJ_AI_32,      "32-Bit Analog Input (Obj:30, Var:01)" },
656   { AL_OBJ_AI_16,      "16-Bit Analog Input (Obj:30, Var:02)" },
657   { AL_OBJ_AI_32NF,    "32-Bit Analog Input Without Flag (Obj:30, Var:03)" },
658   { AL_OBJ_AI_16NF,    "16-Bit Analog Input Without Flag (Obj:30, Var:04)" },
659   { AL_OBJ_AIC_ALL,    "Analog Input Change All Variations (Obj:32, Var:All)" },
660   { AL_OBJ_AIC_32NT,   "32-Bit Analog Change Event w/o Time (Obj:32, Var:01)" },
661   { AL_OBJ_AIC_16NT,   "16-Bit Analog Change Event w/o Time (Obj:32, Var:02)" },
662   { AL_OBJ_AIC_32T,    "32-Bit Analog Change Event with Time (Obj:32, Var:03)" },
663   { AL_OBJ_AIC_16T,    "16-Bit Analog Change Event with Time (Obj:32, Var:04)" },
664   { AL_OBJ_AO_16,      "16-Bit Analog Output Status (Obj:40, Var:02)"},
665   { AL_OBJ_TD,         "Time and Date (Obj:50, Var:01)" },
666   { AL_OBJ_TDELAYF,    "Time Delay - Fine (Obj:52, Var:02)" },
667   { AL_OBJ_CLASS0,     "Class 0 Data (Obj:60, Var:01)" },
668   { AL_OBJ_CLASS1,     "Class 1 Data (Obj:60, Var:02)" },
669   { AL_OBJ_CLASS2,     "Class 2 Data (Obj:60, Var:03)" },
670   { AL_OBJ_CLASS3,     "Class 3 Data (Obj:60, Var:04)" },
671   { AL_OBJ_IIN,        "Internal Indications (Obj:80, Var:01)" },
672   { 0, NULL }
673 };
674
675 /* Application Layer Control Code 'Code' Values */
676 static const value_string dnp3_al_ctlc_code_vals[] = {
677   { AL_OBJCTLC_CODE0,     "NUL Operation" },
678   { AL_OBJCTLC_CODE1,     "Pulse On" },
679   { AL_OBJCTLC_CODE2,     "Pulse Off" },
680   { AL_OBJCTLC_CODE3,     "Latch On" },
681   { AL_OBJCTLC_CODE4,     "Latch Off" },
682   { 0, NULL }
683 };
684
685 /* Application Layer Control Code 'Misc' Values */
686 static const value_string dnp3_al_ctlc_misc_vals[] = {
687   { AL_OBJCTLC_QUEUE,     "Queue" },
688   { AL_OBJCTLC_CLEAR,     "Clear" },
689   { 0, NULL }
690 };
691
692 /* Application Layer Control Code 'Trip/Close' Values */
693 static const value_string dnp3_al_ctlc_tc_vals[] = {
694   { AL_OBJCTLC_TC0,     "NUL" },
695   { AL_OBJCTLC_TC1,     "Close" },
696   { AL_OBJCTLC_TC2,     "Trip" },
697   { 0, NULL }
698 };
699
700 /* Application Layer Control Status Values */
701 static const value_string dnp3_al_ctl_status_vals[] = {
702   { AL_OBJCTL_STAT0,     "Req. Accepted/Init/Queued" },
703   { AL_OBJCTL_STAT1,     "Req. Not Accepted; Arm-Timer Expired" },
704   { AL_OBJCTL_STAT2,     "Req. Not Accepted; No 'SELECT' Received" },
705   { AL_OBJCTL_STAT3,     "Req. Not Accepted; Format Err. in Ctl Req." },
706   { AL_OBJCTL_STAT4,     "Ctl Oper. Not Supported For This Point" },
707   { AL_OBJCTL_STAT5,     "Req. Not Accepted; Ctrl Queue Full/Point Active" },
708   { AL_OBJCTL_STAT6,     "Req. Not Accepted; Ctrl Hardware Problems" },
709   { 0, NULL }
710 };
711
712 /* Application Layer Binary Input Quality Flag Values */
713 static const value_string dnp3_al_biflag_vals[] = {
714   { AL_OBJ_BI_FLAG0, "Online" },
715   { AL_OBJ_BI_FLAG1, "Restart" },
716   { AL_OBJ_BI_FLAG2, "Comm Fail" },
717   { AL_OBJ_BI_FLAG3, "Remote Forced" },
718   { AL_OBJ_BI_FLAG4, "Locally Forced" },
719   { AL_OBJ_BI_FLAG5, "Chatter Filter" },
720   { 0, NULL }
721 };
722
723 /* Application Layer Counter Quality Flag Values */
724 static const value_string dnp3_al_ctrflag_vals[] = {
725   { AL_OBJ_CTR_FLAG0, "Online" },
726   { AL_OBJ_CTR_FLAG1, "Restart" },
727   { AL_OBJ_CTR_FLAG2, "Comm Fail" },
728   { AL_OBJ_CTR_FLAG3, "Remote Forced" },
729   { AL_OBJ_CTR_FLAG4, "Locally Forced" },
730   { AL_OBJ_CTR_FLAG5, "Roll-Over" },
731   { 0, NULL }
732 };
733
734 /* Application Layer Analog Input Quality Flag Values */
735 static const value_string dnp3_al_aiflag_vals[] = {
736   { AL_OBJ_AI_FLAG0, "Online" },
737   { AL_OBJ_AI_FLAG1, "Restart" },
738   { AL_OBJ_AI_FLAG2, "Comm Fail" },
739   { AL_OBJ_AI_FLAG3, "Remote Forced" },
740   { AL_OBJ_AI_FLAG4, "Locally Forced" },
741   { AL_OBJ_AI_FLAG5, "Over-Range" },
742   { AL_OBJ_AI_FLAG6, "Ref. Error" },
743   { 0, NULL }
744 };
745
746 /* Initialize the subtree pointers */
747 static gint ett_dnp3 = -1;
748 static gint ett_dnp3_dl = -1;
749 static gint ett_dnp3_dl_ctl = -1;
750 static gint ett_dnp3_tr_ctl = -1;
751 static gint ett_dnp3_al_data = -1;
752 static gint ett_dnp3_al = -1;
753 static gint ett_dnp3_al_ctl = -1;
754 static gint ett_fragment = -1;
755 static gint ett_fragments = -1;
756 /* Added for Application Layer Decoding */
757 static gint ett_dnp3_al_iin = -1;
758 static gint ett_dnp3_al_obj = -1;
759 static gint ett_dnp3_al_obj_qualifier = -1;
760 static gint ett_dnp3_al_obj_range = -1;
761 static gint ett_dnp3_al_objdet = -1;
762 static gint ett_dnp3_al_obj_quality = -1;
763
764 /* Tables for reassembly of fragments. */
765 static GHashTable *al_fragment_table = NULL;
766 static GHashTable *al_reassembled_table = NULL;
767
768 static const fragment_items frag_items = {
769   &ett_fragment,
770   &ett_fragments,
771   &hf_fragments,
772   &hf_fragment,
773   &hf_fragment_overlap,
774   &hf_fragment_overlap_conflict,
775   &hf_fragment_multiple_tails,
776   &hf_fragment_too_long_fragment,
777   &hf_fragment_error,
778   &hf_fragment_reassembled_in,
779   "fragments"
780 };
781
782 /*****************************************************************/
783 /*                                                               */
784 /* CRC LOOKUP TABLE                                              */
785 /* ================                                              */
786 /* The following CRC lookup table was generated automagically    */
787 /* by the Rocksoft^tm Model CRC Algorithm Table Generation       */
788 /* Program V1.0 using the following model parameters:            */
789 /*                                                               */
790 /*    Width   : 2 bytes.                                         */
791 /*    Poly    : 0x3D65                                           */
792 /*    Reverse : TRUE.                                            */
793 /*                                                               */
794 /* For more information on the Rocksoft^tm Model CRC Algorithm,  */
795 /* see the document titled "A Painless Guide to CRC Error        */
796 /* Detection Algorithms" by Ross Williams                        */
797 /* (ross@guest.adelaide.edu.au.). This document is likely to be  */
798 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft".        */
799 /*                                                               */
800 /*****************************************************************/
801
802 static guint16 crctable[256] =
803 {
804  0x0000, 0x365E, 0x6CBC, 0x5AE2, 0xD978, 0xEF26, 0xB5C4, 0x839A,
805  0xFF89, 0xC9D7, 0x9335, 0xA56B, 0x26F1, 0x10AF, 0x4A4D, 0x7C13,
806  0xB26B, 0x8435, 0xDED7, 0xE889, 0x6B13, 0x5D4D, 0x07AF, 0x31F1,
807  0x4DE2, 0x7BBC, 0x215E, 0x1700, 0x949A, 0xA2C4, 0xF826, 0xCE78,
808  0x29AF, 0x1FF1, 0x4513, 0x734D, 0xF0D7, 0xC689, 0x9C6B, 0xAA35,
809  0xD626, 0xE078, 0xBA9A, 0x8CC4, 0x0F5E, 0x3900, 0x63E2, 0x55BC,
810  0x9BC4, 0xAD9A, 0xF778, 0xC126, 0x42BC, 0x74E2, 0x2E00, 0x185E,
811  0x644D, 0x5213, 0x08F1, 0x3EAF, 0xBD35, 0x8B6B, 0xD189, 0xE7D7,
812  0x535E, 0x6500, 0x3FE2, 0x09BC, 0x8A26, 0xBC78, 0xE69A, 0xD0C4,
813  0xACD7, 0x9A89, 0xC06B, 0xF635, 0x75AF, 0x43F1, 0x1913, 0x2F4D,
814  0xE135, 0xD76B, 0x8D89, 0xBBD7, 0x384D, 0x0E13, 0x54F1, 0x62AF,
815  0x1EBC, 0x28E2, 0x7200, 0x445E, 0xC7C4, 0xF19A, 0xAB78, 0x9D26,
816  0x7AF1, 0x4CAF, 0x164D, 0x2013, 0xA389, 0x95D7, 0xCF35, 0xF96B,
817  0x8578, 0xB326, 0xE9C4, 0xDF9A, 0x5C00, 0x6A5E, 0x30BC, 0x06E2,
818  0xC89A, 0xFEC4, 0xA426, 0x9278, 0x11E2, 0x27BC, 0x7D5E, 0x4B00,
819  0x3713, 0x014D, 0x5BAF, 0x6DF1, 0xEE6B, 0xD835, 0x82D7, 0xB489,
820  0xA6BC, 0x90E2, 0xCA00, 0xFC5E, 0x7FC4, 0x499A, 0x1378, 0x2526,
821  0x5935, 0x6F6B, 0x3589, 0x03D7, 0x804D, 0xB613, 0xECF1, 0xDAAF,
822  0x14D7, 0x2289, 0x786B, 0x4E35, 0xCDAF, 0xFBF1, 0xA113, 0x974D,
823  0xEB5E, 0xDD00, 0x87E2, 0xB1BC, 0x3226, 0x0478, 0x5E9A, 0x68C4,
824  0x8F13, 0xB94D, 0xE3AF, 0xD5F1, 0x566B, 0x6035, 0x3AD7, 0x0C89,
825  0x709A, 0x46C4, 0x1C26, 0x2A78, 0xA9E2, 0x9FBC, 0xC55E, 0xF300,
826  0x3D78, 0x0B26, 0x51C4, 0x679A, 0xE400, 0xD25E, 0x88BC, 0xBEE2,
827  0xC2F1, 0xF4AF, 0xAE4D, 0x9813, 0x1B89, 0x2DD7, 0x7735, 0x416B,
828  0xF5E2, 0xC3BC, 0x995E, 0xAF00, 0x2C9A, 0x1AC4, 0x4026, 0x7678,
829  0x0A6B, 0x3C35, 0x66D7, 0x5089, 0xD313, 0xE54D, 0xBFAF, 0x89F1,
830  0x4789, 0x71D7, 0x2B35, 0x1D6B, 0x9EF1, 0xA8AF, 0xF24D, 0xC413,
831  0xB800, 0x8E5E, 0xD4BC, 0xE2E2, 0x6178, 0x5726, 0x0DC4, 0x3B9A,
832  0xDC4D, 0xEA13, 0xB0F1, 0x86AF, 0x0535, 0x336B, 0x6989, 0x5FD7,
833  0x23C4, 0x159A, 0x4F78, 0x7926, 0xFABC, 0xCCE2, 0x9600, 0xA05E,
834  0x6E26, 0x5878, 0x029A, 0x34C4, 0xB75E, 0x8100, 0xDBE2, 0xEDBC,
835  0x91AF, 0xA7F1, 0xFD13, 0xCB4D, 0x48D7, 0x7E89, 0x246B, 0x1235
836 };
837
838 /*****************************************************************/
839 /*                   End of CRC Lookup Table                     */
840 /*****************************************************************/
841
842 /* calculates crc given a buffer of characters and a length of buffer */
843 static guint16
844 calculateCRC(const void *buf, guint len) {
845   guint16 crc = 0;
846   const guint8 *p = (const guint8 *)buf;
847   while(len-- > 0)
848     crc = crctable[(crc ^ *p++) & 0xff] ^ (crc >> 8);
849   return ~crc;
850 }
851
852 /*****************************************************************/
853 /*  Adds text to item, with trailing "," if required             */
854 /*****************************************************************/
855 static gboolean
856 add_item_text(proto_item *item, const gchar *text, gboolean comma_needed)
857 {
858   if (comma_needed) {
859     proto_item_append_text(item, ", ");
860   }
861   proto_item_append_text(item, text);
862   return TRUE;
863 }
864
865 /*****************************************************************/
866 /*  Application Layer Process Internal Indications (IIN)         */
867 /*****************************************************************/
868 static void
869 dnp3_al_process_iin(tvbuff_t *tvb, int offset, proto_tree *al_tree)
870 {
871
872   guint16       al_iin;
873   proto_item    *tiin;
874   proto_tree    *iin_tree = NULL;
875   gboolean      comma_needed = FALSE;
876
877   al_iin = tvb_get_ntohs(tvb, offset);
878
879   tiin = proto_tree_add_uint_format(al_tree, hf_dnp3_al_iin, tvb, offset, 2, al_iin,
880         "Internal Indications: ");
881   if (al_iin & AL_IIN_RST)    comma_needed = add_item_text(tiin, "Device Restart", comma_needed);
882   if (al_iin & AL_IIN_DOL)    comma_needed = add_item_text(tiin, "Digital Outputs in Local", comma_needed);
883   if (al_iin & AL_IIN_DT)     comma_needed = add_item_text(tiin, "Device Trouble", comma_needed);
884   if (al_iin & AL_IIN_TSR)    comma_needed = add_item_text(tiin, "Time Sync Required", comma_needed);
885   if (al_iin & AL_IIN_CLS3D)  comma_needed = add_item_text(tiin, "Class 3 Data Available", comma_needed);
886   if (al_iin & AL_IIN_CLS2D)  comma_needed = add_item_text(tiin, "Class 2 Data Available", comma_needed);
887   if (al_iin & AL_IIN_CLS1D)  comma_needed = add_item_text(tiin, "Class 1 Data Available", comma_needed);
888   if (al_iin & AL_IIN_BMSG)   comma_needed = add_item_text(tiin, "Broadcast Message Rx'd", comma_needed);
889   if (al_iin & AL_IIN_CC)     comma_needed = add_item_text(tiin, "Device Configuration Corrupt", comma_needed);
890   if (al_iin & AL_IIN_OAE)    comma_needed = add_item_text(tiin, "Operation Already Executing", comma_needed);
891   if (al_iin & AL_IIN_EBO)    comma_needed = add_item_text(tiin, "Event Buffer Overflow", comma_needed);
892   if (al_iin & AL_IIN_PIOOR)  comma_needed = add_item_text(tiin, "Parameters Invalid or Out of Range", comma_needed);
893   if (al_iin & AL_IIN_OBJU)   comma_needed = add_item_text(tiin, "Requested Objects Unknown", comma_needed);
894   proto_item_append_text(tiin, " (0x%04x)", al_iin);
895
896   iin_tree = proto_item_add_subtree(tiin, ett_dnp3_al_iin);
897   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_rst, tvb, offset, 2, FALSE);
898   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_dt, tvb, offset, 2, FALSE);
899   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_dol, tvb, offset, 2, FALSE);
900   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_tsr, tvb, offset, 2, FALSE);
901   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls3d, tvb, offset, 2, FALSE);
902   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls2d, tvb, offset, 2, FALSE);
903   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cls1d, tvb, offset, 2, FALSE);
904   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_bmsg, tvb, offset, 2, FALSE);
905   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_cc, tvb, offset, 2, FALSE);
906   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_oae, tvb, offset, 2, FALSE);
907   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_ebo, tvb, offset, 2, FALSE);
908   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_pioor, tvb, offset, 2, FALSE);
909   proto_tree_add_item(iin_tree, hf_dnp3_al_iin_obju, tvb, offset, 2, FALSE);
910 }
911
912 /*****************************************************************/
913 /* Function to determine Application Layer Object Index size */
914 /*****************************************************************/
915 static int
916 dnp3_al_obj_procindex(tvbuff_t *tvb, int bitindex, int offset, guint8 al_objq_index, guint32 *al_ptaddr)
917 {
918   int indexbytes = 0;
919
920   switch (al_objq_index)
921   {
922     case AL_OBJQL_IDX_NI:        /* No Index */
923      if (bitindex > 0)           /* Increment Address by 1 */
924      {
925       *al_ptaddr += 1;
926      }
927     indexbytes = 0;
928      break;
929     case AL_OBJQL_IDX_1O:
930      *al_ptaddr = tvb_get_guint8(tvb, offset);
931      indexbytes = 1;
932      break;
933     case AL_OBJQL_IDX_2O:
934      *al_ptaddr = tvb_get_letohs(tvb, offset);
935      indexbytes = 2;
936      break;
937     case AL_OBJQL_IDX_4O:
938      *al_ptaddr = tvb_get_letohl(tvb, offset);
939      indexbytes = 4;
940      break;
941   }
942   return indexbytes;
943 }
944
945 /*****************************************************************/
946 /* Function to Determine Application Layer Point Quality Flags & */
947 /* add Point Quality Flag Sub-Tree */
948 /*****************************************************************/
949 static void
950 dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_point, int type)
951 {
952
953   proto_tree  *quality_tree = NULL;
954   int         hf0 = 0, hf1 = 0, hf2 = 0, hf3 = 0, hf4 = 0, hf5 = 0, hf6 = 0, hf7 = 0;
955
956   proto_item_append_text(t_point, "(Quality: ");
957   switch (type) {
958     case 0: /* Binary Input Quality flags */
959       quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
960
961       if (al_ptflags & AL_OBJ_BI_FLAG0) {
962         proto_item_append_text(t_point, "Online");
963       }
964       else {
965         proto_item_append_text(t_point, "Offline");
966       }
967       if (al_ptflags & AL_OBJ_BI_FLAG1) proto_item_append_text(t_point, ", Restart");
968       if (al_ptflags & AL_OBJ_BI_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
969       if (al_ptflags & AL_OBJ_BI_FLAG3) proto_item_append_text(t_point, ", Remote Force");
970       if (al_ptflags & AL_OBJ_BI_FLAG4) proto_item_append_text(t_point, ", Local Force");
971       if (al_ptflags & AL_OBJ_BI_FLAG5) proto_item_append_text(t_point, ", Chatter Filter");
972
973       hf0 = hf_dnp3_al_biq_b0;
974       hf1 = hf_dnp3_al_biq_b1;
975       hf2 = hf_dnp3_al_biq_b2;
976       hf3 = hf_dnp3_al_biq_b3;
977       hf4 = hf_dnp3_al_biq_b4;
978       hf5 = hf_dnp3_al_biq_b5;
979       hf6 = hf_dnp3_al_biq_b6;
980       hf7 = hf_dnp3_al_biq_b7;
981       break;
982
983     case 1: /* Binary Output Quality flags */
984       quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
985
986       if (al_ptflags & AL_OBJ_BO_FLAG0) {
987         proto_item_append_text(t_point, "Online");
988       }
989       else {
990         proto_item_append_text(t_point, "Offline");
991       }
992       if (al_ptflags & AL_OBJ_BO_FLAG1) proto_item_append_text(t_point, ", Restart");
993       if (al_ptflags & AL_OBJ_BO_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
994       if (al_ptflags & AL_OBJ_BO_FLAG3) proto_item_append_text(t_point, ", Remote Force");
995       if (al_ptflags & AL_OBJ_BO_FLAG4) proto_item_append_text(t_point, ", Local Force");
996
997       hf0 = hf_dnp3_al_boq_b0;
998       hf1 = hf_dnp3_al_boq_b1;
999       hf2 = hf_dnp3_al_boq_b2;
1000       hf3 = hf_dnp3_al_boq_b3;
1001       hf4 = hf_dnp3_al_boq_b4;
1002       hf5 = hf_dnp3_al_boq_b5;
1003       hf6 = hf_dnp3_al_boq_b6;
1004       hf7 = hf_dnp3_al_boq_b7;
1005       break;
1006
1007     case 2: /* Counter Quality flags */
1008       quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1009
1010       if (al_ptflags & AL_OBJ_CTR_FLAG0) {
1011         proto_item_append_text(t_point, "Online");
1012       }
1013       else {
1014         proto_item_append_text(t_point, "Offline");
1015       }
1016       if (al_ptflags & AL_OBJ_CTR_FLAG1) proto_item_append_text(t_point, ", Restart");
1017       if (al_ptflags & AL_OBJ_CTR_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
1018       if (al_ptflags & AL_OBJ_CTR_FLAG3) proto_item_append_text(t_point, ", Remote Force");
1019       if (al_ptflags & AL_OBJ_CTR_FLAG4) proto_item_append_text(t_point, ", Local Force");
1020       if (al_ptflags & AL_OBJ_CTR_FLAG5) proto_item_append_text(t_point, ", Roll-over");
1021
1022       hf0 = hf_dnp3_al_ctrq_b0;
1023       hf1 = hf_dnp3_al_ctrq_b1;
1024       hf2 = hf_dnp3_al_ctrq_b2;
1025       hf3 = hf_dnp3_al_ctrq_b3;
1026       hf4 = hf_dnp3_al_ctrq_b4;
1027       hf5 = hf_dnp3_al_ctrq_b5;
1028       hf6 = hf_dnp3_al_ctrq_b6;
1029       hf7 = hf_dnp3_al_ctrq_b7;
1030       break;
1031
1032     case 3: /* Analog Input Quality flags */
1033       quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1034
1035       if (al_ptflags & AL_OBJ_AI_FLAG0) {
1036         proto_item_append_text(t_point, "Online");
1037       }
1038       else {
1039         proto_item_append_text(t_point, "Offline");
1040       }
1041       if (al_ptflags & AL_OBJ_AI_FLAG1) proto_item_append_text(t_point, ", Restart");
1042       if (al_ptflags & AL_OBJ_AI_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
1043       if (al_ptflags & AL_OBJ_AI_FLAG3) proto_item_append_text(t_point, ", Remote Force");
1044       if (al_ptflags & AL_OBJ_AI_FLAG4) proto_item_append_text(t_point, ", Local Force");
1045       if (al_ptflags & AL_OBJ_AI_FLAG5) proto_item_append_text(t_point, ", Over-Range");
1046       if (al_ptflags & AL_OBJ_AI_FLAG6) proto_item_append_text(t_point, ", Reference Check");
1047
1048       hf0 = hf_dnp3_al_aiq_b0;
1049       hf1 = hf_dnp3_al_aiq_b1;
1050       hf2 = hf_dnp3_al_aiq_b2;
1051       hf3 = hf_dnp3_al_aiq_b3;
1052       hf4 = hf_dnp3_al_aiq_b4;
1053       hf5 = hf_dnp3_al_aiq_b5;
1054       hf6 = hf_dnp3_al_aiq_b6;
1055       hf7 = hf_dnp3_al_aiq_b7;
1056       break;
1057
1058     case 4: /* Analog Output Quality flags */
1059       quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1060
1061       if (al_ptflags & AL_OBJ_AO_FLAG0) {
1062         proto_item_append_text(t_point, "Online");
1063       }
1064       else {
1065         proto_item_append_text(t_point, "Offline");
1066       }
1067       if (al_ptflags & AL_OBJ_AO_FLAG1) proto_item_append_text(t_point, ", Restart");
1068       if (al_ptflags & AL_OBJ_AO_FLAG2) proto_item_append_text(t_point, ", Comm Fail");
1069       if (al_ptflags & AL_OBJ_AO_FLAG3) proto_item_append_text(t_point, ", Remote Force");
1070
1071       hf0 = hf_dnp3_al_aoq_b0;
1072       hf1 = hf_dnp3_al_aoq_b1;
1073       hf2 = hf_dnp3_al_aoq_b2;
1074       hf3 = hf_dnp3_al_aoq_b3;
1075       hf4 = hf_dnp3_al_aoq_b4;
1076       hf5 = hf_dnp3_al_aoq_b5;
1077       hf6 = hf_dnp3_al_aoq_b6;
1078       hf7 = hf_dnp3_al_aoq_b7;
1079       break;
1080   }
1081
1082   if (quality_tree != NULL) {
1083     proto_tree_add_item(quality_tree, hf7, tvb, offset, 1, TRUE);
1084     proto_tree_add_item(quality_tree, hf6, tvb, offset, 1, TRUE);
1085     proto_tree_add_item(quality_tree, hf5, tvb, offset, 1, TRUE);
1086     proto_tree_add_item(quality_tree, hf4, tvb, offset, 1, TRUE);
1087     proto_tree_add_item(quality_tree, hf3, tvb, offset, 1, TRUE);
1088     proto_tree_add_item(quality_tree, hf2, tvb, offset, 1, TRUE);
1089     proto_tree_add_item(quality_tree, hf1, tvb, offset, 1, TRUE);
1090     proto_tree_add_item(quality_tree, hf0, tvb, offset, 1, TRUE);
1091   }
1092   proto_item_append_text(t_point, ")");
1093 }
1094
1095 /**********************************************************************/
1096 /* Function to Decode Timestamp From DNP3 Message                     */
1097 /**********************************************************************/
1098 /* 48-bit Time Format                                                 */
1099 /* MSB      FF       EE       DD       CC       BB       AA      LSB  */
1100 /*       ffffffff eeeeeeee dddddddd cccccccc bbbbbbbb aaaaaaaa        */
1101 /*       47    40 39    32 31    24 23    16 15     8 7      0        */
1102 /* Final hex no. should be: 0xAABBCCDDEEFF                            */
1103 /* Epoch time + ms.  dd:mm:yyyy hh:mm:ss.iii                          */
1104 /**********************************************************************/
1105 static char *
1106 dnp3_al_decode_timestamp(tvbuff_t *tvb, int temp_pos, char* buff)
1107 {
1108
1109   guint32    hi, lo;
1110   guint64    al_timestamp, time_ms;
1111   time_t     alts_noms;
1112   struct tm  *ptm;
1113
1114   lo = tvb_get_letohs(tvb, temp_pos);
1115   hi = tvb_get_letohl(tvb, temp_pos + 2);
1116   al_timestamp = ((gint64)hi * 0x10000 + lo);
1117
1118   time_ms = al_timestamp % 1000; /* Determine ms from timestamp) */
1119   al_timestamp = al_timestamp / 1000; /*  Divide 1000 from raw timestamp to remove ms */
1120   alts_noms = (const long) al_timestamp;
1121   ptm = gmtime(&alts_noms);
1122
1123   /*g_snprintf(buff, 25,"%02d/%02d/%4d %02d:%02d:%02d.%03d",(ptm->tm_mon + 1), ptm->tm_mday,
1124           (ptm->tm_year+1900), ptm->tm_hour, ptm->tm_min, ptm->tm_sec, time_ms); */
1125   /* Time-stamp in ISO format - perhaps an option should be added for different locales? */
1126   g_snprintf(buff, 25,"%04d/%02d/%02d %02d:%02d:%02d.%03"PRIu64,(ptm->tm_year+1900),ptm->tm_mday,
1127           (ptm->tm_mon + 1), ptm->tm_hour, ptm->tm_min, ptm->tm_sec, time_ms);
1128
1129
1130   return buff;
1131
1132 }
1133
1134 /*****************************************************************/
1135 /*  Desc:    Application Layer Process Object Details            */
1136 /*  Returns: New offset pointer into tvb                         */
1137 /*****************************************************************/
1138 static int
1139 dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree)
1140 {
1141
1142   guint8        al_objq, al_objq_index, al_objq_code, al_ptflags, al_ctlobj_code,
1143                 al_ctlobj_code_c, al_ctlobj_code_m, al_ctlobj_code_tc, al_ctlobj_count, al_bi_val, bitindex=0;
1144   guint16       al_obj, temp16=0, al_val16=0, al_ctlobj_stat;
1145   guint32       al_val32, num_items=0, al_ptaddr=0, al_ctlobj_on, al_ctlobj_off;
1146   gboolean      al_bit;
1147   guint         temp_pos;
1148   int           rangebytes=0, indexbytes=0;
1149   proto_item    *t_objdet = NULL, *t_point = NULL, *qualifier_item = NULL, *range_item = NULL;
1150   proto_tree    *objdet_tree = NULL, *qualifier_tree, *range_tree;
1151   const gchar   *ctl_code_str, *ctl_misc_str, *ctl_tc_str, *ctl_status_str;
1152   gchar         buff[25];
1153
1154   /* Application Layer Objects in this Message */
1155   al_obj = tvb_get_ntohs(tvb, offset);
1156
1157   /* Create Data Objects Detail Tree */
1158   t_objdet = proto_tree_add_uint_format(robj_tree, hf_dnp3_al_obj, tvb, offset, 2, al_obj,
1159      "Object(s): %s (0x%04x)", val_to_str(al_obj, dnp3_al_obj_vals, "Unknown Object - Abort Decoding..."), al_obj);
1160   objdet_tree = proto_item_add_subtree(t_objdet, ett_dnp3_al_obj);
1161
1162   offset += 2;
1163
1164   /* Object Qualifier */
1165   al_objq = tvb_get_guint8(tvb, offset);
1166   al_objq_index = al_objq & AL_OBJQ_INDEX;
1167   al_objq_index = al_objq_index >> 4; /* bit-shift to the right by 4 (x111xxxx -> xxxxx111) */
1168   al_objq_code = al_objq & AL_OBJQ_CODE;
1169
1170   qualifier_item = proto_tree_add_text(objdet_tree, tvb, offset, 1, "Qualifier Field, Prefix: %s, Code: %s",
1171     val_to_str(al_objq_index, dnp3_al_objq_index_vals, "Unknown Index Type"),
1172     val_to_str(al_objq_code, dnp3_al_objq_code_vals, "Unknown Code Type"));
1173   qualifier_tree = proto_item_add_subtree(qualifier_item, ett_dnp3_al_obj_qualifier);
1174   proto_tree_add_item(qualifier_tree, hf_dnp3_al_objq_index, tvb, offset, 1, FALSE);
1175   proto_tree_add_item(qualifier_tree, hf_dnp3_al_objq_code, tvb, offset, 1, FALSE);
1176
1177   offset += 1;
1178
1179   /* Create (possibly synthesized) number of items and range field tree */
1180   range_item = proto_tree_add_text(objdet_tree, tvb, offset, 0, "Number of Items: ");
1181   range_tree = proto_item_add_subtree(range_item, ett_dnp3_al_obj_range);
1182
1183   switch (al_objq_code)
1184   {
1185     case AL_OBJQL_CODE_SSI8:           /* 8-bit Start and Stop Indices in Range Field */
1186       num_items = ( tvb_get_guint8(tvb, offset+1) - tvb_get_guint8(tvb, offset) + 1);
1187       PROTO_ITEM_SET_GENERATED(range_item);
1188       al_ptaddr = tvb_get_guint8(tvb, offset);
1189       proto_tree_add_item(range_tree, hf_dnp3_al_range_start8, tvb, offset, 1, TRUE);
1190       proto_tree_add_item(range_tree, hf_dnp3_al_range_stop8, tvb, offset + 1, 1, TRUE);
1191       rangebytes = 2;
1192       break;
1193     case AL_OBJQL_CODE_SSI16:          /* 16-bit Start and Stop Indices in Range Field */
1194       num_items = ( tvb_get_letohs(tvb, offset+2) - tvb_get_letohs(tvb, (offset)) + 1);
1195       PROTO_ITEM_SET_GENERATED(range_item);
1196       al_ptaddr = tvb_get_letohs(tvb, offset);
1197       proto_tree_add_item(range_tree, hf_dnp3_al_range_start16, tvb, offset, 2, TRUE);
1198       proto_tree_add_item(range_tree, hf_dnp3_al_range_stop16, tvb, offset + 2, 2, TRUE);
1199       rangebytes = 4;
1200       break;
1201     case AL_OBJQL_CODE_SSI32:          /* 32-bit Start and Stop Indices in Range Field */
1202       num_items = ( tvb_get_letohl(tvb, offset+4) - tvb_get_letohl(tvb, offset) + 1);
1203       PROTO_ITEM_SET_GENERATED(range_item);
1204       al_ptaddr = tvb_get_letohl(tvb, offset);
1205       proto_tree_add_item(range_tree, hf_dnp3_al_range_start32, tvb, offset, 4, TRUE);
1206       proto_tree_add_item(range_tree, hf_dnp3_al_range_stop32, tvb, offset + 4, 2, TRUE);
1207       rangebytes = 8;
1208       break;
1209     case AL_OBJQL_CODE_AA8:            /* 8-bit Absolute Address in Range Field */
1210       num_items = 1;
1211       PROTO_ITEM_SET_GENERATED(range_item);
1212       al_ptaddr = tvb_get_guint8(tvb, offset);
1213       proto_tree_add_item(range_tree, hf_dnp3_al_range_abs8, tvb, offset, 1, TRUE);
1214       rangebytes = 1;
1215       break;
1216     case AL_OBJQL_CODE_AA16:           /* 16-bit Absolute Address in Range Field */
1217       num_items = 1;
1218       PROTO_ITEM_SET_GENERATED(range_item);
1219       al_ptaddr = tvb_get_letohs(tvb, offset);
1220       proto_tree_add_item(range_tree, hf_dnp3_al_range_abs16, tvb, offset, 2, TRUE);
1221       rangebytes = 2;
1222       break;
1223     case AL_OBJQL_CODE_AA32:           /* 32-bit Absolute Address in Range Field */
1224       num_items = 1;
1225       PROTO_ITEM_SET_GENERATED(range_item);
1226       al_ptaddr = tvb_get_letohl(tvb, offset);
1227       proto_tree_add_item(range_tree, hf_dnp3_al_range_abs32, tvb, offset, 4, TRUE);
1228       rangebytes = 4;
1229       break;
1230     case AL_OBJQL_CODE_SF8:            /* 8-bit Single Field Quantity in Range Field */
1231       num_items = tvb_get_guint8(tvb, offset);
1232       proto_tree_add_item(range_tree, hf_dnp3_al_range_quant8, tvb, offset, 1, TRUE);
1233       rangebytes = 1;
1234       proto_item_set_len(range_item, rangebytes);
1235       break;
1236     case AL_OBJQL_CODE_SF16:           /* 16-bit Single Field Quantity in Range Field */
1237       num_items = tvb_get_letohs(tvb, offset);
1238       proto_tree_add_item(range_tree, hf_dnp3_al_range_quant16, tvb, offset, 2, TRUE);
1239       rangebytes = 2;
1240       proto_item_set_len(range_item, rangebytes);
1241       break;
1242     case AL_OBJQL_CODE_SF32:           /* 32-bit Single Field Quantity in Range Field */
1243       num_items = tvb_get_letohl(tvb, offset);
1244       proto_tree_add_item(range_tree, hf_dnp3_al_range_quant32, tvb, offset, 4, TRUE);
1245       rangebytes = 4;
1246       proto_item_set_len(range_item, rangebytes);
1247       break;
1248   }
1249   proto_item_append_text(range_item, "%d", num_items);
1250
1251   offset += rangebytes;
1252
1253   bitindex = 0; /* Temp variable for cycling through points when object values are encoded into
1254             bits; primarily objects 0x0101 & 0x1001 */
1255
1256   for (temp16 = 0; temp16 < num_items; temp16++)
1257   {
1258     switch (al_obj)
1259     {
1260
1261       case AL_OBJ_BI_ALL:      /* Binary Input All Var (Obj:01, Var:All) */
1262       case AL_OBJ_BIC_ALL:     /* Binary Input Change All Var (Obj:02, Var:All) */
1263       case AL_OBJ_CTR_ALL:     /* Binary Counter All Var (Obj:20, Var:All) */
1264       case AL_OBJ_CTRC_ALL:    /* Binary Counter Change All Var (Obj:22 Var:All) */
1265       case AL_OBJ_AI_ALL:      /* Analog Input All Var (Obj:30, Var:All) */
1266       case AL_OBJ_AIC_ALL:     /* Analog Input Change All Var (Obj:32 Var:All) */
1267
1268         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1269         offset += indexbytes;
1270         break;
1271
1272       case AL_OBJ_BI_1BIT:    /* Single-Bit Binary Input (Obj:01, Var:01) */
1273       case AL_OBJ_BO:         /* Binary Output (Obj:10, Var:01) */
1274
1275         if (bitindex <= 7)
1276         {
1277           al_bi_val = tvb_get_guint8(tvb, offset);
1278         }
1279         else /* bitindex > 7 */
1280         {
1281           offset += 1;
1282           al_bi_val = tvb_get_guint8(tvb, offset);
1283           bitindex = 0;
1284         }
1285
1286         /* Extract the bit from the packed byte */
1287         al_bit = (al_bi_val & (1 << bitindex)) > 0;
1288
1289         proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
1290            "Point Number %d, Value: %d", al_ptaddr, al_bit);
1291
1292         al_ptaddr += 1;
1293
1294         if (temp16 == (num_items-1))
1295         {
1296           offset += 1;
1297         }
1298
1299         break;
1300
1301       case AL_OBJ_BI_STAT:    /* Binary Input With Status (Obj:01, Var:02) */
1302       case AL_OBJ_BO_STAT:    /* Binary Output Status (Obj:10, Var:02) */
1303
1304         /* Get Point Flags */
1305         al_ptflags = tvb_get_guint8(tvb, offset);
1306         al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) > 0;
1307
1308         switch (al_obj) {
1309           case AL_OBJ_BI_STAT:
1310             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
1311                "Point Number %d ", al_ptaddr);
1312             dnp3_al_obj_quality(tvb, offset, al_ptflags, t_point, 0);
1313             proto_item_append_text(t_point, ", Value: %d", al_bit);
1314             break;
1315           case AL_OBJ_BO_STAT:
1316             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, 1, al_ptaddr,
1317                "Point Number %d ", al_ptaddr);
1318             dnp3_al_obj_quality(tvb, offset, al_ptflags, t_point, 1);
1319             proto_item_append_text(t_point, ", Value: %d", al_bit);
1320             break;
1321         }
1322
1323         al_ptaddr += 1;
1324         offset += 1;
1325         break;
1326
1327       case AL_OBJ_BIC_TIME:   /* Binary Input Change w/ Time (Obj:02, Var:02)  */
1328
1329         temp_pos = offset;
1330         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1331         temp_pos += indexbytes;
1332
1333         /* Get Point Flags */
1334         al_ptflags = tvb_get_guint8(tvb, temp_pos);
1335         temp_pos += 1;
1336
1337         al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
1338
1339         t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 7), al_ptaddr,
1340           "Point Number %d ", al_ptaddr);
1341         dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 0);
1342         proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_bit, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
1343
1344         offset += (indexbytes + 7);
1345
1346         break;
1347
1348       case AL_OBJ_CTLOP_BLK:  /* Control Relay Output Block (Obj:12, Var:01) */
1349
1350         /* Process Index */
1351         temp_pos = offset;
1352         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1353         temp_pos += indexbytes;
1354
1355         al_ctlobj_code = tvb_get_guint8(tvb, temp_pos);
1356         temp_pos += 1;
1357
1358         /* Bit-Mask xxxx1111 for Control Code 'Code' */
1359         al_ctlobj_code_c = al_ctlobj_code & AL_OBJCTLC_CODE;
1360         ctl_code_str = val_to_str(al_ctlobj_code_c, dnp3_al_ctlc_code_vals, "Ctrl Code Invalid (0x%02x)");
1361
1362         /* Bit-Mask xx11xxxx for Control Code Misc Values */
1363         al_ctlobj_code_m = al_ctlobj_code & AL_OBJCTLC_MISC;
1364         ctl_misc_str = val_to_str(al_ctlobj_code_m, dnp3_al_ctlc_misc_vals, "");
1365
1366         /* Bit-Mask 11xxxxxx for Control Code 'Trip/Close' */
1367         al_ctlobj_code_tc = al_ctlobj_code & AL_OBJCTLC_TC;
1368         ctl_tc_str = val_to_str(al_ctlobj_code_tc, dnp3_al_ctlc_tc_vals, "");
1369
1370         /* Get "Count" Field */
1371         al_ctlobj_count = tvb_get_guint8(tvb, temp_pos);
1372         temp_pos += 1;
1373
1374         /* Get "On Time" Field */
1375         al_ctlobj_on = tvb_get_letohl(tvb, temp_pos);
1376         temp_pos += 4;
1377
1378         /* Get "Off Time" Field */
1379         al_ctlobj_off = tvb_get_letohl(tvb, temp_pos);
1380         temp_pos += 4;
1381
1382         al_ctlobj_stat = tvb_get_guint8(tvb, temp_pos);
1383         ctl_status_str = val_to_str(al_ctlobj_stat, dnp3_al_ctl_status_vals, "Invalid Status (0x%02x)");
1384
1385         proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 11), al_ptaddr,
1386           "Point Number %d, Control Code: [%s,%s,%s (0x%02x)]",
1387              al_ptaddr, ctl_code_str, ctl_misc_str, ctl_tc_str, al_ctlobj_code);
1388
1389         proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes+11),
1390            "  [Count: %d] [On-Time: %d] [Off-Time: %d] [Status: %s (0x%02x)]",
1391                al_ctlobj_count, al_ctlobj_on, al_ctlobj_off, ctl_status_str, al_ctlobj_stat);
1392
1393         offset += (indexbytes + 11);
1394
1395         break;
1396
1397       case AL_OBJ_CTR_32:     /* 32-Bit Binary Counter (Obj:20, Var:01) */
1398       case AL_OBJ_CTR_16:     /* 16-Bit Binary Counter (Obj:20, Var:02) */
1399       case AL_OBJ_FCTR_32:    /* 32-Bit Frozen Counter (Obj:21, Var:01) */
1400       case AL_OBJ_FCTR_16:    /* 16-Bit Frozen Counter (Obj:21, Var:02) */
1401       case AL_OBJ_CTRC_32:    /* 32-Bit Counter Change Event w/o Time (Obj:22, Var:01) */
1402       case AL_OBJ_CTRC_16:    /* 16-Bit Counter Change Event w/o Time (Obj:22, Var:02) */
1403
1404         /* Process Index */
1405         temp_pos = offset;
1406         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1407         temp_pos += indexbytes;
1408
1409         /* Get Point Flags */
1410         al_ptflags = tvb_get_guint8(tvb, temp_pos);
1411         temp_pos += 1;
1412
1413         switch (al_obj)
1414         {
1415           case AL_OBJ_CTR_32:
1416           case AL_OBJ_FCTR_32:
1417           case AL_OBJ_CTRC_32:
1418
1419             al_val32 = tvb_get_letohl(tvb, temp_pos);
1420             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 5), al_ptaddr,
1421                "Point Number %d ", al_ptaddr);
1422             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 2);
1423             proto_item_append_text(t_point, ", Value: %d", al_val32);
1424             offset += (indexbytes + 5);
1425             break;
1426
1427           case AL_OBJ_CTR_16:
1428           case AL_OBJ_FCTR_16:
1429           case AL_OBJ_CTRC_16:
1430
1431             al_val16 = tvb_get_letohs(tvb, temp_pos);
1432             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
1433                "Point Number %d ", al_ptaddr);
1434             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 2);
1435             proto_item_append_text(t_point, ", Value: %d", al_val16);
1436             offset += (indexbytes + 3);
1437             break;
1438         }
1439
1440         break;
1441
1442       case AL_OBJ_AI_32:       /* 32-Bit Analog Input (Obj:30, Var:01) */
1443       case AL_OBJ_AI_16:       /* 16-Bit Analog Input (Obj:30, Var:02) */
1444       case AL_OBJ_AIC_32NT:    /* 32-Bit Analog Change Event w/o Time (Obj:32, Var:01) */
1445       case AL_OBJ_AIC_16NT:    /* 16-Bit Analog Change Event w/o Time (Obj:32, Var:02) */
1446
1447         /* Process Index */
1448         temp_pos = offset;
1449         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1450         temp_pos += indexbytes;
1451
1452         /* Get Point Flags */
1453         al_ptflags = tvb_get_guint8(tvb, temp_pos);
1454         temp_pos += 1;
1455
1456         switch (al_obj)
1457         {
1458           case AL_OBJ_AI_32:
1459           case AL_OBJ_AIC_32NT:
1460
1461             al_val32 = tvb_get_letohl(tvb, temp_pos);
1462             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 5), al_ptaddr,
1463               "Point Number %d ", al_ptaddr);
1464             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
1465             proto_item_append_text(t_point, ", Value: %d", al_val32);
1466             offset += (indexbytes + 5);
1467             break;
1468
1469           case AL_OBJ_AI_16:
1470           case AL_OBJ_AIC_16NT:
1471
1472             al_val16 = tvb_get_letohs(tvb, temp_pos);
1473             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
1474               "Point Number %d ", al_ptaddr);
1475             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
1476             proto_item_append_text(t_point, ", Value: %d", al_val16);
1477             offset += (indexbytes + 3);
1478             break;
1479         }
1480
1481         break;
1482
1483       case AL_OBJ_CTR_32NF:    /* 32-Bit Binary Counter Without Flag (Obj:20, Var:05) */
1484       case AL_OBJ_CTR_16NF:    /* 16-Bit Binary Counter Without Flag (Obj:20, Var:06) */
1485       case AL_OBJ_AI_32NF:     /* 32-Bit Analog Input Without Flag (Obj:30, Var:03) */
1486       case AL_OBJ_AI_16NF:     /* 16-Bit Analog Input Without Flag (Obj:30, Var:04) */
1487
1488         /* Process Index */
1489         temp_pos = offset;
1490         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1491         temp_pos += indexbytes;
1492
1493         switch (al_obj)
1494         {
1495           case AL_OBJ_CTR_32NF:
1496           case AL_OBJ_AI_32NF:
1497
1498             al_val32 = tvb_get_letohl(tvb, temp_pos);
1499             proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 4), al_ptaddr,
1500               "Point Number %d, Value: %d", al_ptaddr, al_val32);
1501             offset += (indexbytes + 4);
1502             break;
1503
1504           case AL_OBJ_CTR_16NF:
1505           case AL_OBJ_AI_16NF:
1506
1507             al_val16 = tvb_get_letohs(tvb, temp_pos);
1508             proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 2), al_ptaddr,
1509               "Point Number %d, Value: %d", al_ptaddr, al_val16);
1510             offset += (indexbytes + 2);
1511             break;
1512         }
1513
1514         break;
1515
1516       case AL_OBJ_AIC_32T:      /* 32-Bit Analog Change Event with Time (Obj:32, Var:03) */
1517       case AL_OBJ_AIC_16T:      /* 16-Bit Analog Change Event with Time (Obj:32, Var:04) */
1518
1519         /* Process Index */
1520         temp_pos = offset;
1521         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1522         temp_pos += indexbytes;
1523
1524         /* Get Point Flags */
1525         al_ptflags = tvb_get_guint8(tvb, temp_pos);
1526         temp_pos += 1;
1527
1528         switch (al_obj)
1529         {
1530           case AL_OBJ_AIC_32T:
1531
1532             al_val32 = tvb_get_letohl(tvb, temp_pos);
1533             temp_pos += 4;
1534             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 11), al_ptaddr,
1535               "Point Number %d ", al_ptaddr);
1536             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
1537             proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_val32, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
1538             offset += (indexbytes + 11); /* 1byte quality, 4bytes value, 6bytes timestamp */
1539             break;
1540
1541           case AL_OBJ_AIC_16T:
1542
1543             al_val16 = tvb_get_letohs(tvb, temp_pos);
1544             temp_pos += 2;
1545             t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 9), al_ptaddr,
1546               "Point Number %d ", al_ptaddr);
1547             dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 3);
1548             proto_item_append_text(t_point, ", Value: %d, Timestamp: %s", al_val16, dnp3_al_decode_timestamp(tvb, temp_pos, buff));
1549             offset += (indexbytes + 9); /* 1byte quality, 2bytes value, 6bytes timestamp */
1550             break;
1551         }
1552
1553         break;
1554
1555       case AL_OBJ_AO_16:     /* 16-Bit Analog Output Status (Obj:40, Var:02)" */
1556
1557         /* Process Index */
1558         temp_pos = offset;
1559         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1560         temp_pos += indexbytes;
1561
1562         /* Get Point Flags */
1563         al_ptflags = tvb_get_guint8(tvb, temp_pos);
1564         temp_pos += 1;
1565
1566         al_val16 = tvb_get_letohs(tvb, temp_pos);
1567         t_point = proto_tree_add_uint_format(objdet_tree, hf_dnp3_al_ptnum, tvb, offset, (indexbytes + 3), al_ptaddr,
1568           "Point Number %d ", al_ptaddr);
1569         dnp3_al_obj_quality(tvb, (offset+indexbytes), al_ptflags, t_point, 4);
1570         proto_item_append_text(t_point, ", Value: %d", al_val16);
1571
1572         offset += (indexbytes + 3);
1573
1574         break;
1575
1576       case AL_OBJ_TD:    /* Time and Date (Obj:50, Var:01) */
1577
1578         proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes+6),
1579            "Time: %s", dnp3_al_decode_timestamp(tvb, offset, buff));
1580         offset += (indexbytes + 6);
1581         break;
1582
1583       case AL_OBJ_TDELAYF: /* Time Delay - Fine (Obj:52, Var:02) */
1584
1585         al_val16 = tvb_get_letohs(tvb, offset);
1586         proto_tree_add_text(objdet_tree, tvb, offset, (indexbytes + 2),"Time Delay: %d ms", al_val16);
1587         offset += (indexbytes + 2);
1588         break;
1589
1590       case AL_OBJ_CLASS0:  /* Class Data Objects */
1591       case AL_OBJ_CLASS1:
1592       case AL_OBJ_CLASS2:
1593       case AL_OBJ_CLASS3:
1594
1595         /* Process Index */
1596         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1597         offset += indexbytes;
1598         break;
1599
1600       case AL_OBJ_IIN:     /* IIN Data Object */
1601
1602         /* Process Index */
1603         indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1604         offset += indexbytes;
1605         break;
1606
1607       default:             /* In case of unknown object */
1608
1609         proto_tree_add_text(objdet_tree, tvb, offset, tvb_reported_length_remaining(tvb, offset),
1610           "Unknown Data Chunk, %d Bytes", tvb_reported_length_remaining(tvb, offset));
1611         offset = tvb_length(tvb); /* Finish decoding if unknown object is encountered... */
1612         break;
1613     }
1614
1615     bitindex += 1;
1616   }
1617
1618   return offset;
1619
1620 }
1621
1622 /*****************************************************************/
1623 /* Application Layer Dissector */
1624 /*****************************************************************/
1625 static int
1626 dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1627 {
1628   guint8        al_ctl, al_seq, al_func;
1629   guint16       bytes;
1630   gboolean      al_fir, al_fin, al_con;
1631   guint         data_len = 0, offset = 0;
1632   proto_item   *ti = NULL, *tc, *t_robj;
1633   proto_tree   *al_tree = NULL, *field_tree = NULL, *robj_tree = NULL;
1634   const gchar  *func_code_str;
1635
1636   data_len = tvb_length(tvb);
1637
1638   /* Handle the control byte and function code */
1639   al_ctl = tvb_get_guint8(tvb, offset);
1640   al_seq = al_ctl & DNP3_AL_SEQ;
1641   al_fir = al_ctl & DNP3_AL_FIR;
1642   al_fin = al_ctl & DNP3_AL_FIN;
1643   al_con = al_ctl & DNP3_AL_CON;
1644   al_func = tvb_get_guint8(tvb, (offset+1));
1645   func_code_str = val_to_str(al_func, dnp3_al_func_vals, "Unknown function (0x%02x)");
1646
1647   if (tree) {
1648     /* format up the text representation */
1649
1650     ti = proto_tree_add_text(tree, tvb, offset, data_len, "Application Layer: (");
1651     if (al_ctl & DNP3_AL_FIR)  proto_item_append_text(ti, "FIR, ");
1652     if (al_ctl & DNP3_AL_FIN)  proto_item_append_text(ti, "FIN, ");
1653     if (al_ctl & DNP3_AL_CON)  proto_item_append_text(ti, "CON, ");
1654     proto_item_append_text(ti, "Sequence %d, %s)", al_seq, func_code_str);
1655
1656     /* Add the al tree branch */
1657     al_tree = proto_item_add_subtree(ti, ett_dnp3_al);
1658
1659     /* Application Layer control byte subtree */
1660     tc = proto_tree_add_uint_format(al_tree, hf_dnp3_al_ctl, tvb, offset, 1, al_ctl,
1661             "Control: 0x%02x (", al_ctl);
1662     if (al_ctl & DNP3_AL_FIR)  proto_item_append_text(tc, "FIR, ");
1663     if (al_ctl & DNP3_AL_FIN)  proto_item_append_text(tc, "FIN, ");
1664     if (al_ctl & DNP3_AL_CON)  proto_item_append_text(tc, "CON, ");
1665     proto_item_append_text(tc, "Sequence %d)", al_seq);
1666
1667     field_tree = proto_item_add_subtree(tc, ett_dnp3_al_ctl);
1668     proto_tree_add_boolean(field_tree, hf_dnp3_al_fir, tvb, offset, 1, al_ctl);
1669     proto_tree_add_boolean(field_tree, hf_dnp3_al_fin, tvb, offset, 1, al_ctl);
1670     proto_tree_add_boolean(field_tree, hf_dnp3_al_con, tvb, offset, 1, al_ctl);
1671     proto_tree_add_item(field_tree, hf_dnp3_al_seq, tvb, offset, 1, FALSE);
1672     offset += 1;
1673
1674     /* If this packet is NOT the final Application Layer Message, exit and continue
1675        processing the remaining data in the fragment.
1676     if (!al_fin)
1677     {
1678       t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Buffering User Data Until Final Frame is Received..");
1679       return 1;
1680     } */
1681
1682     /* Application Layer Function Code Byte  */
1683     proto_tree_add_uint_format(al_tree, hf_dnp3_al_func, tvb, offset, 1, al_func,
1684                 "Function Code: %s (0x%02x)", func_code_str, al_func);
1685     offset += 1;
1686
1687     switch (al_func) {
1688
1689       case AL_FUNC_READ:     /* Read Function Code 0x01 */
1690
1691         /* Create Read Request Data Objects Tree */
1692         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "READ Request Data Objects");
1693         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1694
1695         /* Process Data Object Details */
1696         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1697           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1698         }
1699
1700         break;
1701
1702       case AL_FUNC_WRITE:     /* Write Function Code 0x02 */
1703
1704         /* Create Write Request Data Objects Tree */
1705         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "WRITE Request Data Objects");
1706         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1707
1708         /* Process Data Object Details */
1709         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1710           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1711         }
1712
1713         break;
1714
1715       case AL_FUNC_SELECT:     /* Select Function Code 0x03 */
1716
1717         /* Create Select Request Data Objects Tree */
1718         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "SELECT Request Data Objects");
1719         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1720
1721         /* Process Data Object Details */
1722         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1723           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1724         }
1725
1726         break;
1727
1728       case AL_FUNC_OPERATE:    /* Operate Function Code 0x04 */
1729                                /* Functionally identical to 'SELECT' Function Code */
1730
1731         /* Create Operate Request Data Objects Tree */
1732         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "OPERATE Request Data Objects");
1733         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1734
1735         /* Process Data Object Details */
1736         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1737           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1738         }
1739
1740         break;
1741
1742       case AL_FUNC_DIROP:     /* Direct Operate Function Code 0x05 */
1743                               /* Functionally identical to 'SELECT' Function Code */
1744
1745         /* Create Direct Operate Request Data Objects Tree */
1746         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "DIRECT OPERATE Request Data Objects");
1747         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1748
1749         /* Process Data Object Details */
1750         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1751           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1752         }
1753
1754         break;
1755
1756       case AL_FUNC_ENSPMSG:   /* Enable Spontaneous Messages Function Code 0x14 */
1757
1758         /* Create Enable Spontaneous Messages Data Objects Tree */
1759         t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Enable Spontaneous Msg's Data Objects");
1760         robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1761
1762         /* Process Data Object Details */
1763         while (offset <= (data_len-2))  {  /* 2 octet object code + CRC32 */
1764           offset = dnp3_al_process_object(tvb, offset, robj_tree);
1765         }
1766
1767         break;
1768
1769       case AL_FUNC_DELAYMST:  /* Delay Measurement Function Code 0x17 */
1770
1771         break;
1772
1773       case AL_FUNC_RESPON:   /* Response Function Code 0x81 */
1774       case AL_FUNC_UNSOLI:   /* Unsolicited Response Function Code 0x82 */
1775
1776         /* Application Layer IIN bits req'd if message is a response */
1777         dnp3_al_process_iin(tvb, offset, al_tree);
1778         offset += 2;
1779
1780         /* Ensure there is actual data remaining in the message.
1781            A response will not contain data following the IIN bits,
1782            if there is none available */
1783         bytes = tvb_reported_length_remaining(tvb, offset);
1784         if (bytes > 0)
1785         {
1786           /* Create Response Data Objects Tree */
1787           t_robj = proto_tree_add_text(al_tree, tvb, offset, -1,"RESPONSE Data Objects");
1788           robj_tree = proto_item_add_subtree(t_robj, ett_dnp3_al_objdet);
1789
1790           /* Process Data Object Details */
1791           while (offset <= (data_len-2)) {  /* 2 octet object code + CRC32 */
1792             offset = dnp3_al_process_object(tvb, offset, robj_tree);
1793           }
1794
1795           break;
1796         }
1797
1798       default:    /* Unknown Function */
1799
1800         break;
1801     }
1802   }
1803   else
1804   {
1805     offset += 2;  /* No tree, correct offset */
1806   }
1807
1808   return 0;
1809 }
1810
1811 /*****************************************************************/
1812 /* Data Link and Transport layer dissector */
1813 /*****************************************************************/
1814 static void
1815 dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1816 {
1817
1818 /* Set up structures needed to add the protocol subtree and manage it */
1819     proto_item   *ti = NULL, *tdl, *tc, *al_chunks, *frag_tree_item;
1820     proto_tree   *dnp3_tree = NULL, *dl_tree = NULL, *tr_tree = NULL, *field_tree = NULL, *al_tree = NULL;
1821     int           offset = 0, temp_offset = 0, al_result = 0;
1822     gboolean      dl_prm, tr_fir, tr_fin;
1823     guint8        dl_len, dl_ctl, dl_func, tr_ctl, tr_seq;
1824     const gchar  *func_code_str;
1825     guint16       dl_dst, dl_src, dl_crc, calc_dl_crc;
1826     guint8       *tmp = NULL, *tmp_ptr;
1827     guint8        data_len;
1828     int           data_offset;
1829     gboolean      crc_OK = FALSE;
1830     tvbuff_t     *al_tvb = NULL;
1831     guint         i;
1832     static guint  seq_number = 0;
1833
1834 /* Make entries in Protocol column and Info column on summary display */
1835   if (check_col(pinfo->cinfo, COL_PROTOCOL))
1836     col_set_str(pinfo->cinfo, COL_PROTOCOL, "DNP 3.0");
1837
1838   if (check_col(pinfo->cinfo, COL_INFO))
1839     col_clear(pinfo->cinfo, COL_INFO);
1840
1841   /* Skip "0x0564" header bytes */
1842   temp_offset += 2;
1843
1844   dl_len = tvb_get_guint8(tvb, temp_offset);
1845   temp_offset += 1;
1846
1847   dl_ctl = tvb_get_guint8(tvb, temp_offset);
1848   temp_offset += 1;
1849
1850   dl_dst = tvb_get_letohs(tvb, temp_offset);
1851   temp_offset += 2;
1852
1853   dl_src = tvb_get_letohs(tvb, temp_offset);
1854
1855   dl_func = dl_ctl & DNP3_CTL_FUNC;
1856   dl_prm = dl_ctl & DNP3_CTL_PRM;
1857   func_code_str = val_to_str(dl_func, dl_prm ? dnp3_ctl_func_pri_vals : dnp3_ctl_func_sec_vals,
1858            "Unknown function (0x%02x)");
1859
1860   if (check_col(pinfo->cinfo, COL_INFO))
1861     col_append_fstr(pinfo->cinfo, COL_INFO, "len=%d, from %d to %d, %s",
1862             dl_len, dl_src, dl_dst, func_code_str);
1863
1864   if (tree) {
1865
1866     /* create display subtree for the protocol */
1867     ti = proto_tree_add_item(tree, proto_dnp3, tvb, offset, -1, FALSE);
1868     dnp3_tree = proto_item_add_subtree(ti, ett_dnp3);
1869
1870     /* Create Subtree for Data Link Layer */
1871     tdl = proto_tree_add_text(dnp3_tree, tvb, offset, DNP_HDR_LEN,
1872           "Data Link Layer, Len: %d, From: %d, To: %d, ", dl_len, dl_src, dl_dst);
1873     if (dl_prm) {
1874       if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tdl, "DIR, ");
1875       if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tdl, "PRM, ");
1876       if (dl_ctl & DNP3_CTL_FCB) proto_item_append_text(tdl, "FCB, ");
1877       if (dl_ctl & DNP3_CTL_FCV) proto_item_append_text(tdl, "FCV, ");
1878     }
1879     else {
1880       if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tdl, "DIR, ");
1881       if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tdl, "PRM, ");
1882       if (dl_ctl & DNP3_CTL_RES) proto_item_append_text(tdl, "RES, ");
1883       if (dl_ctl & DNP3_CTL_DFC) proto_item_append_text(tdl, "DFC, ");
1884     }
1885     proto_item_append_text(tdl, func_code_str);
1886     dl_tree = proto_item_add_subtree(tdl, ett_dnp3_dl);
1887
1888     /* start bytes */
1889     proto_tree_add_item(dl_tree, hf_dnp3_start, tvb, offset, 2, FALSE);
1890     offset += 2;
1891
1892     /* add length field */
1893     proto_tree_add_item(dl_tree, hf_dnp3_len, tvb, offset, 1, FALSE);
1894     offset += 1;
1895
1896     /* Add Control Byte Subtree */
1897     tc = proto_tree_add_uint_format(dl_tree, hf_dnp3_ctl, tvb, offset, 1, dl_ctl,
1898             "Control: 0x%02x (", dl_ctl);
1899     /* Add Text to Control Byte Subtree Header */
1900     if (dl_prm) {
1901       if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tc, "DIR, ");
1902       if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tc, "PRM, ");
1903       if (dl_ctl & DNP3_CTL_FCB) proto_item_append_text(tc, "FCB, ");
1904       if (dl_ctl & DNP3_CTL_FCV) proto_item_append_text(tc, "FCV, ");
1905     }
1906     else {
1907       if (dl_ctl & DNP3_CTL_DIR) proto_item_append_text(tc, "DIR, ");
1908       if (dl_ctl & DNP3_CTL_PRM) proto_item_append_text(tc, "PRM, ");
1909       if (dl_ctl & DNP3_CTL_RES) proto_item_append_text(tc, "RES, ");
1910       if (dl_ctl & DNP3_CTL_DFC) proto_item_append_text(tc, "DFC, ");
1911     }
1912     proto_item_append_text(tc, "%s)", func_code_str );
1913     field_tree = proto_item_add_subtree(tc, ett_dnp3_dl_ctl);
1914
1915     /* Add Control Byte Subtree Items */
1916     if (dl_prm) {
1917       proto_tree_add_item(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, TRUE);
1918       proto_tree_add_item(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, TRUE);
1919       proto_tree_add_item(field_tree, hf_dnp3_ctl_fcb, tvb, offset, 1, TRUE);
1920       proto_tree_add_item(field_tree, hf_dnp3_ctl_fcv, tvb, offset, 1, TRUE);
1921       proto_tree_add_item(field_tree, hf_dnp3_ctl_prifunc, tvb, offset, 1, FALSE);
1922     }
1923     else {
1924       proto_tree_add_item(field_tree, hf_dnp3_ctl_dir, tvb, offset, 1, TRUE);
1925       proto_tree_add_item(field_tree, hf_dnp3_ctl_prm, tvb, offset, 1, TRUE);
1926       proto_tree_add_item(field_tree, hf_dnp3_ctl_dfc, tvb, offset, 1, TRUE);
1927       proto_tree_add_item(field_tree, hf_dnp3_ctl_secfunc, tvb, offset, 1, FALSE);
1928     }
1929       offset += 1;
1930
1931     /* add destination and source addresses */
1932     proto_tree_add_item(dl_tree, hf_dnp3_dst, tvb, offset, 2, TRUE);
1933     offset += 2;
1934     proto_tree_add_item(dl_tree, hf_dnp3_src, tvb, offset, 2, TRUE);
1935     offset += 2;
1936
1937     /* and header CRC */
1938     dl_crc = tvb_get_letohs(tvb, offset);
1939     calc_dl_crc = calculateCRC(tvb_get_ptr(tvb, 0, DNP_HDR_LEN - 2), DNP_HDR_LEN - 2);
1940     if (dl_crc == calc_dl_crc)
1941       proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb, offset, 2,
1942                dl_crc, "CRC: 0x%04x [correct]", dl_crc);
1943     else
1944     {
1945       proto_tree_add_boolean_hidden(dl_tree, hf_dnp_hdr_CRC_bad, tvb,
1946                   offset, 2, TRUE);
1947       proto_tree_add_uint_format(dl_tree, hf_dnp_hdr_CRC, tvb,
1948                offset, 2, dl_crc, "CRC: 0x%04x [incorrect, should be 0x%04x]",
1949                      dl_crc, calc_dl_crc);
1950     }
1951     offset += 2;
1952   }
1953   else
1954   {
1955     offset += 10; /* No tree so correct offset */
1956   }
1957
1958   /* If the DataLink function is 'Request Link Status' or 'Status of Link',
1959      or 'Reset Link' we don't expect any Transport or Application Layer Data
1960      NOTE: This code should probably check what DOES have TR or AL data */
1961   if ((dl_func != DL_FUNC_LINK_STAT) && (dl_func != DL_FUNC_STAT_LINK) &&
1962       (dl_func != DL_FUNC_RESET_LINK) && (dl_func != DL_FUNC_ACK))
1963   {
1964
1965     /* get the transport layer byte */
1966     tr_ctl = tvb_get_guint8(tvb, offset);
1967     tr_seq = tr_ctl & DNP3_TR_SEQ;
1968     tr_fir = tr_ctl & DNP3_TR_FIR;
1969     tr_fin = tr_ctl & DNP3_TR_FIN;
1970
1971     if (tree)
1972     {
1973       /* Add Transport Layer Tree */
1974       tc = proto_tree_add_uint_format(dnp3_tree, hf_dnp3_tr_ctl, tvb, offset, 1, tr_ctl,
1975               "Transport Layer: 0x%02x (", tr_ctl);
1976       if (tr_fir) proto_item_append_text(tc, "FIR, ");
1977       if (tr_fin) proto_item_append_text(tc, "FIN, ");
1978       proto_item_append_text(tc, "Sequence %d)", tr_seq);
1979
1980       tr_tree = proto_item_add_subtree(tc, ett_dnp3_tr_ctl);
1981       proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fin, tvb, offset, 1, tr_ctl);
1982       proto_tree_add_boolean(tr_tree, hf_dnp3_tr_fir, tvb, offset, 1, tr_ctl);
1983       proto_tree_add_item(tr_tree, hf_dnp3_tr_seq, tvb, offset, 1, FALSE);
1984     }
1985
1986     /* Allocate AL chunk tree */
1987     if (tree != NULL)
1988     {
1989       al_chunks = proto_tree_add_text(tr_tree, tvb, offset + 1, -1, "Application data chunks");
1990       al_tree = proto_item_add_subtree(al_chunks, ett_dnp3_al_data);
1991     }
1992
1993     /* extract the application layer data, validating the CRCs */
1994
1995     /* XXX - check for dl_len <= 5 */
1996     data_len = dl_len - 5;  /* XXX - dl_len - 6, as we're no longer including the transport layer byte? */
1997     tmp = g_malloc(data_len);
1998     tmp_ptr = tmp;
1999     i = 0;
2000     data_offset = 1;  /* skip the transport layer byte when assembling chunks */
2001     while(data_len > 0)
2002     {
2003       guint8 chk_size;
2004       const guint8 *chk_ptr;
2005       guint16 calc_crc, act_crc;
2006
2007       chk_size = MIN(data_len, AL_MAX_CHUNK_SIZE);
2008       chk_ptr = tvb_get_ptr(tvb, offset, chk_size);
2009       memcpy(tmp_ptr, chk_ptr + data_offset, chk_size - data_offset);
2010       calc_crc = calculateCRC(chk_ptr, chk_size);
2011       offset += chk_size;
2012       tmp_ptr += chk_size - data_offset;
2013       act_crc = tvb_get_letohs(tvb, offset);
2014       offset += 2;
2015       crc_OK = calc_crc == act_crc;
2016       if (crc_OK)
2017       {
2018         if (tree)
2019         {
2020           proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
2021                   "Application Chunk %d Len: %d CRC 0x%04x",
2022                   i, chk_size, act_crc);
2023         }
2024         data_len -= chk_size;
2025       }
2026       else
2027       {
2028         if (tree)
2029         {
2030           proto_tree_add_text(al_tree, tvb, offset - (chk_size + 2), chk_size,
2031                   "Application Chunk %d Len: %d Bad CRC got 0x%04x expected 0x%04x",
2032                   i, chk_size, act_crc, calc_crc);
2033         }
2034         data_len = 0;
2035         break;
2036       }
2037       i++;
2038       data_offset = 0;  /* copy all of the rest of the chunks */
2039     }
2040
2041     /* if all crc OK, set up new tvb */
2042     if (crc_OK)
2043     {
2044       al_tvb = tvb_new_real_data(tmp, tmp_ptr-tmp, tmp_ptr-tmp);
2045       tvb_set_free_cb(al_tvb, g_free);
2046       tvb_set_child_real_data_tvbuff(tvb, al_tvb);
2047
2048       /* Check for fragmented packet */
2049       if (! (tr_fir && tr_fin))
2050       {
2051         /* A fragmented packet */
2052
2053         fragment_data *fd_head;
2054
2055         /* if first fragment, update sequence id */
2056         if (tr_fir)
2057         {
2058           seq_number++;
2059         }
2060
2061         /*
2062         * If we've already seen this frame, look it up in the
2063         * table of reassembled packets, otherwise add it to
2064         * whatever reassembly is in progress, if any, and see
2065         * if it's done.
2066         */
2067         fd_head = fragment_add_seq_check(al_tvb, 0, pinfo, seq_number,
2068                  al_fragment_table,
2069                  al_reassembled_table,
2070                  tr_seq,
2071                  tvb_reported_length(al_tvb),
2072                  !tr_fin);
2073         if (fd_head != NULL)
2074         {
2075           /* We have the complete payload */
2076           al_tvb = tvb_new_real_data(fd_head->data, fd_head->len, fd_head->len);
2077           tvb_set_child_real_data_tvbuff(tvb, al_tvb);
2078           add_new_data_source(pinfo, al_tvb, "Reassembled DNP 3.0 Application Layer message");
2079
2080           if (tree)
2081             /* Show all fragments. */
2082             show_fragment_seq_tree(fd_head, &frag_items, tr_tree, pinfo, al_tvb, &frag_tree_item);
2083         }
2084         else
2085         {
2086           /* We don't have the complete reassembled payload. */
2087           al_tvb = NULL;
2088           if (check_col (pinfo->cinfo, COL_INFO))
2089             col_append_str (pinfo->cinfo, COL_INFO,
2090                 " (Application Layer Message unreassembled)");
2091         }
2092
2093       }
2094       else
2095       {
2096         /* No reassembly required */
2097         add_new_data_source(pinfo, al_tvb, "DNP 3.0 Application Layer message");
2098       }
2099     }
2100     else
2101     {
2102       /* CRC error - throw away the data. */
2103       g_free(tmp);
2104       if (tree)
2105         proto_tree_add_text(dnp3_tree, tvb, 11, -1, "CRC failed, %d chunks", i);
2106     }
2107
2108     if (al_tvb)
2109     {
2110       al_result = dissect_dnp3_al(al_tvb, pinfo, dnp3_tree);
2111     }
2112   }
2113 }
2114
2115 static void
2116 al_defragment_init(void)
2117 {
2118   fragment_table_init(&al_fragment_table);
2119   reassembled_table_init(&al_reassembled_table);
2120 }
2121
2122 /* Register the protocol with Wireshark */
2123
2124 void
2125 proto_register_dnp3(void)
2126 {
2127
2128 /* Setup list of header fields */
2129   static hf_register_info hf[] = {
2130     { &hf_dnp3_start,
2131     { "Start Bytes", "dnp3.start", FT_UINT16, BASE_HEX, NULL, 0x0, "Start Bytes", HFILL }},
2132
2133     { &hf_dnp3_len,
2134     { "Length", "dnp3.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Frame Data Length", HFILL }},
2135
2136     { &hf_dnp3_ctl,
2137     { "Control", "dnp3.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Frame Control Byte", HFILL }},
2138
2139     { &hf_dnp3_ctl_prifunc,
2140     { "Control Function Code", "dnp3.ctl.prifunc", FT_UINT8, BASE_DEC,
2141       VALS(dnp3_ctl_func_pri_vals), DNP3_CTL_FUNC, "Frame Control Function Code", HFILL }},
2142
2143     { &hf_dnp3_ctl_secfunc,
2144     { "Control Function Code", "dnp3.ctl.secfunc", FT_UINT8, BASE_DEC,
2145       VALS(dnp3_ctl_func_sec_vals), DNP3_CTL_FUNC, "Frame Control Function Code", HFILL }},
2146
2147     { &hf_dnp3_ctl_dir,
2148     { "Direction", "dnp3.ctl.dir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DIR, "", HFILL }},
2149
2150     { &hf_dnp3_ctl_prm,
2151     { "Primary", "dnp3.ctl.prm", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_PRM, "", HFILL }},
2152
2153     { &hf_dnp3_ctl_fcb,
2154     { "Frame Count Bit", "dnp3.ctl.fcb", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCB, "", HFILL }},
2155
2156     { &hf_dnp3_ctl_fcv,
2157     { "Frame Count Valid", "dnp3.ctl.fcv", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCV, "", HFILL }},
2158
2159     { &hf_dnp3_ctl_dfc,
2160     { "Data Flow Control", "dnp3.ctl.dfc", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DFC, "", HFILL }},
2161
2162     { &hf_dnp3_dst,
2163     { "Destination", "dnp3.dst", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Address", HFILL }},
2164
2165     { &hf_dnp3_src,
2166     { "Source", "dnp3.src", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Address", HFILL }},
2167
2168     { &hf_dnp_hdr_CRC,
2169     { "CRC", "dnp.hdr.CRC", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2170
2171     { &hf_dnp_hdr_CRC_bad,
2172     { "Bad CRC", "dnp.hdr.CRC_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
2173
2174     { &hf_dnp3_tr_ctl,
2175     { "Transport Control", "dnp3.tr.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Tranport Layer Control Byte", HFILL }},
2176
2177     { &hf_dnp3_tr_fin,
2178     { "Final", "dnp3.tr.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIN, "", HFILL }},
2179
2180     { &hf_dnp3_tr_fir,
2181     { "First", "dnp3.tr.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIR, "", HFILL }},
2182
2183     { &hf_dnp3_tr_seq,
2184     { "Sequence", "dnp3.tr.seq", FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ, "Frame Sequence Number", HFILL }},
2185
2186     { &hf_dnp3_al_ctl,
2187     { "Application Control", "dnp3.al.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Application Layer Control Byte", HFILL }},
2188
2189     { &hf_dnp3_al_fir,
2190     { "First", "dnp3.al.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIR, "", HFILL }},
2191
2192     { &hf_dnp3_al_fin,
2193     { "Final", "dnp3.al.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIN, "", HFILL }},
2194
2195     { &hf_dnp3_al_con,
2196     { "Confirm", "dnp3.al.con", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_CON, "", HFILL }},
2197
2198     { &hf_dnp3_al_seq,
2199     { "Sequence", "dnp3.al.seq", FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ, "Frame Sequence Number", HFILL }},
2200
2201     { &hf_dnp3_al_func,
2202     { "Application Layer Function Code", "dnp3.al.func", FT_UINT8, BASE_DEC,
2203       VALS(dnp3_al_func_vals), DNP3_AL_FUNC, "Application Function Code", HFILL }},
2204
2205     { &hf_dnp3_al_iin,
2206     { "Application Layer IIN bits", "dnp3.al.iin", FT_UINT16, BASE_DEC, NULL, 0x0, "Application Layer IIN", HFILL }},
2207
2208     { &hf_dnp3_al_iin_bmsg,
2209     { "Broadcast Msg Rx", "dnp3.al.iin.bmsg", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_BMSG, "", HFILL }},
2210
2211     { &hf_dnp3_al_iin_cls1d,
2212     { "Class 1 Data Available", "dnp3.al.iin.cls1d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS1D, "", HFILL }},
2213
2214     { &hf_dnp3_al_iin_cls2d,
2215     { "Class 2 Data Available", "dnp3.al.iin.cls2d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS2D, "", HFILL }},
2216
2217     { &hf_dnp3_al_iin_cls3d,
2218     { "Class 3 Data Available", "dnp3.al.iin.cls3d", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CLS3D, "", HFILL }},
2219
2220     { &hf_dnp3_al_iin_tsr,
2221     { "Time Sync Required", "dnp3.al.iin.tsr", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_TSR, "", HFILL }},
2222
2223     { &hf_dnp3_al_iin_dol,
2224     { "Digital Outputs in Local", "dnp3.al.iin.dol", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_DOL, "", HFILL }},
2225
2226     { &hf_dnp3_al_iin_dt,
2227     { "Device Trouble", "dnp3.al.iin.dt", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_DT, "", HFILL }},
2228
2229     { &hf_dnp3_al_iin_rst,
2230     { "Device Restart", "dnp3.al.iin.rst", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_RST, "", HFILL }},
2231
2232     { &hf_dnp3_al_iin_obju,
2233     { "Requested Objects Unknown", "dnp3.al.iin.obju", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_OBJU, "", HFILL }},
2234
2235     { &hf_dnp3_al_iin_pioor,
2236     { "Parameters Invalid or Out of Range", "dnp3.al.iin.pioor", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_PIOOR, "", HFILL }},
2237
2238     { &hf_dnp3_al_iin_ebo,
2239     { "Event Buffer Overflow", "dnp3.al.iin.ebo", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_EBO, "", HFILL }},
2240
2241     { &hf_dnp3_al_iin_oae,
2242     { "Operation Already Executing", "dnp3.al.iin.oae", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_OAE, "", HFILL }},
2243
2244     { &hf_dnp3_al_iin_cc,
2245     { "Configuration Corrupt", "dnp3.al.iin.cc", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CC, "", HFILL }},
2246
2247     { &hf_dnp3_al_obj,
2248     { "Object", "dnp3.al.obj", FT_UINT16, BASE_HEX, VALS(dnp3_al_obj_vals), 0x0, "Application Layer Object", HFILL }},
2249
2250     { &hf_dnp3_al_objq_index,
2251     { "Index Prefix", "dnp3.al.objq.index", FT_UINT8, BASE_DEC, VALS(dnp3_al_objq_index_vals), AL_OBJQ_INDEX, "Object Index Prefixing", HFILL }},
2252
2253     { &hf_dnp3_al_objq_code,
2254     { "Qualifier Code", "dnp3.al.objq.code", FT_UINT8, BASE_DEC, VALS(dnp3_al_objq_code_vals), AL_OBJQ_CODE, "Object Qualifier Code", HFILL }},
2255
2256     { &hf_dnp3_al_range_start8,
2257     { "Start", "dnp3.al.range.start8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2258
2259     { &hf_dnp3_al_range_stop8,
2260     { "Stop", "dnp3.al.range.stop8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2261
2262     { &hf_dnp3_al_range_start16,
2263     { "Start", "dnp3.al.range.start16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2264
2265     { &hf_dnp3_al_range_stop16,
2266     { "Stop", "dnp3.al.range.stop16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2267
2268     { &hf_dnp3_al_range_start32,
2269     { "Start", "dnp3.al.range.start32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2270
2271     { &hf_dnp3_al_range_stop32,
2272     { "Stop", "dnp3.al.range.stop32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2273
2274     { &hf_dnp3_al_range_abs8,
2275     { "Address", "dnp3.al.range.abs8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2276
2277     { &hf_dnp3_al_range_abs16,
2278     { "Address", "dnp3.al.range.abs16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2279
2280     { &hf_dnp3_al_range_abs32,
2281     { "Address", "dnp3.al.range.abs32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2282
2283     { &hf_dnp3_al_range_quant8,
2284     { "Quantity", "dnp3.al.range.quant8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2285
2286     { &hf_dnp3_al_range_quant16,
2287     { "Quantity", "dnp3.al.range.quant16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2288
2289     { &hf_dnp3_al_range_quant32,
2290     { "Quantity", "dnp3.al.range.quant32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2291
2292     { &hf_dnp3_al_ptnum,
2293     { "Object Point Number", "dnp3.al.ptnum", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Point Number", HFILL }},
2294
2295     { &hf_dnp3_al_biq_b0,
2296     { "Online", "dnp3.al.biq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG0, "", HFILL }},
2297
2298     { &hf_dnp3_al_biq_b1,
2299     { "Restart", "dnp3.al.biq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG1, "", HFILL }},
2300
2301     { &hf_dnp3_al_biq_b2,
2302     { "Comm Fail", "dnp3.al.biq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG2, "", HFILL }},
2303
2304     { &hf_dnp3_al_biq_b3,
2305     { "Remote Force", "dnp3.al.biq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG3, "", HFILL }},
2306
2307     { &hf_dnp3_al_biq_b4,
2308     { "Local Force", "dnp3.al.biq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG4, "", HFILL }},
2309
2310     { &hf_dnp3_al_biq_b5,
2311     { "Chatter Filter", "dnp3.al.biq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG5, "", HFILL }},
2312
2313     { &hf_dnp3_al_biq_b6,
2314     { "Reserved", "dnp3.al.biq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG6, "", HFILL }},
2315
2316     { &hf_dnp3_al_biq_b7,
2317     { "Point Value", "dnp3.al.biq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG7, "", HFILL }},
2318
2319     { &hf_dnp3_al_boq_b0,
2320     { "Online", "dnp3.al.boq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG0, "", HFILL }},
2321
2322     { &hf_dnp3_al_boq_b1,
2323     { "Restart", "dnp3.al.boq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG1, "", HFILL }},
2324
2325     { &hf_dnp3_al_boq_b2,
2326     { "Comm Fail", "dnp3.al.boq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG2, "", HFILL }},
2327
2328     { &hf_dnp3_al_boq_b3,
2329     { "Remote Force", "dnp3.al.boq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG3, "", HFILL }},
2330
2331     { &hf_dnp3_al_boq_b4,
2332     { "Local Force", "dnp3.al.boq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG4, "", HFILL }},
2333
2334     { &hf_dnp3_al_boq_b5,
2335     { "Reserved", "dnp3.al.boq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG5, "", HFILL }},
2336
2337     { &hf_dnp3_al_boq_b6,
2338     { "Reserved", "dnp3.al.boq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG6, "", HFILL }},
2339
2340     { &hf_dnp3_al_boq_b7,
2341     { "Point Value", "dnp3.al.boq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG7, "", HFILL }},
2342
2343     { &hf_dnp3_al_ctrq_b0,
2344     { "Online", "dnp3.al.ctrq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG0, "", HFILL }},
2345
2346     { &hf_dnp3_al_ctrq_b1,
2347     { "Restart", "dnp3.al.ctrq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG1, "", HFILL }},
2348
2349     { &hf_dnp3_al_ctrq_b2,
2350     { "Comm Fail", "dnp3.al.ctrq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG2, "", HFILL }},
2351
2352     { &hf_dnp3_al_ctrq_b3,
2353     { "Remote Force", "dnp3.al.ctrq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG3, "", HFILL }},
2354
2355     { &hf_dnp3_al_ctrq_b4,
2356     { "Local Force", "dnp3.al.ctrq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG4, "", HFILL }},
2357
2358     { &hf_dnp3_al_ctrq_b5,
2359     { "Roll-Over", "dnp3.al.ctrq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG5, "", HFILL }},
2360
2361     { &hf_dnp3_al_ctrq_b6,
2362     { "Reserved", "dnp3.al.ctrq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG6, "", HFILL }},
2363
2364     { &hf_dnp3_al_ctrq_b7,
2365     { "Reserved", "dnp3.al.ctrq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG7, "", HFILL }},
2366
2367     { &hf_dnp3_al_aiq_b0,
2368     { "Online", "dnp3.al.aiq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG0, "", HFILL }},
2369
2370     { &hf_dnp3_al_aiq_b1,
2371     { "Restart", "dnp3.al.aiq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG1, "", HFILL }},
2372
2373     { &hf_dnp3_al_aiq_b2,
2374     { "Comm Fail", "dnp3.al.aiq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG2, "", HFILL }},
2375
2376     { &hf_dnp3_al_aiq_b3,
2377     { "Remote Force", "dnp3.al.aiq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG3, "", HFILL }},
2378
2379     { &hf_dnp3_al_aiq_b4,
2380     { "Local Force", "dnp3.al.aiq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG4, "", HFILL }},
2381
2382     { &hf_dnp3_al_aiq_b5,
2383     { "Over-Range", "dnp3.al.aiq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG5, "", HFILL }},
2384
2385     { &hf_dnp3_al_aiq_b6,
2386     { "Reference Check", "dnp3.al.aiq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG6, "", HFILL }},
2387
2388     { &hf_dnp3_al_aiq_b7,
2389     { "Reserved", "dnp3.al.aiq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG7, "", HFILL }},
2390
2391     { &hf_dnp3_al_aoq_b0,
2392     { "Online", "dnp3.al.aoq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG0, "", HFILL }},
2393
2394     { &hf_dnp3_al_aoq_b1,
2395     { "Restart", "dnp3.al.aoq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG1, "", HFILL }},
2396
2397     { &hf_dnp3_al_aoq_b2,
2398     { "Comm Fail", "dnp3.al.aoq.b2", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG2, "", HFILL }},
2399
2400     { &hf_dnp3_al_aoq_b3,
2401     { "Remote Force", "dnp3.al.aoq.b3", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG3, "", HFILL }},
2402
2403     { &hf_dnp3_al_aoq_b4,
2404     { "Reserved", "dnp3.al.aoq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG4, "", HFILL }},
2405
2406     { &hf_dnp3_al_aoq_b5,
2407     { "Reserved", "dnp3.al.aoq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG5, "", HFILL }},
2408
2409     { &hf_dnp3_al_aoq_b6,
2410     { "Reserved", "dnp3.al.aoq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG6, "", HFILL }},
2411
2412     { &hf_dnp3_al_aoq_b7,
2413     { "Reserved", "dnp3.al.aoq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG7, "", HFILL }},
2414
2415     { &hf_fragment,
2416     { "DNP 3.0 AL Fragment", "al.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragment", HFILL }},
2417
2418     { &hf_fragments,
2419     { "DNP 3.0 AL Fragments", "al.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragments", HFILL }},
2420
2421     { &hf_fragment_overlap,
2422     { "Fragment overlap", "al.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
2423
2424     { &hf_fragment_overlap_conflict,
2425     { "Conflicting data in fragment overlap", "al.fragment.overlap.conflict", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2426       "Overlapping fragments contained conflicting data", HFILL }},
2427
2428     { &hf_fragment_multiple_tails,
2429     { "Multiple tail fragments found", "al.fragment.multipletails", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2430       "Several tails were found when defragmenting the packet", HFILL }},
2431
2432     { &hf_fragment_too_long_fragment,
2433     { "Fragment too long", "al.fragment.toolongfragment", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
2434       "Fragment contained data past end of packet", HFILL }},
2435
2436     { &hf_fragment_error,
2437     { "Defragmentation error", "al.fragment.error", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2438       "Defragmentation error due to illegal fragments", HFILL }},
2439     { &hf_fragment_reassembled_in,
2440     { "Reassembled PDU In Frame", "al.fragment.reassembled_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0,
2441       "This PDU is reassembled in this frame", HFILL }}
2442   };
2443
2444 /* Setup protocol subtree array */
2445   static gint *ett[] = {
2446     &ett_dnp3,
2447     &ett_dnp3_dl,
2448     &ett_dnp3_dl_ctl,
2449     &ett_dnp3_tr_ctl,
2450     &ett_dnp3_al_data,
2451     &ett_dnp3_al,
2452     &ett_dnp3_al_ctl,
2453     &ett_dnp3_al_iin,
2454     &ett_dnp3_al_obj,
2455     &ett_dnp3_al_obj_qualifier,
2456     &ett_dnp3_al_obj_range,
2457     &ett_dnp3_al_objdet,
2458     &ett_dnp3_al_obj_quality,
2459     &ett_fragment,
2460     &ett_fragments
2461   };
2462
2463 /* Register the protocol name and description */
2464   proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0",
2465                    "DNP 3.0", "dnp3");
2466
2467 /* Required function calls to register the header fields and subtrees used */
2468   proto_register_field_array(proto_dnp3, hf, array_length(hf));
2469   proto_register_subtree_array(ett, array_length(ett));
2470
2471   al_defragment_init();
2472 }
2473
2474
2475 /* If this dissector uses sub-dissector registration add a registration routine.
2476    This format is required because a script is used to find these routines and
2477    create the code that calls these routines.
2478 */
2479 void
2480 proto_reg_handoff_dnp3(void)
2481 {
2482   dissector_handle_t dnp3_handle;
2483
2484   dnp3_handle = create_dissector_handle(dissect_dnp3, proto_dnp3);
2485   dissector_add("tcp.port", TCP_PORT_DNP, dnp3_handle);
2486   dissector_add("udp.port", UDP_PORT_DNP, dnp3_handle);
2487 }