2 * Routines for DNP dissection
3 * Copyright 2003, Graham Bloice <graham.bloice@trihedral.com>
5 * DNP3.0 Application Layer Object dissection added by Chris Bontje (chrisbontje@shaw.ca)
10 * Wireshark - Network traffic analyzer
11 * By Gerald Combs <gerald@wireshark.org>
12 * Copyright 1998 Gerald Combs
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.
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.
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.
40 #include <epan/packet.h>
41 #include <epan/prefs.h>
42 #include <epan/reassemble.h>
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
53 * ...Application Layer Notes...
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
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
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
78 #define DNP3_TR_FIR 0x40
79 #define DNP3_TR_FIN 0x80
80 #define DNP3_TR_SEQ 0x3f
82 #define AL_MAX_CHUNK_SIZE 16
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
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
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
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 */
141 /***************************************************************************/
142 /* Application Layer Internal Indication (IIN) bits */
143 /* 2 Bytes, message formatting: [First Octet] | [Second Octet] */
144 /***************************************************************************/
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 */
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 */
165 /***************************************************************************/
166 /* Application Layer Data Object Qualifier */
167 /***************************************************************************/
169 #define AL_OBJQ_INDEX 0x70 /* x111xxxx Masks Index from Qualifier */
170 #define AL_OBJQ_CODE 0x0F /* xxxx1111 Masks Code from Qualifier */
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 */
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 */
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 */
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 */
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) */
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 */
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' */
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 */
247 #define AL_OBJCTLC_QUEUE 0x10 /* xxx1xxxx for Control Code 'Queue' */
248 #define AL_OBJCTLC_CLEAR 0x20 /* xx1xxxxx for Control Code 'Clear' */
250 #define AL_OBJCTLC_TC0 0x00 /* 00xxxxxx NUL */
251 #define AL_OBJCTLC_TC1 0x40 /* 01xxxxxx Close */
252 #define AL_OBJCTLC_TC2 0x80 /* 10xxxxxx Trip */
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 */
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) */
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 */
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 */
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 */
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 */
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 */
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 */
368 /***************************************************************************/
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 */
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 */
384 /***************************************************************************/
386 #define AL_OBJ_IIN 0x5001 /* 80 01 Internal Indications */
388 /***************************************************************************/
389 /* End of Application Layer Data Object Definitions */
390 /***************************************************************************/
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;
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;
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" },
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" },
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" },
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" },
542 static const value_string dnp3_tr_flags_vals[] = {
543 { DNP3_TR_FIN, "FIN" },
544 { DNP3_TR_FIR, "FIR" },
548 static const value_string dnp3_al_flags_vals[] = {
549 { DNP3_AL_FIR, "FIR" },
550 { DNP3_AL_FIN, "FIN" },
551 { DNP3_AL_CON, "CON" },
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" },
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" },
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" },
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" },
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)" },
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" },
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" },
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" },
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" },
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" },
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" },
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" },
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;
764 /* Tables for reassembly of fragments. */
765 static GHashTable *al_fragment_table = NULL;
766 static GHashTable *al_reassembled_table = NULL;
768 static const fragment_items frag_items = {
773 &hf_fragment_overlap,
774 &hf_fragment_overlap_conflict,
775 &hf_fragment_multiple_tails,
776 &hf_fragment_too_long_fragment,
778 &hf_fragment_reassembled_in,
782 /*****************************************************************/
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: */
790 /* Width : 2 bytes. */
792 /* Reverse : TRUE. */
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". */
800 /*****************************************************************/
802 static guint16 crctable[256] =
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
838 /*****************************************************************/
839 /* End of CRC Lookup Table */
840 /*****************************************************************/
842 /* calculates crc given a buffer of characters and a length of buffer */
844 calculateCRC(const void *buf, guint len) {
846 const guint8 *p = (const guint8 *)buf;
848 crc = crctable[(crc ^ *p++) & 0xff] ^ (crc >> 8);
852 /*****************************************************************/
853 /* Adds text to item, with trailing "," if required */
854 /*****************************************************************/
856 add_item_text(proto_item *item, const gchar *text, gboolean comma_needed)
859 proto_item_append_text(item, ", ");
861 proto_item_append_text(item, text);
865 /*****************************************************************/
866 /* Application Layer Process Internal Indications (IIN) */
867 /*****************************************************************/
869 dnp3_al_process_iin(tvbuff_t *tvb, int offset, proto_tree *al_tree)
874 proto_tree *iin_tree = NULL;
875 gboolean comma_needed = FALSE;
877 al_iin = tvb_get_ntohs(tvb, offset);
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);
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);
912 /*****************************************************************/
913 /* Function to determine Application Layer Object Index size */
914 /*****************************************************************/
916 dnp3_al_obj_procindex(tvbuff_t *tvb, int bitindex, int offset, guint8 al_objq_index, guint32 *al_ptaddr)
920 switch (al_objq_index)
922 case AL_OBJQL_IDX_NI: /* No Index */
923 if (bitindex > 0) /* Increment Address by 1 */
929 case AL_OBJQL_IDX_1O:
930 *al_ptaddr = tvb_get_guint8(tvb, offset);
933 case AL_OBJQL_IDX_2O:
934 *al_ptaddr = tvb_get_letohs(tvb, offset);
937 case AL_OBJQL_IDX_4O:
938 *al_ptaddr = tvb_get_letohl(tvb, offset);
945 /*****************************************************************/
946 /* Function to Determine Application Layer Point Quality Flags & */
947 /* add Point Quality Flag Sub-Tree */
948 /*****************************************************************/
950 dnp3_al_obj_quality(tvbuff_t *tvb, int offset, guint8 al_ptflags, proto_item *t_point, int type)
953 proto_tree *quality_tree = NULL;
954 int hf0 = 0, hf1 = 0, hf2 = 0, hf3 = 0, hf4 = 0, hf5 = 0, hf6 = 0, hf7 = 0;
956 proto_item_append_text(t_point, "(Quality: ");
958 case 0: /* Binary Input Quality flags */
959 quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
961 if (al_ptflags & AL_OBJ_BI_FLAG0) {
962 proto_item_append_text(t_point, "Online");
965 proto_item_append_text(t_point, "Offline");
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");
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;
983 case 1: /* Binary Output Quality flags */
984 quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
986 if (al_ptflags & AL_OBJ_BO_FLAG0) {
987 proto_item_append_text(t_point, "Online");
990 proto_item_append_text(t_point, "Offline");
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");
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;
1007 case 2: /* Counter Quality flags */
1008 quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1010 if (al_ptflags & AL_OBJ_CTR_FLAG0) {
1011 proto_item_append_text(t_point, "Online");
1014 proto_item_append_text(t_point, "Offline");
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");
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;
1032 case 3: /* Analog Input Quality flags */
1033 quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1035 if (al_ptflags & AL_OBJ_AI_FLAG0) {
1036 proto_item_append_text(t_point, "Online");
1039 proto_item_append_text(t_point, "Offline");
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");
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;
1058 case 4: /* Analog Output Quality flags */
1059 quality_tree = proto_item_add_subtree(t_point, ett_dnp3_al_obj_quality);
1061 if (al_ptflags & AL_OBJ_AO_FLAG0) {
1062 proto_item_append_text(t_point, "Online");
1065 proto_item_append_text(t_point, "Offline");
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");
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;
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);
1092 proto_item_append_text(t_point, ")");
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 /**********************************************************************/
1106 dnp3_al_decode_timestamp(tvbuff_t *tvb, int temp_pos, char* buff)
1110 guint64 al_timestamp, time_ms;
1114 lo = tvb_get_letohs(tvb, temp_pos);
1115 hi = tvb_get_letohl(tvb, temp_pos + 2);
1116 al_timestamp = ((gint64)hi * 0x10000 + lo);
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);
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);
1134 /*****************************************************************/
1135 /* Desc: Application Layer Process Object Details */
1136 /* Returns: New offset pointer into tvb */
1137 /*****************************************************************/
1139 dnp3_al_process_object(tvbuff_t *tvb, int offset, proto_tree *robj_tree)
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;
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;
1154 /* Application Layer Objects in this Message */
1155 al_obj = tvb_get_ntohs(tvb, offset);
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);
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;
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);
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);
1183 switch (al_objq_code)
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);
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);
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);
1209 case AL_OBJQL_CODE_AA8: /* 8-bit Absolute Address in Range Field */
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);
1216 case AL_OBJQL_CODE_AA16: /* 16-bit Absolute Address in Range Field */
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);
1223 case AL_OBJQL_CODE_AA32: /* 32-bit Absolute Address in Range Field */
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);
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);
1234 proto_item_set_len(range_item, rangebytes);
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);
1240 proto_item_set_len(range_item, rangebytes);
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);
1246 proto_item_set_len(range_item, rangebytes);
1249 proto_item_append_text(range_item, "%d", num_items);
1251 offset += rangebytes;
1253 bitindex = 0; /* Temp variable for cycling through points when object values are encoded into
1254 bits; primarily objects 0x0101 & 0x1001 */
1256 for (temp16 = 0; temp16 < num_items; temp16++)
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) */
1268 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1269 offset += indexbytes;
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) */
1277 al_bi_val = tvb_get_guint8(tvb, offset);
1279 else /* bitindex > 7 */
1282 al_bi_val = tvb_get_guint8(tvb, offset);
1286 /* Extract the bit from the packed byte */
1287 al_bit = (al_bi_val & (1 << bitindex)) > 0;
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);
1294 if (temp16 == (num_items-1))
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) */
1304 /* Get Point Flags */
1305 al_ptflags = tvb_get_guint8(tvb, offset);
1306 al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) > 0;
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);
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);
1327 case AL_OBJ_BIC_TIME: /* Binary Input Change w/ Time (Obj:02, Var:02) */
1330 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1331 temp_pos += indexbytes;
1333 /* Get Point Flags */
1334 al_ptflags = tvb_get_guint8(tvb, temp_pos);
1337 al_bit = (al_ptflags & AL_OBJ_BI_FLAG7) >> 7; /* bit shift 1xxxxxxx -> xxxxxxx1 */
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));
1344 offset += (indexbytes + 7);
1348 case AL_OBJ_CTLOP_BLK: /* Control Relay Output Block (Obj:12, Var:01) */
1352 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1353 temp_pos += indexbytes;
1355 al_ctlobj_code = tvb_get_guint8(tvb, temp_pos);
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)");
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, "");
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, "");
1370 /* Get "Count" Field */
1371 al_ctlobj_count = tvb_get_guint8(tvb, temp_pos);
1374 /* Get "On Time" Field */
1375 al_ctlobj_on = tvb_get_letohl(tvb, temp_pos);
1378 /* Get "Off Time" Field */
1379 al_ctlobj_off = tvb_get_letohl(tvb, temp_pos);
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)");
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);
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);
1393 offset += (indexbytes + 11);
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) */
1406 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1407 temp_pos += indexbytes;
1409 /* Get Point Flags */
1410 al_ptflags = tvb_get_guint8(tvb, temp_pos);
1416 case AL_OBJ_FCTR_32:
1417 case AL_OBJ_CTRC_32:
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);
1428 case AL_OBJ_FCTR_16:
1429 case AL_OBJ_CTRC_16:
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);
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) */
1449 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1450 temp_pos += indexbytes;
1452 /* Get Point Flags */
1453 al_ptflags = tvb_get_guint8(tvb, temp_pos);
1459 case AL_OBJ_AIC_32NT:
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);
1470 case AL_OBJ_AIC_16NT:
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);
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) */
1490 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1491 temp_pos += indexbytes;
1495 case AL_OBJ_CTR_32NF:
1496 case AL_OBJ_AI_32NF:
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);
1504 case AL_OBJ_CTR_16NF:
1505 case AL_OBJ_AI_16NF:
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);
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) */
1521 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1522 temp_pos += indexbytes;
1524 /* Get Point Flags */
1525 al_ptflags = tvb_get_guint8(tvb, temp_pos);
1530 case AL_OBJ_AIC_32T:
1532 al_val32 = tvb_get_letohl(tvb, temp_pos);
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 */
1541 case AL_OBJ_AIC_16T:
1543 al_val16 = tvb_get_letohs(tvb, temp_pos);
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 */
1555 case AL_OBJ_AO_16: /* 16-Bit Analog Output Status (Obj:40, Var:02)" */
1559 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1560 temp_pos += indexbytes;
1562 /* Get Point Flags */
1563 al_ptflags = tvb_get_guint8(tvb, temp_pos);
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);
1572 offset += (indexbytes + 3);
1576 case AL_OBJ_TD: /* Time and Date (Obj:50, Var:01) */
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);
1583 case AL_OBJ_TDELAYF: /* Time Delay - Fine (Obj:52, Var:02) */
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);
1590 case AL_OBJ_CLASS0: /* Class Data Objects */
1596 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1597 offset += indexbytes;
1600 case AL_OBJ_IIN: /* IIN Data Object */
1603 indexbytes = dnp3_al_obj_procindex(tvb, bitindex, offset, al_objq_index, &al_ptaddr);
1604 offset += indexbytes;
1607 default: /* In case of unknown object */
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... */
1622 /*****************************************************************/
1623 /* Application Layer Dissector */
1624 /*****************************************************************/
1626 dissect_dnp3_al(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree)
1628 guint8 al_ctl, al_seq, al_func;
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;
1636 data_len = tvb_length(tvb);
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)");
1648 /* format up the text representation */
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);
1656 /* Add the al tree branch */
1657 al_tree = proto_item_add_subtree(ti, ett_dnp3_al);
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);
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);
1674 /* If this packet is NOT the final Application Layer Message, exit and continue
1675 processing the remaining data in the fragment.
1678 t_robj = proto_tree_add_text(al_tree, tvb, offset, -1, "Buffering User Data Until Final Frame is Received..");
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);
1689 case AL_FUNC_READ: /* Read Function Code 0x01 */
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);
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);
1702 case AL_FUNC_WRITE: /* Write Function Code 0x02 */
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);
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);
1715 case AL_FUNC_SELECT: /* Select Function Code 0x03 */
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);
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);
1728 case AL_FUNC_OPERATE: /* Operate Function Code 0x04 */
1729 /* Functionally identical to 'SELECT' Function Code */
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);
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);
1742 case AL_FUNC_DIROP: /* Direct Operate Function Code 0x05 */
1743 /* Functionally identical to 'SELECT' Function Code */
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);
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);
1756 case AL_FUNC_ENSPMSG: /* Enable Spontaneous Messages Function Code 0x14 */
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);
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);
1769 case AL_FUNC_DELAYMST: /* Delay Measurement Function Code 0x17 */
1773 case AL_FUNC_RESPON: /* Response Function Code 0x81 */
1774 case AL_FUNC_UNSOLI: /* Unsolicited Response Function Code 0x82 */
1776 /* Application Layer IIN bits req'd if message is a response */
1777 dnp3_al_process_iin(tvb, offset, al_tree);
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);
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);
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);
1798 default: /* Unknown Function */
1805 offset += 2; /* No tree, correct offset */
1811 /*****************************************************************/
1812 /* Data Link and Transport layer dissector */
1813 /*****************************************************************/
1815 dissect_dnp3(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
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;
1829 gboolean crc_OK = FALSE;
1830 tvbuff_t *al_tvb = NULL;
1832 static guint seq_number = 0;
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");
1838 if (check_col(pinfo->cinfo, COL_INFO))
1839 col_clear(pinfo->cinfo, COL_INFO);
1841 /* Skip "0x0564" header bytes */
1844 dl_len = tvb_get_guint8(tvb, temp_offset);
1847 dl_ctl = tvb_get_guint8(tvb, temp_offset);
1850 dl_dst = tvb_get_letohs(tvb, temp_offset);
1853 dl_src = tvb_get_letohs(tvb, temp_offset);
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)");
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);
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);
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);
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, ");
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, ");
1885 proto_item_append_text(tdl, func_code_str);
1886 dl_tree = proto_item_add_subtree(tdl, ett_dnp3_dl);
1889 proto_tree_add_item(dl_tree, hf_dnp3_start, tvb, offset, 2, FALSE);
1892 /* add length field */
1893 proto_tree_add_item(dl_tree, hf_dnp3_len, tvb, offset, 1, FALSE);
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 */
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, ");
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, ");
1912 proto_item_append_text(tc, "%s)", func_code_str );
1913 field_tree = proto_item_add_subtree(tc, ett_dnp3_dl_ctl);
1915 /* Add Control Byte Subtree Items */
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);
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);
1931 /* add destination and source addresses */
1932 proto_tree_add_item(dl_tree, hf_dnp3_dst, tvb, offset, 2, TRUE);
1934 proto_tree_add_item(dl_tree, hf_dnp3_src, tvb, offset, 2, TRUE);
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);
1945 proto_tree_add_boolean_hidden(dl_tree, hf_dnp_hdr_CRC_bad, tvb,
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);
1955 offset += 10; /* No tree so correct offset */
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))
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;
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);
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);
1986 /* Allocate AL chunk tree */
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);
1993 /* extract the application layer data, validating the CRCs */
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);
2000 data_offset = 1; /* skip the transport layer byte when assembling chunks */
2004 const guint8 *chk_ptr;
2005 guint16 calc_crc, act_crc;
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);
2012 tmp_ptr += chk_size - data_offset;
2013 act_crc = tvb_get_letohs(tvb, offset);
2015 crc_OK = calc_crc == act_crc;
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);
2024 data_len -= chk_size;
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);
2038 data_offset = 0; /* copy all of the rest of the chunks */
2041 /* if all crc OK, set up new tvb */
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);
2048 /* Check for fragmented packet */
2049 if (! (tr_fir && tr_fin))
2051 /* A fragmented packet */
2053 fragment_data *fd_head;
2055 /* if first fragment, update sequence id */
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
2067 fd_head = fragment_add_seq_check(al_tvb, 0, pinfo, seq_number,
2069 al_reassembled_table,
2071 tvb_reported_length(al_tvb),
2073 if (fd_head != NULL)
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");
2081 /* Show all fragments. */
2082 show_fragment_seq_tree(fd_head, &frag_items, tr_tree, pinfo, al_tvb, &frag_tree_item);
2086 /* We don't have the complete reassembled payload. */
2088 if (check_col (pinfo->cinfo, COL_INFO))
2089 col_append_str (pinfo->cinfo, COL_INFO,
2090 " (Application Layer Message unreassembled)");
2096 /* No reassembly required */
2097 add_new_data_source(pinfo, al_tvb, "DNP 3.0 Application Layer message");
2102 /* CRC error - throw away the data. */
2105 proto_tree_add_text(dnp3_tree, tvb, 11, -1, "CRC failed, %d chunks", i);
2110 al_result = dissect_dnp3_al(al_tvb, pinfo, dnp3_tree);
2116 al_defragment_init(void)
2118 fragment_table_init(&al_fragment_table);
2119 reassembled_table_init(&al_reassembled_table);
2122 /* Register the protocol with Wireshark */
2125 proto_register_dnp3(void)
2128 /* Setup list of header fields */
2129 static hf_register_info hf[] = {
2131 { "Start Bytes", "dnp3.start", FT_UINT16, BASE_HEX, NULL, 0x0, "Start Bytes", HFILL }},
2134 { "Length", "dnp3.len", FT_UINT8, BASE_DEC, NULL, 0x0, "Frame Data Length", HFILL }},
2137 { "Control", "dnp3.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Frame Control Byte", HFILL }},
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 }},
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 }},
2148 { "Direction", "dnp3.ctl.dir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DIR, "", HFILL }},
2151 { "Primary", "dnp3.ctl.prm", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_PRM, "", HFILL }},
2154 { "Frame Count Bit", "dnp3.ctl.fcb", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCB, "", HFILL }},
2157 { "Frame Count Valid", "dnp3.ctl.fcv", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_FCV, "", HFILL }},
2160 { "Data Flow Control", "dnp3.ctl.dfc", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_CTL_DFC, "", HFILL }},
2163 { "Destination", "dnp3.dst", FT_UINT16, BASE_DEC, NULL, 0x0, "Destination Address", HFILL }},
2166 { "Source", "dnp3.src", FT_UINT16, BASE_DEC, NULL, 0x0, "Source Address", HFILL }},
2169 { "CRC", "dnp.hdr.CRC", FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
2171 { &hf_dnp_hdr_CRC_bad,
2172 { "Bad CRC", "dnp.hdr.CRC_bad", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "", HFILL }},
2175 { "Transport Control", "dnp3.tr.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Tranport Layer Control Byte", HFILL }},
2178 { "Final", "dnp3.tr.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIN, "", HFILL }},
2181 { "First", "dnp3.tr.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_TR_FIR, "", HFILL }},
2184 { "Sequence", "dnp3.tr.seq", FT_UINT8, BASE_DEC, NULL, DNP3_TR_SEQ, "Frame Sequence Number", HFILL }},
2187 { "Application Control", "dnp3.al.ctl", FT_UINT8, BASE_HEX, NULL, 0x0, "Application Layer Control Byte", HFILL }},
2190 { "First", "dnp3.al.fir", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIR, "", HFILL }},
2193 { "Final", "dnp3.al.fin", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_FIN, "", HFILL }},
2196 { "Confirm", "dnp3.al.con", FT_BOOLEAN, 8, TFS(&flags_set_truth), DNP3_AL_CON, "", HFILL }},
2199 { "Sequence", "dnp3.al.seq", FT_UINT8, BASE_DEC, NULL, DNP3_AL_SEQ, "Frame Sequence Number", HFILL }},
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 }},
2206 { "Application Layer IIN bits", "dnp3.al.iin", FT_UINT16, BASE_DEC, NULL, 0x0, "Application Layer IIN", HFILL }},
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 }},
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 }},
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 }},
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 }},
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 }},
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 }},
2226 { &hf_dnp3_al_iin_dt,
2227 { "Device Trouble", "dnp3.al.iin.dt", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_DT, "", HFILL }},
2229 { &hf_dnp3_al_iin_rst,
2230 { "Device Restart", "dnp3.al.iin.rst", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_RST, "", HFILL }},
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 }},
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 }},
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 }},
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 }},
2244 { &hf_dnp3_al_iin_cc,
2245 { "Configuration Corrupt", "dnp3.al.iin.cc", FT_BOOLEAN, 16, TFS(&flags_set_truth), AL_IIN_CC, "", HFILL }},
2248 { "Object", "dnp3.al.obj", FT_UINT16, BASE_HEX, VALS(dnp3_al_obj_vals), 0x0, "Application Layer Object", HFILL }},
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 }},
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 }},
2256 { &hf_dnp3_al_range_start8,
2257 { "Start", "dnp3.al.range.start8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2259 { &hf_dnp3_al_range_stop8,
2260 { "Stop", "dnp3.al.range.stop8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2262 { &hf_dnp3_al_range_start16,
2263 { "Start", "dnp3.al.range.start16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2265 { &hf_dnp3_al_range_stop16,
2266 { "Stop", "dnp3.al.range.stop16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2268 { &hf_dnp3_al_range_start32,
2269 { "Start", "dnp3.al.range.start32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Start Index", HFILL }},
2271 { &hf_dnp3_al_range_stop32,
2272 { "Stop", "dnp3.al.range.stop32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Stop Index", HFILL }},
2274 { &hf_dnp3_al_range_abs8,
2275 { "Address", "dnp3.al.range.abs8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2277 { &hf_dnp3_al_range_abs16,
2278 { "Address", "dnp3.al.range.abs16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2280 { &hf_dnp3_al_range_abs32,
2281 { "Address", "dnp3.al.range.abs32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Absolute Address", HFILL }},
2283 { &hf_dnp3_al_range_quant8,
2284 { "Quantity", "dnp3.al.range.quant8", FT_UINT8, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2286 { &hf_dnp3_al_range_quant16,
2287 { "Quantity", "dnp3.al.range.quant16", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2289 { &hf_dnp3_al_range_quant32,
2290 { "Quantity", "dnp3.al.range.quant32", FT_UINT32, BASE_DEC, NULL, 0x0, "Object Quantity", HFILL }},
2292 { &hf_dnp3_al_ptnum,
2293 { "Object Point Number", "dnp3.al.ptnum", FT_UINT16, BASE_DEC, NULL, 0x0, "Object Point Number", HFILL }},
2295 { &hf_dnp3_al_biq_b0,
2296 { "Online", "dnp3.al.biq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG0, "", HFILL }},
2298 { &hf_dnp3_al_biq_b1,
2299 { "Restart", "dnp3.al.biq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG1, "", HFILL }},
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 }},
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 }},
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 }},
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 }},
2313 { &hf_dnp3_al_biq_b6,
2314 { "Reserved", "dnp3.al.biq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BI_FLAG6, "", HFILL }},
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 }},
2319 { &hf_dnp3_al_boq_b0,
2320 { "Online", "dnp3.al.boq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG0, "", HFILL }},
2322 { &hf_dnp3_al_boq_b1,
2323 { "Restart", "dnp3.al.boq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG1, "", HFILL }},
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 }},
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 }},
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 }},
2334 { &hf_dnp3_al_boq_b5,
2335 { "Reserved", "dnp3.al.boq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG5, "", HFILL }},
2337 { &hf_dnp3_al_boq_b6,
2338 { "Reserved", "dnp3.al.boq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_BO_FLAG6, "", HFILL }},
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 }},
2343 { &hf_dnp3_al_ctrq_b0,
2344 { "Online", "dnp3.al.ctrq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG0, "", HFILL }},
2346 { &hf_dnp3_al_ctrq_b1,
2347 { "Restart", "dnp3.al.ctrq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG1, "", HFILL }},
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 }},
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 }},
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 }},
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 }},
2361 { &hf_dnp3_al_ctrq_b6,
2362 { "Reserved", "dnp3.al.ctrq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG6, "", HFILL }},
2364 { &hf_dnp3_al_ctrq_b7,
2365 { "Reserved", "dnp3.al.ctrq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_CTR_FLAG7, "", HFILL }},
2367 { &hf_dnp3_al_aiq_b0,
2368 { "Online", "dnp3.al.aiq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG0, "", HFILL }},
2370 { &hf_dnp3_al_aiq_b1,
2371 { "Restart", "dnp3.al.aiq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG1, "", HFILL }},
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 }},
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 }},
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 }},
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 }},
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 }},
2388 { &hf_dnp3_al_aiq_b7,
2389 { "Reserved", "dnp3.al.aiq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AI_FLAG7, "", HFILL }},
2391 { &hf_dnp3_al_aoq_b0,
2392 { "Online", "dnp3.al.aoq.b0", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG0, "", HFILL }},
2394 { &hf_dnp3_al_aoq_b1,
2395 { "Restart", "dnp3.al.aoq.b1", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG1, "", HFILL }},
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 }},
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 }},
2403 { &hf_dnp3_al_aoq_b4,
2404 { "Reserved", "dnp3.al.aoq.b4", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG4, "", HFILL }},
2406 { &hf_dnp3_al_aoq_b5,
2407 { "Reserved", "dnp3.al.aoq.b5", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG5, "", HFILL }},
2409 { &hf_dnp3_al_aoq_b6,
2410 { "Reserved", "dnp3.al.aoq.b6", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG6, "", HFILL }},
2412 { &hf_dnp3_al_aoq_b7,
2413 { "Reserved", "dnp3.al.aoq.b7", FT_BOOLEAN, 8, TFS(&flags_set_truth), AL_OBJ_AO_FLAG7, "", HFILL }},
2416 { "DNP 3.0 AL Fragment", "al.fragment", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragment", HFILL }},
2419 { "DNP 3.0 AL Fragments", "al.fragments", FT_NONE, BASE_NONE, NULL, 0x0, "DNP 3.0 Application Layer Fragments", HFILL }},
2421 { &hf_fragment_overlap,
2422 { "Fragment overlap", "al.fragment.overlap", FT_BOOLEAN, BASE_NONE, NULL, 0x0, "Fragment overlaps with other fragments", HFILL }},
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 }},
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 }},
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 }},
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 }}
2444 /* Setup protocol subtree array */
2445 static gint *ett[] = {
2455 &ett_dnp3_al_obj_qualifier,
2456 &ett_dnp3_al_obj_range,
2457 &ett_dnp3_al_objdet,
2458 &ett_dnp3_al_obj_quality,
2463 /* Register the protocol name and description */
2464 proto_dnp3 = proto_register_protocol("Distributed Network Protocol 3.0",
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));
2471 al_defragment_init();
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.
2480 proto_reg_handoff_dnp3(void)
2482 dissector_handle_t dnp3_handle;
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);